[mapguide-commits] r9230 - in trunk/MgDev: . Common/Foundation/System Common/Geometry Common/PlatformBase/Services Common/Schema Server/src/UnitTesting UnitTest/WebTier/MapAgent/MapAgentForms Web/src/DotNetUnmanagedApi/Geometry Web/src/HttpHandler Web/src/MapGuideApi

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Jul 11 08:44:27 PDT 2017


Author: jng
Date: 2017-07-11 08:44:27 -0700 (Tue, 11 Jul 2017)
New Revision: 9230

Added:
   trunk/MgDev/Common/Geometry/PreparedGeometry.cpp
   trunk/MgDev/Common/Geometry/PreparedGeometry.h
   trunk/MgDev/Common/Schema/GeometryInfo-3.3.0.xsd
   trunk/MgDev/Common/Schema/UnitOfMeasure-3.3.0.xsd
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/binaryoperationform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/boundaryform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/bufferform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/convexhullform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/distanceform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geometryinfoform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geoprocessingapi.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/simplifyform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/spatialpredicateform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/tessellateform.html
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.h
   trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.h
Modified:
   trunk/MgDev/
   trunk/MgDev/Common/Foundation/System/Util.cpp
   trunk/MgDev/Common/Foundation/System/Util.h
   trunk/MgDev/Common/Geometry/Geometry.cpp
   trunk/MgDev/Common/Geometry/Geometry.h
   trunk/MgDev/Common/Geometry/Geometry.vcxproj
   trunk/MgDev/Common/Geometry/Geometry.vcxproj.filters
   trunk/MgDev/Common/Geometry/GeometryBuild.cpp
   trunk/MgDev/Common/Geometry/GeometryClassId.h
   trunk/MgDev/Common/Geometry/GeometryCommon.h
   trunk/MgDev/Common/Geometry/GeometrySimplifier.cpp
   trunk/MgDev/Common/Geometry/Makefile.am
   trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.cpp
   trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h
   trunk/MgDev/Server/src/UnitTesting/TestGeometry.cpp
   trunk/MgDev/Server/src/UnitTesting/TestGeometry.h
   trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp
   trunk/MgDev/Server/src/UnitTesting/TestMisc.h
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectaggregatesform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectfeaturesform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/services.html
   trunk/MgDev/Web/src/DotNetUnmanagedApi/Geometry/GeometryApiGen.xml
   trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj
   trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters
   trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpRequest.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h
   trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.h
   trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.h
   trunk/MgDev/Web/src/HttpHandler/Makefile.am
   trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
   trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h
   trunk/MgDev/Web/src/HttpHandler/XmlJsonConvert.cpp
   trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml
Log:
Merge from sandbox/jng/geoprocessing. This completes MapGuide RFC 161



Property changes on: trunk/MgDev
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/2.4/MgDev:6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev:8276-8286,8288-8292,8297,8299,8301,8303,8314-8315,8318,8335,8340,8354-8355,8365,8373
/branches/3.0/MgDev:8658,8705,8710
/branches/3.1/MgDev:9026,9058-9059,9067-9068
/sandbox/VC140:8684-8759
/sandbox/adsk/2.6l:8727
/sandbox/adsk/3.0m:8563,8584,8607,8625,8694-8695
/sandbox/adsk/3.1n:8871,8895,8901,8912-8913,8921-8922,8942,9019-9020
/sandbox/jng/clean_json:8818-9180
/sandbox/jng/cmdline:9199-9217
/sandbox/jng/convenience_apis:8262-8268,8271-8363
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/php56x:8975-8985
/sandbox/jng/rfc155:8872-8884
/sandbox/jng/simplify:8814-9141
/sandbox/jng/tiling:8174-8208
/sandbox/jng/utfgrid:9179-9212
/sandbox/jng/v30:8212-8227
/sandbox/rfc94:5099-5163
   + /branches/2.4/MgDev:6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev:8276-8286,8288-8292,8297,8299,8301,8303,8314-8315,8318,8335,8340,8354-8355,8365,8373
/branches/3.0/MgDev:8658,8705,8710
/branches/3.1/MgDev:9026,9058-9059,9067-9068
/sandbox/VC140:8684-8759
/sandbox/adsk/2.6l:8727
/sandbox/adsk/3.0m:8563,8584,8607,8625,8694-8695
/sandbox/adsk/3.1n:8871,8895,8901,8912-8913,8921-8922,8942,9019-9020
/sandbox/jng/clean_json:8818-9180
/sandbox/jng/cmdline:9199-9217
/sandbox/jng/convenience_apis:8262-8268,8271-8363
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geoprocessing:9205-9229
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/php56x:8975-8985
/sandbox/jng/rfc155:8872-8884
/sandbox/jng/simplify:8814-9141
/sandbox/jng/tiling:8174-8208
/sandbox/jng/utfgrid:9179-9212
/sandbox/jng/v30:8212-8227
/sandbox/rfc94:5099-5163

Modified: trunk/MgDev/Common/Foundation/System/Util.cpp
===================================================================
--- trunk/MgDev/Common/Foundation/System/Util.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Foundation/System/Util.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -1083,6 +1083,40 @@
     str = &buf[0];
 }
 
