wiki:MapGuideRfc161

Version 4 (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 Modified14 Jun 2017
AuthorJackie Ng
RFC Statusdraft
Implementation Status
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

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

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

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

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>

MgGeometry enhancements

In addition to mapagent enhancements, this RFC enhances the MgGeometry class with support for "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.

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.

Benchmark repeated evaluation of spatial operations using MgGeometry vs MgPreparedGeometry. Verify that using MgPreparedGeometry provides noticeable performance over using MgGeometry

Funding / Resources

Community

Note: See TracWiki for help on using the wiki.