[mapguide-commits] r9245 - in sandbox/jng/ogc: Common/MapGuideCommon/Services Common/PlatformBase/Services Common/Stylization Server/src/Services/Kml Server/src/Services/Mapping Server/src/Services/Rendering Server/src/Wms Web/src/HttpHandler

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Nov 10 06:54:23 PST 2017


Author: jng
Date: 2017-11-10 06:54:23 -0800 (Fri, 10 Nov 2017)
New Revision: 9245

Added:
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.h
Modified:
   sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
   sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.h
   sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingDefs.h
   sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.cpp
   sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.h
   sandbox/jng/ogc/Common/PlatformBase/Services/GeoJsonWriter.h
   sandbox/jng/ogc/Common/Stylization/RendererStyles.h
   sandbox/jng/ogc/Server/src/Services/Kml/ServerKmlService.cpp
   sandbox/jng/ogc/Server/src/Services/Mapping/MappingUtil.cpp
   sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.cpp
   sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.h
   sandbox/jng/ogc/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
   sandbox/jng/ogc/Server/src/Services/Rendering/RenderingOperationFactory.cpp
   sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.cpp
   sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.h
   sandbox/jng/ogc/Server/src/Wms/1.1.1.xml.awd
   sandbox/jng/ogc/Server/src/Wms/OgcWmsService.config.awd
   sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj
   sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj.filters
   sandbox/jng/ogc/Web/src/HttpHandler/HttpHandlerBuild.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.h
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.h
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.h
Log:
After many years of scratching my head when looking at this part of the codebase, I think I've finally had my lightbulb moment for how this OGC templating engine that drives MapGuide's WFS and WMS services is meant to work.

So with this submission and knowledge gained, we finally have support for GeoJSON as an output format for WMS GetFeatureInfo (currently for 1.1.1, but we'll cover other versions in future submissions). 

Now currently our WMS GetFeatureInfo implementation does not return geometry data, so supporting GeoJSON for WMS GetFeatureInfo is kind of pointless if we can't output geometry data.

To support this we add a new overload of MgRenderingService.QueryFeatureProperties to indicate whether to capture the geometry property. If true (and currently we're hard-coding it to be true for WMS GetFeatureInfo), the FeaturePropRenderer will include a MgGeometryProperty in each MgPropertyCollection that is created to be returned.

On the web tier side, we have:
 - A new MgWmsFeatureGeometry class that implements the IOgcResourceEnumerator contract required to emit the new FeatureGeometry.Value XML entity.
 - MgWmsFeatureProperties now emits a new FeatureProperty.IsLast XML entity. This is a hack-ish entity needed for GeoJSON support as the GeoJSON template definition will need to know when to and when not to emit a "," to delimit GeoJSON feature properties.
 - A new ProcedureEnumFeatureGeometries method on MgOgcWmsServer to service a new EnumFeatureGeometries directive. This procedure will only iterate once (because there will only ever be one geometry property present)
 - Updated all implementations of the IOgcResourceEnumerator contract with a SetFormat() method to allow passing down the INFO_FORMAT value all the way down to MgWmsFeatureGeometry where this determines how the new FeatureGeometry.Value XML entity is to be substituted. Currently:
   - If it is application/json: Outputs GeoJSON geometry
   - If it is anything else: Outputs the WKT text

As part of this submission, I've cleaned up MgRenderingService so that all overloads of QueryFeatureProperties (published or internal) are pure virtual functions. I don't remember why I originally had an overload QueryFeatureProperties implemented in MgRenderingService to throw MgNotImplementedException

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -1065,6 +1065,74 @@
     return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
 }
 
+/////////////////////////////////////////////////////////////////
+/// \brief
+/// The QueryFeatureProperties operation identifies those features that
+/// meet the specified spatial selection criteria. This operation
+/// is used to implement WMS feature info and returns property values
+/// for all features which match the spatial query
+///
+/// \param map
+/// Input
+/// map object containing current state of map.
+/// \param layerNames
+/// Input
+/// Active layer names for which to query features
+/// \param filterGeometry
+/// Input
+/// geometry object specifying the selection area
+/// \param selectionVariant
+/// Input
+/// selection criterion - integer value corresponding to one of
+/// the MgFeatureSpatialOperations values
+/// \param featureFilter
+/// Input
+/// an XML selection string containing the required feature IDs
+/// \param maxFeatures
+/// Input
+/// the maximum number of features to return
+/// \param layerAttributeFilter
+/// Input
+/// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+///
+/// \return
+/// An MgSelection instance identifying the features that meet the
+/// selection criteria. Returns null if no features are identified.
+///
+MgBatchPropertyCollection* MgProxyRenderingService::QueryFeatureProperties(
+    MgMap* map,
+    MgStringCollection* layerNames,
+    MgGeometry* filterGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    INT32 layerAttributeFilter,
+    bool bIncludeFeatureBBOX,
+    bool bIncludeGeometry)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+        MgCommand::knObject,                            // Return type expected
+        MgRenderingServiceOpId::QueryFeatureProperties3,// Command Code
+        9,                                              // No of arguments
+        Rendering_Service,                              // Service Id
+        BUILD_VERSION(3, 3, 0),                         // Operation version
+        MgCommand::knObject, map,                       // Argument#1
+        MgCommand::knObject, layerNames,                // Argument#2
+        MgCommand::knObject, filterGeometry,            // Argument#3
+        MgCommand::knInt32, selectionVariant,           // Argument#4
+        MgCommand::knString, &featureFilter,            // Argument#5
+        MgCommand::knInt32, maxFeatures,                // Argument#6
+        MgCommand::knInt32, layerAttributeFilter,       // Argument#7
+        MgCommand::knInt8, (INT8)bIncludeFeatureBBOX,   // Argument#8
+        MgCommand::knInt8, (INT8)bIncludeGeometry,      // Argument#9
+        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
+}
+
 //////////////////////////////////////////////////////////////////
 /// \brief
 /// Sets the connection properties for the Proxy Service.  This

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.h
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -954,6 +954,57 @@
         INT32 layerAttributeFilter,
         bool bIncludeFeatureBBOX);
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    /// \param bIncludeGeometry
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX,
+        bool bIncludeGeometry);
+
 protected:
 
     //////////////////////////////////////////////////////////////////

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingDefs.h
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingDefs.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingDefs.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -46,6 +46,7 @@
     static const int RenderMap6                 = 0x1111E912;
     static const int RenderMap7                 = 0x1111E913;
     static const int RenderTileUTFGrid          = 0x1111E914;
