vector<Feature*> ShapeFile::addFeatures(GraphicElement* pGraphicElement, GraphicObject* pObject, RasterElement* pGeoref, string& message) { vector<Feature*> features; message.clear(); if (pGraphicElement == NULL) { message = "Features cannot be added because the data element is invalid!"; return features; } if (pGeoref == NULL || !pGeoref->isGeoreferenced()) { message = "No georeferencing information can be found."; return features; } // Do not allow erase or toggle objects if (pObject != NULL) { if (pObject->getDrawMode() != DRAW) { message = "The " + pObject->getName() + " object is an erase or toggle object, so a feature " "will not be added."; return features; } } // Get the objects list<GraphicObject*> objects; if (pObject != NULL) { objects.push_back(pObject); } else { GraphicGroup* pGroup = pGraphicElement->getGroup(); if (pGroup != NULL) { // If the element is displayed in an annotation layer, use the selected objects AnnotationLayer* pAnnotationLayer = dynamic_cast<AnnotationLayer*>(pGroup->getLayer()); if (pAnnotationLayer != NULL) { pAnnotationLayer->getSelectedObjects(objects); } if (objects.empty()) { objects = pGroup->getObjects(); } } } // Create the features string elementName = pGraphicElement->getName(); const DynamicObject* pMetadata = getSourceMetadata(*pGraphicElement); switch (mShape) { case ShapefileTypes::POINT_SHAPE: { if (dynamic_cast<AnnotationElement*>(pGraphicElement) != NULL) { if (objects.empty()) { message = "Cannot create a shape file from an empty element."; return features; } // Get names of attributes which should be copied/exported. vector<string> attrNames; const DynamicObject* pAttributeMetadata = getSourceAttributeMetadata(*pGraphicElement); if (pAttributeMetadata != NULL) { pAttributeMetadata->getAttributeNames(attrNames); } for (list<GraphicObject*>::const_iterator it = objects.begin(); it != objects.end(); ++it) { GraphicObject* pCurrentObject = *it; if (pCurrentObject != NULL) { // Do not allow erase or toggle objects if (pCurrentObject->getDrawMode() != DRAW) { continue; } string objectName = pCurrentObject->getName(); vector<LocationType> vertices; pCurrentObject->getRotatedExtents(vertices); // Each point created from this object uses the same metadata. int idx = -1; if (pMetadata != NULL) { idx = getAttributeIndex(*pCurrentObject, *pMetadata); } LocationType pixel; for (vector<LocationType>::const_iterator verticesIter = vertices.begin(); verticesIter != vertices.end(); ++verticesIter) { // Add the feature SessionItem* pSessionItem = pGraphicElement; if (pObject != NULL) { pSessionItem = pObject; } Feature* pFeature = new Feature(pSessionItem); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); // Fields pFeature->addField("Name", string()); if (!elementName.empty()) { if (pObject != NULL) { pFeature->setFieldValue("Name", elementName + ": " + pObject->getName()); } else { pFeature->setFieldValue("Name", elementName + ": " + objectName); } } pixel.mX = verticesIter->mX + 0.5; pixel.mY = verticesIter->mY + 0.5; QString pixelName = "(" + QString::number(verticesIter->mX + 1) + ", " + QString::number(verticesIter->mY + 1) + ")"; pFeature->setFieldValue("Pixel", pixelName.toStdString()); if (idx > -1 && pAttributeMetadata != NULL) { copyMetadata(attrNames, idx, *pAttributeMetadata, *pFeature); } LocationType geo = pGeoref->convertPixelToGeocoord(*verticesIter); pFeature->addVertex(geo.mY, geo.mX); } } } } else { // The BitMaskIterator does not support negative extents and // the BitMask does not correctly handle the outside flag so // the BitMaskIterator is used for cases when the outside flag is true and // the BitMask is used for cases when the outside flag is false AoiElement* pAoiElement = dynamic_cast<AoiElement*>(pGraphicElement); VERIFYRV(pAoiElement != NULL, features); const BitMask* pMask = pAoiElement->getSelectedPoints(); if (pObject != NULL) { pMask = pObject->getPixels(); if (pMask == NULL) { message = "The " + pObject->getName() + " object cannot be represented by the " + StringUtilities::toDisplayString(mShape) + " shape type, so a feature will not be added."; return features; } } if (pMask != NULL) { BitMaskIterator maskIt(pMask, pGeoref); if ((maskIt.getCount() > 0 && pMask->isOutsideSelected() == true) || (pMask->getCount() > 0 && pMask->isOutsideSelected() == false)) { // Add features for each selected pixel int startColumn = 0; int endColumn = 0; int startRow = 0; int endRow = 0; if (pMask->isOutsideSelected() == true) { maskIt.getBoundingBox(startColumn, startRow, endColumn, endRow); } else { pMask->getBoundingBox(startColumn, startRow, endColumn, endRow); } LocationType pixel; for (int i = startColumn; i <= endColumn; i++) { for (int j = startRow; j <= endRow; j++) { if ((maskIt.getPixel(i, j) && pMask->isOutsideSelected() == true) || (pMask->getPixel(i, j) && pMask->isOutsideSelected() == false)) { // Add the feature SessionItem* pSessionItem = pGraphicElement; if (pObject != NULL) { pSessionItem = pObject; } Feature* pFeature = new Feature(pSessionItem); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); pixel.mX = i + 0.5; pixel.mY = j + 0.5; // Fields pFeature->addField("Name", string()); pFeature->addField("Pixel", string()); if (!elementName.empty()) { if (pObject != NULL) { pFeature->setFieldValue("Name", elementName + ": " + pObject->getName()); } else { pFeature->setFieldValue("Name", elementName); } } QString pixelName = "(" + QString::number(i + 1) + ", " + QString::number(j + 1) + ")"; pFeature->setFieldValue("Pixel", pixelName.toStdString()); // Vertex pixel = pGeoref->convertPixelToGeocoord(pixel); pFeature->addVertex(pixel.mY, pixel.mX); // Longitude as x-coord } } } } } } } break; case ShapefileTypes::POLYLINE_SHAPE: { if (objects.empty()) { message = "Cannot create a shape file from an empty element."; return features; } // Get names of attributes which should be copied/exported. vector<string> attrNames; const DynamicObject* pAttributeMetadata = getSourceAttributeMetadata(*pGraphicElement); if (pAttributeMetadata != NULL) { pAttributeMetadata->getAttributeNames(attrNames); } for (list<GraphicObject*>::const_iterator it = objects.begin(); it != objects.end(); ++it) { GraphicObject* pCurrentObject = *it; if (pCurrentObject != NULL) { GraphicObjectType objectType = pCurrentObject->getGraphicObjectType(); if ((objectType == LINE_OBJECT) || (objectType == POLYLINE_OBJECT) || (objectType == HLINE_OBJECT) || (objectType == VLINE_OBJECT)) { // Do not allow erase or toggle objects if (pCurrentObject->getDrawMode() != DRAW) { continue; } string objectName = pCurrentObject->getName(); vector<LocationType> vertices; pCurrentObject->getRotatedExtents(vertices); if (vertices.empty() == false) { Feature* pFeature = new Feature(pCurrentObject); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); pFeature->addField("Name", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName + ": " + objectName); } // Copy attributes. if ((pMetadata != NULL) && (pAttributeMetadata != NULL)) { int idx = getAttributeIndex(*pCurrentObject, *pMetadata); if (idx > -1) { copyMetadata(attrNames, idx, *pAttributeMetadata, *pFeature); } } for (vector<LocationType>::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter) { LocationType geo = pGeoref->convertPixelToGeocoord(*iter); pFeature->addVertex(geo.mY, geo.mX); } } } } } } break; case ShapefileTypes::POLYGON_SHAPE: { if (objects.empty()) { message = "Cannot create a shape file from an empty element."; return features; } // Get names of attributes which should be copied/exported. vector<string> attrNames; const DynamicObject* pAttributeMetadata = getSourceAttributeMetadata(*pGraphicElement); if (pAttributeMetadata != NULL) { pAttributeMetadata->getAttributeNames(attrNames); } for (list<GraphicObject*>::const_iterator it = objects.begin(); it != objects.end(); ++it) { GraphicObject* pCurrentObject = *it; if (pCurrentObject != NULL) { GraphicObjectType objectType = pCurrentObject->getGraphicObjectType(); if ((objectType == RECTANGLE_OBJECT) || (objectType == ROUNDEDRECTANGLE_OBJECT) || (objectType == ELLIPSE_OBJECT) || (objectType == TRIANGLE_OBJECT) || (objectType == POLYGON_OBJECT) || (objectType == ARC_OBJECT)) { // Do not allow erase or toggle objects if (pCurrentObject->getDrawMode() != DRAW) { continue; } string objectName = pCurrentObject->getName(); vector<LocationType> vertices; pCurrentObject->getRotatedExtents(vertices); if (vertices.empty() == false) { // To represent non-polygon objects as polygons, add the first vertex as the last vertex if (objectType != POLYGON_OBJECT) { vertices.push_back(vertices.front()); } Feature* pFeature = new Feature(pCurrentObject); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); pFeature->addField("Name", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName + ": " + objectName); } // Copy attributes. if ((pMetadata != NULL) && (pAttributeMetadata != NULL)) { int idx = getAttributeIndex(*pCurrentObject, *pMetadata); if (idx > -1) { copyMetadata(attrNames, idx, *pAttributeMetadata, *pFeature); } } for (vector<LocationType>::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter) { LocationType geo = pGeoref->convertPixelToGeocoord(*iter); pFeature->addVertex(geo.mY, geo.mX); } } } } } } break; case ShapefileTypes::MULTIPOINT_SHAPE: { if (dynamic_cast<AnnotationElement*>(pGraphicElement) != NULL) { if (objects.empty()) { message = "Cannot create a shape file from an empty element."; return features; } // Get names of attributes which should be copied/exported. vector<string> attrNames; const DynamicObject* pAttributeMetadata = getSourceAttributeMetadata(*pGraphicElement); if (pAttributeMetadata != NULL) { pAttributeMetadata->getAttributeNames(attrNames); } for (list<GraphicObject*>::const_iterator it = objects.begin(); it != objects.end(); ++it) { GraphicObject* pCurrentObject = *it; if (pCurrentObject != NULL) { // Do not allow erase or toggle objects if (pCurrentObject->getDrawMode() != DRAW) { continue; } Feature* pFeature = new Feature(pGraphicElement); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); // Fields pFeature->addField("Name", string()); if (!elementName.empty()) { if (pObject != NULL) { pFeature->setFieldValue("Name", elementName + ": " + pObject->getName()); } else { pFeature->setFieldValue("Name", elementName); } } // Copy attributes. if ((pMetadata != NULL) && (pAttributeMetadata != NULL)) { int idx = getAttributeIndex(*pCurrentObject, *pMetadata); if (idx > -1) { copyMetadata(attrNames, idx, *pAttributeMetadata, *pFeature); } } vector<LocationType> vertices; pCurrentObject->getRotatedExtents(vertices); for (vector<LocationType>::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter) { LocationType geo = pGeoref->convertPixelToGeocoord(*iter); pFeature->addVertex(geo.mY, geo.mX); } } } } else { // The BitMaskIterator does not support negative extents and // the BitMask does not correctly handle the outside flag so // the BitMaskIterator is used for cases when the outside flag is true and // the BitMask is used for cases when the outside flag is false AoiElement* pAoiElement = dynamic_cast<AoiElement*>(pGraphicElement); VERIFYRV(pAoiElement != NULL, features); const BitMask* pMask = pAoiElement->getSelectedPoints(); if (pObject != NULL) { pMask = pObject->getPixels(); if (pMask == NULL) { message = "The " + pObject->getName() + " object cannot be represented by the " + StringUtilities::toDisplayString(mShape) + " shape type, so a feature will not be added."; return features; } } if (pMask != NULL) { BitMaskIterator maskIt(pMask, pGeoref); if ((maskIt.getCount() > 0 && pMask->isOutsideSelected() == true) || (pMask->getCount() > 0 && pMask->isOutsideSelected() == false)) { // Add the feature SessionItem* pSessionItem = pGraphicElement; if (pObject != NULL) { pSessionItem = pObject; } Feature* pFeature = new Feature(pSessionItem); features.push_back(pFeature); mFeatures.push_back(pFeature); VERIFYNR(pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified))); // Fields pFeature->addField("Name", string()); if (!elementName.empty()) { if (pObject != NULL) { pFeature->setFieldValue("Name", elementName + ": " + pObject->getName()); } else { pFeature->setFieldValue("Name", elementName); } } // Vertices int startColumn = 0; int endColumn = 0; int startRow = 0; int endRow = 0; if (pMask->isOutsideSelected() == true) { maskIt.getBoundingBox(startColumn, startRow, endColumn, endRow); } else { pMask->getBoundingBox(startColumn, startRow, endColumn, endRow); } LocationType pixel; for (int i = startColumn; i <= endColumn; i++) { for (int j = startRow; j <= endRow; j++) { if ((maskIt.getPixel(i, j) && pMask->isOutsideSelected() == true) || (pMask->getPixel(i, j) && pMask->isOutsideSelected() == false)) { pixel.mX = i + 0.5; pixel.mY = j + 0.5; pixel = pGeoref->convertPixelToGeocoord(pixel); pFeature->addVertex(pixel.mY, pixel.mX); // Longitude as x-coord } } } } } } } break; default: message = "Shape type not recognized."; return features; } if (features.empty()) { message = elementName + " has no objects that can be represented with the " + StringUtilities::toDisplayString(mShape) + " shape type, so no features can be added."; } return features; }
bool ConnectedComponents::execute(PlugInArgList* pInArgList, PlugInArgList* pOutArgList) { if (pInArgList == NULL) { return false; } mProgress = ProgressTracker(pInArgList->getPlugInArgValue<Progress>(Executable::ProgressArg()), "Labeling connected components", "app", "{aa2169d0-9c0a-4d41-9f1d-9a9e83ecf32b}"); mpView = pInArgList->getPlugInArgValue<SpatialDataView>(Executable::ViewArg()); AoiElement* pAoi = pInArgList->getPlugInArgValue<AoiElement>("AOI"); if (pAoi == NULL && mpView != NULL) { Layer* pLayer = mpView->getActiveLayer(); if (pLayer == NULL) { std::vector<Layer*> layers; mpView->getLayerList()->getLayers(AOI_LAYER, layers); if (!layers.empty()) { pLayer = layers.front(); } } pAoi = pLayer == NULL ? NULL : dynamic_cast<AoiElement*>(pLayer->getDataElement()); } const BitMask* mpBitmask = (pAoi == NULL) ? NULL : pAoi->getSelectedPoints(); if (mpBitmask == NULL) { mProgress.report("Must specify an AOI.", 0, ERRORS, true); return false; } if (mpBitmask->isOutsideSelected()) { mProgress.report("Infinite AOIs can not be processed.", 0, ERRORS, true); return false; } // Get the extents and create the output element int x1 = 0; int x2 = 0; int y1 = 0; int y2 = 0; mpBitmask->getMinimalBoundingBox(x1, y1, x2, y2); if (x1 > x2) { std::swap(x1, x2); } if (y1 > y2) { std::swap(y1, y2); } if (x1 < 0 || y1 < 0) { mProgress.report("Negative pixel locations are not supported and will be ignored.", 1, WARNING, true); x1 = std::max(x1, 0); y1 = std::max(y1, 0); x2 = std::max(x2, 0); y2 = std::max(y2, 0); } // Include a 1 pixel border so we include the edge pixels x1--; x2++; y1--; y2++; unsigned int width = x2 - x1 + 1; unsigned int height = y2 - y1 + 1; mXOffset = x1; mYOffset = y1; mpLabels = static_cast<RasterElement*>( Service<ModelServices>()->getElement("Blobs", TypeConverter::toString<RasterElement>(), pAoi)); if (mpLabels != NULL) { if (!isBatch()) { Service<DesktopServices>()->showSuppressibleMsgDlg( getName(), "The \"Blobs\" element exists and will be deleted.", MESSAGE_INFO, "ConnectedComponents::DeleteExisting"); } Service<ModelServices>()->destroyElement(mpLabels); mpLabels = NULL; } mpLabels = RasterUtilities::createRasterElement("Blobs", height, width, INT2UBYTES, true, pAoi); if (mpLabels == NULL) { mProgress.report("Unable to create label element.", 0, ERRORS, true); return false; } ModelResource<RasterElement> pLabels(mpLabels); try { cv::Mat data(height, width, CV_8UC1, cv::Scalar(0)); for (unsigned int y = 0; y < height; ++y) { mProgress.report("Reading AOI data", 10 * y / height, NORMAL); for (unsigned int x = 0; x < width; ++x) { if (mpBitmask->getPixel(x + mXOffset, y + mYOffset)) { data.at<unsigned char>(y, x) = 255; } } } mProgress.report("Finding contours", 15, NORMAL); std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(data, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE); cv::Mat labels(height, width, CV_16UC1, mpLabels->getRawData()); mProgress.report("Filling blobs", 50, NORMAL); unsigned short lastLabel = 0; fillContours(labels, contours, hierarchy, lastLabel, 0, 0); // create a pseudocolor layer for display mProgress.report("Displaying results", 90, NORMAL); mpLabels->updateData(); if (!createPseudocolor(lastLabel)) { mProgress.report("Unable to create blob layer", 0, ERRORS, true); return false; } // add blob count to the metadata DynamicObject* pMeta = pLabels->getMetadata(); VERIFY(pMeta); unsigned int numBlobs = static_cast<unsigned int>(lastLabel); pMeta->setAttribute("BlobCount", numBlobs); if (numBlobs == 0 && !isBatch()) { // Inform the user that there were no blobs so they don't think there was an // error running the algorithm. No need to do this in batch since this is // represented in the metadata already. mProgress.report("No blobs were found.", 95, WARNING); } // update the output arg list if (pOutArgList != NULL) { pOutArgList->setPlugInArgValue("Blobs", pLabels.get()); pOutArgList->setPlugInArgValue("Number of Blobs", &numBlobs); } } catch(const cv::Exception& exc) { mProgress.report(exc.what(), 0, ERRORS, true); return false; } pLabels.release(); mProgress.report("Labeling connected components", 100, NORMAL); mProgress.upALevel(); return true; }
vector<Feature*> ShapeFile::addFeatures(DataElement* pElement, RasterElement* pGeoref, string& message) { vector<Feature*> features; message.clear(); if (pElement == NULL) { message = "Features cannot be added because the data element is invalid!"; return features; } if (pGeoref == NULL || !pGeoref->isGeoreferenced()) { message = "No georeferencing information can be found."; return features; } // Create the features string elementName = pElement->getName(); AoiElement* pAoi = dynamic_cast<AoiElement*>(pElement); if (pAoi != NULL) { if (mShape == POINT_SHAPE) { // The BitMaskIterator does not support negative extents and // the BitMask does not correctly handle the outside flag so // the BitMaskIterator is used for cases when the outside flag is true and // the BitMask is used for cases when the outside flag is false const BitMask* pMask = pAoi->getSelectedPoints(); if (pMask != NULL) { BitMaskIterator maskIt(pMask, pGeoref); if ((maskIt.getCount() > 0 && pMask->isOutsideSelected() == true) || (pMask->getCount() > 0 && pMask->isOutsideSelected() == false)) { // Add features for each selected pixel int startColumn = 0; int endColumn = 0; int startRow = 0; int endRow = 0; if (pMask->isOutsideSelected() == true) { maskIt.getBoundingBox(startColumn, startRow, endColumn, endRow); } else { pMask->getBoundingBox(startColumn, startRow, endColumn, endRow); } LocationType pixel; for (int i = startColumn; i <= endColumn; i++) { for (int j = startRow; j <= endRow; j++) { if ((maskIt.getPixel(i, j) && pMask->isOutsideSelected() == true) || (pMask->getPixel(i, j) && pMask->isOutsideSelected() == false)) { // Add the feature Feature* pFeature = new Feature(mShape); if (pFeature != NULL) { features.push_back(pFeature); mFeatures.push_back(pFeature); pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified)); pixel.mX = i + 0.5; pixel.mY = j + 0.5; // Fields pFeature->addField("Name", string()); pFeature->addField("Pixel", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName); } string pixelName = ""; if (!pixelName.empty()) { pFeature->setFieldValue("Pixel", pixelName); } // Vertex pixel = pGeoref->convertPixelToGeocoord(pixel); pFeature->addVertex(pixel.mY, pixel.mX); // Longitude as x-coord } } } } } } } else if (mShape == POLYLINE_SHAPE) { GraphicGroup* pGroup = pAoi->getGroup(); if (pGroup != NULL) { const list<GraphicObject*>& objects = pGroup->getObjects(); if (objects.empty()) { message = "Error Shape File 101: Cannot create a shape file from an empty AOI."; return features; } else if (objects.size() != 1) { message = "Error Shape File 102: Can only create a polyline shape file " "from an AOI which contains a single object."; return features; } const PolylineObject* pObj = dynamic_cast<const PolylineObject*>(objects.front()); if (pObj == NULL || pObj->getGraphicObjectType() != POLYLINE_OBJECT) { message = "Error Shape File 103: Can only create a polyline shape file " "from an AOI which contains a single polyline."; return features; } const std::vector<LocationType>& vertices = pObj->getVertices(); Feature* pFeature = new Feature(mShape); if (pFeature != NULL) { features.push_back(pFeature); mFeatures.push_back(pFeature); pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified)); pFeature->addField("Name", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName); } for (vector<LocationType>::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter) { LocationType geo = pGeoref->convertPixelToGeocoord(*iter); pFeature->addVertex(geo.mY, geo.mX); } } } } else if (mShape == POLYGON_SHAPE) { GraphicGroup* pGroup = pAoi->getGroup(); if (pGroup != NULL) { const list<GraphicObject*>& objects = pGroup->getObjects(); if (objects.empty()) { message = "Error Shape File 101: Cannot create a shape file from an empty AOI."; return features; } else if (objects.size() != 1) { message = "Error Shape File 102: Can only create a polygon shape file " "from an AOI which contains a single object."; return features; } const PolygonObject* pObj = dynamic_cast<const PolygonObject*>(objects.front()); if (pObj == NULL || pObj->getGraphicObjectType() != POLYGON_OBJECT) { message = "Error Shape File 103: Can only create a polygon shape file " "from an AOI which contains a single polygon."; return features; } const std::vector<LocationType>& vertices = pObj->getVertices(); Feature* pFeature = new Feature(mShape); if (pFeature != NULL) { features.push_back(pFeature); mFeatures.push_back(pFeature); pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified)); pFeature->addField("Name", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName); } for (vector<LocationType>::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter) { LocationType geo = pGeoref->convertPixelToGeocoord(*iter); pFeature->addVertex(geo.mY, geo.mX); } } } } else if (mShape == MULTIPOINT_SHAPE) { // The BitMaskIterator does not support negative extents and // the BitMask does not correctly handle the outside flag so // the BitMaskIterator is used for cases when the outside flag is true and // the BitMask is used for cases when the outside flag is false const BitMask* pMask = pAoi->getSelectedPoints(); if (pMask != NULL) { BitMaskIterator maskIt(pMask, pGeoref); if ((maskIt.getCount() > 0 && pMask->isOutsideSelected() == true) || (pMask->getCount() > 0 && pMask->isOutsideSelected() == false)) { // Add the feature Feature* pFeature = new Feature(mShape); if (pFeature != NULL) { features.push_back(pFeature); mFeatures.push_back(pFeature); pFeature->attach(SIGNAL_NAME(Subject, Modified), Slot(this, &ShapeFile::shapeModified)); // Fields pFeature->addField("Name", string()); if (!elementName.empty()) { pFeature->setFieldValue("Name", elementName); } // Vertices int startColumn = 0; int endColumn = 0; int startRow = 0; int endRow = 0; if (pMask->isOutsideSelected() == true) { maskIt.getBoundingBox(startColumn, startRow, endColumn, endRow); } else { pMask->getBoundingBox(startColumn, startRow, endColumn, endRow); } LocationType pixel; for (int i = startColumn; i <= endColumn; i++) { for (int j = startRow; j <= endRow; j++) { if ((maskIt.getPixel(i, j) && pMask->isOutsideSelected() == true) || (pMask->getPixel(i, j) && pMask->isOutsideSelected() == false)) { pixel.mX = i + 0.5; pixel.mY = j + 0.5; pixel = pGeoref->convertPixelToGeocoord(pixel); pFeature->addVertex(pixel.mY, pixel.mX); // Longitude as x-coord } } } } } } } else { message = "Shape type not recognized."; return features; } } if (features.empty()) { message = elementName + " has no selected points, so no features can be added."; } return features; }