geo_types/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(missing_debug_implementations)]
3#![doc(html_logo_url = "https://raw.githubusercontent.com/georust/meta/master/logo/logo.png")]
4//! The `geo-types` library defines geometric types for the [GeoRust] ecosystem.
5//!
6//! In most cases, you will only need to use this crate if you’re a crate author and want
7//! compatibility with other GeoRust crates. Otherwise, the [`geo`](https://crates.io/crates/geo)
8//! crate re-exports these types and additionally provides geospatial algorithms.
9//!
10//! ## Geometries
11//!
12//! - **[`Point`]**: A single point represented by one [`Coord`]
13//! - **[`MultiPoint`]**: A collection of [`Point`]s
14//! - **[`Line`]**: A line segment represented by two [`Coord`]s
15//! - **[`LineString`]**: A series of contiguous line segments represented by two or more
16//! [`Coord`]s
17//! - **[`MultiLineString`]**: A collection of [`LineString`]s
18//! - **[`Polygon`]**: A bounded area represented by one [`LineString`] exterior ring, and zero or
19//! more [`LineString`] interior rings
20//! - **[`MultiPolygon`]**: A collection of [`Polygon`]s
21//! - **[`Rect`]**: An axis-aligned bounded rectangle represented by minimum and maximum
22//! [`Coord`]s
23//! - **[`Triangle`]**: A bounded area represented by three [`Coord`] vertices
24//! - **[`GeometryCollection`]**: A collection of [`Geometry`]s
25//! - **[`Geometry`]**: An enumeration of all geometry types, excluding [`Coord`]
26//!
27//! ## Coordinates and Numeric Types
28//!
29//! - **[`Coord`]**: A two-dimensional coordinate. All geometry types are composed of [`Coord`]s, though [`Coord`] itself is not a [`Geometry`] type. See [`Point`] for a single coordinate geometry.
30//!
31//! By default, coordinates are 64-bit floating point numbers, but this is generic, and you may specify any numeric type that implements [`CoordNum`] or [`CoordFloat`]. As well as [`f64`], this includes common numeric types like [`f32`], [`i32`], [`i64`], etc.
32//!
33//! ```rust
34//! use geo_types::Point;
35//!
36//! // Geometries are f64 by default
37//! let point: Point = Point::new(1.0, 2.0);
38//! assert_eq!(std::mem::size_of::<Point>(), 64 * 2 / 8);
39//!
40//! // You can be explicit about the numeric type.
41//! let f64_point: Point<f64> = Point::new(1.0, 2.0);
42//! assert_eq!(std::mem::size_of::<Point<f64>>(), 64 * 2 / 8);
43//!
44//! // Or specify some non-default numeric type
45//! let f32_point: Point<f32> = Point::new(1.0, 2.0);
46//! assert_eq!(std::mem::size_of::<Point<f32>>(), 32 * 2 / 8);
47//!
48//! // Integer geometries are supported too, though not all
49//! // algorithms will be implemented for all numeric types.
50//! let i32_point: Point<i32> = Point::new(1, 2);
51//! assert_eq!(std::mem::size_of::<Point<i32>>(), 32 * 2 / 8);
52//! ```
53//!
54//! # Semantics
55//!
56//! The geospatial types provided here aim to adhere to the [OpenGIS Simple feature access][OGC-SFA]
57//! standards. Thus, the types here are inter-operable with other implementations of the standards:
58//! [JTS], [GEOS], etc.
59//!
60//! # Features
61//!
62//! The following optional [Cargo features] are available:
63//!
64//! - `std`: Enables use of the full `std` library. Enabled by default.
65//! - `multithreading`: Enables multi-threaded iteration over `Multi*` geometries. **Disabled**
66//! by default but **enabled** by `geo`'s default features.
67//! - `approx`: Allows geometry types to be checked for approximate equality with [approx]
68//! - `arbitrary`: Allows geometry types to be created from unstructured input with [arbitrary]
69//! - `serde`: Allows geometry types to be serialized and deserialized with [Serde]
70//! - `use-rstar_0_8`: Allows geometry types to be inserted into [rstar] R*-trees (`rstar v0.8`)
71//! - `use-rstar_0_9`: Allows geometry types to be inserted into [rstar] R*-trees (`rstar v0.9`)
72//! - `use-rstar_0_10`: Allows geometry types to be inserted into [rstar] R*-trees (`rstar v0.10`)
73//! - `use-rstar_0_11`: Allows geometry types to be inserted into [rstar] R*-trees (`rstar v0.11`)
74//! - `use-rstar_0_12`: Allows geometry types to be inserted into [rstar] R*-trees (`rstar v0.12`)
75//!
76//! This library can be used in `#![no_std]` environments if the default `std` feature is disabled. At
77//! the moment, the `arbitrary` and `use-rstar_0_8` features require `std`. This may change in a
78//! future release.
79//!
80//! [approx]: https://github.com/brendanzab/approx
81//! [arbitrary]: https://github.com/rust-fuzz/arbitrary
82//! [Cargo features]: https://doc.rust-lang.org/cargo/reference/features.html
83//! [GeoRust]: https://georust.org
84//! [GEOS]: https://trac.osgeo.org/geos
85//! [JTS]: https://github.com/locationtech/jts
86//! [OGC-SFA]: https://www.ogc.org/standards/sfa
87//! [rstar]: https://github.com/Stoeoef/rstar
88//! [Serde]: https://serde.rs/
89extern crate alloc;
90
91use core::fmt::Debug;
92use num_traits::{Float, Num, NumCast};
93
94#[cfg(feature = "serde")]
95#[macro_use]
96extern crate serde;
97
98#[cfg(test)]
99#[macro_use]
100extern crate approx;
101
102#[deprecated(since = "0.7.0", note = "use `CoordFloat` or `CoordNum` instead")]
103pub trait CoordinateType: Num + Copy + NumCast + PartialOrd + Debug {}
104#[allow(deprecated)]
105impl<T: Num + Copy + NumCast + PartialOrd + Debug> CoordinateType for T {}
106
107/// For algorithms which can use both integer **and** floating point `Point`s/`Coord`s
108///
109/// Floats (`f32` and `f64`) and Integers (`u8`, `i32` etc.) implement this.
110///
111/// For algorithms which only make sense for floating point, like area or length calculations,
112/// see [CoordFloat](trait.CoordFloat.html).
113#[allow(deprecated)]
114pub trait CoordNum: CoordinateType + Debug {}
115#[allow(deprecated)]
116impl<T: CoordinateType + Debug> CoordNum for T {}
117
118/// For algorithms which can only use floating point `Point`s/`Coord`s, like area or length calculations
119pub trait CoordFloat: CoordNum + Float {}
120impl<T: CoordNum + Float> CoordFloat for T {}
121
122pub mod geometry;
123pub use geometry::*;
124
125pub use geometry::line_string::PointsIter;
126
127#[allow(deprecated)]
128pub use geometry::rect::InvalidRectCoordinatesError;
129
130mod error;
131pub use error::Error;
132
133#[macro_use]
134mod macros;
135
136#[macro_use]
137mod wkt_macro;
138
139#[cfg(feature = "arbitrary")]
140mod arbitrary;
141
142#[cfg(any(
143 feature = "rstar_0_8",
144 feature = "rstar_0_9",
145 feature = "rstar_0_10",
146 feature = "rstar_0_11",
147 feature = "rstar_0_12"
148))]
149#[doc(hidden)]
150pub mod private_utils;
151
152mod debug;
153
154#[doc(hidden)]
155pub mod _alloc {
156 //! Needed to access these types from `alloc` in macros when the std feature is
157 //! disabled and the calling context is missing `extern crate alloc`. These are
158 //! _not_ meant for public use.
159 pub use ::alloc::vec;
160}
161
162#[cfg(test)]
163mod tests {
164 use alloc::vec;
165
166 use super::*;
167 use core::convert::TryFrom;
168
169 #[test]
170 fn type_test() {
171 let c = coord! {
172 x: 40.02f64,
173 y: 116.34,
174 };
175
176 let p = Point::from(c);
177
178 let Point(c2) = p;
179 assert_eq!(c, c2);
180 assert_relative_eq!(c.x, c2.x);
181 assert_relative_eq!(c.y, c2.y);
182
183 let p: Point<f32> = (0f32, 1f32).into();
184 assert_relative_eq!(p.x(), 0.);
185 assert_relative_eq!(p.y(), 1.);
186 }
187
188 #[test]
189 fn convert_types() {
190 let p: Point<f32> = Point::new(0., 0.);
191 let p1 = p;
192 let g: Geometry<f32> = p.into();
193 let p2 = Point::try_from(g).unwrap();
194 assert_eq!(p1, p2);
195 }
196
197 #[test]
198 fn polygon_new_test() {
199 let exterior = LineString::new(vec![
200 coord! { x: 0., y: 0. },
201 coord! { x: 1., y: 1. },
202 coord! { x: 1., y: 0. },
203 coord! { x: 0., y: 0. },
204 ]);
205 let interiors = vec![LineString::new(vec![
206 coord! { x: 0.1, y: 0.1 },
207 coord! { x: 0.9, y: 0.9 },
208 coord! { x: 0.9, y: 0.1 },
209 coord! { x: 0.1, y: 0.1 },
210 ])];
211 let p = Polygon::new(exterior.clone(), interiors.clone());
212
213 assert_eq!(p.exterior(), &exterior);
214 assert_eq!(p.interiors(), &interiors[..]);
215 }
216
217 #[test]
218 fn iters() {
219 let _: MultiPoint<_> = vec![(0., 0.), (1., 2.)].into();
220 let _: MultiPoint<_> = vec![(0., 0.), (1., 2.)].into_iter().collect();
221
222 let mut l1: LineString<_> = vec![(0., 0.), (1., 2.)].into();
223 assert_eq!(l1[1], coord! { x: 1., y: 2. }); // index into linestring
224 let _: LineString<_> = vec![(0., 0.), (1., 2.)].into_iter().collect();
225
226 // index mutably into a linestring
227 l1[0] = coord! { x: 1., y: 1. };
228 assert_eq!(l1, vec![(1., 1.), (1., 2.)].into());
229 }
230
231 #[test]
232 fn test_coordinate_types() {
233 let p: Point<u8> = Point::new(0, 0);
234 assert_eq!(p.x(), 0u8);
235
236 let p: Point<i64> = Point::new(1_000_000, 0);
237 assert_eq!(p.x(), 1_000_000i64);
238 }
239
240 #[cfg(feature = "rstar_0_8")]
241 #[test]
242 /// ensure Line's SpatialObject impl is correct
243 fn line_test() {
244 use rstar_0_8::primitives::Line as RStarLine;
245 use rstar_0_8::{PointDistance, RTreeObject};
246
247 let rl = RStarLine::new(Point::new(0.0, 0.0), Point::new(5.0, 5.0));
248 let l = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 5., y: 5. });
249 assert_eq!(rl.envelope(), l.envelope());
250 // difference in 15th decimal place
251 assert_relative_eq!(26.0, rl.distance_2(&Point::new(4.0, 10.0)));
252 assert_relative_eq!(25.999999999999996, l.distance_2(&Point::new(4.0, 10.0)));
253 }
254
255 #[cfg(feature = "rstar_0_9")]
256 #[test]
257 /// ensure Line's SpatialObject impl is correct
258 fn line_test_0_9() {
259 use rstar_0_9::primitives::Line as RStarLine;
260 use rstar_0_9::{PointDistance, RTreeObject};
261
262 let rl = RStarLine::new(Point::new(0.0, 0.0), Point::new(5.0, 5.0));
263 let l = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 5., y: 5. });
264 assert_eq!(rl.envelope(), l.envelope());
265 // difference in 15th decimal place
266 assert_relative_eq!(26.0, rl.distance_2(&Point::new(4.0, 10.0)));
267 assert_relative_eq!(25.999999999999996, l.distance_2(&Point::new(4.0, 10.0)));
268 }
269
270 #[cfg(feature = "rstar_0_10")]
271 #[test]
272 /// ensure Line's SpatialObject impl is correct
273 fn line_test_0_10() {
274 use rstar_0_10::primitives::Line as RStarLine;
275 use rstar_0_10::{PointDistance, RTreeObject};
276
277 let rl = RStarLine::new(Point::new(0.0, 0.0), Point::new(5.0, 5.0));
278 let l = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 5., y: 5. });
279 assert_eq!(rl.envelope(), l.envelope());
280 // difference in 15th decimal place
281 assert_relative_eq!(26.0, rl.distance_2(&Point::new(4.0, 10.0)));
282 assert_relative_eq!(25.999999999999996, l.distance_2(&Point::new(4.0, 10.0)));
283 }
284
285 #[cfg(feature = "rstar_0_11")]
286 #[test]
287 /// ensure Line's SpatialObject impl is correct
288 fn line_test_0_11() {
289 use rstar_0_11::primitives::Line as RStarLine;
290 use rstar_0_11::{PointDistance, RTreeObject};
291
292 let rl = RStarLine::new(Point::new(0.0, 0.0), Point::new(5.0, 5.0));
293 let l = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 5., y: 5. });
294 assert_eq!(rl.envelope(), l.envelope());
295 // difference in 15th decimal place
296 assert_relative_eq!(26.0, rl.distance_2(&Point::new(4.0, 10.0)));
297 assert_relative_eq!(25.999999999999996, l.distance_2(&Point::new(4.0, 10.0)));
298 }
299
300 #[cfg(feature = "rstar_0_12")]
301 #[test]
302 /// ensure Line's SpatialObject impl is correct
303 fn line_test_0_12() {
304 use rstar_0_12::primitives::Line as RStarLine;
305 use rstar_0_12::{PointDistance, RTreeObject};
306
307 let rl = RStarLine::new(Point::new(0.0, 0.0), Point::new(5.0, 5.0));
308 let l = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 5., y: 5. });
309 assert_eq!(rl.envelope(), l.envelope());
310 // difference in 15th decimal place
311 assert_relative_eq!(26.0, rl.distance_2(&Point::new(4.0, 10.0)));
312 assert_relative_eq!(25.999999999999996, l.distance_2(&Point::new(4.0, 10.0)));
313 }
314
315 #[test]
316 fn test_rects() {
317 let r = Rect::new(coord! { x: -1., y: -1. }, coord! { x: 1., y: 1. });
318 let p: Polygon<_> = r.into();
319 assert_eq!(
320 p,
321 Polygon::new(
322 vec![(-1., -1.), (1., -1.), (1., 1.), (-1., 1.), (-1., -1.)].into(),
323 vec![]
324 )
325 );
326 }
327}