+    static const int QueryFeatureProperties3    = 0x1111E915;
 };
 /// \endcond
 

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.cpp
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -47,17 +47,4 @@
 void MgRenderingService::Dispose()
 {
     delete this;
-}
-
-MgBatchPropertyCollection* MgRenderingService::QueryFeatureProperties(
-    MgMap* map,
-    MgStringCollection* layerNames,
-    MgGeometry* filterGeometry,
-    INT32 selectionVariant,
-    CREFSTRING featureFilter,
-    INT32 maxFeatures,
-    INT32 layerAttributeFilter,
-    bool bIncludeFeatureBBOX)
-{
-    throw new MgNotImplementedException(L"MgRenderingService.QueryFeatureProperties", __LINE__, __WFILE__, NULL, L"", NULL);
 }
\ No newline at end of file

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.h
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/RenderingService.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -948,6 +948,9 @@
     /// \param layerAttributeFilter
     /// Input
     /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
     ///
     /// \return
     /// An MgSelection instance identifying the features that meet the
@@ -961,8 +964,59 @@
         CREFSTRING featureFilter,
         INT32 maxFeatures,
         INT32 layerAttributeFilter,
-        bool bIncludeFeatureBBOX);
+        bool bIncludeFeatureBBOX) = 0;
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    /// \param bIncludeGeometry
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX,
+        bool bIncludeGeometry) = 0;
+
 protected:
 
     /////////////////////////////////////////////////////////////////

Modified: sandbox/jng/ogc/Common/PlatformBase/Services/GeoJsonWriter.h
===================================================================
--- sandbox/jng/ogc/Common/PlatformBase/Services/GeoJsonWriter.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/PlatformBase/Services/GeoJsonWriter.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -195,6 +195,7 @@
 
 INTERNAL_API:
     STRING GeometryToGeoJson(MgGeometry* geom);
+    void ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix = true);
 
 protected:
     virtual void Dispose();
@@ -202,7 +203,6 @@
 private:
     static STRING EscapeJsonString(CREFSTRING str);
     void ValueToString(MgReader* reader, INT32 index, REFSTRING str);
-    void ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix = true);
     void CoordinateToGeoJson(MgCoordinate* coord, REFSTRING str);
     void CoordinatesToGeoJson(MgCoordinateIterator* coords, REFSTRING str);
     void PolygonToGeoJson(MgPolygon* poly, REFSTRING str);

