read

Rust is a relatively new programming language and many problems being tackled in Rust have existing solutions in C/C++. As a Rust developer in need of some non-trivial functionality, you often must choose between using a Rust wrapper of an existing C/C++ library and a pure Rust alternative. In this article, I compare geo, a crate that provides primitives and algorithms for two dimensional geometric operations, with the most prominent alternative, geos, a wrapper of the C++ libgeos library. You can use these crates together because they interoperate via the Rust ecosystem for Geospatial analysis.

As is frequently the case, libgeos is more mature than the Rust upstart. It has a longer history of development1, a more formalized project steering committee, and illustrious clients including PostGIS, QGIS, GDAL and Shapely. geo potentially has better memory safety because it is written in (safe) Rust.

libgeos is implemented in C++ and exports a C API. geos wraps (most of) this C API in two steps – The geos-sys crate provides raw FFI bindings for the C API, and geos wraps it in a more idiomatic Rust API. libgeos itself is a port of the Java JTS library, so you could add another conceptual step in the porting / wrapping chain.

In the rest of this article, I address a single point of comparison between these alternatives – feature parity. As a rust developer, the relevant API for you is the one exported finally by the geos crate so I mostly reference that in my comparison.

libgeos’ feature set is more extensive than geo’s and it uses more complex namespaces for organization of the functionality. For my comparison, I choose a different option for organizing the functionality – I classify geo’s functions using PostGIS reference documentation sections. PostGIS is a widely used and extensive implementation of the OGC Simple Feature Access-SQL standard so it is useful to map the features to PostGIS. I also think that PostGIS has the most intuitive organization of the feature set and the best in-depth documentation of each function. For each section, I map geo’s functionality to geos, and call out features that are missing in geo.

Finally, all of these projects are actively being developed. This comparison (and links below) apply best to geo 0.18.0, geos 8.0.3 and PostGIS 3.2.

Measurement Functions

geo provides 8 of 27 functions in this section of the PostGIS reference.

Missing features includes:

Beyond these, PostGIS provides some convenience functions that are easy to implement using those available in geo and geos.

Next, I map features available in geo to those from PostGIS and geos.

