wiki:MapGuideRfc161

Version 8 (modified by jng, 7 years ago) ( diff )

--

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 RFCs page.

Status

RFC Template Version(1.0)
Submission Date14 Jun 2017
Last Modified28 Jun 2017
AuthorJackie Ng
RFC Statusready for review
Implementation Statuspending
Proposed Milestone3.3
Assigned PSC guide(s)(when determined)
Voting History(vote date)
+1
+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:

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 MapGuideRfc158

The result adheres to the new UnitOfMeasure-3.3.0.xsd XML schema

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="UnitOfMeasure">
    <xs:annotation>
      <xs:documentation>Unit of measure</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Value" type="xs:double" />
        <xs:element name="Unit" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

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 MapGuideRfc158

The result adheres to the new GeometryInfo-3.3.0.xsd XML schema

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="GeometryInfo">
    <xs:annotation>
      <xs:documentation>Geometry Information</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Area" type="xs:double" />
        <xs:element name="Dimension" type="xs:int" />
        <xs:element name="Length" type="xs:double" />
        <xs:element name="IsClosed" type="xs:boolean" />
        <xs:element name="IsEmpty" type="xs:boolean" />
        <xs:element name="IsSimple" type="xs:boolean" />
        <xs:element name="IsValid" type="xs:boolean" />
        <xs:element name="Envelope" type="Envelope" />
        <xs:element name="Centroid" type="Coordinate" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="Coordinate">
    <xs:annotation>
      <xs:documentation>Represents a bounding box</xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="X" type="xs:double">
        <xs:annotation>
          <xs:documentation>x-coordinate</xs:documentation>
        </xs:annotation>
      </xs:element>
      <xs:element name="Y" type="xs:double">
        <xs:annotation>
          <xs:documentation>y-coordinate</xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="Envelope">
    <xs:annotation>
      <xs:documentation>Represents a bounding box defined in terms of a lower left coordinate and an upper right coordinate</xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="LowerLeft" type="Coordinate">
        <xs:annotation>
          <xs:documentation>Lower-left coordinate</xs:documentation>
        </xs:annotation>
      </xs:element>
      <xs:element name="UpperRight" type="Coordinate">
        <xs:annotation>
          <xs:documentation>Upper-right coordinate</xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

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 MapGuideRfc158

Configurable coordinate precision

As implied by some of the new mapagent operations, the GeoJSON output support introduced in 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
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// void SetPrecision(int precision);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// void SetPrecision(int precision);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// void SetPrecision(int precision);
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \param precision (int)
    /// The decimal precision to write out coordinates
    ///
    ///
    void SetPrecision(INT32 precision);

    //////////////////////////////////////////////////////////////////
    /// \brief
    /// Gets the decimal precision to use when writing out coordinates
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// int GetPrecision();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// int GetPrecision();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// int GetPrecision();
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \return
    /// Returns the current precision
    ///
    INT32 GetPrecision();

    //////////////////////////////////////////////////////////////////
    /// \brief
    /// Sets whether to apply coordinate precision when writing out GeoJSON coordinates
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// void SetPrecisionEnabled(bool enabled);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// void SetPrecisionEnabled(boolean enabled);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// void SetPrecisionEnabled(bool enabled);
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \param enabled (bool)
    /// If true, enables coordinate precision. Otherwise disables it
    ///
    /// \return
    /// Returns the GeoJSON output as a string.
    ///
    void SetPrecisionEnabled(bool enabled);

    //////////////////////////////////////////////////////////////////
    /// \brief
    /// Gets whether coordinate precision is enabled
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// bool IsPrecisionEnabled();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// boolean IsPrecisionEnabled();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// bool IsPrecisionEnabled();
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \return
    /// True if coordinate precision is enabled. False otherwise
    ///
    bool IsPrecisionEnabled();
};

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.
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// virtual MgGeometry Prepare();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// virtual MgGeometry Prepare();
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// virtual MgGeometry Prepare();
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \since 3.3
    ///
    /// \return
    /// A tesellated version of this geometry. If this geometry is not curve-based, the operation does nothing and this method returns itself.
    ///
    MgGeometry* Tessellate();
};

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.
    ///
    /// <!-- 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);
};

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
    ///
    /// <!-- 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();
};

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

Note: See TracWiki for help on using the wiki.