Modified: sandbox/jng/ogc/Common/Stylization/RendererStyles.h
===================================================================
--- sandbox/jng/ogc/Common/Stylization/RendererStyles.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Common/Stylization/RendererStyles.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -728,12 +728,12 @@
 {
 public:
     RS_FeatureClassInfo() :
-        m_name(L""), m_source(L"")
+        m_name(L""), m_source(L""), m_geometry(L"")
     {
     }
 
-    RS_FeatureClassInfo(const RS_String& name, const RS_String& source) :
-        m_name(name), m_source(source)
+    RS_FeatureClassInfo(const RS_String& name, const RS_String& source, const RS_String& geometry) :
+        m_name(name), m_source(source), m_geometry(geometry)
     {
     }
 
@@ -751,10 +751,12 @@
     inline RS_String&              name()     { return m_name; }
     inline std::vector<RS_String>& mappings() { return m_propMappings; }
     inline RS_String&              source()   { return m_source; }
+    inline RS_String&              geometry() { return m_geometry; }
 
 private:
     RS_String m_source;
     RS_String m_name;
+    RS_String m_geometry;
     std::vector<RS_String> m_propMappings;
 };
 

Modified: sandbox/jng/ogc/Server/src/Services/Kml/ServerKmlService.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Kml/ServerKmlService.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Kml/ServerKmlService.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -480,7 +480,7 @@
 
         if (NULL != fdoReader.p)
         {
-            RS_FeatureClassInfo fcInfo(vl->GetFeatureName(), vl->GetResourceID());
+            RS_FeatureClassInfo fcInfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
             MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
             for (int j=0; j<pmappings->GetCount(); j++)
             {

Modified: sandbox/jng/ogc/Server/src/Services/Mapping/MappingUtil.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Mapping/MappingUtil.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Mapping/MappingUtil.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -549,7 +549,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: check to see if name is FeatureClass or Extension name
-                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
 
                     MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
                     for (int j=0; j<pmappings->GetCount(); j++)
@@ -661,7 +661,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: check to see if name is FeatureClass or Extension name
-                    RS_FeatureClassInfo fcinfo(gl->GetFeatureName(), gl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(gl->GetFeatureName(), gl->GetResourceID(), gl->GetGeometry());
 
                     //check for overridden feature query filter and remember it.
                     //we will use this when making feature queries

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -24,9 +24,11 @@
 
 #define SPECIAL_PROP_LAYER_NAME     L"_MgLayerName"
 #define SPECIAL_PROP_BOUNDING_BOX   L"_MgFeatureBoundingBox"
+#define SPECIAL_PROP_GEOMETRY       L"_MgGeometry"
 
 FeaturePropRenderer::FeaturePropRenderer(MgSelection* selection, int maxFeatures, double mapScale, bool bIncludeFeatureBBOX)
-: FeatureInfoRenderer(selection, maxFeatures, mapScale)
+: FeatureInfoRenderer(selection, maxFeatures, mapScale),
+  m_bCaptureGeometry(false)
 {
     m_featprops = new MgBatchPropertyCollection();
     m_currentFeature = NULL;
@@ -93,6 +95,47 @@
         featureProps->Add(boundingBoxProperty);
     }
 
+    //Add geometry if we're instructed to capture it
+    if (m_bCaptureGeometry)
+    {
+        FdoPtr<FdoIFeatureReader> fr = feature->GetInternalReader();
+        const FdoString* geomName = m_fcInfo->geometry().c_str();
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty();
+        //Not using geometry prop name here as we want to specially denote the designated geometry value
+        geomProp->SetName(SPECIAL_PROP_GEOMETRY);
+        try
+        {
+            if (!fr->IsNull(geomName))
+            {
+                FdoInt32 len = 0;
+                const FdoByte* data = fr->GetGeometry(geomName, &len);
+
+                if (data != NULL)
+                {
+                    Ptr<MgByte> mgBytes = new MgByte((BYTE_ARRAY_IN)data, len);
+                    Ptr<MgByteSource> bSource = new MgByteSource(mgBytes);
+                    bSource->SetMimeType(MgMimeType::Agf);
+                    Ptr<MgByteReader> agf = bSource->GetReader();
+                    geomProp->SetValue(agf);
+                }
+                else
+                {
+                    geomProp->SetNull(true);
+                }
+            }
+            else
+            {
+                geomProp->SetNull(true);
+            }
+        }
+        catch (FdoException* ex)
+        {
+            FDO_SAFE_RELEASE(ex);
+        }
+
+        featureProps->Add(geomProp);
+    }
+
     //for each property in the property mapping, add to the
     //return property collection
 
@@ -175,6 +218,11 @@
     bbox->SetValue(val);
 }
 
+void FeaturePropRenderer::SetGeometryCapture(bool bCaptureGeometry) 
+{
+    m_bCaptureGeometry = bCaptureGeometry;
+}
+
 void FeaturePropRenderer::ProcessPolygon(LineBuffer*   lb,
                                          RS_FillStyle& fill)
 {

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.h
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/FeaturePropRenderer.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -74,6 +74,8 @@
     void GetGeometryBounds(const LineBuffer* lb, RS_Bounds& bounds);
     void SetBBOXProperty(const RS_Bounds& bounds, MgStringProperty* bbox);
 
+    void SetGeometryCapture(bool bCaptureGeometry);
+
     MgBatchPropertyCollection* GetProperties()
     {
         return SAFE_ADDREF(m_featprops);
@@ -83,6 +85,7 @@
     MgBatchPropertyCollection* m_featprops;
     MgPropertyCollection* m_currentFeature;
     bool m_bIncludeFeatureBBOX;
+    bool m_bCaptureGeometry;
 };
 
 #endif

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -60,7 +60,7 @@
 
     ACE_ASSERT(m_stream != NULL);
 
-    if (7 == m_packet.m_NumArguments || 8 == m_packet.m_NumArguments)
+    if (7 == m_packet.m_NumArguments || 8 == m_packet.m_NumArguments || 9 == m_packet.m_NumArguments)
     {
         Ptr<MgMap> map = (MgMap*)m_stream->GetObject();
         Ptr<MgResourceIdentifier> resource = map->GetResourceId();
@@ -82,10 +82,15 @@
         m_stream->GetInt32(layerAttributeFilter);
 
         bool bIncludeFeatureBBOX = false;
-        if (8 == m_packet.m_NumArguments)
+        if (8 <= m_packet.m_NumArguments)
         {
             m_stream->GetBoolean(bIncludeFeatureBBOX);
         }
+        bool bIncludeGeometry = false;
+        if (9 == m_packet.m_NumArguments)
+        {
+            m_stream->GetBoolean(bIncludeGeometry);
+        }
         BeginExecution();
 
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
@@ -102,19 +107,29 @@
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
         MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(layerAttributeFilter);
-        if (8 == m_packet.m_NumArguments)
+        if (8 <= m_packet.m_NumArguments)
         {
             MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
             MG_LOG_OPERATION_MESSAGE_ADD_BOOL(bIncludeFeatureBBOX);
         }
+        if (9 == m_packet.m_NumArguments)
+        {
+            MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+            MG_LOG_OPERATION_MESSAGE_ADD_BOOL(bIncludeGeometry);
+        }
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
         Validate();
 
         Ptr<MgBatchPropertyCollection> info;
-        if (8 == m_packet.m_NumArguments)
+        if (9 == m_packet.m_NumArguments)
         {
             info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
+                featureFilter, maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX, bIncludeGeometry);
+        }
+        else if (8 == m_packet.m_NumArguments)
+        {
+            info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
                 featureFilter, maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX);
         }
         else

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/RenderingOperationFactory.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -260,6 +260,17 @@
                 L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
         }
         break;
+    case MgRenderingServiceOpId::QueryFeatureProperties3:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3, 3):
+            handler.reset(new MgOpQueryFeatureProperties());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
     case MgRenderingServiceOpId::RenderMapLegend:
         switch (VERSION_NO_PHASE(operationVersion))
         {

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -1328,6 +1328,20 @@
                                                                             INT32 layerAttributeFilter,
                                                                             bool bIncludeFeatureBBOX)
 {
+    return QueryFeatureProperties(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
+                                                                            MgStringCollection* layerNames,
+                                                                            MgGeometry* filterGeometry,
+                                                                            INT32 selectionVariant, // Within, Touching, Topmost
+                                                                            CREFSTRING featureFilter,
+                                                                            INT32 maxFeatures,
+                                                                            INT32 layerAttributeFilter,
+                                                                            bool bIncludeFeatureBBOX,
+                                                                            bool bIncludeGeometry)
+{
     Ptr<MgBatchPropertyCollection> ret;
 
     MG_TRY()
@@ -1339,6 +1353,8 @@
     Ptr<MgSelection> sel;   //TODO: do we need this for this API? new MgSelection(map);
     FeaturePropRenderer fpr(sel, maxFeatures, map->GetViewScale(), bIncludeFeatureBBOX);
 
+    fpr.SetGeometryCapture(bIncludeGeometry);
+
     RenderForSelection(map, layerNames, filterGeometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter, &fpr);
 
     ret = fpr.GetProperties();
@@ -1901,7 +1917,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: can FeatureName be an extension name rather than a FeatureClass?
-                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
 
                     MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
                     for (int i=0; i<pmappings->GetCount(); i++)

Modified: sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.h
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Services/Rendering/ServerRenderingService.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -232,6 +232,17 @@
                                         INT32 layerAttributeFilter,
                                         bool bIncludeFeatureBBOX);
 
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+                                        MgMap* map,
+                                        MgStringCollection* layerNames,
+                                        MgGeometry* filterGeometry,
+                                        INT32 selectionVariant,
+                                        CREFSTRING featureFilter,
+                                        INT32 maxFeatures,
+                                        INT32 layerAttributeFilter,
+                                        bool bIncludeFeatureBBOX,
+                                        bool bIncludeGeometry);
+
 private:
     static void ComputeXYZTileExtents(MgMap* map, INT32 x, INT32 y, INT32 z, RS_Bounds& extent);
     // used for tile generation