description Compute area of a planar polygon.
ST_Area
geo algorithm::area::Area
geos Geom::area
description Compute the azimuthal angle between two geometries.
ST_Azimuth
geo algorithm::bearing::Bearing
geos Not available
description Find a point on a geometry closest to another geometry.
ST_ClosestPoint
geo algorithm::closest_point::ClosestPoint
geos Geom::nearest_points
description Find the Euclidean distance between geometries. All three packages have support for optimized computation of the distance using an index. Additionally, PostGIS provides an algebra based on this function.
ST_Distance
geo algorithm::euclidean_distance::EuclideanDistance, algorithm::euclidean_distance::nearest_neighbour_distance
geos Geom::distance, Geom::distance_indexed
description Compute the Cartesian length of a geometry. Only applicable to lines and multi-lines.
ST_Length
geo algorithm::euclidean_length::EuclideanLength
geos Geom::length
description Compute a measure of similarity of two geometries, due to Maurice Frechet. PostGIS and geos provide a way to densify the geometries beforehand, which can improve the distance estimate.
ST_FrechetDistance
geo algorithm::frechet_distance::FrechetDistance
geos Geom::frechet_distance, Geom::frechet_distance_densify
description Compute the great-arc distance between two geometries on a geodetic model. geo provides two algorithms for this computation based on a spheroidal model of the earth. PostGIS provides one algorithm each based on spherical and spheroidal models.
ST_DistanceSphere, ST_DistanceSpheroid (based on Vincenty's method)
geo algorithm::vincenty_distance::VincentyDistance, algorithm::geodesic_distance::GeodesicDistance (improvement over Vincenty's method)
geos Not available
description Compute the great-arc length of a geometry. Implementations follow great-arc distance computations closely.
ST_LengthSpheroid (based on Vincenty's method)
geo algorithm::vincenty_length::VincentyLength, algorithm::geodesic_length::GeodesicLength (improvement over Vincenty's method)
geos Not available

Geometry Accessors

geo effectively provides 15 of 42 functions in this section of the PostGIS reference . While there is a large gap in the feature set in this section, many of the missing functions have easy and idiomatic implementations using available accessors and iterators. Also, some of the functions are not applicable to geo because of limitations of the types of geometries supported.

Missing features includes:

  • Functions related to 3D and 4D geometries. The extra coordinates are used to specify the height (z) and/or a measure (m) at the given point. These are not applicable to geo as geo only supports 2D geometries. geos supports 3D geometries (with a z-dimension) but has no notion of a measure.
  • Functions related to curves (with non-linear interpolation between points) and surfaces (3D non-linear surfaces). These are not applicable to geo and geos as neither library supports non-linear geometries.
  • A method to obtain the amount of memory consumed by a geometry. Not available in geo and geos.

Beyond these, PostGIS provides some convenience functions that are easy to implement using those available in geo and geos.

description Compute the bounding rectangle for a geometry. Additionally, PostGIS has an algebra relating the bounding rectangles of two geometries.
ST_Envelope
geo algorithm::bounding_rect::BoundingRect
geos Geom::envelope
description Compute the dimensionality of a geometry. Only geo properly handles collinear points.
ST_Dimension
geo algorithm::dimensions::HasDimensions
geos Geom::get_num_dimensions
description Access specific points on a line or multi-line.
ST_NumPoints, ST_PointN, ST_StartPoint, ST_EndPoint
geo LineString::points_iter, Line::start_point, Line::end_point etc.
geos Geom::get_num_points, Geom::get_point_n, Geom::get_start_point, Geom::get_end_point
description Destructure a point. geo only supports 2D geometries. geos supports the z dimension. PostGIS supports the z and m dimensions.
ST_X, ST_Y, ST_Z, ST_Zmflag
geo Point::x, Point::y, Point::x_y
geos Geom::get_x, Geom::get_y, Geom::get_z
description Get the boundaries of a polygon.
ST_ExteriorRing, ST_NumInteriorRings, ST_InteriorRingN
geo Polygon::exterior (Polygon::exterior_mut), Polygon::interiors (Polygon::interiors_mut)
geos Geom::get_exterior_ring, Geom::get_num_interior_rings, Geom::get_interior_ring_n
description Get the winding order (clockwise / counter-clockwise) of the exterior ring of a polygon. geo provides a larger variety of associated functions.
ST_IsPolygonCW, ST_IsPolygonCCW
geo algorithm::winding_order::Winding
geos CoordSeq::is_ccw

Geometry Processing

Geo provides 6 of 26 functions in this section of the PostGIS reference. There are significant gaps in the feature set between geo and geos in this section.

Missing features include:

description Compute the geometric center of mass of a geometry.
ST_Centroid
geo algorithm::centroid::Centroid
geos Geom::get_centroid
description Compute a potentially concave polygon bounding a geometry. There is no formal definition of a concave hull and the results from PostGIS and geo may disagree.
ST_ConcaveHull
geo algorithm::concave_hull::ConcaveHull
geos Not available in _geos_
description Compute the convex hull of a geometry. geo allows an additional, slower, algorithm that properly handles geometries with collinear points.
ST_ConvexHull
geo algorithm::convex_hull::quick_hull, algorithm::convex_hull::graham_hull
geos Geom::convex_hull
description Simplify a geometry using Ramer-Douglas-Peuker (RDP) algorithm.
ST_Simplify
geo algorithm::simplify::Simplify, algorithm::simplify::SimplifyIdx
geos Geom::simplify
description Simplify a geometry using the Visvalingam–Whyatt (VW) algorithm.
ST_SimplifyVW
geo algorithm::simplifyvw::SimplifyVW, algorithm::simplifyvw::SimplifyVwIdx
geos Not available in _geos_
description Simplify a geometry preserving topological relationships. PostGIS and geos use the RDP algorithm described above. geo uses the VW algorithm.
ST_SimplifyPreserveTopology
geo algorithm::simplifyvw::SimplifyVWPreserve
geos Geom::topology_preserve_simplify

Overlay Functions

This section of the PostGIS reference documents functions that compute results arising from the overlay of two geometries. geo only provides 1 of 10 functions in this section, with a significant feature gap between geo and geos.

Missing features include:

  • Several CPU or memory efficient implementations of the union operation, and it’s converse. Partially available in geos.
  • A special case of union used to dissolve collections of lines into a single line. Available in geos.
  • Difference and symmetric difference of geometries. Available in geos.
  • A subdivision operation to speed up indexed queries on a large geometry. Not available in geos.
description Compute the point-set intersection of two geometries. geo only provides a limited implementation for lines.
ST_Intersection
geo algorithm::line_intersection::LineIntersection
geos Geom::intersection

Topological Relationships

There are 16 functions in this section of the PostGIS reference, but most are special cases of the most general ST_Relate function that determines the DE-9IM relationship matrix between two geometries. geo provides this general function. libgeos also provides this function, but it is not exposed by geos.

For the more specific functions, geos provides an optional preprocessing step that can speed up repeated relationship queries against a large geometry. geo does not provide a similar optimization.

description Determine if a geometry is contained completely inside another.
ST_Contains
geo algorithm::contains::Contains
geos Geom::contains
description Determine if two geometries have any points in common.
ST_Intersects
geo algorithm::intersects::Intersects
geos Geom::intersects
description Evaluate the DE-9IM relationship matrix between two geometries. Although geos does not provide this function, it provides many more methods like the two above to check specific relationships between geometries.
ST_Relate
geo algorithm::relate::Relate
geos Not available in _geos_

Affine Transformations

There are 8 functions in this section of the PostGIS reference, but all of them are specific cases of the most general ST_Affine function. geo provides 2 functions that cover all transformations except scaling. geos does not support any features in this section directly. In either case, this feature set can be implemented using mutable iterators on points in the geometry.

description Rotate a geometry about a point. geo also provides a convenience method to rotate about the centroid of the geometry.
ST_Rotate
geo algorithm::rotate::RotatePoint, algorithm::rotate::Rotate
geos Not available in _geos_
description Translate a geometry.
ST_Translate
geo algorithm::translate::Translate
geos Not available in _geos_

Linear Referencing

geo provides 2 of 10 functions in this section of the PostGIS reference. Of the remaining, 6 are not applicable to geo because they are related to 3D or 4D geometries, and others are convenience methods easily implemented using the 2 available functions.

description Find a point on a line at a distance a given fraction of the length from the start.
ST_LineInterpolatePoint
geo algorithm::line_interpolate_point::LineInterpolatePoint
geos Geom::interpolate, Geom::interpolate_normalized
description Find the point on a line closest to a given point (potentially off the line).
ST_LineLocatePoint
geo algorithm::line_locate_point::LineLocatePoint
geos Geom::project, Geom::project_normalized

Missing classes of features

There are several sections of features in the PostGIS reference not available in geo at all:

  • Geometry Editors provide methods to mutate geometries. These can be implemented using mutable references to the coordinates in the geometry. Not available in geos.
  • Bounding Box Operators and Distance Operators provide syntactic sugar for an algebra using available methods to relate geometries. Not available in geos.
  • Clustering Functions include widely used algorithms for clustering of geometries using distance metrics. I would expect a separate crate to provide higher-order features like clustering, built using the foundational features available in geo or geos. Not available in geos.

Some other features from PostGIS that are not applicable to geo include computation of trends in the measure dimension, specification of a spatial reference system and specific functions exported from CGAL.

Beyond PostGIS

Conversely, geo provides some features beyond those documented in the PostGIS reference.

Conclusion

I hope that my systematic comparison of the features in geo and geos will help you make an informed choice between the two alternatives as you start building your geospatial application in Rust. I invite you to also benefit from the original reason for this comparison – to inspire my contributions to the geo crate!

  1. I couldn’t find the first commit for libgeos. The oldest reference I have is from this commit-hook post to the osgeo mailing list dated Nov 22, 2007. For geo, the first commit was on Jan 16, 2015.