[[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