Modified: sandbox/jng/ogc/Server/src/Wms/1.1.1.xml.awd
===================================================================
--- sandbox/jng/ogc/Server/src/Wms/1.1.1.xml.awd	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Wms/1.1.1.xml.awd	2017-11-10 14:54:23 UTC (rev 9245)
@@ -94,9 +94,19 @@
  <Define item="FeatureInfo.text">
   FeatureInfo:
   <?EnumFeatureProperties using="&FeatureProperty.text;" ?>
-
+  <?EnumFeatureGeometries using="&FeatureGeometry.text;" ?>
  </Define>
 
+ <!-- 
+ Ugly, but we have to do 2 iteration passes to output the right
+ content in the right places for GeoJSON
+  -->
+ <Define item="FeatureInfo.json">{
+    "type": "Feature",
+    "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>},
+    "geometry": <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?>
+}</Define>
+
  <Define item="FeatureProperty.xml">
   <Property name="&FeatureProperty.Name;" value="&FeatureProperty.Value;"></Property>
  </Define>
@@ -109,6 +119,17 @@
   &FeatureProperty.Name;=&FeatureProperty.Value;
  </Define>
 
+ <!-- Output all non-geometry properties -->
+ <Define item="FeatureProperty.json">
+  <?If l="&FeatureProperty.Name" op="neq" r="_MgGeometry" ?>"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?><?Endif?>
+ </Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.json">&FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.text">&FeatureGeometry.Value;</Define>
+
  <!-- We're currently not supporting child layers... -->
  <Define item="Layer.Sublayers"></Define>
 
