add partial support for geometries with circular segments - STEMLab/geotools GitHub Wiki

Description

GeoTools ad the moment provides not support for geometries containing arcs of circle, as described in GML 3 and supported by various spatial databases. The basics for this proposal have been laid out in this thread on GeoTools devel:

http://osgeo-org.1560.x6.nabble.com/Supporting-circular-arcs-in-GeoTools-td5055895.html

This proposal aims to add such support, with two selections of code paths, some that will recognize the geometries as curved and provide special treatment for them, and others that will not recognize them, and for which the Geometry will linearize itself when any regular JTS method is called.

The code paths that will make special treatment of the curved geometries will be:

  • Rendering, in particular the curved geometries will be linearized taking into account the current display resolution
  • GML 3 encoding
  • Geometry reprojection, limited to the axis flipping case, to avoid the geometries to linearize themselves on the fly while generating GML3 outputs compliant with the URN CRS notation)

Geometric primitives

The new geometry classes would be subclasses of known JTS classes and will auto-linearize themselves in case their coordinate sequence, array, or set of points is requested directly, but would also expose enough information to have them treated as full curved geometries. The basic builiding block of the new geometries will be the CircularArc class, which is an arc of circle defined by 3 points (start, middle, end).

In the following inheritance tree the new classes are in italic:

  • LineString
    • LinearRing
      • Ring: a list of CircularArc and LineString object that overall forms a closed ring
      • *Circle: *a set of two CircularArc closing on each other (it might also be represented as a circle by center point)
    • CircularArc: a circular arc by 3 points
  • MultiLineString
    • Curve: a set of connected *CircularArc *(this class might be not needed)
    • CompoundCurve: a list of CircularArc and LineString connected with each other forming a continuous line.

It is to be noted there is no CurvePolygon/CurveMultiPolygon class, this is because both in GML and in some databases the concept is not there, a Polygon is generally made of rings that can contain curve elements, so all that is needed is to check the contents of the polygon when dealing with it. These classes might be added during the implementation in case some code path needs them.

An informal representation of the CircularArc class public methods might be:

public class CircularArc {

  double[] controlPoints; // will contain 6 entries, but let's leave it open to have 9 in the future
  public CircularArc(double[] controlPoints, double tolerance) { ... };
  public CircularArc(double sx, double sy, double mx, double my, double ex, double ey) {...}
  public int getDimension(); // will return 2 for now
  public double[] getControlPoints() {...}
  public double[] linearize(double tolerance) {...}

}

As an example, the Ring geometry class will look as follows:

public Ring extends LinearRing {
 /**
 * Closed coordinate seq used to init the class
 */
 static final CoordinateSequence FAKE_RING = ...;
 CircularArc arc;
 Geometry linearized;
 double tolerance = UNSPECIFIED;

 public Ring(CircularArc arc) {
   super(FAKE_RING);
   this.arc = arc;
 }

 public Geometry linearize(double tolerance) { ... }

 public Geometry linearize() {
   if(linearized == null) {
     double tolerance = getTolerance();
     linearized = super.linearize(tolerance);
   }
   return linearized;
 }

 double getTolerance() {
   if(tolerance == UNSPECIFIED) {
     // compute tolerance based on curvature
   }
   return tolerance;
 }
 
 public Coordinate[] getCoordinates() {
   Geometry linearized = linearize();
   return linearized.getCoordinates();
 }
 
 ...

}

Linearization

As suggested above, all the curve geometry classes will linearize themselves when accessed via the normal JTS methods (minus envelope calculation of course). All the classes will expose a "linearize(tolerance)" method that clients can call to obtain a linearized version of the geometry with a given max distance from the actual curve geometry, and the method will be called internally, when coordinate access or JTS topological methods will be called. All the curve geometries will thus be built with a default tolerance that can be provided either as part of their construction argument, or assumed to be otherwise "0.01 * CircularArc.radius" (so each arc will have its own).

The geometry construction code paths considered in this work will be the data stores, reading from code, and GML parsing. In the first case, the JDBCDataStore will be modified to accept a query hint Hints.LinearizationTolerance that will be passed, when present, to the geometries being constructed, and the GML parsing will get an object providing the linearization tolerance to be included as part of the picocontainer context:

interface LinearizationToleranceProvider {

    double getTolerance();

}

The above will allow to adopt a different tolerance on a case by case basis, while still allowing the XML parsing configuration to be built once.

Algorithms wise, GeoTools already contains a Circle class that can do arc circle linearization, and it's currently being used to parse and linearize on the fly the ArcString and Circle GML elements. This class will be removed as the implementation will now parse them into CompoundCurve and Circle respectively. The linearization code contained in the class will be equally discarded, as it might result in polygons made of circular arcs not being valid upon linearization (the hull might end up intersecting a hole if they are not linearized in synch).

The linearization will be instead based on the WKTReader2 class, in particular the circularSegmentize method, that will be moved to CircularArc and then reused from WTKReader2, with some adjustment, to ensure concentric circle segments are not allowed to intersect, in particular, the circle sampling will start from a fixed location in the circle (e.g., the topmost point) and move clockwise until the actual segment of circle to linearize is reached. Also, the number of segments to be used will be estimated from the tolerance by taking a starting point number of segments (4) and doubling them until the desired tolerance is reached. While this does not not yet guarantee complete security that a polygon made of circular arcs will be linearized into a valid one, it should provide good enough results for practical purposes.

Store support

The only store that will initially deal with curved geometries will be Oracle, and only limited to parsing them. No write support is planned at the moment, nor support for other stores, although it is hoped that this initial batch of work will make it significantly easier for others to implement curve support in more stores later down the road.

Status

This proposal is under construction.

Voting has not started yet:

Tasks

This section is used to make sure your proposal is complete (did you remember documentation?) and has enough paid or volunteer time lined up to be a success

  1. Update the user guide: add a section on geometries made of circular arcs, how to recognize them, how to deal with them
  2. Update or provided sample code in demo

Documentation Changes

  • A new tutorial describing curved geometries
  • One sample showing how to build some, wrap them in features, and encode the result in GML3