[[PageOutline]]
= !MapGuide RFC 161 - Geo-Processing Services =
This page contains a change request (RFC) for the !MapGuide Open Source project.
More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page.
== Status ==
||RFC Template Version||(1.0)||
||Submission Date||14 Jun 2017||
||Last Modified||12 July 2017||
||Author||Jackie Ng||
||RFC Status||Implemented||
||Implementation Status||completed||
||Proposed Milestone||3.3||
||Assigned PSC guide(s)||(when determined)||
||'''Voting History'''||(vote date)||
||+1||Jackie,Gordon||
||+0||||
||-0||||
||-1||||
||no vote|| ||
== Overview ==
This RFC proposes to add geo-processing capabilities to the mapagent and enhance MgGeometry with additional capabilities offered by the underlying GEOS library we're wrapping.
== Motivation ==
The mapagent in its current form offers no services for geo-processing. Such capabilities require custom code using MgGeometry from the MapGuide Web API.
For basic geo-processing such as geometry manipulation (union/buffer/etc) or testing of common spatial predicates (contains/intersects/etc), we should be able to tap into such functionality in the mapagent.
== Proposed Solution ==
This RFC enhances the mapagent with support for the following operations:
=== Buffer ===
Performs a buffer of the given input geometry in with the specified distance.
This is the mapagent equivalent of `MgGeometry::Buffer()`
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.BUFFER || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the geometry to buffer ||
|| DISTANCE || number || Yes || The buffer distance in the specific units ||
|| UNITS || mi/km/ft/m || Yes || miles/kilometers/feet/meters ||
|| FORMAT || WKT/GEOJSON || Yes || Output the buffer result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Yes || The coordinate system (CS-Map code) of the input geometry ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the buffer geometry into. If not specified, the buffer geometry will be in the input coordinate system ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
=== Simplify ===
Returns a simplified form of the given input geometry.
This is the mapagent equivalent of `MgGeometrySimplifier::Simplify()`
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.SIMPLIFY || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the geometry to simplify ||
|| TOLERANCE || number || Yes || The simplification tolerance ||
|| ALGORITHM || 0/1 || Yes || 0=Douglas-Peucker, 1=Topology Preserving ||
|| FORMAT || WKT/GEOJSON || Yes || Output the simplification result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) of the input geometry. Only required in combination with `TRANSFORMTO` if you intend to transform the simplified geometry ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the simplified geometry into. Only required in combination with `COORDINATESYSTEM ` if you intend to transform the simplified geometry ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
=== Binary Operation ===
Performs the given binary operation against the 2 input geometries specified (in WKT) as WKT or GeoJSON with optional transformation.
The following binary operations are supported:
* Union
* Difference
* Intersection
* SymmetricDifference
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.BINARYOPERATION || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRYA || string || Yes || The Well-Known Text of the first input geometry ||
|| GEOMETRYB || string || Yes || The Well-Known Text of the second input geometry ||
|| OPERATOR || UNION/DIFFERENCE/INTERSECTION/SYMMETRICDIFFERENCE || Yes || The desired operator for this operation ||
|| FORMAT || WKT/GEOJSON || Yes || Output the operation result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) of the input geometries. Only required in combination with `TRANSFORMTO` if you intend to transform the geometry result ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the simplified geometry into. Only required in combination with `COORDINATESYSTEM ` if you intend to transform the geometry result ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
All operators are invoked in the form of {{{GEOMETRYA OPERATOR GEOMETRYB}}}. Where ordering of input geometries matters (the operator is not commutative), refer to this rule.
=== Spatial Predicate ===
Tests and returns whether the 2 input geometries specified (in WKT) passes the given spatial predicate.
The following spatial predicates are supported:
* Contains
* Crosses
* Disjoint
* Equals
* Intersects
* Overlaps
* Touches
* Within
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.SPATIALPREDICATE || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRYA || string || Yes || The Well-Known Text of the first input geometry ||
|| GEOMETRYB || string || Yes || The Well-Known Text of the second input geometry ||
|| OPERATOR || CONTAINS/CROSSES/DISJOINT/EQUALS/INTERSECTS/OVERLAPS/TOUCHES/WITHIN || Yes || The desired operator for this spatial predicate test ||result ||
All operators are invoked in the form of {{{GEOMETRYA OPERATOR GEOMETRYB}}}. Where ordering of input geometries matters (the operator is not commutative), refer to this rule.
=== Convex Hull ===
Returns the smallest convex Polygon that contains all the points in the given Geometry
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.CONVEXHULL || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the input geometry ||
|| FORMAT || WKT/GEOJSON || Yes || Output the operation result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) of the input geometries. Only required in combination with `TRANSFORMTO` if you intend to transform the geometry result ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the simplified geometry into. Only required in combination with `COORDINATESYSTEM ` if you intend to transform the geometry result ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
=== Boundary ===
Returns the geometry that represents the input geometry's boundary
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.BOUNDARY || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the input geometry ||
|| FORMAT || WKT/GEOJSON || Yes || Output the operation result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) of the input geometries. Only required in combination with `TRANSFORMTO` if you intend to transform the geometry result ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the simplified geometry into. Only required in combination with `COORDINATESYSTEM ` if you intend to transform the geometry result ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
=== Tessellate ===
Returns the geometry that is a tessellated form of the input geometry. This operation is provided for approximating curve-based geometries to non-curve equivalents and has no effect if the input geometry is not curve-based (the operation will return the input geometry)
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.TESSELLATE || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the input geometry ||
|| FORMAT || WKT/GEOJSON || Yes || Output the operation result as WKT or GeoJSON ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) of the input geometries. Only required in combination with `TRANSFORMTO` if you intend to transform the geometry result ||
|| TRANSFORMTO || string || Optional || The coordinate system (CS-Map code) to transform the simplified geometry into. Only required in combination with `COORDINATESYSTEM ` if you intend to transform the geometry result ||
|| PRECISION || number || Optional || The decimal precision to use when outputting as GeoJSON. If not specified, coordinates will be output as-is if output format is GeoJSON ||
=== Distance ===
Returns the shortest distance between this geometry and another
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.DISTANCE || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the input geometry ||
|| OTHERGEOMETRY || string || Yes || The Well-Known Text of the other geometry (to compute distance to) ||
|| COORDINATESYSTEM || string || Optional || The coordinate system (CS-Map code) to use for measuring distance. If provided, the distance result with be returned in meters. If not provided, a linear distance measurement is used and the result will be returned in unknown units. ||
|| FORMAT || string || Yes || {{{text/xml}}} for XML, {{{application/json}}} for JSON ||
|| CLEAN || 1/0 || Optional || If requested format is {{{application/json}}}, returns a clean JSON structure per [wiki:MapGuideRfc158] ||
The result adheres to the new {{{UnitOfMeasure-3.3.0.xsd}}} XML schema
{{{
Unit of measure
}}}
=== Geometry Info ===
Returns information about the input geometry
|| '''Name''' || '''Value''' || '''Required''' || '''Description''' ||
|| OPERATION || GEO.DISTANCE || Yes || Operation to execute ||
|| VERSION || 3.3.0 || Yes || Operation version ||
|| CLIENTAGENT || text || Optional || Descriptive text for client ||
|| GEOMETRY || string || Yes || The Well-Known Text of the input geometry ||
|| FORMAT || string || Yes || {{{text/xml}}} for XML, {{{application/json}}} for JSON ||
|| CLEAN || 1/0 || Optional || If requested format is {{{application/json}}}, returns a clean JSON structure per [wiki:MapGuideRfc158] ||
The result adheres to the new {{{GeometryInfo-3.3.0.xsd}}} XML schema
{{{
Geometry Information
Represents a bounding box
x-coordinate
y-coordinate
Represents a bounding box defined in terms of a lower left coordinate and an upper right coordinate
Lower-left coordinate
Upper-right coordinate
}}}
== GeoJSON improvements ==
As GeoJSON is a key output format for a majority of these new operations, this RFC includes some improvements to the GeoJSON support introduced in [wiki:MapGuideRfc158]
=== Configurable coordinate precision ===
As implied by some of the new mapagent operations, the GeoJSON output support introduced in [wiki:MapGuideRfc158] has been enhanced with support for configurable coordinate precision.
Before this RFC, GeoJSON coordinates were output verbatim from their source geometry counterparts. Generally speaking, coordinates beyond 7 decimal places in most coordinate systems are superfluous and adds unnecessary bloat to GeoJSON content when converting feature geometry.
As a result, the {{{MgGeoJsonWriter}}} class has been extended to allow a custom decimal precision to be specified. Coordinate precision is opt-in so it requires manual activation.
{{{
class MG_PLATFORMBASE_API MgGeoJsonWriter : public MgGuardDisposable
{
PUBLISHED_API:
...
//////////////////////////////////////////////////////////////////
/// \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
///
///
/// \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
///
///
/// \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
///
///
/// \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
///
///
/// \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();
};
}}}
By default, {{{MgGeoJsonWriter}}} will output coordinates as-is.
If not specified, 7 decimal places will be default when converting feature data to GeoJSON using {{{MgGeoJsonWriter}}} if coordinate precision is enabled, but no call to {{{SetPrecision}}} is made.
=== Auto-tessellation of curves ===
The GeoJSON spec does not define curve geometries, as a result if one was converting a feature with curve-based geometry to GeoJSON, the {{{geometry}}} component is currently always going to be {{{null}}}
For this RFC, curve geometries are automatically tessellated to their non-curve equivalents.
== MgGeometry enhancements ==
In addition to mapagent enhancements, this RFC enhances the `MgGeometry` API with extra capabilities.
=== Tessellation ===
The GeoJSON support has demonstrated the need to provide some means for any curve-based `MgGeometry` to return a tessellated version of itself so it can be used in cases where curve-based geometries are not supported (such as converting to GeoJSON).
To support such cases, we'll introduce a new API to {{{MgGeometry}}} to support tessellation
{{{
class MG_GEOMETRY_API MgGeometry : public MgGeometricEntity
{
PUBLISHED_API:
...
///////////////////////////////////////////////////////////////////////
/// \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.
///
///
/// \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();
};
}}}
Implementation-wise, this method merely delegates to the existing {{{MgSpatialUtility::TessellateCurve(MgGeometry*)}}} method already in the MgGeometry project.
=== Prepared geometries ===
Prepared geometries is a performance optimization that improves the performance of operations between a single target geometry and a batch of test geometries. By preparing the target geometry, various internal data structures of the prepared geometry can be pre-computed, which then allows subsequent geometric operations to be evaluated with maximum efficiency.
The RFC introduces a new `MgPreparedGeometry` class to the MapGuide API
{{{
////////////////////////////////////////////////////////////////
/// \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.
///
///
/// \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.
///
Illustration
/// d, e and f are MultiPoint geometries.
/// \n
/// \image html crosses.png
///
///
/// \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.
///
///
/// \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.
///
///
/// \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.
/// Illustration
/// c and d are MultiPoint geometries.
/// \image html overlaps.png
///
///
/// \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.
/// Illustration
/// e are MultiPoint geometries and f is a LineString.
/// \image html touches.png
///
///
/// \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.
/// Illustration
/// 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
///
///
/// \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);
};
}}}
`MgPreparedGeometry` instances are obtained by calling a new `Prepare` method on a `MgGeometry` instance
{{{
class MG_GEOMETRY_API MgGeometry : public MgGeometricEntity
{
PUBLISHED_API:
...
///////////////////////////////////////////////////////////////////////
/// \brief
/// Returns a prepared version of this geometry that is optimized for
/// repeated evaluation of spatial predicate operations
///
///
/// \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();
};
}}}
It is important to note that the use-case of `MgPreparedGeometry` is primarily for fast/repeated evaluation of spatial predicates. As such, `MgPreparedGeometry` does not follow the geometry class hierarchy like its `MgGeometry` counterpart. If one wants to know the actual geometric information about the `MgPreparedGeometry`, they should retain a reference to the original `MgGeometry` that they `Prepare()`'d from.
Also, this is not a substitute for equivalent spatial filtering criteria on a Feature Source if its provider capabilities allow for it. Data-store level evaluation of these spatial predicates will generally always be faster than doing it at the application level through this new API.
Implementation-wise, `MgPreparedGeometry` wraps the underlying `PreparedGeometry` class provided by GEOS. We use the pimpl pattern to avoid leaking out the `PreparedGeometry` dependency (and consequently any geos headers) in the public header of `MgPreparedGeometry`.
== Implications ==
These are new API additions.
== Test Plan ==
Test new mapagent geo-processing operations and verify that their output is the same as the results provided by using `MgGeometry` APIs directly.
Add tests for double to string conversion with specific decimal precision.
Benchmark repeated evaluation of spatial operations using `MgGeometry` vs `MgPreparedGeometry`. Verify that using `MgPreparedGeometry` provides noticeable performance over using `MgGeometry`
== Funding / Resources ==
Community
== Addendum ==
Made coordinate precision behavior opt-in