@@ -377,7 +398,15 @@
  <?EnumFeatureInfo using="&FeatureInfo.text;" ?>
 </Response>
 
+<!-- 
 
+  WMS GetFeatureInfo - (Geo)JSON
+
+-->
+<Response request="GetFeatureInfo" content-type="application/json">
+  <?EnumFeatureInfo using="&FeatureInfo.json;" ?>
+</Response>
+
 <!--
 
   Exception format - XML

Modified: sandbox/jng/ogc/Server/src/Wms/OgcWmsService.config.awd
===================================================================
--- sandbox/jng/ogc/Server/src/Wms/OgcWmsService.config.awd	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Server/src/Wms/OgcWmsService.config.awd	2017-11-10 14:54:23 UTC (rev 9245)
@@ -180,6 +180,7 @@
    <item>text/xml</item>
    <item>text/html</item>
    <item>text/plain</item>
+   <item>application/json</item>
  </Define>
 
  <!-- These are the supported Exception formats

Modified: sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj	2017-11-10 14:54:23 UTC (rev 9245)
@@ -784,6 +784,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="WmsFeatureGeometry.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="WmsFeatureInfo.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1101,6 +1107,7 @@
     <ClInclude Include="WfsFeatureDefinitions.h" />
     <ClInclude Include="WfsGetFeatureParams.h" />
     <ClInclude Include="WmsFeatureInfo.h" />
+    <ClInclude Include="WmsFeatureGeometry.h" />
     <ClInclude Include="WmsFeatureProperties.h" />
     <ClInclude Include="WmsLayerDefinitions.h" />
     <ClInclude Include="WmsMapUtil.h" />

Modified: sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj.filters
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-11-10 14:54:23 UTC (rev 9245)
@@ -416,6 +416,9 @@
     <ClCompile Include="HttpGeoBoundary.cpp">
       <Filter>GeoProcessing</Filter>
     </ClCompile>
+    <ClCompile Include="WmsFeatureGeometry.cpp">
+      <Filter>Ogc</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="HttpApplyResourcePackage.h">
@@ -814,6 +817,9 @@
     <ClInclude Include="HttpGeoBoundary.h">
       <Filter>GeoProcessing</Filter>
     </ClInclude>
+    <ClInclude Include="WmsFeatureGeometry.h">
+      <Filter>Ogc</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="HttpHandler.rc" />

Modified: sandbox/jng/ogc/Web/src/HttpHandler/HttpHandlerBuild.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -151,6 +151,7 @@
 #include "WmsLayerDefinitions.cpp"
 #include "WmsFeatureInfo.cpp"
 #include "WmsFeatureProperties.cpp"
+#include "WmsFeatureGeometry.cpp"
 #include "WfsFeatureDefinitions.cpp"
 #include "XmlParser.cpp"
 #include "Dictionary.cpp"

