geo/
lib.rs

1#![doc(html_logo_url = "https://raw.githubusercontent.com/georust/meta/master/logo/logo.png")]
2
3//! The `geo` crate provides planar geospatial geometries and algorithms.
4//!
5//! # Overview
6//!
7//! - Full DE-9IM support and topological relationship calculations such as containment and intersection
8//! - Affine operations on geometries (scale, rotate, skew, translate)
9//! - Boolean operations on geometries (clip, union, difference, intersection, xor)
10//! - Buffer / offset operations on geometries
11//! - Clustering operations such as DBSCAN and _k_-means
12//! - Euclidean, as well as spherical, haversine and other non-planar length and distance calculations
13//! - Support for projecting and converting between coordinate reference systems using PROJ
14//! - IO using the `geojson` and `geozero` crates.
15//!
16//! For a full listing of available geometry types, functionality and features, see below:
17//!
18//! # Types
19//!
20//! - **[`Coord`]**: A two-dimensional coordinate. All geometry types are composed of [`Coord`]s, though [`Coord`] itself is not a [`Geometry`] type
21//! - **[`Point`]**: A single point represented by one [`Coord`]
22//! - **[`MultiPoint`]**: A collection of [`Point`]s
23//! - **[`Line`]**: A line segment represented by two [`Coord`]s
24//! - **[`LineString`]**: A series of contiguous line segments represented by two or more
25//!   [`Coord`]s
26//! - **[`MultiLineString`]**: A collection of [`LineString`]s
27//! - **[`Polygon`]**: A bounded area represented by one [`LineString`] exterior ring, and zero or
28//!   more [`LineString`] interior rings
29//! - **[`MultiPolygon`]**: A collection of [`Polygon`]s
30//! - **[`Rect`]**: An axis-aligned bounded rectangle represented by minimum and maximum
31//!   [`Coord`]s
32//! - **[`Triangle`]**: A bounded area represented by three [`Coord`] vertices
33//! - **[`GeometryCollection`]**: A collection of [`Geometry`]s
34//! - **[`Geometry`]**: An enumeration of all geometry types, excluding [`Coord`]
35//!
36//! The preceding types are reexported from the [`geo-types`] crate. Consider using that crate
37//! if you only need access to these types and no other `geo` functionality.
38//!
39//! ## Semantics
40//!
41//! The geospatial types provided here aim to adhere to the [OpenGIS Simple feature access][OGC-SFA]
42//! standards. Thus, the types here are inter-operable with other implementations of the standards:
43//! [JTS], [GEOS], etc.
44//!
45//! # Algorithms
46//!
47//! ## Measures
48//!
49//! Algorithms for measures along a line, and how a line is measured.
50//!
51//! ### Metric Spaces
52//!
53//! - **[`Euclidean`]**: The [Euclidean plane] measures distance with the pythagorean formula. Not suitable for lon/lat geometries.
54//! - **[`Haversine`]**: The [Haversine Formula] measures distance on a sphere. Only suitable for lon/lat geometries.
55//! - **[`Geodesic`]**: Geodesic methods based on [Karney (2013)] more accurately reflect the shape of the Earth, but are slower than Haversine. Only suitable for lon/lat geometries.
56//! - **[`Rhumb`]**: [Rhumb line] (a.k.a. loxodrome) measures can be useful for navigation applications where maintaining a constant bearing or direction is important. Only suitable for lon/lat geometries.
57//!
58//! ### Operations on Metric Spaces
59//!
60//! - **[`Distance`]**: Calculate the minimum distance between two geometries.
61//! - **[`Length`]**: Calculate the length of a `Line`, `LineString`, or `MultiLineString`.
62//! - **[`Bearing`]**: Calculate the bearing between two points.
63//!
64//! - **[`Destination`]**: Calculate the destination point from an origin point, given a bearing and a distance.
65//! - **[`InterpolateLine`]**: Interpolate a `Point` along a `Line` or `LineString`.
66//! - **[`InterpolatePoint`]**: Interpolate points along a line.
67//! - **[`Densify`]**: Insert points into a geometry so there is never more than `max_segment_length` between points.
68//!
69//! ### Misc measures
70//!
71//! - **[`HausdorffDistance`]**: Calculate "the maximum of the distances from a point in any of the sets to the nearest point in the other set." (Rote, 1991)
72//! - **[`VincentyDistance`]**: Calculate the minimum geodesic distance between geometries using Vincenty’s formula
73//! - **[`VincentyLength`]**: Calculate the geodesic length of a geometry using Vincenty’s formula
74//! - **[`FrechetDistance`]**: Calculate the similarity between [`LineString`]s using the Fréchet distance
75//!
76//! ## Area
77//!
78//! - **[`Area`]**: Calculate the planar area of a geometry
79//! - **[`ChamberlainDuquetteArea`]**: Calculate the geodesic area of a geometry on a sphere using the algorithm presented in _Some Algorithms for Polygons on a Sphere_ by Chamberlain and Duquette (2007)
80//! - **[`GeodesicArea`]**: Calculate the geodesic area and perimeter of a geometry on an ellipsoid using the algorithm presented in _Algorithms for geodesics_ by Charles Karney (2013)
81//!
82//! ## Boolean Operations
83//!
84//! - **[`BooleanOps`]**: Combine or split (Multi)Polygons using intersection, union, xor, or difference operations
85//! - **[`unary_union`]**: Efficient union of many [`Polygon`] or [`MultiPolygon`]s
86//!
87//! ## Outlier Detection / Clustering
88//!
89//! - **[`OutlierDetection`]**: Detect outliers in a group of points using [LOF](https://en.wikipedia.org/wiki/Local_outlier_factor)
90//! - **[`Dbscan`]**: Calculate point clusters using the DBSCAN algorithm
91//! - **[`KMeans`]**: Calculate point clusters using the k-means algorithm
92//!
93//! ## Simplification
94//!
95//! - **[`Simplify`]**: Simplify a geometry using the Ramer–Douglas–Peucker algorithm
96//! - **[`SimplifyIdx`]**: Calculate a simplified geometry using the Ramer–Douglas–Peucker algorithm, returning coordinate indices
97//! - **[`SimplifyVw`]**: Simplify a geometry using the Visvalingam-Whyatt algorithm
98//! - **[`SimplifyVwPreserve`]**: Simplify a geometry using a topology-preserving variant of the Visvalingam-Whyatt algorithm
99//! - **[`SimplifyVwIdx`]**: Calculate a simplified geometry using the Visvalingam-Whyatt algorithm, returning coordinate indices
100//!
101//! ## Query
102//!
103//! - **[`ClosestPoint`]**: Find the point on a geometry
104//!   closest to a given point
105//! - **[`HaversineClosestPoint`]**: Find the point on a geometry
106//!   closest to a given point on a sphere using spherical coordinates and lines being great arcs
107//! - **[`IsConvex`]**: Calculate the convexity of a [`LineString`]
108//! - **[`LineLocatePoint`]**: Calculate the
109//!   fraction of a line’s total length representing the location of the closest point on the
110//!   line to the given point
111//! - **[`InteriorPoint`]**:
112//!   Calculates a representative point inside a `Geometry`
113//!
114//! ## Topology
115//!
116//! - **[`Contains`]**: Calculate if a geometry contains another
117//!   geometry
118//! - **[`ContainsProperly`]**: Calculate if a geometry completely contains another geometry within its interior
119//! - **[`CoordinatePosition`]**: Calculate the position of a coordinate relative to a geometry
120//! - **[`Covers`]**: Calculate if a geometry covers another geometry
121//! - **[`HasDimensions`]**: Determine the dimensions of a geometry
122//! - **[`Intersects`]**: Calculate if a geometry intersects
123//!   another geometry
124//! - **[`line_intersection`]**: Calculates the
125//!   intersection, if any, between two lines
126//! - **[`Intersections`]**: Find all line segment intersections using an efficient sweep line algorithm (Bentley-Ottmann)
127//! - **[`Relate`]**: Topologically relate two geometries based on
128//!   [DE-9IM](https://en.wikipedia.org/wiki/DE-9IM) semantics
129//! - **[`Within`]**: Calculate if a geometry lies completely within another geometry
130//!
131//! ## Triangulation
132//!
133//! - **[`TriangulateEarcut`](triangulate_earcut)**: Triangulate polygons using the earcut algorithm. Requires the `earcutr` feature, which is enabled by default
134//! - **[`TriangulateDelaunay`](triangulate_delaunay)**: Produce constrained or unconstrained Delaunay triangulations of polygons. Requires the `spade` feature, which is enabled by default
135//!
136//! ## Winding
137//!
138//! - **[`Orient`]**: Apply a specified winding [`Direction`](orient::Direction) to a [`Polygon`]’s interior and exterior rings
139//! - **[`Winding`]**: Calculate and manipulate the [`WindingOrder`](winding_order::WindingOrder) of a [`LineString`]
140//!
141//! ## Iteration
142//!
143//! - **[`CoordsIter`]**: Iterate over the coordinates of a geometry
144//! - **[`MapCoords`]**: Map a function over all the coordinates
145//!   in a geometry, returning a new geometry
146//! - **[`MapCoordsInPlace`]**: Map a function over all the
147//!   coordinates in a geometry in-place
148//! - **[`LinesIter`]**: Iterate over lines of a geometry
149//!
150//! ## Boundary
151//!
152//! - **[`BoundingRect`]**: Calculate the axis-aligned
153//!   bounding rectangle of a geometry
154//! - **[`MinimumRotatedRect`]**: Calculate the
155//!   minimum bounding box of a geometry
156//! - **[`ConcaveHull`]**: Calculate the concave hull of a
157//!   geometry
158//! - **[`ConvexHull`]**: Calculate the convex hull of a
159//!   geometry
160//! - **[`Extremes`]**: Calculate the extreme coordinates and
161//!   indices of a geometry
162//!
163//! ## Affine transformations
164//!
165//! - **[`Rotate`]**: Rotate a geometry around its centroid
166//! - **[`Scale`]**: Scale a geometry up or down by a factor
167//! - **[`Skew`]**: Skew a geometry by shearing angles along the `x` and `y` dimension
168//! - **[`Translate`]**: Translate a geometry along its axis
169//! - **[`AffineOps`]**: generalised composable affine operations
170//!
171//! ## Conversion
172//!
173//! - **[`Convert`]**: Convert (infallibly) the numeric type of a geometry’s coordinate value
174//! - **[`TryConvert`]**: Convert (fallibly) the numeric type of a geometry’s coordinate value
175//! - **[`ToDegrees`]**: Radians to degrees coordinate transforms for a given geometry
176//! - **[`ToRadians`]**: Degrees to radians coordinate transforms for a given geometry
177//!
178//! ## Miscellaneous
179//!
180//! - **[`Buffer`]**: Create a new geometry whose boundary is offset the specified distance from the input.
181//! - **[`Centroid`]**: Calculate the centroid of a geometry
182//! - **[`ChaikinSmoothing`]**: Smoothen `LineString`, `Polygon`, `MultiLineString` and `MultiPolygon` using Chaikin's algorithm
183//! - **[`proj`]**: Project geometries with the `proj` crate (requires the `use-proj` feature)
184//! - **[`LineStringSegmentize`]**: Segment a LineString into `n` segments
185//! - **[`LineStringSegmentizeHaversine`]**: Segment a LineString using Haversine distance
186//! - **[`Transform`]**: Transform a geometry using Proj
187//! - **[`RemoveRepeatedPoints`]**: Remove repeated points from a geometry
188//! - **[`Validation`]**: Checks if the geometry is well formed. Some algorithms may not work correctly with invalid geometries
189//!
190//! # Spatial Indexing
191//!
192//! `geo` geometries ([`Point`], [`Line`], [`LineString`], [`Polygon`], [`MultiPolygon`]) can be used with the [rstar](https://docs.rs/rstar/0.12.0/rstar/struct.RTree.html#usage)
193//! R*-tree crate for fast distance and nearest-neighbour queries. Multi- geometries can be added to the tree by iterating over
194//! their members and adding them. Note in particular the availability of the [`bulk_load`](https://docs.rs/rstar/0.12.0/rstar/struct.RTree.html#method.bulk_load)
195//! method and [`GeomWithData`](https://docs.rs/rstar/0.12.0/rstar/primitives/struct.GeomWithData.html) struct.
196//!
197//! # Features
198//!
199//! The following optional [Cargo features] are available:
200//!
201//! - `earcutr`:
202//!     - Enables the `earcutr` crate, which provides triangulation of polygons using the earcut algorithm
203//!     - ☑ Enabled by default
204//! - `proj-network`:
205//!     - Enables [network grid] support for the [`proj` crate]
206//!     - After enabling this feature, [further configuration][proj crate file download] is required to use the network grid.
207//!     - ☐ Disabled by default
208//! - `proj`:
209//!     - Enables coordinate conversion and transformation of `Point` geometries using the [`proj` crate]
210//!     - ☐ Disabled by default
211//! - `serde`:
212//!     - Allows geometry types to be serialized and deserialized with [Serde]
213//!     - ☐ Disabled by default
214//! - `multithreading`:
215//!     - Enables multithreading support (via Rayon), and activates the `multithreading` flag
216//!       in `geo-types`, enabling multi-threaded iteration over `Multi*` geometries
217//!     - ☑ Enabled by default
218//!
219//! # Ecosystem
220//!
221//! There’s a wide variety of `geo`-compatible crates in the ecosystem that offer functionality not
222//! included in the `geo` crate, including:
223//!
224//! * Reading and writing file formats (e.g. [GeoJSON][geojson crate], [WKT][wkt crate],
225//!   [shapefile][shapefile crate])
226//! * [Latitude and longitude parsing][latlng crate]
227//! * [Label placement][polylabel crate]
228//! * [Geocoding][geocoding crate]
229//! * [and much more...][georust website]
230//!
231//! [Euclidean plane]: https://en.wikipedia.org/wiki/Euclidean_plane
232//! [`geo-types`]: https://crates.io/crates/geo-types
233//! [haversine formula]: https://en.wikipedia.org/wiki/Haversine_formula
234//! [`proj` crate]: https://github.com/georust/proj
235//! [geojson crate]: https://crates.io/crates/geojson
236//! [Karney (2013)]:  https://arxiv.org/pdf/1109.4448.pdf
237//! [wkt crate]: https://crates.io/crates/wkt
238//! [shapefile crate]: https://crates.io/crates/shapefile
239//! [latlng crate]: https://crates.io/crates/latlon
240//! [polylabel crate]: https://crates.io/crates/polylabel
241//! [geocoding crate]: https://crates.io/crates/geocoding
242//! [georust website]: https://georust.org
243//! [Cargo features]: https://doc.rust-lang.org/cargo/reference/features.html
244//! [GEOS]: https://trac.osgeo.org/geos
245//! [JTS]: https://github.com/locationtech/jts
246//! [network grid]: https://proj.org/usage/network.html
247//! [OGC-SFA]: https://www.ogc.org/standards/sfa
248//! [proj crate file download]: https://docs.rs/proj/*/proj/#grid-file-download
249//! [rhumb line]: https://en.wikipedia.org/wiki/Rhumb_line
250//! [Serde]: https://serde.rs/
251
252#[cfg(feature = "serde")]
253#[macro_use]
254extern crate serde;
255
256pub use crate::algorithm::*;
257pub use crate::types::Closest;
258use std::cmp::Ordering;
259
260pub use crate::algorithm::sweep::Intersections;
261pub use crate::indexed::PreparedGeometry;
262pub use geo_types::{CoordFloat, CoordNum, coord, line_string, point, polygon, wkt};
263
264pub mod geometry;
265pub use geometry::*;
266
267/// This module includes all the functions of geometric calculations
268pub mod algorithm;
269mod geometry_cow;
270mod types;
271mod utils;
272use crate::kernels::{RobustKernel, SimpleKernel};
273pub(crate) use geometry_cow::GeometryCow;
274
275#[cfg(test)]
276#[macro_use]
277extern crate approx;
278
279#[macro_use]
280extern crate log;
281
282/// Mean radius of Earth in meters
283/// This is the value recommended by the IUGG:
284/// Moritz, H. (2000). Geodetic Reference System 1980. Journal of Geodesy, 74(1), 128–133. doi:10.1007/s001900050278
285/// "Derived Geometric Constants: **R1: mean radius**" (p131)
286/// - <https://link.springer.com/article/10.1007%2Fs001900050278>
287/// - <https://sci-hub.se/https://doi.org/10.1007/s001900050278>
288/// - <https://en.wikipedia.org/wiki/Earth_radius#Mean_radius>
289const MEAN_EARTH_RADIUS: f64 = HaversineMeasure::GRS80_MEAN_RADIUS.radius();
290
291// Radius of Earth at the equator in meters (derived from the WGS-84 ellipsoid)
292const EQUATORIAL_EARTH_RADIUS: f64 = 6_378_137.0;
293
294// Radius of Earth at the poles in meters (derived from the WGS-84 ellipsoid)
295const POLAR_EARTH_RADIUS: f64 = 6_356_752.314_245;
296
297// Flattening of the WGS-84 ellipsoid - https://en.wikipedia.org/wiki/Flattening
298const EARTH_FLATTENING: f64 =
299    (EQUATORIAL_EARTH_RADIUS - POLAR_EARTH_RADIUS) / EQUATORIAL_EARTH_RADIUS;
300
301/// A prelude which re-exports the traits for manipulating objects in this
302/// crate. Typically imported with `use geo::prelude::*`.
303pub mod prelude {
304    pub use crate::algorithm::*;
305}
306
307/// A common numeric trait used for geo algorithms
308///
309/// Different numeric types have different tradeoffs. `geo` strives to utilize generics to allow
310/// users to choose their numeric types. If you are writing a function which you'd like to be
311/// generic over all the numeric types supported by geo, you probably want to constrain
312/// your function input to `GeoFloat`. For methods which work for integers, and not just floating
313/// point, see [`GeoNum`].
314///
315/// # Examples
316///
317/// ```
318/// use geo::{GeoFloat, MultiPolygon, Polygon, Point};
319///
320/// // An admittedly silly method implementation, but the signature shows how to use the GeoFloat trait
321/// fn farthest_from<'a, T: GeoFloat>(point: &Point<T>, polygons: &'a MultiPolygon<T>) -> Option<&'a Polygon<T>> {
322///     polygons.iter().fold(None, |accum, next| {
323///         match accum {
324///             None => Some(next),
325///             Some(farthest) => {
326///                 use geo::{euclidean_distance::EuclideanDistance};
327///                 if next.euclidean_distance(point) > farthest.euclidean_distance(point) {
328///                     Some(next)
329///                 } else {
330///                     Some(farthest)
331///                 }
332///             }
333///         }
334///     })
335/// }
336/// ```
337pub trait GeoFloat:
338    GeoNum + num_traits::Float + num_traits::Signed + num_traits::Bounded + float_next_after::NextAfter
339{
340}
341impl<T> GeoFloat for T where
342    T: GeoNum
343        + num_traits::Float
344        + num_traits::Signed
345        + num_traits::Bounded
346        + float_next_after::NextAfter
347{
348}
349
350/// A trait for methods which work for both integers **and** floating point
351pub trait GeoNum: CoordNum {
352    type Ker: Kernel<Self>;
353
354    /// Return the ordering between self and other.
355    ///
356    /// For integers, this should behave just like [`Ord`].
357    ///
358    /// For floating point numbers, unlike the standard partial comparison between floating point numbers, this comparison
359    /// always produces an ordering.
360    ///
361    /// See [f64::total_cmp](https://doc.rust-lang.org/src/core/num/f64.rs.html#1432) for details.
362    fn total_cmp(&self, other: &Self) -> Ordering;
363}
364
365macro_rules! impl_geo_num_for_float {
366    ($t: ident) => {
367        impl GeoNum for $t {
368            type Ker = RobustKernel;
369            fn total_cmp(&self, other: &Self) -> Ordering {
370                self.total_cmp(other)
371            }
372        }
373    };
374}
375macro_rules! impl_geo_num_for_int {
376    ($t: ident) => {
377        impl GeoNum for $t {
378            type Ker = SimpleKernel;
379            fn total_cmp(&self, other: &Self) -> Ordering {
380                self.cmp(other)
381            }
382        }
383    };
384}
385
386// This is the list of primitives that we support.
387impl_geo_num_for_float!(f32);
388impl_geo_num_for_float!(f64);
389impl_geo_num_for_int!(i16);
390impl_geo_num_for_int!(i32);
391impl_geo_num_for_int!(i64);
392impl_geo_num_for_int!(i128);
393impl_geo_num_for_int!(isize);
394
395// Some gymnastics to help migrate people off our old feature flag naming conventions
396#[allow(unused)]
397mod deprecated_feature_flags {
398    #[cfg_attr(
399        not(feature = "__allow_deprecated_features"),
400        deprecated(
401            since = "0.31.1",
402            note = "The `use-serde` feature has been renamed to simply `serde`. Use the `serde` feature instead."
403        )
404    )]
405    pub struct UseSerde;
406
407    #[cfg_attr(
408        not(feature = "__allow_deprecated_features"),
409        deprecated(
410            since = "0.31.1",
411            note = "The `use-proj` feature has been renamed to simply `proj`. Use the `proj` feature instead."
412        )
413    )]
414    pub struct UseProj;
415}
416#[cfg(feature = "use-proj")]
417pub use deprecated_feature_flags::UseProj;
418#[cfg(feature = "use-serde")]
419pub use deprecated_feature_flags::UseSerde;
420
421#[cfg(test)]
422mod tests {
423    use super::*;
424
425    #[test]
426    fn total_ord_float() {
427        assert_eq!(GeoNum::total_cmp(&3.0f64, &2.0f64), Ordering::Greater);
428        assert_eq!(GeoNum::total_cmp(&2.0f64, &2.0f64), Ordering::Equal);
429        assert_eq!(GeoNum::total_cmp(&1.0f64, &2.0f64), Ordering::Less);
430        assert_eq!(GeoNum::total_cmp(&1.0f64, &f64::NAN), Ordering::Less);
431        assert_eq!(GeoNum::total_cmp(&f64::NAN, &f64::NAN), Ordering::Equal);
432        assert_eq!(GeoNum::total_cmp(&f64::INFINITY, &f64::NAN), Ordering::Less);
433    }
434
435    #[test]
436    fn total_ord_int() {
437        assert_eq!(GeoNum::total_cmp(&3i32, &2i32), Ordering::Greater);
438        assert_eq!(GeoNum::total_cmp(&2i32, &2i32), Ordering::Equal);
439        assert_eq!(GeoNum::total_cmp(&1i32, &2i32), Ordering::Less);
440    }
441
442    #[test]
443    fn numeric_types() {
444        let _n_i16 = Point::new(1i16, 2i16);
445        let _n_i32 = Point::new(1i32, 2i32);
446        let _n_i64 = Point::new(1i64, 2i64);
447        let _n_i128 = Point::new(1i128, 2i128);
448        let _n_isize = Point::new(1isize, 2isize);
449        let _n_f32 = Point::new(1.0f32, 2.0f32);
450        let _n_f64 = Point::new(1.0f64, 2.0f64);
451    }
452}