+void MgUtil::DoubleToString(double val, string& str, INT32 decimals)
+{
+    if (decimals <= 0) //Took a wrong turn?
+    {
+        DoubleToString(val, str);
+    }
+    else
+    {
+        std::stringstream ss;
+        ss << std::fixed << std::setprecision(decimals) << val;
+        str = ss.str();
+        // Slice off trailing 0s
+        size_t end = str.find_last_not_of('0') + 1;
+        str.erase(end);
+    }
+}
+
+void MgUtil::DoubleToString(double val, STRING& str, INT32 decimals)
+{
+    if (decimals <= 0) //Took a wrong turn?
+    {
+        DoubleToString(val, str);
+    }
+    else
+    {
+        std::wstringstream ws;
+        ws << std::fixed << std::setprecision(decimals) << val;
+        str = ws.str();
+        // Slice off trailing 0s
+        size_t end = str.find_last_not_of(L'0') + 1;
+        str.erase(end);
+    }
+}
+
 bool MgUtil::ValuesEqual(double value1, double value2, double tolerance, bool output)
 {
     bool valuesEqual = true;

Modified: trunk/MgDev/Common/Foundation/System/Util.h
===================================================================
--- trunk/MgDev/Common/Foundation/System/Util.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Foundation/System/Util.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -553,6 +553,8 @@
     static void SingleToString(float val, STRING& str);
     static void DoubleToString(double val, string& str);
     static void DoubleToString(double val, STRING& str);
+    static void DoubleToString(double val, string& str, INT32 decimals);
+    static void DoubleToString(double val, STRING& str, INT32 decimals);
 
     static bool ValuesEqual(double value1, double value2,
         double tolerance = MgUtil::DefaultCompareTolerance,

Modified: trunk/MgDev/Common/Geometry/Geometry.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/Geometry.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/Geometry.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -259,3 +259,13 @@
 {
     return MgGeometryEntityType::Geometry;
 }
+
+MgPreparedGeometry* MgGeometry::Prepare()
+{
+    return MgPreparedGeometry::Create(this);
+}
+
+MgGeometry* MgGeometry::Tessellate()
+{
+    return MgSpatialUtility::TesselateCurve(this);
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/Geometry/Geometry.h
===================================================================
--- trunk/MgDev/Common/Geometry/Geometry.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/Geometry.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -18,6 +18,7 @@
 #ifndef _MGGEOMETRY_H_
 #define _MGGEOMETRY_H_
 
+class MgPreparedGeometry;
 class MgGeometry;
 template class MG_GEOMETRY_API Ptr<MgGeometry>;
 
@@ -733,6 +734,54 @@
     ///
     virtual MgGeometry* Union(MgGeometry* other);
 
+    ///////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns a prepared version of this geometry that is optimized for
+    /// repeated evaluation of spatial predicate operations
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \since 3.3
+    ///
+    /// \return
+    /// An MgPreparedGeometry representing the prepared version of this geometry
+    ///
+    MgPreparedGeometry* Prepare();
+
+    ///////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns a tessellated version of this geometry. A tessellated version of this
+    /// geometry will have all arc/curve geometry components approximated with line
+    /// strings. Thus, this method is only applicable for curve geometries and has
+    /// no effect on non-curve geometries.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgGeometry Prepare();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \since 3.3
+    ///
+    /// \return
+    /// A tesellated version of this geometry. If this geometry is not curve-based, the operation does nothing and this method returns itself.
+    ///
+    MgGeometry* Tessellate();
+
 INTERNAL_API:
 
     virtual INT32 GetEntityType();

Modified: trunk/MgDev/Common/Geometry/Geometry.vcxproj
===================================================================
--- trunk/MgDev/Common/Geometry/Geometry.vcxproj	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/Geometry.vcxproj	2017-07-11 15:44:27 UTC (rev 9230)
@@ -492,6 +492,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="PreparedGeometry.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="Spatial\MathUtility.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -907,6 +913,7 @@
     <ClInclude Include="Parse\ParseAwktUtil.h" />
     <ClInclude Include="Parse\StringUtility.h" />
     <ClInclude Include="Parse\yyAwkt.h" />
+    <ClInclude Include="PreparedGeometry.h" />
     <ClInclude Include="Spatial\MathUtility.h" />
     <ClInclude Include="Spatial\SpatialUtility.h" />
     <ClInclude Include="Spatial\SpatialUtilityCircularArc.h" />

Modified: trunk/MgDev/Common/Geometry/Geometry.vcxproj.filters
===================================================================
--- trunk/MgDev/Common/Geometry/Geometry.vcxproj.filters	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/Geometry.vcxproj.filters	2017-07-11 15:44:27 UTC (rev 9230)
@@ -373,6 +373,7 @@
     <ClCompile Include="Ring.cpp" />
     <ClCompile Include="WktReaderWriter.cpp" />
     <ClCompile Include="GeometrySimplifier.cpp" />
+    <ClCompile Include="PreparedGeometry.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Buffer\BorderWalker.h">
@@ -973,6 +974,7 @@
     <ClInclude Include="WktReaderWriter.h" />
     <ClInclude Include="GeometrySimplifier.h" />
     <ClInclude Include="GeometrySimplificationAlgorithmType.h" />
+    <ClInclude Include="PreparedGeometry.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Geometry.rc" />

Modified: trunk/MgDev/Common/Geometry/GeometryBuild.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/GeometryBuild.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/GeometryBuild.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -56,6 +56,7 @@
 #include "PointCollection.cpp"
 #include "Polygon.cpp"
 #include "PolygonCollection.cpp"
+#include "PreparedGeometry.cpp"
 #include "Region.cpp"
 #include "Ring.cpp"
 #include "WktReaderWriter.cpp"

Modified: trunk/MgDev/Common/Geometry/GeometryClassId.h
===================================================================
--- trunk/MgDev/Common/Geometry/GeometryClassId.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/GeometryClassId.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -79,6 +79,8 @@
 // Simplifier
 #define Geometry_GeometrySimplifier                       GEOMETRY_ID+54
 
+#define Geometry_PreparedGeometry                         GEOMETRY_ID+55
+
 // CoordinateSystem API
 #define CoordinateSystem_CoordinateSystem                           GEOMETRY_COORDINATE_SYSTEM_ID+0
 #define CoordinateSystem_CoordinateSystemFactory                    GEOMETRY_COORDINATE_SYSTEM_ID+1

Modified: trunk/MgDev/Common/Geometry/GeometryCommon.h
===================================================================
--- trunk/MgDev/Common/Geometry/GeometryCommon.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/GeometryCommon.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -100,6 +100,8 @@
 #include "MultiPoint.h"
 #include "MultiPolygon.h"
 
+#include "PreparedGeometry.h"
+
 #include "AgfReaderWriter.h"
 #include "WktReaderWriter.h"
 

Modified: trunk/MgDev/Common/Geometry/GeometrySimplifier.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/GeometrySimplifier.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/GeometrySimplifier.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -33,7 +33,7 @@
 MgGeometry* MgGeometrySimplifier::Simplify(MgGeometry* geom, double tolerance, INT32 algorithm)
 {
     Ptr<MgGeometry> simplified;
-    Geometry* gInput = NULL;
+    std::auto_ptr<Geometry> gInput;
     std::auto_ptr<Geometry> gOutput;
     MG_GEOMETRY_TRY()
 
@@ -50,15 +50,15 @@
     WKTReader r(&gf);
     WKTWriter w;
 
-    gInput = r.read(MgUtil::WideCharToMultiByte(inputWKt));
+    gInput.reset(r.read(MgUtil::WideCharToMultiByte(inputWKt)));
 
     switch (algorithm)
     {
     case MgGeometrySimplificationAlgorithmType::DouglasPeucker:
-        gOutput = geos::simplify::DouglasPeuckerSimplifier::simplify(gInput, tolerance);
+        gOutput = geos::simplify::DouglasPeuckerSimplifier::simplify(gInput.get(), tolerance);
         break;
     case MgGeometrySimplificationAlgorithmType::TopologyPreserving:
-        gOutput = geos::simplify::TopologyPreservingSimplifier::simplify(gInput, tolerance);
+        gOutput = geos::simplify::TopologyPreservingSimplifier::simplify(gInput.get(), tolerance);
         break;
     }
 
@@ -72,6 +72,7 @@
     }
     
     MG_GEOMETRY_CATCH_AND_THROW(L"MgGeometrySimplifier.Simplify")
+
     return simplified.Detach();
 }
 

Modified: trunk/MgDev/Common/Geometry/Makefile.am
===================================================================
--- trunk/MgDev/Common/Geometry/Makefile.am	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/Geometry/Makefile.am	2017-07-11 15:44:27 UTC (rev 9230)
@@ -100,6 +100,7 @@
   PointCollection.cpp \
   Polygon.cpp \
   PolygonCollection.cpp \
+  PreparedGeometry.cpp \
   Region.cpp \
   Ring.cpp \
   WktReaderWriter.cpp\
@@ -267,6 +268,7 @@
   PointCollection.h \
   Polygon.h \
   PolygonCollection.h \
+  PreparedGeometry.h \
   QuadToInstruction.h \
   Region.h \
   Ring.h \

Copied: trunk/MgDev/Common/Geometry/PreparedGeometry.cpp (from rev 9229, sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.cpp)
===================================================================
--- trunk/MgDev/Common/Geometry/PreparedGeometry.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Geometry/PreparedGeometry.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,142 @@
+//
+//  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 "GeometryCommon.h"
+#include <geos/geom/prep/PreparedGeometry.h>
+#include <geos/geom/prep/PreparedGeometryFactory.h>
+
+using namespace geos::geom::prep;
+
+class MgPreparedGeometry::PreparedGeometryImpl 
+{
+public:
+    PreparedGeometryImpl() 
+      : m_pg(NULL), 
+        m_pm(new PrecisionModel()), 
+        m_gf(NULL),
+        m_geom(NULL)
+    {
+        m_gf.reset(new GeometryFactory(m_pm.get(), 10));
+    }
+    ~PreparedGeometryImpl() 
+    {
+        PreparedGeometryFactory::destroy(m_pg);
+    }
+    Geometry* Convert(MgGeometry* geom)
+    {
+        WKTReader r(m_gf.get());
+        Ptr<MgGeometry> tGeom = MgSpatialUtility::TesselateCurve(geom);
+        STRING wktGeom = tGeom->ToAwkt(true);
+
+        return r.read(MgUtil::WideCharToMultiByte(wktGeom));
+    }
+    void Prepare(MgGeometry* geom)
+    {
+        WKTReader r(m_gf.get());
+        Ptr<MgGeometry> tGeom = MgSpatialUtility::TesselateCurve(geom);
+        STRING wktGeom = tGeom->ToAwkt(true);
+
+        m_geom.reset(r.read(MgUtil::WideCharToMultiByte(wktGeom)));
+        m_pg = PreparedGeometryFactory::prepare(m_geom.get());
+    }
+
+    const PreparedGeometry* m_pg;
+
+private:
+    std::auto_ptr<Geometry> m_geom;
+    std::auto_ptr<PrecisionModel> m_pm;
+    std::auto_ptr<GeometryFactory> m_gf;
+};
+
+MgPreparedGeometry* MgPreparedGeometry::Create(MgGeometry* geom)
+{
+    Ptr<MgPreparedGeometry> pGeom;
+
+    MG_GEOMETRY_TRY()
+
+    PreparedGeometryImpl* impl = new PreparedGeometryImpl();
+    impl->Prepare(geom);
+
+    pGeom = new MgPreparedGeometry(impl);
+
+    MG_GEOMETRY_CATCH_AND_THROW(L"MgPreparedGeometry.Create")
+
+    return SAFE_ADDREF((MgPreparedGeometry*)pGeom);
+}
+
+MgPreparedGeometry::MgPreparedGeometry(PreparedGeometryImpl* impl)
+    : d_ptr(impl)
+{
+
+}
+
+MgPreparedGeometry::~MgPreparedGeometry()
+{
+
+}
+
+bool MgPreparedGeometry::Contains(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->contains(gOther.get());
+}
+
+bool MgPreparedGeometry::Crosses(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->crosses(gOther.get());
+}
+
+bool MgPreparedGeometry::Disjoint(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->disjoint(gOther.get());
+}
+
+bool MgPreparedGeometry::Intersects(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->intersects(gOther.get());
+}
+
+bool MgPreparedGeometry::Overlaps(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->overlaps(gOther.get());
+}
+
+bool MgPreparedGeometry::Touches(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->touches(gOther.get());
+}
+
+bool MgPreparedGeometry::Within(MgGeometry * other)
+{
+    std::auto_ptr<Geometry> gOther(d_ptr->Convert(other));
+    return d_ptr->m_pg->within(gOther.get());
+}
+
+INT32 MgPreparedGeometry::GetClassId() 
+{ 
+    return m_cls_id; 
+}
+
+void MgPreparedGeometry::Dispose()
+{
+    delete this;
+}

Copied: trunk/MgDev/Common/Geometry/PreparedGeometry.h (from rev 9229, sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.h)
===================================================================
--- trunk/MgDev/Common/Geometry/PreparedGeometry.h	                        (rev 0)
+++ trunk/MgDev/Common/Geometry/PreparedGeometry.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,303 @@
+//
+//  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 _MGPREPAREDGEOMETRY_H_
+#define _MGPREPAREDGEOMETRY_H_
+
+class MgGeometry;
+
+////////////////////////////////////////////////////////////////
+/// \brief
+/// MgPreparedGeometry is an prepared form of MgGeometry optimized for the case of 
+/// repeated evaluation of spatial predicates against it and any other geometry
+///
+class MG_GEOMETRY_API MgPreparedGeometry : public MgGuardDisposable
+{
+PUBLISHED_API:
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// This is a convenience method. Given 2 geometries a and b,
+    /// a.Contains(b) is true if and only if b.MgGeometry::Within(a)
+    /// is true.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Contains(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Contains(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Contains(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this one.
+    ///
+    /// \return
+    /// True if the other geometry is within this geometry, false
+    /// otherwise.
+    ///
+    virtual bool Contains(MgGeometry* other);
+
+    //////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Given 2 geometries a and b, a.Crosses(b) is true if and only
+    /// if the dimension of the intersection of the interior of a and
+    /// the interior of b is less than the greater of the dimension
+    /// of the interior of a and the dimension of the interior of b
+    /// and the intersection of a and b is neither a nor b.
+    ///
+    /// \remarks
+    /// A Point cannot cross another geometry because the
+    /// intersection of the Point with the other geometry is the
+    /// Point.
+    /// \n
+    /// Two MultiPoint geometries cannot cross one another because
+    /// the dimension of the intersection of their interiors, namely
+    /// the 0-dimension, is not less than the greater of the
+    /// dimensions of their interiors, namely the 0-dimension.
+    /// \n
+    /// [\link OGC99049 OGC99-049 \endlink] implicitly excludes a Crosses
+    /// relationship between 2 polygons. According to the definition,
+    /// the possibility of such a relationship would require that the
+    /// intersection of the interior of one polygon with that of
+    /// another be a Point or Line.
+    /// <h2>Illustration</h2>
+    /// d, e and f are MultiPoint geometries.
+    /// \n
+    /// \image html crosses.png
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Crosses(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Crosses(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Crosses(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this
+    /// one.
+    ///
+    /// \return
+    /// True if this geometry spatially crosses the other geometry,
+    /// false otherwise.
+    ///
+    virtual bool Crosses(MgGeometry* other);
+
+    /////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Given 2 geometries a and b, a.Disjoint(b)is true if and only
+    /// if the intersection of a and b is empty.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Disjoint(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Disjoint(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Disjoint(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this one.
+    ///
+    /// \return
+    /// True if this geometry is spatially disjoint from the other
+    /// geometry, false otherwise.
+    ///
+    virtual bool Disjoint(MgGeometry* other);
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// This is a convenience method. Given 2 geometries a and b,
+    /// a.Intersects(b) is true if and only if a.\link MgGeometry::Disjoint Disjoint \endlink(b)
+    /// is false.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Intersects(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Intersects(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Intersects(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this one.
+    ///
+    /// \return
+    /// True if this geometry is not disjoint with respect to the
+    /// other geometry, false otherwise.
+    ///
+    virtual bool Intersects(MgGeometry* other);
+
+    /////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Given 2 geometries a and b, a.Overlaps(b) is true if and only
+    /// if the dimension of the interior of a equals the dimension of
+    /// the interior of b equals the dimension of the intersection of
+    /// the interior of a and the interior of b and the intersection
+    /// of a and b is neither a nor b.
+    ///
+    /// \remarks
+    /// A Point cannot overlap a Point, and a MultiPoint cannot
+    /// overlap a Point but a MultiPoint can overlap a MultiPoint.
+    /// <h2>Illustration</h2>
+    /// c and d are MultiPoint geometries.
+    /// \image html overlaps.png
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Overlaps(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Overlaps(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Overlaps(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this one.
+    ///
+    /// \return
+    /// True if this geometry spatially overlaps the other geometry,
+    /// false otherwise.
+    ///
+    virtual bool Overlaps(MgGeometry* other);
+
+    //////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Given 2 geometries a and b, a.Touches(b) is true if and only
+    /// if the intersection of the interior of a and the interior of
+    /// b is empty and the intersection of a and b is not empty.
+    ///
+    /// \remarks
+    /// A Point cannot touch a Point because a Point has no boundary
+    /// and so the intersection of the interiors of the two
+    /// geometries is not empty.
+    /// \n
+    /// A Point can touch a non-closed Line at one of the end points
+    /// of the Line.
+    /// \n
+    /// A Point cannot touch a closed Line because all of the points
+    /// in the Line are interior to it.
+    /// <h2>Illustration</h2>
+    /// e are MultiPoint geometries and f is a LineString.
+    /// \image html touches.png
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Touches(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Touches(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Touches(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this
+    /// one.
+    ///
+    /// \return
+    /// True if this geometry spatially touches the other geometry,
+    /// false otherwise.
+    ///
+    virtual bool Touches(MgGeometry* other);
+
+    //////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Given 2 geometries a and b, a.Within(b) is true if and only
+    /// if the intersection of a and b is a and the intersection of
+    /// the interior of a and the interior of b is not empty.
+    ///
+    /// \remarks
+    /// If the entire point-set of a geometry intersects the boundary
+    /// of another geometry, the former is not within the latter.
+    /// <h2>Illustration</h2>
+    /// The end point of d and the end point of e intersect. a, b, i,
+    /// j, k, and m are MultiPoints. The concentric circles represent
+    /// intersecting points. The polygon n1n2n3n4 is within the
+    /// polygon p1p2p3p4 and vice versa. The LineString q1q2 is
+    /// within the LineString r1r2 and vice versa. The MultiPoint j
+    /// is within the MultiPoint k and vice versa. The Point f is
+    /// within the point g and vice versa.
+    /// \n
+    /// \image html within.png
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool Within(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual boolean Within(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool Within(MgGeometry other);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param other (MgGeometry)
+    /// The MgGeometry to test against this
+    /// one.
+    ///
+    /// \return
+    /// True if this geometry is spatially within the other geometry,
+    /// false otherwise.
+    ///
+    virtual bool Within(MgGeometry* other);
+
+INTERNAL_API:
+    static MgPreparedGeometry* Create(MgGeometry* geom);
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Get the unique identifier for the class
+    ///
+    /// \return
+    /// Class Identifider.
+    ///
+    virtual INT32 GetClassId();
+
+private:
+    class PreparedGeometryImpl;
+    std::auto_ptr<PreparedGeometryImpl> d_ptr;
+    MgPreparedGeometry(PreparedGeometryImpl* impl);
+
+protected:
+    virtual ~MgPreparedGeometry();
+
+    //////////////////////////////////////////////
+    /// \brief
+    /// Dispose this object.
+    ///
+    virtual void Dispose();
+
+CLASS_ID:
+    static const INT32 m_cls_id = Geometry_PreparedGeometry;
+};
+
+#endif

Modified: trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.cpp
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -6,8 +6,14 @@
 MgGeoJsonWriter::MgGeoJsonWriter()
 {
     m_agfRw = new MgAgfReaderWriter();
+    m_precisionEnabled = false;
+    m_precision = 7;
 }
 
+INT32 MgGeoJsonWriter::GetPrecision() { return m_precision; }
+
+void MgGeoJsonWriter::SetPrecision(INT32 precision) { m_precision = precision; }
+
 STRING MgGeoJsonWriter::FeatureToGeoJson(MgFeatureReader* featureReader, MgTransform* transform)
 {
     Ptr<MgClassDefinition> clsDef = featureReader->GetClassDefinition();
@@ -36,7 +42,7 @@
 
     MG_TRY()
 
-        CHECKARGUMENTNULL(reader, L"MgGeoJsonWriter.FeatureToGeoJson");
+    CHECKARGUMENTNULL(reader, L"MgGeoJsonWriter.FeatureToGeoJson");
 
     if (!idPropertyName.empty())
         idIndex = reader->GetPropertyIndex(idPropertyName);
@@ -67,7 +73,9 @@
                 geom = m_agfRw->Read(agf, transform);
             else
                 geom = m_agfRw->Read(agf);
-            ToGeoJson(geom, geomVal);
+            
+            Ptr<MgGeometry> g = geom->Tessellate();
+            ToGeoJson(g, geomVal);
         }
         catch (MgException* ex)
         {
@@ -97,7 +105,9 @@
                             geom = m_agfRw->Read(agf, transform);
                         else
                             geom = m_agfRw->Read(agf);
-                        ToGeoJson(geom, geomVal);
+
+                        Ptr<MgGeometry> g = geom->Tessellate();
+                        ToGeoJson(g, geomVal);
                     }
                     catch (MgException* ex)
                     {
@@ -166,6 +176,25 @@
     return ret;
 }
 
+STRING MgGeoJsonWriter::GeometryToGeoJson(MgGeometry* geom)
+{
+    STRING ret;
+    MG_TRY()
+
+    ret = L"{ \"type\": \"Feature\", "; //START FEATURE
+    ret += L"\"properties\": {}, "; //PROPERTIES
+    
+    STRING geomVal;
+    Ptr<MgGeometry> g = geom->Tessellate();
+    ToGeoJson(g, geomVal);
+    ret += geomVal; //GEOMETRY
+
+    ret += L"}"; //END FEATURE
+
+    MG_CATCH_AND_THROW(L"MgGeoJsonWriter.GeometryToGeoJson")
+    return ret;
+}
+
 void MgGeoJsonWriter::ValueToString(MgReader* reader, INT32 index, REFSTRING str)
 {
     INT32 propType = reader->GetPropertyType(index);
@@ -193,6 +222,7 @@
     case MgPropertyType::Double:
         {
             double val = reader->GetDouble(index);
+            //NOTE: Not applying precision here as that is for coordinate output
             MgUtil::DoubleToString(val, str);
         }
         break;
@@ -361,9 +391,17 @@
 {
     str = L"[";
     STRING sx;
-    MgUtil::DoubleToString(coord->GetX(), sx);
     STRING sy;
-    MgUtil::DoubleToString(coord->GetY(), sy);
+    if (m_precisionEnabled)
+    {
+        MgUtil::DoubleToString(coord->GetX(), sx, m_precision);
+        MgUtil::DoubleToString(coord->GetY(), sy, m_precision);
+    }
+    else
+    {
+        MgUtil::DoubleToString(coord->GetX(), sx);
+        MgUtil::DoubleToString(coord->GetY(), sy);
+    }
     str += sx;
     str += L", ";
     str += sy;
@@ -383,9 +421,17 @@
 
         str += L"[";
         STRING sx;
-        MgUtil::DoubleToString(coord->GetX(), sx);
         STRING sy;
-        MgUtil::DoubleToString(coord->GetY(), sy);
+        if (m_precisionEnabled)
+        {
+            MgUtil::DoubleToString(coord->GetX(), sx, m_precision);
+            MgUtil::DoubleToString(coord->GetY(), sy, m_precision);
+        }
+        else 
+        {
+            MgUtil::DoubleToString(coord->GetX(), sx);
+            MgUtil::DoubleToString(coord->GetY(), sy);
+        }
         str += sx;
         str += L", ";
         str += sy;
@@ -506,4 +552,14 @@
 void MgGeoJsonWriter::Dispose()
 {
     delete this;
+}
+
+void MgGeoJsonWriter::SetPrecisionEnabled(bool enabled)
+{
+    m_precisionEnabled = enabled;
+}
+
+bool MgGeoJsonWriter::IsPrecisionEnabled()
+{
+    return m_precisionEnabled;
 }
\ No newline at end of file

Modified: trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -108,6 +108,94 @@
     ///
     STRING FeatureToGeoJson(MgReader* reader, MgTransform* transform, CREFSTRING idPropertyName, CREFSTRING geomPropName);
 
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the decimal precision to use when writing out coordinates. If you do not call this method, the default precision used is 7 decimal places.
+    /// Precision must be enabled in order for this setting to have any effect
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// void SetPrecision(int precision);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// void SetPrecision(int precision);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// void SetPrecision(int precision);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param precision (int)
+    /// The decimal precision to write out coordinates
+    ///
+    ///
+    void SetPrecision(INT32 precision);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the decimal precision to use when writing out coordinates
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// int GetPrecision();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// int GetPrecision();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// int GetPrecision();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current precision
+    ///
+    INT32 GetPrecision();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets whether to apply coordinate precision when writing out GeoJSON coordinates
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// void SetPrecisionEnabled(bool enabled);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// void SetPrecisionEnabled(boolean enabled);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// void SetPrecisionEnabled(bool enabled);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param enabled (bool)
+    /// If true, enables coordinate precision. Otherwise disables it
+    ///
+    /// \return
+    /// Returns the GeoJSON output as a string.
+    ///
+    void SetPrecisionEnabled(bool enabled);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets whether coordinate precision is enabled
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// bool IsPrecisionEnabled();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// boolean IsPrecisionEnabled();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// bool IsPrecisionEnabled();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// True if coordinate precision is enabled. False otherwise
+    ///
+    bool IsPrecisionEnabled();
+
+INTERNAL_API:
+    STRING GeometryToGeoJson(MgGeometry* geom);
+
 protected:
     virtual void Dispose();
 
@@ -123,6 +211,8 @@
     void MultiPolygonToGeoJson(MgMultiPolygon* multi, REFSTRING str);
 
     Ptr<MgAgfReaderWriter> m_agfRw;
+    INT32 m_precision;
+    bool m_precisionEnabled;
 };
 /// \}
 

Copied: trunk/MgDev/Common/Schema/GeometryInfo-3.3.0.xsd (from rev 9229, sandbox/jng/geoprocessing/Common/Schema/GeometryInfo-3.3.0.xsd)
===================================================================
--- trunk/MgDev/Common/Schema/GeometryInfo-3.3.0.xsd	                        (rev 0)
+++ trunk/MgDev/Common/Schema/GeometryInfo-3.3.0.xsd	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+  <xs:element name="GeometryInfo">
+    <xs:annotation>
+      <xs:documentation>Geometry Information</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="Area" type="xs:double" />
+        <xs:element name="Dimension" type="xs:int" />
+        <xs:element name="Length" type="xs:double" />
+        <xs:element name="IsClosed" type="xs:boolean" />
+        <xs:element name="IsEmpty" type="xs:boolean" />
+        <xs:element name="IsSimple" type="xs:boolean" />
+        <xs:element name="IsValid" type="xs:boolean" />
+        <xs:element name="Envelope" type="Envelope" />
+        <xs:element name="Centroid" type="Coordinate" />
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="Coordinate">
+    <xs:annotation>
+      <xs:documentation>Represents a bounding box</xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element name="X" type="xs:double">
+        <xs:annotation>
+          <xs:documentation>x-coordinate</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element name="Y" type="xs:double">
+        <xs:annotation>
+          <xs:documentation>y-coordinate</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="Envelope">
+    <xs:annotation>
+      <xs:documentation>Represents a bounding box defined in terms of a lower left coordinate and an upper right coordinate</xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element name="LowerLeft" type="Coordinate">
+        <xs:annotation>
+          <xs:documentation>Lower-left coordinate</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element name="UpperRight" type="Coordinate">
+        <xs:annotation>
+          <xs:documentation>Upper-right coordinate</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+</xs:schema>

Copied: trunk/MgDev/Common/Schema/UnitOfMeasure-3.3.0.xsd (from rev 9229, sandbox/jng/geoprocessing/Common/Schema/UnitOfMeasure-3.3.0.xsd)
===================================================================
--- trunk/MgDev/Common/Schema/UnitOfMeasure-3.3.0.xsd	                        (rev 0)
+++ trunk/MgDev/Common/Schema/UnitOfMeasure-3.3.0.xsd	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+  <xs:element name="UnitOfMeasure">
+    <xs:annotation>
+      <xs:documentation>Unit of measure</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="Value" type="xs:double" />
+        <xs:element name="Unit" type="xs:string" />
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>

Modified: trunk/MgDev/Server/src/UnitTesting/TestGeometry.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestGeometry.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Server/src/UnitTesting/TestGeometry.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -16,6 +16,7 @@
 //
 
 #include "MapGuideCommon.h"
+#include "ServiceManager.h"
 #include "TestGeometry.h"
 #include "CppUnitExtensions.h"
 #include "FoundationDefs.h"
@@ -41,11 +42,97 @@
 void TestGeometry::TestStart()
 {
     ACE_DEBUG((LM_INFO, ACE_TEXT("\nRunning Geometry tests. (Mentor)\n")));
+#ifdef TEST_PREPARED_GEOMETRY_PERF
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if (serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestGeometry::TestStart", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceService> pService = dynamic_cast<MgResourceService*>(serviceManager->RequestService(MgServiceType::ResourceService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestGeometry::TestStart", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        //Set the user information for the current thread to be administrator
+        MgUserInformation::SetCurrentUserInfo(NULL);
+        Ptr<MgUserInformation> userInfo = new MgUserInformation(L"Administrator", L"admin");
+        if (userInfo != NULL)
+        {
+            userInfo->SetLocale(TEST_LOCALE);
+            MgUserInformation::SetCurrentUserInfo(userInfo);
+
+            MgResourceIdentifier resourceIdentifier1(L"Library://UnitTests/Data/Sheboygan_Parcels.FeatureSource");
+    #ifdef _WIN32
+            STRING resourceContentFileName1 = L"..\\UnitTestFiles\\Sheboygan_Parcels.FeatureSource";
+            STRING dataFileName1 = L"..\\UnitTestFiles\\Sheboygan_Parcels.sdf";
+    #else
+            STRING resourceContentFileName1 = L"../UnitTestFiles/Sheboygan_Parcels.FeatureSource";
+            STRING dataFileName1 = L"../UnitTestFiles/Sheboygan_Parcels.sdf";
+    #endif
+
+            //Add a new resource
+            Ptr<MgByteSource> contentSource1 = new MgByteSource(resourceContentFileName1);
+            Ptr<MgByteReader> contentReader1 = contentSource1->GetReader();
+            pService->SetResource(&resourceIdentifier1, contentReader1, NULL);
+
+            //Set the resource data
+            Ptr<MgByteSource> dataSource1 = new MgByteSource(dataFileName1);
+            Ptr<MgByteReader> dataReader1 = dataSource1->GetReader();
+            pService->SetResourceData(&resourceIdentifier1, L"Sheboygan_Parcels.sdf", L"File", dataReader1);
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+#endif
 }
 
 
 void TestGeometry::TestEnd()
 {
+#ifdef TEST_PREPARED_GEOMETRY_PERF
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if (serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestEnd",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceService> pService = dynamic_cast<MgResourceService*>(serviceManager->RequestService(MgServiceType::ResourceService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestEnd",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        // set user info
+        Ptr<MgUserInformation> userInfo = new MgUserInformation(L"Administrator", L"admin");
+        userInfo->SetLocale(TEST_LOCALE);
+        MgUserInformation::SetCurrentUserInfo(userInfo);
+
+        Ptr<MgResourceIdentifier> fsres1 = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_Parcels.FeatureSource");
+        pService->DeleteResource(fsres1);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+#endif
     ACE_DEBUG((LM_INFO, ACE_TEXT("\nGeometry tests completed.\n\n")));
 }
 
@@ -1965,6 +2052,12 @@
         CPPUNIT_ASSERT(touches);
         touches = polygon->Touches(point);
         CPPUNIT_ASSERT(touches);
+        Ptr<MgPreparedGeometry> ppoint = point->Prepare();
+        Ptr<MgPreparedGeometry> ppolygon = polygon->Prepare();
+        touches = ppoint->Touches(polygon);
+        CPPUNIT_ASSERT(touches);
+        touches = ppolygon->Touches(point);
+        CPPUNIT_ASSERT(touches);
 
         //TEST 2
         MgGeometryFactory factory;
@@ -1974,6 +2067,12 @@
         CPPUNIT_ASSERT(!touches);
         touches = polygon->Touches(point);
         CPPUNIT_ASSERT(!touches);
+        ppoint = point->Prepare();
+        ppolygon = polygon->Prepare();
+        touches = ppoint->Touches(polygon);
+        CPPUNIT_ASSERT(!touches);
+        touches = ppolygon->Touches(point);
+        CPPUNIT_ASSERT(!touches);
 
         //TEST 3
         Ptr<MgMultiPolygon> multiPolygon = CreateMultiPolygon();
@@ -1982,6 +2081,12 @@
         CPPUNIT_ASSERT(!touches);
         touches = multiPolygon->Touches(point);
         CPPUNIT_ASSERT(!touches);
+        ppoint = point->Prepare();
+        Ptr<MgPreparedGeometry> pmultiPolygon = multiPolygon->Prepare();
+        touches = ppoint->Touches(multiPolygon);
+        CPPUNIT_ASSERT(!touches);
+        touches = pmultiPolygon->Touches(point);
+        CPPUNIT_ASSERT(!touches);
 
         //TEST 4
         Ptr<MgCoordinateCollection> collection = new MgCoordinateCollection();
@@ -2015,6 +2120,9 @@
         point = factory.CreatePoint(coord);
         touches = polygon->Touches(point);
         CPPUNIT_ASSERT(!touches);
+        ppolygon = polygon->Prepare();
+        touches = ppolygon->Touches(point);
+        CPPUNIT_ASSERT(!touches);
 
         //TEST 5
         coord1 = factory.CreateCoordinateXY( 45.0,  45.0);
@@ -2047,6 +2155,9 @@
         point = factory.CreatePoint(coord);
         touches = point->Touches(polygon);
         CPPUNIT_ASSERT(!touches);
+        ppoint = point->Prepare();
+        touches = ppoint->Touches(polygon);
+        CPPUNIT_ASSERT(!touches);
 
         //TEST 6
         coord1 = factory.CreateCoordinateXY(100.0, 100.0);
@@ -2713,4 +2824,237 @@
     {
         throw;
     }
+}
+
+void TestGeometry::TestCase_PreparedGeometryPerformance()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if (serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestGeometry::TestCase_PreparedGeometry", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> pService = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestGeometry::TestCase_PreparedGeometry", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgAgfReaderWriter> agfRw = new MgAgfReaderWriter();
+        Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+
+        STRING wkt = L"POLYGON ((-87.70660400390625 43.761672246385025, -87.7045440673828 43.76576337413024, -87.7093505859375 43.77196151943297, -87.71999359130858 43.7755561494101, -87.73458480834961 43.770350063442635, -87.73355484008789 43.76315996157264, -87.73853302001953 43.758820688867885, -87.73595809936523 43.74642103270366, -87.72789001464842 43.735135112939105, -87.71844863891602 43.73191017368391, -87.71175384521484 43.73575527365514, -87.70797729492188 43.739228054975506, -87.7090072631836 43.74158447044938, -87.71278381347655 43.739848173302434, -87.71724700927734 43.737615717267765, -87.72720336914062 43.7374916894919, -87.72926330566406 43.74567697163676, -87.7313232421875 43.75125720420175, -87.73149490356445 43.75931662167704, -87.72222518920898 43.76092837491792, -87.72136688232422 43.76787081559809, -87.71467208862305 43.76712702120528, -87.71175384521484 43.76092837491792, -87.70660400390625 43.761672246385025))";
+        Ptr<MgGeometry> testGeom = wktRw->Read(wkt);
+
+        Ptr<MgResourceIdentifier> resource = new MgResourceIdentifier();
+        STRING className = L"";
+        Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
+        CPPUNIT_ASSERT_THROW_MG(pService->SelectFeatures(resource, className, options), MgInvalidArgumentException*);
+
+        resource = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_Parcels.FeatureSource");
+        className = L"Parcels";
+        Ptr<MgFeatureReader> reader = pService->SelectFeatures(resource, className, options);
+        Ptr<MgClassDefinition> clsDef = reader->GetClassDefinition();
+        STRING geomName = clsDef->GetDefaultGeometryPropertyName();
+
+        INT32 containsCount1 = 0;
+        INT32 crossesCount1 = 0;
+        INT32 disjointCount1 = 0;
+        INT32 intersectsCount1 = 0;
+        INT32 overlapsCount1 = 0;
+        INT32 touchesCount1 = 0;
+        INT32 withinCount1 = 0;
+
+        long lStart = GetTickCount();
+        while (reader->ReadNext())
+        {
+            try 
+            {
+                Ptr<MgByteReader> agf = ((MgReader*)reader)->GetGeometry(geomName);
+                Ptr<MgGeometry> geom = agfRw->Read(agf);
+
+                if (testGeom->Contains(geom))
+                    containsCount1++;
+                if (testGeom->Crosses(geom))
+                    crossesCount1++;
+                if (testGeom->Disjoint(geom))
+                    disjointCount1++;
+                if (testGeom->Intersects(geom))
+                    intersectsCount1++;
+                if (testGeom->Overlaps(geom))
+                    overlapsCount1++;
+                if (testGeom->Touches(geom))
+                    touchesCount1++;
+                if (testGeom->Within(geom))
+                    withinCount1++;
+            }
+            catch (MgException* ex)
+            {
+                SAFE_RELEASE(ex);
+            }
+        }
+        reader->Close();
+        ACE_DEBUG((LM_INFO, ACE_TEXT("\n\n  Execution Time: = %6.4f (s)\n"), ((GetTickCount() - lStart) / 1000.0)));
+        ACE_DEBUG((LM_INFO, ACE_TEXT("  Contains: %d, Crosses: %d, Disjoint: %d, Intersects: %d, Overlaps: %d, Touches: %d, Within: %d\n"), containsCount1, crossesCount1, disjointCount1, intersectsCount1, overlapsCount1, touchesCount1, withinCount1));
+
+        //Now, with prepared geometry
+        Ptr<MgPreparedGeometry> prep = testGeom->Prepare();
+
+        reader = pService->SelectFeatures(resource, className, options);
+        INT32 containsCount2 = 0;
+        INT32 crossesCount2 = 0;
+        INT32 disjointCount2 = 0;
+        INT32 intersectsCount2 = 0;
+        INT32 overlapsCount2 = 0;
+        INT32 touchesCount2 = 0;
+        INT32 withinCount2 = 0;
+
+        lStart = GetTickCount();
+        while (reader->ReadNext())
+        {
+            try
+            {
+                Ptr<MgByteReader> agf = ((MgReader*)reader)->GetGeometry(geomName);
+                Ptr<MgGeometry> geom = agfRw->Read(agf);
+
+                if (prep->Contains(geom))
+                    containsCount2++;
+                if (prep->Crosses(geom))
+                    crossesCount2++;
+                if (prep->Disjoint(geom))
+                    disjointCount2++;
+                if (prep->Intersects(geom))
+                    intersectsCount2++;
+                if (prep->Overlaps(geom))
+                    overlapsCount2++;
+                if (prep->Touches(geom))
+                    touchesCount2++;
+                if (prep->Within(geom))
+                    withinCount2++;
+            }
+            catch (MgException* ex)
+            {
+                SAFE_RELEASE(ex);
+            }
+        }
+        reader->Close();
+        ACE_DEBUG((LM_INFO, ACE_TEXT("\n  Execution Time: = %6.4f (s)\n"), ((GetTickCount() - lStart) / 1000.0)));
+        ACE_DEBUG((LM_INFO, ACE_TEXT("  Contains: %d, Crosses: %d, Disjoint: %d, Intersects: %d, Overlaps: %d, Touches: %d, Within: %d\n"), containsCount2, crossesCount2, disjointCount2, intersectsCount2, overlapsCount2, touchesCount2, withinCount2));
+
+        CPPUNIT_ASSERT(containsCount1 == containsCount2);
+        CPPUNIT_ASSERT(crossesCount2 == crossesCount2);
+        CPPUNIT_ASSERT(disjointCount2 == disjointCount2);
+        CPPUNIT_ASSERT(intersectsCount2 == intersectsCount2);
+        CPPUNIT_ASSERT(overlapsCount2 == overlapsCount2);
+        CPPUNIT_ASSERT(touchesCount2 == touchesCount2);
+        CPPUNIT_ASSERT(withinCount2 == withinCount2);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestGeometry::TestCase_CurvePolygon_AsGeoJSON()
+{
+    try
+    {
+        Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+        Ptr<MgGeometry> geom = wktRw->Read(L"CURVEPOLYGON ((0 0 (LINESTRINGSEGMENT (10 10, 10 20, 20 20), ARC (20 15, 10 10))), (0 0 (ARC (11 11, 12 12), LINESTRINGSEGMENT (10 10, 20 20, 40 40, 90 90))))");
+
+        Ptr<MgGeoJsonWriter> gw = new MgGeoJsonWriter();
+        STRING geoJson = gw->GeometryToGeoJson(geom);
+
+        CPPUNIT_ASSERT(geoJson.find(L"geometry\": null") == STRING::npos);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestGeometry::TestCase_CurveString_AsGeoJSON()
+{
+    try
+    {
+        Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+        Ptr<MgGeometry> geom = wktRw->Read(L"CURVESTRING (0 0 (CIRCULARARCSEGMENT (11 11, 12 12), LINESTRINGSEGMENT (10 10, 20 20, 30 40)))");
+
+        Ptr<MgGeoJsonWriter> gw = new MgGeoJsonWriter();
+        STRING geoJson = gw->GeometryToGeoJson(geom);
+
+        CPPUNIT_ASSERT(geoJson.find(L"geometry\": null") == STRING::npos);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestGeometry::TestCase_MultiCurvePolygon_AsGeoJSON()
+{
+    try
+    {
+        Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+        Ptr<MgGeometry> geom = wktRw->Read(L"MULTICURVEPOLYGON (((0 0 (LINESTRINGSEGMENT (10 10, 10 20, 20 20), ARC (20 15, 10 10))), (0 0 (ARC (11 11, 12 12), LINESTRINGSEGMENT (10 10, 20 20, 40 40, 90 90)))),((0 0 (LINESTRINGSEGMENT (10 10, 10 20, 20 20), ARC (20 15, 10 10))), (0 0 (ARC (11 11, 12 12), LINESTRINGSEGMENT (10 10, 20 20, 40 40, 90 90)))))");
+
+        Ptr<MgGeoJsonWriter> gw = new MgGeoJsonWriter();
+        STRING geoJson = gw->GeometryToGeoJson(geom);
+
+        CPPUNIT_ASSERT(geoJson.find(L"geometry\": null") == STRING::npos);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestGeometry::TestCase_MultiCurveString_AsGeoJSON()
+{
+    try
+    {
+        Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+        Ptr<MgGeometry> geom = wktRw->Read(L"MULTICURVESTRING ((0 0 (LINESTRINGSEGMENT (10 10, 20 20, 30 40))),(0 0 (ARC (11 11, 12 12), LINESTRINGSEGMENT (10 10, 20 20, 30 40))))");
+
+        Ptr<MgGeoJsonWriter> gw = new MgGeoJsonWriter();
+        STRING geoJson = gw->GeometryToGeoJson(geom);
+
+        CPPUNIT_ASSERT(geoJson.find(L"geometry\": null") == STRING::npos);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
 }
\ No newline at end of file

Modified: trunk/MgDev/Server/src/UnitTesting/TestGeometry.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestGeometry.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Server/src/UnitTesting/TestGeometry.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -20,6 +20,8 @@
 
 #include <cppunit/extensions/HelperMacros.h>
 
+//#define TEST_PREPARED_GEOMETRY_PERF
+
 #ifndef _WIN32
 //Linux: different naming for string functions
 #define stricmp strcasecmp
@@ -68,6 +70,15 @@
     CPPUNIT_TEST(TestCase_Simplify_DP);
     CPPUNIT_TEST(TestCase_Simplify_TP);
 
+    CPPUNIT_TEST(TestCase_CurveString_AsGeoJSON);
+    CPPUNIT_TEST(TestCase_CurvePolygon_AsGeoJSON);
+    CPPUNIT_TEST(TestCase_MultiCurvePolygon_AsGeoJSON);
+    CPPUNIT_TEST(TestCase_MultiCurveString_AsGeoJSON);
+
+#ifdef TEST_PREPARED_GEOMETRY_PERF
+    CPPUNIT_TEST(TestCase_PreparedGeometryPerformance);
+#endif
+
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
 
@@ -116,6 +127,13 @@
     void TestCase_Simplify_DP();
     void TestCase_Simplify_TP();
 
+    void TestCase_CurveString_AsGeoJSON();
+    void TestCase_CurvePolygon_AsGeoJSON();
+    void TestCase_MultiCurvePolygon_AsGeoJSON();
+    void TestCase_MultiCurveString_AsGeoJSON();
+
+    void TestCase_PreparedGeometryPerformance();
+
     MgPoint*             CreatePoint();
     MgLineString*        CreateLineString();
     MgLinearRing*        CreateLinearRing();

Modified: trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Server/src/UnitTesting/TestMisc.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -643,4 +643,76 @@
     {
         throw;
     }
+}
+
+void TestMisc::TestCase_DoubleToStringWithDecimals()
+{
+    try
+    {
+        double d = 1.23456789032748754;
+
+        std::string s;
+        STRING ws;
+
+        MgUtil::DoubleToString(d, ws, 4);
+        MgUtil::DoubleToString(d, s, 4);
+
+        CPPUNIT_ASSERT(L"1.2346" == ws);
+        CPPUNIT_ASSERT("1.2346" == s);
+
+        ws.clear();
+        s.clear();
+
+        MgUtil::DoubleToString(d, ws, 8);
+        MgUtil::DoubleToString(d, s, 8);
+
+        CPPUNIT_ASSERT(L"1.23456789" == ws);
+        CPPUNIT_ASSERT("1.23456789" == s);
+
+        ws.clear();
+        s.clear();
+
+        std::string s1;
+        STRING ws1;
+        //This should be the equivalent to not even passing in precision at all
+        MgUtil::DoubleToString(d, ws, -1);
+        MgUtil::DoubleToString(d, s, -1);
+        MgUtil::DoubleToString(d, ws1);
+        MgUtil::DoubleToString(d, s1);
+
+        CPPUNIT_ASSERT(ws1 == ws);
+        CPPUNIT_ASSERT(s1 == s);
+
+        double d1 = 1.1;
+
+        ws.clear();
+        s.clear();
+
+        MgUtil::DoubleToString(d1, ws, 4);
+        MgUtil::DoubleToString(d1, s, 4);
+
+        CPPUNIT_ASSERT(L"1.1" == ws);
+        CPPUNIT_ASSERT("1.1" == s);
+
+        double d2 = 123.3457483434945;
+
+        ws.clear();
+        s.clear();
+
+        MgUtil::DoubleToString(d2, ws, 8);
+        MgUtil::DoubleToString(d2, s, 8);
+
+        CPPUNIT_ASSERT(L"123.34574834" == ws);
+        CPPUNIT_ASSERT("123.34574834" == s);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
 }
\ No newline at end of file

Modified: trunk/MgDev/Server/src/UnitTesting/TestMisc.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMisc.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Server/src/UnitTesting/TestMisc.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -31,6 +31,7 @@
     CPPUNIT_TEST(TestCase_1304);
     CPPUNIT_TEST(TestCase_MapLayerCollections);
     CPPUNIT_TEST(TestCase_ApiVersionCheck);
+    CPPUNIT_TEST(TestCase_DoubleToStringWithDecimals);
 
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
@@ -51,6 +52,7 @@
     void TestCase_MapLayerCollections();
     void TestCase_CreateMapWithInitialDisplayParams();
     void TestCase_ApiVersionCheck();
+    void TestCase_DoubleToStringWithDecimals();
 
 private:
     Ptr<MgSiteConnection> m_siteConnection;

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/binaryoperationform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/binaryoperationform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/binaryoperationform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/binaryoperationform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,44 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.BINARYOPERATION" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry A (WKT):
+<input type="text" name="GEOMETRYA" value="" size="100">
+<p> Geometry B (WKT):
+<input type="text" name="GEOMETRYB" value="" size="100">
+<p> Operator:
+<select name="OPERATOR">
+    <option value="UNION">Union</option>
+    <option value="DIFFERENCE">Difference</option>
+    <option value="INTERSECTION">Intersection</option>
+    <option value="SYMMETRICDIFFERENCE">SymmetricDifference</option>
+</select>
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/boundaryform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/boundaryform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/boundaryform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/boundaryform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,35 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.BOUNDARY" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/bufferform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/bufferform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/bufferform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/bufferform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,44 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.BUFFER" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Buffer Distance:
+<input type="text" name="DISTANCE" value="" size="10">
+<p> Buffer Units:
+<select name="UNITS">
+    <option value="mi">Miles</option>
+    <option value="km">Kilometers</option>
+    <option value="ft">Feet</option>
+    <option value="m">Meters</option>
+</select>
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/convexhullform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/convexhullform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/convexhullform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/convexhullform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,35 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.CONVEXHULL" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/distanceform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/distanceform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/distanceform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/distanceform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,35 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.DISTANCE" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Other Geometry (WKT):
+<input type="text" name="OTHERGEOMETRY" value="" size="100">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="text/xml">text/xml</option>
+    <option value="application/json">application/json</option>
+</select>
+<p>
+    Clean JSON: <input type="text" name="CLEAN" value="1" ID="TextClean">
+<p> Coordinate System (CS-Map Code, for non-linear measurment):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geometryinfoform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/geometryinfoform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geometryinfoform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geometryinfoform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,31 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.GEOMETRYINFO" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="text/xml">text/xml</option>
+    <option value="application/json">application/json</option>
+</select>
+<p>
+    Clean JSON: <input type="text" name="CLEAN" value="1" ID="TextClean">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geoprocessingapi.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/geoprocessingapi.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geoprocessingapi.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/geoprocessingapi.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+        <title></title>
+        <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
+        <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    </head>
+    <body>
+        <UL>
+            <LI>
+                <A href="boundaryform.html" target="showform">Boundary</A>
+            <LI>
+                <A href="bufferform.html" target="showform">Buffer</A>
+            <LI>
+                <A href="convexhullform.html" target="showform">ConvexHull</A>
+            <LI>
+                <A href="distanceform.html" target="showform">Distance</A>
+            <LI>
+                <A href="geometryinfoform.html" target="showform">GeometryInfo</A>
+            <LI>
+                <A href="simplifyform.html" target="showform">Simplify</A>
+            <LI>
+                <A href="tessellateform.html" target="showform">Tessellate</A>
+            <LI>
+                <A href="binaryoperationform.html" target="showform">BinaryOperation</A>
+            <LI>
+                <A href="spatialpredicateform.html" target="showform">SpatialPredicate</A>
+        </UL>
+    </body>
+</html>

Modified: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectaggregatesform.html
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectaggregatesform.html	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectaggregatesform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -37,6 +37,8 @@
 			</select>
             <p>
                 Clean JSON: <input type="text" name="CLEAN" value="0" ID="TextClean">
+            <p> Coordinate Precision (if requesting clean JSON):
+                <input type="text" name="PRECISION" value="7" size="10">
             <p>
         <input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
         </form>

Modified: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectfeaturesform.html
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectfeaturesform.html	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/selectfeaturesform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -37,6 +37,8 @@
 			</select>
             <p>
                 Clean JSON: <input type="text" name="CLEAN" value="0" ID="TextClean">
+            <p> Coordinate Precision (if requesting clean JSON):
+                <input type="text" name="PRECISION" value="7" size="10">
             <p>
             <input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
         </form>

Modified: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/services.html
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/services.html	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/services.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -11,6 +11,7 @@
 <b>Services API</b>
 <li><a href="drawingserviceapi.html" target="apilist">Drawing</a></li>
 <li><a href="featureserviceapi.html" target="apilist">Feature</a></li>
+<li><a href="geoprocessingapi.html" target="apilist">Geo-Processing</a></li>
 <li><a href="mappingserviceapi.html" target="apilist">Mapping</a></li>
 <li><a href="renderingserviceapi.html" target="apilist">Rendering</a></li>
 <li><a href="resourceserviceapi.html" target="apilist">Resource</a></li>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/simplifyform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/simplifyform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/simplifyform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/simplifyform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,42 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.SIMPLIFY" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Algorithm:
+<select name="ALGORITHM">
+    <option value="0">Douglas-Peucker</option>
+    <option value="1">Topology Preserving</option>
+</select>
+<p> Tolerance:
+<input type="text" name="TOLERANCE" value="" size="10">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/spatialpredicateform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/spatialpredicateform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/spatialpredicateform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/spatialpredicateform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,37 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.SPATIALPREDICATE" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry A (WKT):
+<input type="text" name="GEOMETRYA" value="" size="100">
+<p> Geometry B (WKT):
+<input type="text" name="GEOMETRYB" value="" size="100">
+<p> Operator:
+<select name="OPERATOR">
+    <option value="CONTAINS">Contains</option>
+    <option value="CROSSES">Crosses</option>
+    <option value="DISJOINT">Disjoint</option>
+    <option value="EQUALS">Equals</option>
+    <option value="INTERSECTS">Intersects</option>
+    <option value="OVERLAPS">Overlaps</option>
+    <option value="TOUCHES">Touches</option>
+    <option value="WITHIN">Within</option>
+</select>
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Copied: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/tessellateform.html (from rev 9229, sandbox/jng/geoprocessing/UnitTest/WebTier/MapAgent/MapAgentForms/tessellateform.html)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/tessellateform.html	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/tessellateform.html	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,35 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="setactiontarget.js" >
+</script>
+</head>
+<body>
+<form name="input" action="" method="get">
+<b>Operation:</b>
+<input type="text" name="OPERATION" value="GEO.TESSELLATE" size="50">
+<p> Version:
+<input type="text" name="VERSION" value="3.3.0" size="10">
+<p> Locale:
+<input type="text" name="LOCALE" value="en" size="10">
+<p> Client Agent:
+<input type="text" name="CLIENTAGENT" value="MapGuide Developer" size="100">
+<p> Geometry (WKT):
+<input type="text" name="GEOMETRY" value="" size="100">
+<p> Output Format:
+<select name="FORMAT">
+    <option value="WKT">Geometry Well-Known Text</option>
+    <option value="GEOJSON">GeoJSON</option>
+</select>
+<p> Input Coordinate System (CS-Map Code):
+<input type="text" name="COORDINATESYSTEM" value="" size="10">
+<p> Output Coordinate System (CS-Map Code):
+<input type="text" name="TRANSFORMTO" value="" size="10">
+<p> Coordinate Precision (if requesting GeoJSON):
+<input type="text" name="PRECISION" value="7" size="10">
+<p>
+<input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">
+</form>
+</body>
+</html>
+<html>

Modified: trunk/MgDev/Web/src/DotNetUnmanagedApi/Geometry/GeometryApiGen.xml
===================================================================
--- trunk/MgDev/Web/src/DotNetUnmanagedApi/Geometry/GeometryApiGen.xml	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/DotNetUnmanagedApi/Geometry/GeometryApiGen.xml	2017-07-11 15:44:27 UTC (rev 9230)
@@ -130,6 +130,7 @@
     <Header path="../../../../Common/Geometry/PointCollection.h" />
     <Header path="../../../../Common/Geometry/Polygon.h" />
     <Header path="../../../../Common/Geometry/PolygonCollection.h" />
+    <Header path="../../../../Common/Geometry/PreparedGeometry.h" />
     <Header path="../../../../Common/Geometry/Transform.h" />
     <Header path="../../../../Common/Geometry/WktReaderWriter.h" />
   

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBinaryOperation.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,131 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoBinaryOperation.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoBinaryOperation)
+
+MgHttpGeoBinaryOperation::MgHttpGeoBinaryOperation(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT_A = params->GetParameterValue(MgHttpResourceStrings::reqGeoA);
+    m_geomWKT_B = params->GetParameterValue(MgHttpResourceStrings::reqGeoB);
+    m_operator = params->GetParameterValue(MgHttpResourceStrings::reqGeoOperator);
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoBinaryOperation::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> geomA = wktRw->Read(m_geomWKT_A);
+    Ptr<MgGeometry> geomB = wktRw->Read(m_geomWKT_B);
+    Ptr<MgGeometry> result;
+
+    if (m_operator == L"UNION")
+        result = geomA->Union(geomB);
+    else if (m_operator == L"DIFFERENCE")
+        result = geomA->Difference(geomB);
+    else if (m_operator == L"INTERSECTION")
+        result = geomA->Intersection(geomB);
+    else if (m_operator == L"SYMMETRICDIFFERENCE")
+        result = geomA->SymetricDifference(geomB);
+    else
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqGeoOperator);
+        arguments.Add(m_operator);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoBinaryOperation.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidFeatureSpatialOperation", NULL);
+    }
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoBinaryOperation.Execute")
+}
+
+void MgHttpGeoBinaryOperation::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoBinaryOperation.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoBinaryOperation.ValidateOperationVersion");
+}
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBinaryOperation.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBinaryOperation.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,66 @@
+//
+//  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 MG_HTTP_GEO_BINARY_OPERATION_H
+#define MG_HTTP_GEO_BINARY_OPERATION_H
+
+class MgHttpGeoBinaryOperation : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoBinaryOperation(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+private:
+    STRING m_geomWKT_A;
+    STRING m_geomWKT_B;
+    STRING m_operator;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBoundary.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,118 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoBoundary.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoBoundary)
+
+MgHttpGeoBoundary::MgHttpGeoBoundary(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoBoundary::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoBoundary.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+    Ptr<MgGeometry> result = input->ConvexHull();
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoBoundary.Execute")
+}
+
+void MgHttpGeoBoundary::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+        // There are multiple supported versions
+        INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoBoundary.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoBoundary.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBoundary.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBoundary.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,65 @@
+//
+//  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 MG_HTTP_GEO_BOUNDARY_H
+#define MG_HTTP_GEO_BOUNDARY_H
+
+class MgHttpGeoBoundary : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoBoundary(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBuffer.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,153 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoBuffer.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoBuffer)
+
+MgHttpGeoBuffer::MgHttpGeoBuffer(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_units = params->GetParameterValue(MgHttpResourceStrings::reqGeoBufferUnits);
+    m_distance = MgUtil::StringToDouble(params->GetParameterValue(MgHttpResourceStrings::reqGeoBufferDistance));
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoBuffer::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoBuffer.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    if (m_coordinateSystem.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqGeoCoordinateSystem);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoBuffer.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    if (m_format != L"WKT" && m_format != L"GEOJSON")
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqGeoFormat);
+        arguments.Add(m_format);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoBuffer.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidValueOutsideRange", NULL);
+    }
+
+    //Convert distance to meters
+    if (m_units == L"mi")      //miles
+        m_distance *= 1609.35;
+    else if (m_units == L"km") //kilometers
+        m_distance *= 1000;
+    else if (m_units == L"ft") //feet
+        m_distance *= 0.30480;
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+
+    Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+    Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+    Ptr<MgMeasure> measure = cs->GetMeasure();
+
+    double bufDist = cs->ConvertMetersToCoordinateSystemUnits(m_distance);
+    Ptr<MgGeometry> result = input->Buffer(bufDist, measure);
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoBuffer.Execute")
+}
+
+void MgHttpGeoBuffer::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoBuffer.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoBuffer.ValidateOperationVersion");
+}
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoBuffer.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoBuffer.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,67 @@
+//
+//  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 MG_HTTP_GEO_BUFFER_H
+#define MG_HTTP_GEO_BUFFER_H
+
+class MgHttpGeoBuffer : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoBuffer(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    STRING m_units;
+    double m_distance;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoConvexHull.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,118 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoConvexHull.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoConvexHull)
+
+MgHttpGeoConvexHull::MgHttpGeoConvexHull(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoConvexHull::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoConvexHull.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+    Ptr<MgGeometry> result = input->ConvexHull();
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoConvexHull.Execute")
+}
+
+void MgHttpGeoConvexHull::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoConvexHull.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoConvexHull.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoConvexHull.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoConvexHull.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,65 @@
+//
+//  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 MG_HTTP_GEO_CONVEX_HULL_H
+#define MG_HTTP_GEO_CONVEX_HULL_H
+
+class MgHttpGeoConvexHull : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoConvexHull(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoDistance.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,125 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoDistance.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoDistance)
+
+MgHttpGeoDistance::MgHttpGeoDistance(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_geomOther = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometryOther);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+}
+
+void MgHttpGeoDistance::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+        // Check common parameters
+        ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoDistance.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    if (m_geomOther.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometryOther);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoDistance.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+    Ptr<MgGeometry> other = wktRw->Read(m_geomOther);
+
+    Ptr<MgCoordinateSystem> cs;
+    Ptr<MgMeasure> measure;
+
+    if (!m_coordinateSystem.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        cs = csFactory->CreateFromCode(m_coordinateSystem);
+        measure = cs->GetMeasure();
+    }
+
+    double distance = input->Distance(other, measure);
+    if (NULL != cs.p)
+    {
+        distance = cs->ConvertCoordinateSystemUnitsToMeters(distance);
+    }
+
+    std::string mbXml;
+    mbXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+    mbXml += "<UnitOfMeasure xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"UnitOfMeasure-3.3.0.xsd\">";
+    mbXml += "<Value>";
+    std::string sDistance;
+    MgUtil::DoubleToString(distance, sDistance);
+    mbXml += sDistance;
+    mbXml += "</Value>";
+    if (NULL != measure.p) //If a measure was given, this will be in meters
+    {
+        mbXml += "<Unit>meters</Unit>";
+    }
+    else //Otherwise this is a linear distance measure. We don't know what the units are here
+    {
+        mbXml += "<Unit>unknown</Unit>";
+    }
+    
+    mbXml += "</UnitOfMeasure>";
+
+    Ptr<MgByteSource> bs = new MgByteSource((BYTE_ARRAY_IN)mbXml.c_str(), (INT32)mbXml.length());
+    bs->SetMimeType(MgMimeType::Xml);
+    Ptr<MgByteReader> br = bs->GetReader();
+
+    //Convert to alternate response format, if necessary
+    ProcessFormatConversion(br);
+
+    hResult->SetResultObject(br, br->GetMimeType());
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoDistance.Execute")
+}
+
+void MgHttpGeoDistance::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoDistance.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoDistance.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoDistance.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoDistance.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,62 @@
+//
+//  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 MG_HTTP_GEO_DISTANCE_H
+#define MG_HTTP_GEO_DISTANCE_H
+
+class MgHttpGeoDistance : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoDistance(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    STRING m_geomOther;
+    STRING m_coordinateSystem;
+};
+
+#endif
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoSimplify.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,135 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoSimplify.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoSimplify)
+
+MgHttpGeoSimplify::MgHttpGeoSimplify(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_algorithm = MgUtil::StringToInt32(params->GetParameterValue(MgHttpResourceStrings::reqGeoAlgorithm));
+    m_tolerance = MgUtil::StringToDouble(params->GetParameterValue(MgHttpResourceStrings::reqGeoTolerance));
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoSimplify::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoSimplify.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    if (m_algorithm != MgGeometrySimplificationAlgorithmType::DouglasPeucker &&
+        m_algorithm != MgGeometrySimplificationAlgorithmType::TopologyPreserving)
+    {
+        STRING arg;
+        MgUtil::Int32ToString(m_algorithm, arg);
+
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqGeoAlgorithm);
+        arguments.Add(arg);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoSimplify.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidValueOutsideRange", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+    Ptr<MgGeometrySimplifier> simp = new MgGeometrySimplifier();
+    Ptr<MgGeometry> result = simp->Simplify(input, m_tolerance, m_algorithm);
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoSimplify.Execute")
+}
+
+void MgHttpGeoSimplify::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoSimplify.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoSimplify.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoSimplify.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoSimplify.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,67 @@
+//
+//  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 MG_HTTP_GEO_SIMPLIFY_H
+#define MG_HTTP_GEO_SIMPLIFY_H
+
+class MgHttpGeoSimplify : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoSimplify(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    INT32 m_algorithm;
+    double m_tolerance;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoSpatialPredicate.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,93 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoSpatialPredicate.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoSpatialPredicate)
+
+MgHttpGeoSpatialPredicate::MgHttpGeoSpatialPredicate(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT_A = params->GetParameterValue(MgHttpResourceStrings::reqGeoA);
+    m_geomWKT_B = params->GetParameterValue(MgHttpResourceStrings::reqGeoB);
+    m_operator = params->GetParameterValue(MgHttpResourceStrings::reqGeoOperator);
+}
+
+
+void MgHttpGeoSpatialPredicate::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> geomA = wktRw->Read(m_geomWKT_A);
+    Ptr<MgGeometry> geomB = wktRw->Read(m_geomWKT_B);
+    bool result = false;
+
+    if (m_operator == L"CONTAINS")
+        result = geomA->Contains(geomB);
+    else if (m_operator == L"CROSSES")
+        result = geomA->Crosses(geomB);
+    else if (m_operator == L"DISJOINT")
+        result = geomA->Disjoint(geomB);
+    else if (m_operator == L"EQUALS")
+        result = geomA->Equals(geomB);
+    else if (m_operator == L"INTERSECTS")
+        result = geomA->Intersects(geomB);
+    else if (m_operator == L"OVERLAPS")
+        result = geomA->Overlaps(geomB);
+    else if (m_operator == L"TOUCHES")
+        result = geomA->Touches(geomB);
+    else if (m_operator == L"WITHIN")
+        result = geomA->Within(geomB);
+    else
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqGeoOperator);
+        arguments.Add(m_operator);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoSpatialPredicate.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidFeatureSpatialOperation", NULL);
+    }
+
+    Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(result);
+    hResult->SetResultObject(value, MgMimeType::Text);
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoSpatialPredicate.Execute")
+}
+
+void MgHttpGeoSpatialPredicate::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoSpatialPredicate.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoSpatialPredicate.ValidateOperationVersion");
+}
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoSpatialPredicate.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoSpatialPredicate.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,62 @@
+//
+//  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 MG_HTTP_GEO_SPATIAL_PREDICATE_H
+#define MG_HTTP_GEO_SPATIAL_PREDICATE_H
+
+class MgHttpGeoSpatialPredicate : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoSpatialPredicate(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT_A;
+    STRING m_geomWKT_B;
+    STRING m_operator;
+};
+
+#endif
\ No newline at end of file

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoTessellate.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,118 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeoTessellate.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeoTessellate)
+
+MgHttpGeoTessellate::MgHttpGeoTessellate(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+    m_format = params->GetParameterValue(MgHttpResourceStrings::reqGeoFormat);
+    m_coordinateSystem = params->GetParameterValue(MgHttpResourceStrings::reqGeoCoordinateSystem);
+    m_transformTo = params->GetParameterValue(MgHttpResourceStrings::reqGeoTransformTo);
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
+}
+
+void MgHttpGeoTessellate::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeoTessellate.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+    Ptr<MgGeometry> result = input->Tessellate();
+
+    if (!m_transformTo.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> cs = csFactory->CreateFromCode(m_coordinateSystem);
+        Ptr<MgCoordinateSystem> target = csFactory->CreateFromCode(m_transformTo);
+        Ptr<MgCoordinateSystemTransform> xform = csFactory->GetTransform(cs, target);
+        Ptr<MgGeometry> xGeom = (MgGeometry*)result->Transform(xform);
+
+        result = xGeom;
+    }
+
+    if (m_format == L"WKT")
+    {
+        STRING wkt = wktRw->Write(result);
+        Ptr<MgHttpPrimitiveValue> value = new MgHttpPrimitiveValue(wkt);
+        hResult->SetResultObject(value, MgMimeType::Text);
+    }
+    else if (m_format == L"GEOJSON")
+    {
+        MgGeoJsonWriter gw;
+        gw.SetPrecisionEnabled(m_bEnablePrecision);
+        gw.SetPrecision(m_precision);
+        STRING geoJson = gw.GeometryToGeoJson(result);
+
+        std::string mbGeoJson;
+        MgUtil::WideCharToMultiByte(geoJson, mbGeoJson);
+
+        Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)mbGeoJson.c_str(), (INT32)mbGeoJson.length());
+        byteSource->SetMimeType(MgMimeType::Json);
+        Ptr<MgByteReader> byteReader = byteSource->GetReader();
+
+        hResult->SetResultObject(byteReader, byteReader->GetMimeType());
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeoTessellate.Execute")
+}
+
+void MgHttpGeoTessellate::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+        // There are multiple supported versions
+        INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeoTessellate.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeoTessellate.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeoTessellate.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeoTessellate.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,65 @@
+//
+//  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 MG_HTTP_GEO_TESSELLATE_H
+#define MG_HTTP_GEO_TESSELLATE_H
+
+class MgHttpGeoTessellate : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeoTessellate(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+    STRING m_format;
+    STRING m_coordinateSystem;
+    STRING m_transformTo;
+    INT32 m_precision;
+    bool m_bEnablePrecision;
+};
+
+#endif

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.cpp (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeometryInfo.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,161 @@
+//
+//  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 "HttpHandler.h"
+#include "HttpGeometryInfo.h"
+
+HTTP_IMPLEMENT_CREATE_OBJECT(MgHttpGeometryInfo)
+
+MgHttpGeometryInfo::MgHttpGeometryInfo(MgHttpRequest* hRequest)
+{
+    InitializeCommonParameters(hRequest);
+    Ptr<MgHttpRequestParam> params = hRequest->GetRequestParam();
+    m_geomWKT = params->GetParameterValue(MgHttpResourceStrings::reqFeatGeometry);
+}
+
+void MgHttpGeometryInfo::Execute(MgHttpResponse & hResponse)
+{
+    Ptr<MgHttpResult> hResult = hResponse.GetResult();
+
+    MG_HTTP_HANDLER_TRY()
+
+    // Check common parameters
+    ValidateCommonParameters();
+
+    if (m_geomWKT.empty())
+    {
+        MgStringCollection arguments;
+        arguments.Add(MgHttpResourceStrings::reqFeatGeometry);
+        arguments.Add(MgResources::BlankArgument);
+
+        throw new MgInvalidArgumentException(L"MgHttpGeometryInfo.Execute",
+            __LINE__, __WFILE__, &arguments, L"MgStringEmpty", NULL);
+    }
+
+    Ptr<MgWktReaderWriter> wktRw = new MgWktReaderWriter();
+    Ptr<MgGeometry> input = wktRw->Read(m_geomWKT);
+
+    //Collect all geometry information
+    double area = input->GetArea();
+    INT32 dim = input->GetDimension();
+    double length = input->GetLength();
+    bool isClosed = input->IsClosed();
+    bool isEmpty = input->IsEmpty();
+    bool isSimple = input->IsSimple();
+    bool isValid = input->IsValid();
+    Ptr<MgEnvelope> env = input->Envelope();
+    Ptr<MgPoint> centroid = input->GetCentroid();
+    Ptr<MgCoordinate> cCentroid = centroid->GetCoordinate();
+    Ptr<MgCoordinate> envLL = env->GetLowerLeftCoordinate();
+    Ptr<MgCoordinate> envUR = env->GetUpperRightCoordinate();
+
+    std::string mbXml;
+    mbXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+    mbXml += "<GeometryInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"GeometryInfo-3.3.0.xsd\">";
+    mbXml += "<Area>";
+    std::string sArea;
+    MgUtil::DoubleToString(area, sArea);
+    mbXml += sArea;
+    mbXml += "</Area>";
+    mbXml += "<Dimension>";
+    std::string sDim;
+    MgUtil::Int32ToString(dim, sDim);
+    mbXml += sDim;
+    mbXml += "</Dimension>";
+    mbXml += "<Length>";
+    std::string sLen;
+    MgUtil::DoubleToString(length, sLen);
+    mbXml += sLen;
+    mbXml += "</Length>";
+    mbXml += "<IsClosed>";
+    mbXml += (isClosed ? "true" : "false");
+    mbXml += "</IsClosed>";
+    mbXml += "<IsEmpty>";
+    mbXml += (isEmpty ? "true" : "false");
+    mbXml += "</IsEmpty>";
+    mbXml += "<IsSimple>";
+    mbXml += (isSimple ? "true" : "false");
+    mbXml += "</IsSimple>";
+    mbXml += "<IsValid>";
+    mbXml += (isValid ? "true" : "false");
+    mbXml += "</IsValid>";
+    mbXml += "<Envelope>";
+    mbXml += "<LowerLeft>";
+    mbXml += "<X>";
+    std::string sLLX;
+    MgUtil::DoubleToString(envLL->GetX(), sLLX);
+    mbXml += sLLX;
+    mbXml += "</X>";
+    mbXml += "<Y>";
+    std::string sLLY;
+    MgUtil::DoubleToString(envLL->GetY(), sLLY);
+    mbXml += sLLY;
+    mbXml += "</Y>";
+    mbXml += "</LowerLeft>";
+    mbXml += "<UpperRight>";
+    mbXml += "<X>";
+    std::string sURX;
+    MgUtil::DoubleToString(envUR->GetX(), sURX);
+    mbXml += sURX;
+    mbXml += "</X>";
+    mbXml += "<Y>";
+    std::string sURY;
+    MgUtil::DoubleToString(envUR->GetY(), sURY);
+    mbXml += sURY;
+    mbXml += "</Y>";
+    mbXml += "</UpperRight>";
+    mbXml += "</Envelope>";
+    mbXml += "<Centroid>";
+    mbXml += "<X>";
+    std::string sCentX;
+    MgUtil::DoubleToString(cCentroid->GetX(), sCentX);
+    mbXml += sCentX;
+    mbXml += "</X>";
+    mbXml += "<Y>";
+    std::string sCentY;
+    MgUtil::DoubleToString(cCentroid->GetY(), sCentY);
+    mbXml += sCentY;
+    mbXml += "</Y>";
+    mbXml += "</Centroid>";
+    mbXml += "</GeometryInfo>";
+
+    Ptr<MgByteSource> bs = new MgByteSource((BYTE_ARRAY_IN)mbXml.c_str(), (INT32)mbXml.length());
+    bs->SetMimeType(MgMimeType::Xml);
+    Ptr<MgByteReader> br = bs->GetReader();
+
+    //Convert to alternate response format, if necessary
+    ProcessFormatConversion(br);
+
+    hResult->SetResultObject(br, br->GetMimeType());
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpGeometryInfo.Execute")
+}
+
+void MgHttpGeometryInfo::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(3, 3, 0))
+    {
+        throw new MgInvalidOperationVersionException(
+            L"MgHttpGeometryInfo.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpGeometryInfo.ValidateOperationVersion");
+}

Copied: trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.h (from rev 9229, sandbox/jng/geoprocessing/Web/src/HttpHandler/HttpGeometryInfo.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/HttpGeometryInfo.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -0,0 +1,60 @@
+//
+//  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 MG_HTTP_GEOMETRY_INFO_H
+#define MG_HTTP_GEOMETRY_INFO_H
+
+class MgHttpGeometryInfo : public MgHttpRequestResponseHandler
+{
+    HTTP_DECLARE_CREATE_OBJECT()
+
+public:
+    /// <summary>
+    /// Initializes the common parameters of the request.
+    /// </summary>
+    /// <param name="name">Input
+    /// MgHttpRequest
+    /// This contains all the parameters of the request.
+    /// </param>
+    /// <returns>
+    /// nothing
+    /// </returns>
+    MgHttpGeometryInfo(MgHttpRequest *hRequest);
+
+    /// <summary>
+    /// Executes the specific request.
+    /// </summary>
+    /// <param name="hResponse">Input
+    /// This contains the response (including MgHttpResult and StatusCode) from the server.
+    /// </param>
+    void Execute(MgHttpResponse& hResponse);
+
+    /// <summary>
+    /// Returns the classification of this request/response handler
+    /// </summary>
+    /// <returns>
+    /// Classification of handler
+    /// </returns>
+    MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
+
+    virtual void ValidateOperationVersion();
+
+private:
+    STRING m_geomWKT;
+};
+
+#endif

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj	2017-07-11 15:44:27 UTC (rev 9230)
@@ -210,6 +210,18 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="HttpGeoBoundary.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="HttpGeoConvexHull.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="HttpCopyResource.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -282,6 +294,48 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="HttpGeoBinaryOperation.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="HttpGeoBuffer.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="HttpGeoDistance.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="HttpGeometryInfo.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="HttpGeoSimplify.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="HttpGeoSpatialPredicate.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="HttpGeoTessellate.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="HttpGetRepositoryContent.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -945,6 +999,8 @@
   <ItemGroup>
     <ClInclude Include="HttpApplyResourcePackage.h" />
     <ClInclude Include="HttpChangeResourceOwner.h" />
+    <ClInclude Include="HttpGeoBoundary.h" />
+    <ClInclude Include="HttpGeoConvexHull.h" />
     <ClInclude Include="HttpCopyResource.h" />
     <ClInclude Include="HttpCreateRepository.h" />
     <ClInclude Include="HttpCreateRuntimeMap.h" />
@@ -957,6 +1013,13 @@
     <ClInclude Include="HttpEnumerateResourceReferences.h" />
     <ClInclude Include="HttpEnumerateResources.h" />
     <ClInclude Include="HttpEnumerateUnmanagedData.h" />
+    <ClInclude Include="HttpGeoBuffer.h" />
+    <ClInclude Include="HttpGeoBinaryOperation.h" />
+    <ClInclude Include="HttpGeoDistance.h" />
+    <ClInclude Include="HttpGeometryInfo.h" />
+    <ClInclude Include="HttpGeoSimplify.h" />
+    <ClInclude Include="HttpGeoSpatialPredicate.h" />
+    <ClInclude Include="HttpGeoTessellate.h" />
     <ClInclude Include="HttpGetRepositoryContent.h" />
     <ClInclude Include="HttpGetRepositoryHeader.h" />
     <ClInclude Include="HttpGetResourceContent.h" />

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-07-11 15:44:27 UTC (rev 9230)
@@ -40,6 +40,9 @@
     <Filter Include="Byte Source Adapters">
       <UniqueIdentifier>{0f2e34d9-18f7-49af-b11f-8d3c874192ec}</UniqueIdentifier>
     </Filter>
+    <Filter Include="GeoProcessing">
+      <UniqueIdentifier>{d7514524-5f3c-40fd-8b93-45a3020d8614}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="HttpApplyResourcePackage.cpp">
@@ -386,6 +389,33 @@
     <ClCompile Include="HttpDescribeRuntimeMap.cpp">
       <Filter>Mapping Service</Filter>
     </ClCompile>
+    <ClCompile Include="HttpGeoBuffer.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoBinaryOperation.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoSimplify.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoSpatialPredicate.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoDistance.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoConvexHull.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeometryInfo.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoTessellate.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
+    <ClCompile Include="HttpGeoBoundary.cpp">
+      <Filter>GeoProcessing</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="HttpApplyResourcePackage.h">
@@ -757,6 +787,33 @@
     <ClInclude Include="HttpDescribeRuntimeMap.h">
       <Filter>Mapping Service</Filter>
     </ClInclude>
+    <ClInclude Include="HttpGeoBuffer.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoSimplify.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoSpatialPredicate.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoBinaryOperation.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoDistance.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoConvexHull.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeometryInfo.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoTessellate.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
+    <ClInclude Include="HttpGeoBoundary.h">
+      <Filter>GeoProcessing</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="HttpHandler.rc" />

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -55,6 +55,15 @@
 #include "HttpEnumerateApplicationTemplates.cpp"
 #include "HttpEnumerateApplicationWidgets.cpp"
 #include "HttpEnumerateApplicationContainers.cpp"
+#include "HttpGeoBoundary.cpp"
+#include "HttpGeoBuffer.cpp"
+#include "HttpGeoBinaryOperation.cpp"
+#include "HttpGeoConvexHull.cpp"
+#include "HttpGeoDistance.cpp"
+#include "HttpGeometryInfo.cpp"
+#include "HttpGeoSimplify.cpp"
+#include "HttpGeoSpatialPredicate.cpp"
+#include "HttpGeoTessellate.cpp"
 #include "HttpGetCapabilities.cpp"
 #include "HttpGetConnectionPropertyValues.cpp"
 #include "HttpGetDefaultTileSizeX.cpp"

Modified: trunk/MgDev/Web/src/HttpHandler/HttpRequest.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpRequest.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpRequest.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -124,6 +124,17 @@
 #include "HttpCsGetBaseLibrary.h"
 #include "HttpCsIsValid.h"
 
+// Geo-Processing
+#include "HttpGeoBoundary.h"
+#include "HttpGeoBuffer.h"
+#include "HttpGeoBinaryOperation.h"
+#include "HttpGeoConvexHull.h"
+#include "HttpGeoDistance.h"
+#include "HttpGeometryInfo.h"
+#include "HttpGeoSimplify.h"
+#include "HttpGeoSpatialPredicate.h"
+#include "HttpGeoTessellate.h"
+
 #include <algorithm>
 using namespace std;
 
@@ -431,6 +442,15 @@
     httpClassCreators[MgHttpResourceStrings::opEnumerateApplicationContainers] = MgHttpEnumerateApplicationContainers::CreateObject;
     httpClassCreators[MgHttpResourceStrings::opGetDefaultTileSizeX] = MgHttpGetDefaultTileSizeX::CreateObject;
     httpClassCreators[MgHttpResourceStrings::opGetDefaultTileSizeY] = MgHttpGetDefaultTileSizeY::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoBoundary] = MgHttpGeoBoundary::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoBuffer] = MgHttpGeoBuffer::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoBinaryOperation] = MgHttpGeoBinaryOperation::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoConvexHull] = MgHttpGeoConvexHull::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoDistance] = MgHttpGeoDistance::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeometryInfo] = MgHttpGeometryInfo::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoSimplify] = MgHttpGeoSimplify::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoSpatialPredicate] = MgHttpGeoSpatialPredicate::CreateObject;