Modified: sandbox/jng/ogc/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -154,9 +154,9 @@
     Ptr<MgCoordinate> mcsLowerLeft = mcsExtent->GetLowerLeftCoordinate();
     Ptr<MgCoordinate> mcsUpperRight = mcsExtent->GetUpperRightCoordinate();
 
-	//When GetFeatureInfo for point or line geometry, simply using click point to query cannot get any matching.
-	//Expand selection geometry a little to be a linearRing so that can query point and line.
-	double margin = 2;
+    //When GetFeatureInfo for point or line geometry, simply using click point to query cannot get any matching.
+    //Expand selection geometry a little to be a linearRing so that can query point and line.
+    double margin = 2;
     // Convert the pixel coords to MCS coords
     double mcsMinX = mcsLowerLeft->GetX() + ((double)m_iCoord - margin) * mcsExtent->GetWidth() / map->GetDisplayWidth();
     double mcsMaxY = mcsUpperRight->GetY() -((double)m_jCoord - margin) * mcsExtent->GetHeight() / map->GetDisplayHeight();
@@ -229,13 +229,17 @@
         // Get the selection geometry
         Ptr<MgGeometry> selectionGeometry = GetSelectionGeometry(map);
 
+        bool bCaptureGeometry = true;
+
         // Call the C++ API
         Ptr<MgBatchPropertyCollection> propertyCollection = service->QueryFeatureProperties(map, queryLayers, selectionGeometry,
-            MgFeatureSpatialOperations::Intersects, L"", m_featureCount, 1 /*Any visible features*/);
+            MgFeatureSpatialOperations::Intersects, L"", m_featureCount, 1 /*Any visible features*/, false /* no bbox */, bCaptureGeometry);
 
         // Create the object to store the feature info
         Ptr<MgWmsFeatureInfo> wmsFeatureInfo = new MgWmsFeatureInfo(propertyCollection);
 
+        wmsFeatureInfo->SetFormat(m_infoFormat);
+
         // The WMS Server takes ownership of the feature info
         wmsServer->SetFeatureInfo(wmsFeatureInfo);
     }

Modified: sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -93,6 +93,7 @@
 
 CPSZ kpszPiEnumLayers                      = _("EnumLayers");
 CPSZ kpszPiEnumFeatureProperties           = _("EnumFeatureProperties");
+CPSZ kpszPiEnumFeatureGeometries           = _("EnumFeatureGeometries");
 CPSZ kpszPiEnumFeatureInfo                 = _("EnumFeatureInfo");
 extern CPSZ kpszPiAttributeUsing;  // for consistency, borrow the "using" attribute from base class.
 CPSZ kpszPiEnumLayersDefaultFormat         = _("&Layer.Name;\n");
@@ -784,6 +785,10 @@
     {
         ProcedureEnumFeatureInfo(PI);
     }
+    else if (sProc == kpszPiEnumFeatureGeometries)
+    {
+        ProcedureEnumFeatureGeometries(PI);
+    }
     else
     {
         return false;
@@ -863,6 +868,31 @@
     }
 }
 
