Пример #1
0
string TextObjectImp::getSubstitutedText()
{
   string txt = getText();

   DataElement* pParent = getElement();
   pParent = (pParent == NULL) ? NULL : pParent->getParent();
   DataDescriptor* pParentDesc = (pParent == NULL) ? NULL : pParent->getDataDescriptor();
   DynamicObject* pParentMetadata = (pParentDesc == NULL) ? NULL : pParentDesc->getMetadata();
   for (int i = 0; i < 50; ++i)
   {
      //each pass does replacement of $M(a) currently in the string.
      //do 50 passes to perform sub-expansion at most fifty times, ie. prevent infinite loop
      //for non-terminating recursive expansion
      string::size_type pos = txt.find("$");
      while (pos != string::npos)
      {
         if (pos + 1 >= txt.size())
         {
            break;
         }
         string type = txt.substr(pos+1, 1);
         if (type != "$") //ie. not $$, the escape sequence so continue
         {
            bool replaced = false;
            if (pos+4 < txt.size()) //ie. $M(a)
            {
               if (txt[pos+2] == '(')
               {
                  string::size_type closeParen = txt.find(')', pos+2);
                  if (closeParen == string::npos)
                  {
                     closeParen = txt.size();
                  }
                  string variableName = txt.substr(pos+3, closeParen-(pos+2)-1);
                  string replacementString;
                  if (type == "M" || type == "S")
                  {
                     DataElement* pElmnt = pParent;
                     DynamicObject* pMetadata = pParentMetadata;
                     if (variableName.substr(0, 2) == "//")
                     {
                        string::size_type endNamePos = variableName.find("//", 2);
                        if (endNamePos != string::npos)
                        {
                           string elementName = variableName.substr(2, endNamePos - 2);
                           variableName = variableName.substr(endNamePos + 2);
                           if (!variableName.empty())
                           {
                              if (elementName[0] == '[' && elementName[elementName.size() - 1] == ']')
                              {
                                 elementName = elementName.substr(1, elementName.size() - 2);
                                 std::list<GraphicObject*> objects;
                                 getLayer()->getObjects(VIEW_OBJECT, objects);
                                 for (std::list<GraphicObject*>::iterator object = objects.begin();
                                    object != objects.end(); ++object)
                                 {
                                    GraphicObject* pObj = *object;
                                    if (pObj->getName() == elementName)
                                    {
                                       SpatialDataView* pSdv = dynamic_cast<SpatialDataView*>(pObj->getObjectView());
                                       if (pSdv != NULL)
                                       {
                                          pElmnt = pSdv->getLayerList()->getPrimaryRasterElement();
                                          DataDescriptor* pDesc =
                                             (pElmnt == NULL) ? NULL : pElmnt->getDataDescriptor();
                                          pMetadata = (pDesc == NULL) ? NULL : pDesc->getMetadata();
                                       }
                                       break;
                                    }
                                 }
                              }
                              else
                              {
                                 pElmnt = Service<ModelServices>()->getElement(elementName,
                                    TypeConverter::toString<RasterElement>(), NULL);
                                 DataDescriptor* pDesc = (pElmnt == NULL) ? NULL : pElmnt->getDataDescriptor();
                                 pMetadata = (pDesc == NULL) ? NULL : pDesc->getMetadata();
                              }
                           }
                           else
                           {
                              pElmnt = NULL;
                              pMetadata = NULL;
                           }
                        }
                     }
                     bool success = false;
                     if (type == "M" && pMetadata != NULL)
                     {
                        DataVariant var = pMetadata->getAttributeByPath(variableName);
                        if (var.isValid())
                        {
                           DataVariant::Status status;
                           replacementString = var.toDisplayString(&status);
                           success = (status == DataVariant::SUCCESS);
                           if (mMetadataObjects.find(pMetadata) == mMetadataObjects.end())
                           {
                              mMetadataObjects.insert(make_pair(pMetadata, new AttachmentPtr<DynamicObject>(
                                 pMetadata, SIGNAL_NAME(Subject, Modified),
                                 Slot(this, &TextObjectImp::invalidateTexture))));
                           }
                        }
                     }
                     else if (type == "S" && pElmnt != NULL && variableName == "CLASSIFICATION")
                     {
                        Classification* pClass = pElmnt->getDataDescriptor()->getClassification();
                        pClass->getClassificationText(replacementString);
                        success = true;
                        if (mClassificationObjects.find(pClass) == mClassificationObjects.end())
                        {
                           mClassificationObjects.insert(make_pair(pClass, new AttachmentPtr<Classification>(
                              pClass, SIGNAL_NAME(Subject, Modified),
                              Slot(this, &TextObjectImp::invalidateTexture))));
                        }
                     }
                     if (!success)
                     {
                        replacementString = "Error!";
                     }
                     replaced = true;
                  }
                  if (replaced)
                  {
                     txt.replace(pos, closeParen-pos+1, replacementString);
                     pos = txt.find("$", pos+replacementString.size());
                  }
               }
            }
            if (!replaced)
            {
               pos = txt.find("$", pos+1);
            }
         }
         else
         {
            pos = txt.find("$", pos+2);
         }
      }
   }
   string::size_type pos = txt.find("$$");
   while (pos != string::npos)
   {
      txt.replace(pos, 2, "$");
      pos = txt.find("$$");
   }

   return txt;
}
Пример #2
0
void Kml::generatePolygonalLayer(const GraphicLayer* pGraphicLayer, bool visible, int order, const Layer* pGeoLayer)
{
   VERIFYNRV(pGeoLayer != NULL);
   if (pGraphicLayer == NULL)
   {
      return;
   }
   RasterElement* pGeoElement = dynamic_cast<RasterElement*>(pGeoLayer->getDataElement());
   mXml.pushAddPoint(mXml.addElement("Folder"));
   string name = pGraphicLayer->getDisplayName();
   if (name.empty())
   {
      name = pGraphicLayer->getName();
   }
   mXml.addText(name, mXml.addElement("name"));
   mXml.addText(pGraphicLayer->getDisplayText(), mXml.addElement("description"));
   mXml.addText(visible ? "1" : "0", mXml.addElement("visibility"));
   list<GraphicObject*> objects;
   pGraphicLayer->getObjects(objects);
   for (list<GraphicObject*>::const_iterator object = objects.begin(); object != objects.end(); ++object)
   {
      GraphicObject* pObject = *object;
      if (pObject == NULL)
      {
         continue;
      }
      mXml.pushAddPoint(mXml.addElement("Placemark"));
      mXml.addText(pObject->getName(), mXml.addElement("name"));
      mXml.addText(pObject->isVisible() ? "1" : "0", mXml.addElement("visibility"));
      mXml.pushAddPoint(mXml.addElement("Style"));
      mXml.pushAddPoint(mXml.addElement("PolyStyle"));
      ColorType c = pObject->getFillColor();
      QChar fc('0');
      mXml.addText(QString("%1%2%3%4").arg(c.mAlpha, 2, 16, fc).arg(c.mBlue, 2, 16, fc).arg(
         c.mGreen, 2, 16, fc).arg(c.mRed, 2, 16, fc).toAscii().data(),
         mXml.addElement("color"));
      mXml.addText(pObject->getLineState() ? "1" : "0", mXml.addElement("outline"));
      mXml.addText(pObject->getFillState() ? "1" : "0", mXml.addElement("fill"));
      mXml.popAddPoint(); // PolyStyle
      mXml.pushAddPoint(mXml.addElement("LineStyle"));
      c = pObject->getLineColor();
      mXml.addText(QString("%1%2%3%4").arg(c.mAlpha, 2, 16, fc).arg(c.mBlue, 2, 16, fc).arg(
         c.mGreen, 2, 16, fc).arg(c.mRed, 2, 16, fc).toAscii().data(),
         mXml.addElement("color"));
      mXml.addText(StringUtilities::toXmlString(pObject->getLineWidth()), mXml.addElement("width"));
      mXml.popAddPoint(); // LineStyle
      mXml.popAddPoint(); // Style
      switch (pObject->getGraphicObjectType())
      {
      case MULTIPOINT_OBJECT:
         {
            mXml.pushAddPoint(mXml.addElement("MultiGeometry"));
            vector<LocationType> vertices = static_cast<MultipointObject*>(pObject)->getVertices();
            for (vector<LocationType>::const_iterator vertex = vertices.begin(); vertex != vertices.end(); ++vertex)
            {
               mXml.pushAddPoint(mXml.addElement("Point"));
               mXml.addText(QString::number(order).toAscii().data(), mXml.addElement("drawOrder"));
               LocationType geo = pGeoElement->convertPixelToGeocoord(*vertex);
               mXml.addText(QString("%1,%2").arg(geo.mY, 0, 'f', 10).arg(geo.mX, 0, 'f', 10).toAscii().data(),
                  mXml.addElement("coordinates"));
               mXml.popAddPoint(); // Point
            }
            mXml.popAddPoint();
            break;
         }
      case LINE_OBJECT:
      case POLYLINE_OBJECT:
      case HLINE_OBJECT:
      case VLINE_OBJECT:
      case ROW_OBJECT:
      case COLUMN_OBJECT:
         {
            mXml.pushAddPoint(mXml.addElement("LineString"));
            mXml.addText(QString::number(order).toAscii().data(), mXml.addElement("drawOrder"));
            mXml.addText("1", mXml.addElement("tessellate"));
            QStringList coords;
            vector<LocationType> vertices;
            if (pObject->getGraphicObjectType() == POLYLINE_OBJECT)
            {
               vertices = static_cast<PolylineObject*>(pObject)->getVertices();
            }
            else
            {
               LocationType ll = pObject->getLlCorner();
               LocationType ur = pObject->getUrCorner();
               vertices.push_back(ll);
               vertices.push_back(ur);
            }
            for (vector<LocationType>::const_iterator vertex = vertices.begin(); vertex != vertices.end(); ++vertex)
            {
               LocationType geo = pGeoElement->convertPixelToGeocoord(*vertex);
               coords << QString("%1,%2").arg(geo.mY, 0, 'f', 10).arg(geo.mX, 0, 'f', 10);
            }
            mXml.addText(coords.join(" ").toAscii().data(), mXml.addElement("coordinates"));
            mXml.popAddPoint(); // LineString
            break;
         }
      case RECTANGLE_OBJECT:
      case TRIANGLE_OBJECT:
      case POLYGON_OBJECT:
         {
            mXml.pushAddPoint(mXml.addElement("Polygon"));
            mXml.addText(QString::number(order).toAscii().data(), mXml.addElement("drawOrder"));
            mXml.addText("1", mXml.addElement("tessellate"));
            mXml.pushAddPoint(mXml.addElement("LinearRing", mXml.addElement("outerBoundaryIs")));
            QStringList coords;
            vector<LocationType> vertices;
            LocationType ll = pObject->getLlCorner();
            LocationType ur = pObject->getUrCorner();
            LocationType center = (ll + ur);
            center.mX /= 2.0;
            center.mY /= 2.0;
            if (pObject->getGraphicObjectType() == RECTANGLE_OBJECT)
            {
               vertices.push_back(ll);
               vertices.push_back(LocationType(ll.mX, ur.mY));
               vertices.push_back(ur);
               vertices.push_back(LocationType(ur.mX, ll.mY));
            }
            else if (pObject->getGraphicObjectType() == TRIANGLE_OBJECT)
            {
               double apex = pObject->getApex();
               vertices.push_back(ll);
               vertices.push_back(LocationType(ur.mX, ll.mY));
               vertices.push_back(LocationType(ll.mX + apex * (ur.mX - ll.mX), ur.mY));
               vertices.push_back(ll);
            }
            else
            {
               vertices = static_cast<PolygonObject*>(pObject)->getVertices();
            }
            QPointF qcenter(center.mX, center.mY);
            QMatrix matrix;
            matrix.rotate(pObject->getRotation());
            for (vector<LocationType>::const_iterator vertex = vertices.begin(); vertex != vertices.end(); ++vertex)
            {
               QPointF point(vertex->mX - center.mX, vertex->mY - center.mY);
               point = point * matrix;
               point += qcenter;
               LocationType geo = pGeoElement->convertPixelToGeocoord(LocationType(point.x(), point.y()));
               coords << QString("%1,%2").arg(geo.mY, 0, 'f', 10).arg(geo.mX, 0, 'f', 10);
            }
            mXml.addText(coords.join(" ").toAscii().data(), mXml.addElement("coordinates"));
            mXml.popAddPoint(); // LinearRing
            mXml.popAddPoint(); // Polygon
            break;
         }
      default: // not supported
         break;
      }
      mXml.popAddPoint(); // Placemark
   }
   mXml.popAddPoint(); // Folder
}
Пример #3
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;
}