+    httpClassCreators[MgHttpResourceStrings::opGeoTessellate] = MgHttpGeoTessellate::CreateObject;
 
     httpPostHandlerCreators.push_back(MgHttpWfsGetCapabilities::ProcessPostRequest);
     httpPostHandlerCreators.push_back(MgHttpWfsDescribeFeatureType::ProcessPostRequest);

Modified: trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -149,6 +149,7 @@
 const STRING MgHttpResourceStrings::reqFeatGeomProperty = L"GEOMPROPERTY";
 const STRING MgHttpResourceStrings::reqFeatSpatialOp = L"SPATIALOP";
 const STRING MgHttpResourceStrings::reqFeatGeometry = L"GEOMETRY";
+const STRING MgHttpResourceStrings::reqFeatGeometryOther = L"OTHERGEOMETRY";
 const STRING MgHttpResourceStrings::reqFeatProperties = L"PROPERTIES";
 const STRING MgHttpResourceStrings::reqFeatActiveOnly = L"ACTIVEONLY";
 const STRING MgHttpResourceStrings::reqFeatComputedProperties = L"COMPUTED_PROPERTIES";
@@ -363,6 +364,29 @@
 const STRING MgHttpResourceStrings::opEnumerateApplicationWidgets = L"ENUMERATEAPPLICATIONWIDGETS";
 const STRING MgHttpResourceStrings::opEnumerateApplicationContainers = L"ENUMERATEAPPLICATIONCONTAINERS";
 