+// Interpret a <?EnumFeatureGeometries using= ?> processing instruction
+// This will enumerate all feature geometries (only one)
+void MgOgcWmsServer::ProcedureEnumFeatureGeometries(MgXmlProcessingInstruction& PIEnum)
+{
+    STRING sFormat;
+    if (!PIEnum.GetAttribute(kpszPiAttributeUsing, sFormat))
+        sFormat = kpszPiEnumFeaturePropertiesDefaultFormat;
+
+    CDictionaryStackFrame forFeatureGeometries(this);
+
+    if (m_pFeatureInfo != NULL)
+    {
+        Ptr<MgWmsFeatureProperties> pProps = m_pFeatureInfo->GetCurrentProperties();
+        if (pProps != NULL)
+        {
+            Ptr<MgWmsFeatureGeometry> geom = pProps->GetGeometry();
+            while (geom->Next())
+            {
+                geom->GenerateDefinitions(*m_pTopOfDefinitions);
+                ProcessExpandableText(sFormat);
+            }
+        }
+    }
+}
+
 // Set the feature info (used for generating GetFeatureInfo response)
 void MgOgcWmsServer::SetFeatureInfo(MgWmsFeatureInfo* pFeatureInfo)
 {

Modified: sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.h
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/OgcWmsServer.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -24,6 +24,7 @@
 #include "WmsLayerDefinitions.h"
 #include "WmsFeatureInfo.h"
 #include "WmsFeatureProperties.h"
+#include "WmsFeatureGeometry.h"
 
 class MgOgcWmsServer: public MgOgcServer
 {
@@ -88,6 +89,7 @@
     void ProcedureEnumLayers            (MgXmlProcessingInstruction& PIEnum);
     void ProcedureEnumFeatureProperties (MgXmlProcessingInstruction& PIEnum);
     void ProcedureEnumFeatureInfo       (MgXmlProcessingInstruction& PIEnum);
+    void ProcedureEnumFeatureGeometries (MgXmlProcessingInstruction& PIEnum);
 
     bool ValidateGetCapabilitiesParameters();
     bool ValidateGetFeatureInfoParameters();

Added: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.cpp	                        (rev 0)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -0,0 +1,77 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "OgcFramework.h"
+#include "WmsFeatureGeometry.h"
+
+MgWmsFeatureGeometry::MgWmsFeatureGeometry(MgGeometry * geom)
+    : m_bRead(false), m_format(MgMimeType::Text)
+{
+    m_geom = SAFE_ADDREF(geom);
+}
+
+MgWmsFeatureGeometry::~MgWmsFeatureGeometry()
+{
+    m_geom = NULL;
+}
+
+void MgWmsFeatureGeometry::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
+bool MgWmsFeatureGeometry::Next()
+{
+    // Per the IOgcResourceEnumerator contract, we have to iterate, but we only want to iterate once
+    if (!m_bRead) 
+    {
+        m_bRead = true;
+        return true;
+    }
+    return false;
+}
+
+void MgWmsFeatureGeometry::GenerateDefinitions(MgUtilDictionary& dictionary)
+{
+    if (NULL != m_geom.p)
+    {
+        if (MgMimeType::Json == m_format) //Give GeoJSON geometry to json
+        {
+            MgGeoJsonWriter gjw;
+            STRING value;
+            gjw.ToGeoJson(m_geom, value, false);
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), value);
+        }
+        else //Give everything else WKT
+        {
+            MgWktReaderWriter wktRw;
+            STRING value = wktRw.Write(m_geom);
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), value);
+        }
+    }
+    else
+    {
+        if (MgMimeType::Json == m_format) 
+        {
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), _("null"));
+        }
+        else 
+        {
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), _(""));
+        }
+    }
+}

Added: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.h
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.h	                        (rev 0)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -0,0 +1,49 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MgWmsFeatureInfoGeometry_h
+#define _MgWmsFeatureInfoGeometry_h
+
+#include "XmlParser.h"
+#include "Dictionary.h"
+
+class MgWmsFeatureGeometry : public IOgcResourceEnumerator, public MgDisposable
+{
+public:
+    MgWmsFeatureGeometry(MgGeometry* geom);
+    //Default constructor to keep Ptr<> happy
+    MgWmsFeatureGeometry() {};
+    virtual ~MgWmsFeatureGeometry();
+    
+    void SetFormat(CREFSTRING format);
+
+    bool Next();
+    void GenerateDefinitions(MgUtilDictionary& Dictionary);
+
+protected:
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+    Ptr<MgGeometry> m_geom;
+    bool m_bRead;
+    STRING m_format;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -62,6 +62,11 @@
     }
 }
 
+void MgWmsFeatureInfo::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
 MgWmsFeatureProperties* MgWmsFeatureInfo::GetCurrentProperties()
 {
     MgWmsFeatureProperties* wmsProps = NULL;
@@ -71,6 +76,7 @@
         if(props != NULL)
         {
             wmsProps = new MgWmsFeatureProperties(props);
+            wmsProps->SetFormat(m_format);
         }
     }
     return wmsProps;

Modified: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.h
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureInfo.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -32,6 +32,8 @@
     MgWmsFeatureInfo(){};
     virtual ~MgWmsFeatureInfo();
 
+    void SetFormat(CREFSTRING format);
+
     bool Next();
     void GenerateDefinitions(MgUtilDictionary& Dictionary);
     MgWmsFeatureProperties* GetCurrentProperties();
@@ -45,6 +47,7 @@
 private:
    Ptr<MgBatchPropertyCollection> m_propertyCollection;
    int m_index;
+   STRING m_format;
 };
 
 #endif//_MgWmsFeatureInfo_h

Modified: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.cpp	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.cpp	2017-11-10 14:54:23 UTC (rev 9245)
@@ -20,7 +20,8 @@
 
 
 MgWmsFeatureProperties::MgWmsFeatureProperties(MgPropertyCollection* propertyCollection)
-:   m_index(-1)
+:   m_index(-1),
+    m_format(MgMimeType::Xml)
 {
     m_propertyCollection = SAFE_ADDREF(propertyCollection);
 }
@@ -29,15 +30,56 @@
 {
 }
 
