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).
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.9.0</version> </dependency>
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
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
There is an experimental module for using this library in idiomatic Scala. See the scala module
The JavaDoc is published on javadoc.io.
The Geometry model
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
G2D (spherical coordinates) and
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
parallel hierarchy exists. This leads to the following class hierarchy.
Geometry is a topologically closed set (in the mathematical sense) of
Positions. The instantiable
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 are called the vertices of the
A distinctive feature of this library is that
Geometry class is parameterized by
Position type. This means that e.g.
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
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
LineString), minus the space enclosed by any inner
MultiPoint: a collection of
MultiLineString: a collection of
MultiPolygon: a collection of
GeometryCollection: a collection of
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
- Find the system by its EPSG ID in the
CrsRegistryhas 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);
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.
MeasureGeometryOperations: operations specific to projected (planar) geometries with a Measure (i.e.
At present there is no support for operations on geometries in a
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);
Because JTS has been the dominant geometry library in the Java ecosystem, JTS interoperability has been a major concern.
JTS class supports conversion from/to JTS
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);