+// Geo-Processing Operations
+const STRING MgHttpResourceStrings::opGeoBoundary = L"GEO.BOUNDARY";
+const STRING MgHttpResourceStrings::opGeoBuffer = L"GEO.BUFFER";
+const STRING MgHttpResourceStrings::opGeoConvexHull = L"GEO.CONVEXHULL";
+const STRING MgHttpResourceStrings::opGeoDistance = L"GEO.DISTANCE";
+const STRING MgHttpResourceStrings::opGeometryInfo = L"GEO.GEOMETRYINFO";
+const STRING MgHttpResourceStrings::opGeoSimplify = L"GEO.SIMPLIFY";
+const STRING MgHttpResourceStrings::opGeoSpatialPredicate = L"GEO.SPATIALPREDICATE";
+const STRING MgHttpResourceStrings::opGeoTessellate = L"GEO.TESSELLATE";
+const STRING MgHttpResourceStrings::opGeoBinaryOperation = L"GEO.BINARYOPERATION";
+
+const STRING MgHttpResourceStrings::reqGeoA = L"GEOMETRYA";
+const STRING MgHttpResourceStrings::reqGeoB = L"GEOMETRYB";
+const STRING MgHttpResourceStrings::reqGeoBufferDistance = L"DISTANCE";
+const STRING MgHttpResourceStrings::reqGeoBufferUnits = L"UNITS";
+const STRING MgHttpResourceStrings::reqGeoOperator = L"OPERATOR";
+const STRING MgHttpResourceStrings::reqGeoCoordinateSystem = L"COORDINATESYSTEM";
+const STRING MgHttpResourceStrings::reqGeoFormat = L"FORMAT";
+const STRING MgHttpResourceStrings::reqGeoTransformTo = L"TRANSFORMTO";
+const STRING MgHttpResourceStrings::reqGeoAlgorithm = L"ALGORITHM";
+const STRING MgHttpResourceStrings::reqGeoTolerance = L"TOLERANCE";
+const STRING MgHttpResourceStrings::reqGeoPrecision = L"PRECISION";
+
 // Coordinate System Request Parameters
 const STRING MgHttpResourceStrings::reqCsWkt = L"CSWKT";
 const STRING MgHttpResourceStrings::reqCsCode = L"CSCODE";