+void MgWmsFeatureProperties::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
+MgWmsFeatureGeometry* MgWmsFeatureProperties::GetGeometry()
+{
+    Ptr<MgWmsFeatureGeometry> ret;
+    Ptr<MgGeometry> geom = NULL;
+    if (m_propertyCollection != NULL)
+    {
+        INT32 gidx = m_propertyCollection->IndexOf(_("_MgGeometry"));
+        if (gidx >= 0)
+        {
+            Ptr<MgProperty> prop = m_propertyCollection->GetItem(gidx);
+            if (prop->GetPropertyType() == MgPropertyType::Geometry)
+            {
+                MgGeometryProperty* gp = static_cast<MgGeometryProperty*>(prop.p);
+                if (!gp->IsNull())
+                {
+                    Ptr<MgByteReader> agf = gp->GetValue();
+                    MgAgfReaderWriter agfRw;
+                    geom = agfRw.Read(agf);
+                }
+            }
+        }
+    }
+
+    ret = new MgWmsFeatureGeometry(geom);
+    ret->SetFormat(m_format);
+
+    return ret.Detach();
+}
+
+bool MgWmsFeatureProperties::IsSpecialProperty(MgProperty* prop)
+{
+    return (szcmp(prop->GetName().c_str(), _("_MgLayerName")) == 0)
+        || (szcmp(prop->GetName().c_str(), _("_MgGeometry")) == 0)
+        || (szcmp(prop->GetName().c_str(), _("_MgFeatureBoundingBox")) == 0);
+}
+
 bool MgWmsFeatureProperties::Next()
 {
     if(m_propertyCollection != NULL && m_index < m_propertyCollection->GetCount() - 1)
     {
         m_index++;
 
-        // Skip the special layer name property
+        // Skip the special properties
         Ptr<MgProperty> prop = m_propertyCollection->GetItem(m_index);
-        if(szcmp(prop->GetName().c_str(), _("_MgLayerName")) == 0)
+        if (IsSpecialProperty(prop))
         {
             return Next();
         }
@@ -53,18 +95,24 @@
 {
     if(m_propertyCollection != NULL && m_index >= 0 && m_index < m_propertyCollection->GetCount())
     {
-        Ptr<MgStringProperty> stringProp = (MgStringProperty*)m_propertyCollection->GetItem(m_index);
-        if(stringProp != NULL)
+        Ptr<MgProperty> prop = m_propertyCollection->GetItem(m_index);
+        STRING name = MgUtil::ReplaceEscapeCharInXml(prop->GetName());
+        // Skip the special properties
+        if (!IsSpecialProperty(prop))
         {
-            STRING name = MgUtil::ReplaceEscapeCharInXml(stringProp->GetName());
-
-            // Skip the special layer name property
-            if(szcmp(name.c_str(), _("_MgLayerName")) != 0)
+            STRING sIndex;
+            MgUtil::Int32ToString(m_index, sIndex);
+            if (prop->GetPropertyType() == MgPropertyType::String)
             {
+                MgStringProperty* stringProp = static_cast<MgStringProperty*>(prop.p);
                 STRING value = MgUtil::ReplaceEscapeCharInXml(stringProp->GetValue());
 
                 dictionary.AddDefinition(_("FeatureProperty.Name"), name.c_str());
                 dictionary.AddDefinition(_("FeatureProperty.Value"), value.c_str());
+                //A bit hack-ish but we need this for formats like GeoJSON so we know whether to insert a "," or not
+                //The server implementation will ensure that all the non-special properties are at the end of the collection
+                //ie. _MgLayerName, _MgGeometry, etc will never be the last property
+                dictionary.AddDefinition(_("FeatureProperty.IsLast"), (m_index == m_propertyCollection->GetCount() - 1) ? _("1") : _("0"));
             }
         }
     }

Modified: sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.h
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.h	2017-10-06 16:08:24 UTC (rev 9244)
+++ sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureProperties.h	2017-11-10 14:54:23 UTC (rev 9245)
@@ -21,6 +21,8 @@
 #include "XmlParser.h"
 #include "Dictionary.h"
 
+class MgWmsFeatureGeometry;
+
 class MgWmsFeatureProperties: public IOgcResourceEnumerator, public MgDisposable
 {
 public:
@@ -30,8 +32,11 @@
     MgWmsFeatureProperties(){};
     virtual ~MgWmsFeatureProperties();
 
+    void SetFormat(CREFSTRING format);
+
     bool Next();
     void GenerateDefinitions(MgUtilDictionary& Dictionary);
+    MgWmsFeatureGeometry* GetGeometry();
 
 protected:
     virtual void Dispose()
@@ -40,8 +45,10 @@
     }
 
 private:
-   Ptr<MgPropertyCollection> m_propertyCollection;
-   int m_index;
+    static bool IsSpecialProperty(MgProperty* prop);
+    Ptr<MgPropertyCollection> m_propertyCollection;
+    int m_index;
+    STRING m_format;
 };
 
 #endif//_MgWmsFeatureProperties_h



More information about the mapguide-commits mailing list