Exemple #1
0
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;
}
Exemple #2
0
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;
}