Modified: trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -125,6 +125,7 @@
     static const STRING reqFeatGeomProperty;
     static const STRING reqFeatSpatialOp;
     static const STRING reqFeatGeometry;
+    static const STRING reqFeatGeometryOther;
     static const STRING reqFeatActiveOnly;
     static const STRING reqFeatComputedProperties;
     static const STRING reqFeatComputedAliases;
@@ -367,7 +368,29 @@
     static const STRING opEnumerateApplicationWidgets;
     static const STRING opEnumerateApplicationContainers;
 
+    // Geo-Processing Operations
+    static const STRING opGeoBoundary;
+    static const STRING opGeoBuffer;
+    static const STRING opGeoConvexHull;
+    static const STRING opGeoDistance;
+    static const STRING opGeometryInfo;
+    static const STRING opGeoSimplify;
+    static const STRING opGeoSpatialPredicate;
+    static const STRING opGeoTessellate;
+    static const STRING opGeoBinaryOperation;
 
+    static const STRING reqGeoA;
+    static const STRING reqGeoB;
+    static const STRING reqGeoBufferDistance;
+    static const STRING reqGeoBufferUnits;
+    static const STRING reqGeoOperator;
+    static const STRING reqGeoCoordinateSystem;
+    static const STRING reqGeoFormat;
+    static const STRING reqGeoTransformTo;
+    static const STRING reqGeoAlgorithm;
+    static const STRING reqGeoTolerance;
+    static const STRING reqGeoPrecision;
+
     // Coordinate System Request Parameters
     static const STRING reqCsWkt;
     static const STRING reqCsCode;

