A geometry model that conforms to the OGC Simple Features for SQL specification.

Build Status Language grade: Java javadoc

Geolatte-geom

A geometry model for Java with:

  • immutable data structures
  • support for 2D, 3D, 2DM and 3DM geometries
  • A DSL for creating Geometries
  • support for several dialects of WKT/WKB (Postgis, Sql Server, SFA 1.1.0 and 1.2.1)
  • Codecs for translating from/to native database formats for Postgis, Mysql, Oracle, and Microsoft SQL Server.
  • Pluggable, extendable Geometry operations
  • Coordinate reference system aware
  • space filling curves

The library's geometry model is largely based on the Simple Feature Access (1.2.1) specification.

GeoLatte-geom is fully interoperable with the Java Topology Suite (JTS).

Using Geolatte-geom

Currently we require Java 1.8 or later.

The library is published on Maven Central. For Maven, you can include the following dependency.

<dependency>
    <groupId>org.geolatte</groupId>
    <artifactId>geolatte-geom</artifactId>
    <version>1.8.0</version>
</dependency>

Quick start

Creating Geometries

To create a Geometry we first need to specify the Coordinate Reference System we will be working in. Let's say we use WGS84 (for other options, see below).

import org.geolatte.geom.*;

import static org.geolatte.geom.crs.CoordinateReferenceSystems.WGS84;

The easiest way to create Geometry instances is by using the built-in builder DSL. This allows you to specify 2D Positions (coordinates) using c(x,y)for Cartesian or projected coordinates, and g(long,lat) for geodetic or spherical coordinates. (There are also variants for the higher dimensions).

import static org.geolatte.geom.builder.DSL.*;

Now we can create geometries like so.

  Point<G2D> pnt=point(WGS84,g(4.33,53.21));
  
  LineString<G2D> lstr=linestring(WGS84,g(4.43,53.21),g(4.44,53.20),g(4.45,53.19));
  
  Polygon<G2D> pgn=polygon(WGS84,ring(g(4.43,53.21),g(4.44,53.22),g(4.43,53.21)));

We can also create Geometries in a higher-dimensional space. Let's do it in 3D.

First we again need to specify the coordinate reference system we will be working in. In this case, we derive the system from WGS84 by adding a Vertical system for the elevation.

  CoordinateReferenceSystem<G3D>  wgs84E=WGS84.addVerticalSystem(LinearUnit.METER,G3D.class);
        ...

        Point<G3D> pointWithElevation=point(wgs84E,g(4.33,53.21,350));

Encoding and Decoding Geometries to WKT/WKB

Now let's write these out as WKT string.

import org.geolatte.geom.codec.Wkt;
  
  String wkt=Wkt.toWkt(pnt);
          // "SRID=4326;POINT(4.33 53.21)"

          // or maybe using a specific dialect such as SFA 1.2.1
          String wktZ=Wkt.toWkt(pntWithElevation,Wkt.Dialect.SFA_1_2_1);
// "POINT Z (4.33 53.21 350)"

There is a very similar API for WKB encoding/decoding (see the Wkb codec class).

For historical and practical reasons. The default dialects for WKB/WKT are those used in Postgis.

Encoding and Decoding to GeoJson

See the json module

Using Scala?

There is an experimental module for using this library in idiomatic Scala. See the scala module

Javadoc

The JavaDoc is published on javadoc.io.

The Geometry model

Positions

A Position is a tuple of coordinates that specify a position relative to a coordinate reference system. It corresponds with to the concept of direct position in the Simple Feature and ISO-19107 specifications.

The coordinate space can be 2-, 3- or 4-dimensional. The first two dimensions are used to specify a point on the earth's surface. The third dimension usually represent altitude or elevation, and the fourth a measurement.

There are two major types of 2D coordinate reference systems. GeographicCoordinateReferenceSystems specify points on the earth's surface using spherical coordinates (i.e. latitude and longitude). ProjectedCoordinateReferenceSystems use cartesian coordinates (x and y) on a projected plane.

From these 2D base systems we can construct higher-dimensional systems by adding a VerticalCoordinateReferenceSystem for elevation and/or a LinearCoordinateReferenceSystem for a (user-defined) measurement (see below).

Consequently, the instantiable (2D) types of Position are G2D (spherical coordinates) and C2D (cartesian coordinates) in a geographic, resp. projected coordinate reference system. Subtypes of G2Dfor the higher dimensional coordinate reference system are G3D (position + elevation), G2DM (position + measure), and G3DM. For C2D a parallel hierarchy exists. This leads to the following class hierarchy.

