[mapguide-commits] r9207 - in sandbox/jng/geoprocessing: Common/Geometry Server/src/UnitTesting
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sat Jun 10 09:13:00 PDT 2017
Author: jng
Date: 2017-06-10 09:13:00 -0700 (Sat, 10 Jun 2017)
New Revision: 9207
Added:
sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.cpp
sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.h
Modified:
sandbox/jng/geoprocessing/Common/Geometry/Geometry.cpp
sandbox/jng/geoprocessing/Common/Geometry/Geometry.h
sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj
sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj.filters
sandbox/jng/geoprocessing/Common/Geometry/GeometryBuild.cpp
sandbox/jng/geoprocessing/Common/Geometry/GeometryClassId.h
sandbox/jng/geoprocessing/Common/Geometry/GeometryCommon.h
sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.cpp
sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.h
Log:
Enhance the MgGeometry API with support for prepared geometries.
- A new MgPreparedGeometry represents a prepared version of a given MgGeometry and is obtained by calling Prepare() on the MgGeometry instance.
- A prepared geometry is optimized for repeated evaluation of boolean spatial predicates against any geometries.
- A new performance test exercises performance of prepared geometries vs un-prepared geometries. The test exercises a battery of spatial predicates with the full set of 17565 Sheboygan parcels against a "C" shaped geometry in the area of Sheboygan. The test shows a 2.5x to 3x improvement (24-26 seconds with un-prepared vs 8-9 seconds with prepared)
- The existing Touches unit test has been updated to also test against the prepared versions of the test geometries.
Modified: sandbox/jng/geoprocessing/Common/Geometry/Geometry.cpp
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/Geometry.cpp 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/Geometry.cpp 2017-06-10 16:13:00 UTC (rev 9207)
@@ -259,3 +259,8 @@
{
return MgGeometryEntityType::Geometry;
}
+
+MgPreparedGeometry* MgGeometry::Prepare()
+{
+ return MgPreparedGeometry::Create(this);
+}
\ No newline at end of file
Modified: sandbox/jng/geoprocessing/Common/Geometry/Geometry.h
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/Geometry.h 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/Geometry.h 2017-06-10 16:13:00 UTC (rev 9207)
@@ -18,6 +18,7 @@
#ifndef _MGGEOMETRY_H_
#define _MGGEOMETRY_H_
+class MgPreparedGeometry;
class MgGeometry;
template class MG_GEOMETRY_API Ptr<MgGeometry>;
@@ -733,6 +734,27 @@
///
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
+ ///
+ /// \return
+ /// An MgPreparedGeometry representing the prepared version of this geometry
+ ///
+ MgPreparedGeometry* Prepare();
+
INTERNAL_API:
virtual INT32 GetEntityType();
Modified: sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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: sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj.filters
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj.filters 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/Geometry.vcxproj.filters 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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: sandbox/jng/geoprocessing/Common/Geometry/GeometryBuild.cpp
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/GeometryBuild.cpp 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/GeometryBuild.cpp 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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: sandbox/jng/geoprocessing/Common/Geometry/GeometryClassId.h
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/GeometryClassId.h 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/GeometryClassId.h 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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: sandbox/jng/geoprocessing/Common/Geometry/GeometryCommon.h
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/GeometryCommon.h 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Common/Geometry/GeometryCommon.h 2017-06-10 16:13:00 UTC (rev 9207)
@@ -100,6 +100,8 @@
#include "MultiPoint.h"
#include "MultiPolygon.h"
+#include "PreparedGeometry.h"
+
#include "AgfReaderWriter.h"
#include "WktReaderWriter.h"
Added: sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.cpp
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.cpp (rev 0)
+++ sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.cpp 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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;
+}
Added: sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.h
===================================================================
--- sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.h (rev 0)
+++ sandbox/jng/geoprocessing/Common/Geometry/PreparedGeometry.h 2017-06-10 16:13:00 UTC (rev 9207)
@@ -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: sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.cpp
===================================================================
--- sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.cpp 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.cpp 2017-06-10 16:13:00 UTC (rev 9207)
@@ -16,6 +16,7 @@
//
#include "MapGuideCommon.h"
+#include "ServiceManager.h"
#include "TestGeometry.h"
#include "CppUnitExtensions.h"
#include "FoundationDefs.h"
@@ -41,11 +42,93 @@
void TestGeometry::TestStart()
{
ACE_DEBUG((LM_INFO, ACE_TEXT("\nRunning Geometry tests. (Mentor)\n")));
+ 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()));
+ }
}
void TestGeometry::TestEnd()
{
+ 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;
+ }
ACE_DEBUG((LM_INFO, ACE_TEXT("\nGeometry tests completed.\n\n")));
}
@@ -1965,6 +2048,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 +2063,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 +2077,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 +2116,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 +2151,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 +2820,141 @@
{
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;
+ }
}
\ No newline at end of file
Modified: sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.h
===================================================================
--- sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.h 2017-06-10 09:44:55 UTC (rev 9206)
+++ sandbox/jng/geoprocessing/Server/src/UnitTesting/TestGeometry.h 2017-06-10 16:13:00 UTC (rev 9207)
@@ -68,6 +68,8 @@
CPPUNIT_TEST(TestCase_Simplify_DP);
CPPUNIT_TEST(TestCase_Simplify_TP);
+ CPPUNIT_TEST(TestCase_PreparedGeometryPerformance);
+
CPPUNIT_TEST(TestEnd); // This must be the very last unit test
CPPUNIT_TEST_SUITE_END();
@@ -116,6 +118,8 @@
void TestCase_Simplify_DP();
void TestCase_Simplify_TP();
+ void TestCase_PreparedGeometryPerformance();
+
MgPoint* CreatePoint();
MgLineString* CreateLineString();
MgLinearRing* CreateLinearRing();
More information about the mapguide-commits
mailing list