Modified: trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -42,6 +42,19 @@
     //Default to xml if not specified
     if (m_responseFormat.empty())
         m_responseFormat = MgMimeType::Xml;
+
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
 }
 
 /// <summary>
@@ -110,7 +123,7 @@
 
     Ptr<MgFeatureReader> featureReader = service->SelectFeatures(&resId, m_className, qryOptions);
     //MgByteSource owns this and will clean it up when done
-    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(featureReader, m_responseFormat, m_bCleanJson);
+    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(featureReader, m_responseFormat, m_bCleanJson, m_bEnablePrecision, m_precision);
 
     Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
     byteSource->SetMimeType(m_responseFormat);

Modified: trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpSelectFeatures.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -46,6 +46,8 @@
 private:
     STRING  m_resId;
     STRING  m_className;
+    INT32   m_precision;
+    bool    m_bEnablePrecision;
 };
 
 #endif  // _FS_SELECT_FEATURES_H

Modified: trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -52,6 +52,19 @@
     //Default to xml if not specified
     if (m_responseFormat.empty())
         m_responseFormat = MgMimeType::Xml;
+
+    m_precision = -1;
+    m_bEnablePrecision = false;
+    STRING sPrecision = params->GetParameterValue(MgHttpResourceStrings::reqGeoPrecision);
+    if (!sPrecision.empty())
+    {
+        INT32 precision = MgUtil::StringToInt32(sPrecision);
+        if (precision > 0)
+        {
+            m_precision = precision;
+            m_bEnablePrecision = true;
+        }
+    }
 }
 
 /// <summary>