Position Class Diagram

Geometry

A Geometry is a topologically closed set (in the mathematical sense) of Positions. The instantiable Geometry subclasses all specify this set using one or more boundaries. The boundaries in turn are specified by interpolation between consecutive elements in a list of Positions. These Positions are called the vertices of the Geometry.

A distinctive feature of this library is that Geometry class is parameterized by Position type. This means that e.g. a Point<C2D> is a different type than Point<G2D>. This ensures that it is always explicit what the coordinates mean (projected or spherical), and what types of operation make sense. E.g. the euclydian distance on the plane works for projected coordinates, but makes no sense for spherical coordinates.

The instantiable subclasses of Geometry are:

  • Point: a single position
  • LineString: a 1-dimensional curve specified by linear interpolation between its vertices
  • Polygon: a 2-dimensional space enclosed by an outer LinearRing (a closed LineString), minus the space enclosed by any inner LinearRings.
  • MultiPoint: a collection of Points
  • MultiLineString: a collection of LineStrings
  • MultiPolygon: a collection of Polygons
  • GeometryCollection: a collection of Geometrys

Coordinate Reference Systems

For many operations a CoordinateReferenceSystem is required. The most important ways to create or get hold of an CoordinateReferenceSystem instance is:

  • Using one of the statically declared systems in the CoordinateReferenceSystems class (e.g. WGS84, WEB_MERCATOR)
  • Find the system by its EPSG ID in the CrsRepository. The CrsRegistry has most of the coordinate reference systems in use.

As already mentioned, you can create higher-dimensional coordinate reference systems by adding a vertical or linear system.

  CoordinateReferenceSystem<C2D> crs=CrsRegistry.getProjectedCoordinateReferenceSystemForEPSG(31370);
  CoordinateReferenceSystem<C3D> crsZ=crs.addVerticalSystem(LinearUnit.METER,C3D.class);
  CoordinateReferenceSystem<C3DM> crsZM=crsZ.addLinearSystem(LinearUnit.METER,C3DM.class);

Geometry operations

The Simple Feature specification specifies a number of spatial query and analysis operations as methods on the Geometry classes. From a design standpoint, declaring these operations as methods has several drawbacks:

  • Some operations need very different implementations in case of projected vs. geographic coordinate reference systems.
  • It precludes the possibility of having alternative implementations for the operations with perhaps very different performance or correctness properties

For these reasons the spatial operations are separated into their own classes. Currently, two types are supported:

  • ProjectedGeometryOperations : operations on projected (planar) geometries (i.e. C2D and subtypes)
  • MeasureGeometryOperations : operations specific to projected (planar) geometries with a Measure (i.e. C2DM , C3DM)

At present there is no support for operations on geometries in a GeographicCoordinateSystem.

You can get hold of an operations class using the GeometryOperations factory class. Currently there are only default implementations available. The ProjectedGeometryOperations implementation will delegate most operations to the corresponding JTS implementation.

    // example of a contains test with planar geometries
    ProjectedGeometryOperations pgo=GeometryOperations.projectedGeometryOperations();
            Point<C2D> point=point(WEB_MERCATOR,c(4.33,53.21));
        Polygon<C2D> polygon=polygon(WEB_MERCATOR,ring(c(4.43,53.21),c(4.44,53.22),c(4.43,53.21)));
        boolean isPntInPoly=pgo.contains(polygon,point);

        // example  op an operation on measured geometries
        MeasureGeometryOperations mgo=GeometryOperations.measureGeometryOperations();
        LineString<C2DM> linestring=linestring(crsM,cM(4.43,53.21,0),cM(4.44,53.20,1),cM(4.45,53.19,2));
        //create a geometry along the linestring that is between 1.5 and 1.8
        Geometry<C2DM> c2DMGeometry=mgo.locateBetween(linestring,1.5,1.8);

JTS interop

Because JTS has been the dominant geometry library in the Java ecosystem, JTS interoperability has been a major concern. The JTS class supports conversion from/to JTS Geometry instances.

  import org.geolatte.geom.jts.JTS;
//Geolatte to JTS
  org.locationtech.jts.geom.Point jtsPoint=JTS.to(point(WGS84,g(4.32,53.12)));
          //.. and back
          org.geolatte.geom.Point<?> glPnt=JTS.from(jtsPoint);
        //or if you know the CRS in advance
        org.geolatte.geom.Point<G2D> glPnt2=JTS.from(jtsPoint,WGS84);