@@ -120,7 +133,7 @@
 
     Ptr<MgDataReader> dataReader = service->SelectAggregate(&resId, m_className, qryOptions);
     //MgByteSource owns this and will clean it up when done
-    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(dataReader, m_responseFormat, m_bCleanJson);
+    ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(dataReader, m_responseFormat, m_bCleanJson, m_bEnablePrecision, m_precision);
 
     Ptr<MgByteSource> byteSource = new MgByteSource(bsImpl);
     byteSource->SetMimeType(m_responseFormat);

Modified: trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/HttpSelectFeaturesSpatially.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -49,6 +49,8 @@
     STRING  m_geometry;
     STRING  m_geometryClass;
     INT32   m_operation;
+    INT32   m_precision;
+    bool    m_bEnablePrecision;
 };
 
 #endif  // _FS_SELECT_FEATURES_SPATIALLY_H

Modified: trunk/MgDev/Web/src/HttpHandler/Makefile.am
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/Makefile.am	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/Makefile.am	2017-07-11 15:44:27 UTC (rev 9230)
@@ -54,6 +54,15 @@
   HttpEnumerateApplicationContainers.cpp \
   HttpEnumerateApplicationWidgets.cpp \
   HttpEnumerateApplicationTemplates.cpp \
+  HttpGeoBinaryOperation.cpp \
+  HttpGeoBoundary.cpp \
+  HttpGeoBuffer.cpp \
+  HttpGeoConvexHull.cpp \
+  HttpGeoDistance.cpp \
+  HttpGeometryInfo.cpp \
+  HttpGeoSimplify.cpp \
+  HttpGeoSpatialPredicate.cpp \
+  HttpGeoTessellate.cpp \
   HttpGetCapabilities.cpp \
   HttpGetClassDefinition.cpp \
   HttpGetClasses.cpp \
@@ -179,6 +188,15 @@
   HttpEnumerateApplicationContainers.h \
   HttpEnumerateApplicationWidgets.h \
   HttpEnumerateApplicationTemplates.h \
+  HttpGeoBinaryOperation.h \
+  HttpGeoBoundary.h \
+  HttpGeoBuffer.h \
+  HttpGeoConvexHull.h \
+  HttpGeoDistance.h \
+  HttpGeometryInfo.h \
+  HttpGeoSimplify.h \
+  HttpGeoSpatialPredicate.h \
+  HttpGeoTessellate.h \
   HttpGetCapabilities.h \
   HttpGetClassDefinition.h \
   HttpGetClasses.h \

Modified: trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -17,7 +17,7 @@
 #include "ReaderByteSourceImpl.h"
 #include "PlatformBase.h"
 
-MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson)
+MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson, bool bEnablePrecision, INT32 precision)
 {
     m_reader = SAFE_ADDREF(reader);
     m_format = format;
@@ -27,6 +27,8 @@
     m_bInternalReaderHasMore = true;
     m_bFirstRecord = true;
     m_bCleanJson = bCleanJson;
+    m_bEnablePrecision = bEnablePrecision;
+    m_precision = precision;
 }
 
 MgReaderByteSourceImpl::~MgReaderByteSourceImpl()
@@ -167,6 +169,8 @@
                 if (m_bCleanJson)
                 {
                     MgGeoJsonWriter geoJsonWriter;
+                    geoJsonWriter.SetPrecisionEnabled(m_bEnablePrecision);
+                    geoJsonWriter.SetPrecision(m_precision);
                     STRING sGeoJson;
                     if (m_reader->GetReaderType() == MgReaderType::FeatureReader)
                     {

Modified: trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-07-11 15:44:27 UTC (rev 9230)
@@ -29,7 +29,7 @@
     DECLARE_CLASSNAME(MgReaderByteSourceImpl)
 
 public:
-    MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson);
+    MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson, bool bEnablePrecision, INT32 precision);
     virtual ~MgReaderByteSourceImpl();
 
     ///////////////////////////////////////////////////////////////////////////
@@ -89,9 +89,11 @@
     bool m_bReadHeader;
     bool m_bInternalReaderHasMore;
     bool m_bFirstRecord;
+    bool m_bEnablePrecision;
 
     std::string m_buf;
     INT32 m_bufOffset;
+    INT32 m_precision;
 };
 
 #endif
\ No newline at end of file

Modified: trunk/MgDev/Web/src/HttpHandler/XmlJsonConvert.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/XmlJsonConvert.cpp	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/HttpHandler/XmlJsonConvert.cpp	2017-07-11 15:44:27 UTC (rev 9230)
@@ -944,6 +944,22 @@
     s_elementPathTypeMap["/ClassDefinition/Properties/Property/HasMeasure"] = XML_DATA_TYPE_BOOLEAN;
     s_elementPathTypeMap["/ClassDefinition/Properties/Property/DefaultImageXSize"] = XML_DATA_TYPE_NUM_INT;
     s_elementPathTypeMap["/ClassDefinition/Properties/Property/DefaultImageYSize"] = XML_DATA_TYPE_NUM_INT;
+    //UnitOfMeasure-3.3.0.xsd
+    s_elementPathTypeMap["/UnitOfMeasure/Value"] = XML_DATA_TYPE_NUM_DOUBLE;
+    //GeometryInfo-3.3.0.xsd
+    s_elementPathTypeMap["/GeometryInfo/Area"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Dimension"] = XML_DATA_TYPE_NUM_INT;
+    s_elementPathTypeMap["/GeometryInfo/Length"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/IsClosed"] = XML_DATA_TYPE_BOOLEAN;
+    s_elementPathTypeMap["/GeometryInfo/IsEmpty"] = XML_DATA_TYPE_BOOLEAN;
+    s_elementPathTypeMap["/GeometryInfo/IsSimple"] = XML_DATA_TYPE_BOOLEAN;
+    s_elementPathTypeMap["/GeometryInfo/IsValid"] = XML_DATA_TYPE_BOOLEAN;
+    s_elementPathTypeMap["/GeometryInfo/Envelope/LowerLeft/X"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Envelope/LowerLeft/Y"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Envelope/UpperRight/X"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Envelope/UpperRight/Y"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Centroid/X"] = XML_DATA_TYPE_NUM_DOUBLE;
+    s_elementPathTypeMap["/GeometryInfo/Centroid/Y"] = XML_DATA_TYPE_NUM_DOUBLE;
     //Miscellaneous MapGuide response types that don't have a formal schema
     s_elementPathTypeMap["/SessionTimeout/Value"] = XML_DATA_TYPE_NUM_INT;
     s_elementPathTypeMap["/FeatureInformation/SelectedFeatures/SelectedLayer/LayerMetadata/Property/Type"] = XML_DATA_TYPE_NUM_INT;

Modified: trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml
===================================================================
--- trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml	2017-06-28 15:18:59 UTC (rev 9229)
+++ trunk/MgDev/Web/src/MapGuideApi/MapGuideApiGen.xml	2017-07-11 15:44:27 UTC (rev 9230)
@@ -213,6 +213,7 @@
     <Header path="../../../Common/Geometry/PointCollection.h" />
     <Header path="../../../Common/Geometry/Polygon.h" />
     <Header path="../../../Common/Geometry/PolygonCollection.h" />
+    <Header path="../../../Common/Geometry/PreparedGeometry.h" />
     <Header path="../../../Common/Geometry/Transform.h" />
     <Header path="../../../Common/Geometry/WktReaderWriter.h" />
   



More information about the mapguide-commits mailing list