1pub(crate) mod coord;
2pub(crate) mod geometry_collection;
3pub(crate) mod line;
4pub(crate) mod line_string;
5pub(crate) mod multi_line_string;
6pub(crate) mod multi_point;
7pub(crate) mod multi_polygon;
8pub(crate) mod point;
9pub(crate) mod polygon;
10pub(crate) mod rect;
11pub(crate) mod triangle;
12
13#[allow(deprecated)]
15pub use coord::{Coord, Coordinate};
16pub use geometry_collection::GeometryCollection;
17pub use line::Line;
18pub use line_string::LineString;
19pub use multi_line_string::MultiLineString;
20pub use multi_point::MultiPoint;
21pub use multi_polygon::MultiPolygon;
22pub use point::Point;
23pub use polygon::Polygon;
24pub use rect::Rect;
25pub use triangle::Triangle;
26
27use crate::{CoordNum, Error};
28
29use core::any::type_name;
30use core::convert::TryFrom;
31
32#[derive(Eq, PartialEq, Clone, Hash)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub enum Geometry<T: CoordNum = f64> {
51 Point(Point<T>),
52 Line(Line<T>),
53 LineString(LineString<T>),
54 Polygon(Polygon<T>),
55 MultiPoint(MultiPoint<T>),
56 MultiLineString(MultiLineString<T>),
57 MultiPolygon(MultiPolygon<T>),
58 GeometryCollection(GeometryCollection<T>),
59 Rect(Rect<T>),
60 Triangle(Triangle<T>),
61}
62
63impl<T: CoordNum> From<Point<T>> for Geometry<T> {
64 fn from(x: Point<T>) -> Self {
65 Self::Point(x)
66 }
67}
68impl<T: CoordNum> From<Line<T>> for Geometry<T> {
69 fn from(x: Line<T>) -> Self {
70 Self::Line(x)
71 }
72}
73impl<T: CoordNum> From<LineString<T>> for Geometry<T> {
74 fn from(x: LineString<T>) -> Self {
75 Self::LineString(x)
76 }
77}
78impl<T: CoordNum> From<Polygon<T>> for Geometry<T> {
79 fn from(x: Polygon<T>) -> Self {
80 Self::Polygon(x)
81 }
82}
83impl<T: CoordNum> From<MultiPoint<T>> for Geometry<T> {
84 fn from(x: MultiPoint<T>) -> Self {
85 Self::MultiPoint(x)
86 }
87}
88impl<T: CoordNum> From<MultiLineString<T>> for Geometry<T> {
89 fn from(x: MultiLineString<T>) -> Self {
90 Self::MultiLineString(x)
91 }
92}
93impl<T: CoordNum> From<MultiPolygon<T>> for Geometry<T> {
94 fn from(x: MultiPolygon<T>) -> Self {
95 Self::MultiPolygon(x)
96 }
97}
98
99impl<T: CoordNum> From<Rect<T>> for Geometry<T> {
107 fn from(x: Rect<T>) -> Self {
108 Self::Rect(x)
109 }
110}
111
112impl<T: CoordNum> From<Triangle<T>> for Geometry<T> {
113 fn from(x: Triangle<T>) -> Self {
114 Self::Triangle(x)
115 }
116}
117
118impl<T: CoordNum> Geometry<T> {
119 #[deprecated(
132 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<Point>"
133 )]
134 pub fn into_point(self) -> Option<Point<T>> {
135 if let Geometry::Point(x) = self {
136 Some(x)
137 } else {
138 None
139 }
140 }
141
142 #[deprecated(
144 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<LineString>"
145 )]
146 pub fn into_line_string(self) -> Option<LineString<T>> {
147 if let Geometry::LineString(x) = self {
148 Some(x)
149 } else {
150 None
151 }
152 }
153
154 #[deprecated(
156 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<Line>"
157 )]
158 pub fn into_line(self) -> Option<Line<T>> {
159 if let Geometry::Line(x) = self {
160 Some(x)
161 } else {
162 None
163 }
164 }
165
166 #[deprecated(
168 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<Polygon>"
169 )]
170 pub fn into_polygon(self) -> Option<Polygon<T>> {
171 if let Geometry::Polygon(x) = self {
172 Some(x)
173 } else {
174 None
175 }
176 }
177
178 #[deprecated(
180 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<MultiPoint>"
181 )]
182 pub fn into_multi_point(self) -> Option<MultiPoint<T>> {
183 if let Geometry::MultiPoint(x) = self {
184 Some(x)
185 } else {
186 None
187 }
188 }
189
190 #[deprecated(
192 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<MultiLineString>"
193 )]
194 pub fn into_multi_line_string(self) -> Option<MultiLineString<T>> {
195 if let Geometry::MultiLineString(x) = self {
196 Some(x)
197 } else {
198 None
199 }
200 }
201
202 #[deprecated(
204 note = "Will be removed in an upcoming version. Switch to std::convert::TryInto<MultiPolygon>"
205 )]
206 pub fn into_multi_polygon(self) -> Option<MultiPolygon<T>> {
207 if let Geometry::MultiPolygon(x) = self {
208 Some(x)
209 } else {
210 None
211 }
212 }
213}
214
215macro_rules! try_from_geometry_impl {
216 ($($type: ident),+) => {
217 $(
218 impl <T: CoordNum> TryFrom<Geometry<T>> for $type<T> {
222 type Error = Error;
223
224 fn try_from(geom: Geometry<T>) -> Result<Self, Self::Error> {
225 match geom {
226 Geometry::$type(g) => Ok(g),
227 other => Err(Error::MismatchedGeometry {
228 expected: type_name::<$type<T>>(),
229 found: inner_type_name(other)
230 })
231 }
232 }
233 }
234 )+
235 }
236}
237
238try_from_geometry_impl!(
239 Point,
240 Line,
241 LineString,
242 Polygon,
243 MultiPoint,
244 MultiLineString,
245 MultiPolygon,
246 Rect,
249 Triangle
250);
251
252fn inner_type_name<T>(geometry: Geometry<T>) -> &'static str
253where
254 T: CoordNum,
255{
256 match geometry {
257 Geometry::Point(_) => type_name::<Point<T>>(),
258 Geometry::Line(_) => type_name::<Line<T>>(),
259 Geometry::LineString(_) => type_name::<LineString<T>>(),
260 Geometry::Polygon(_) => type_name::<Polygon<T>>(),
261 Geometry::MultiPoint(_) => type_name::<MultiPoint<T>>(),
262 Geometry::MultiLineString(_) => type_name::<MultiLineString<T>>(),
263 Geometry::MultiPolygon(_) => type_name::<MultiPolygon<T>>(),
264 Geometry::GeometryCollection(_) => type_name::<GeometryCollection<T>>(),
265 Geometry::Rect(_) => type_name::<Rect<T>>(),
266 Geometry::Triangle(_) => type_name::<Triangle<T>>(),
267 }
268}
269
270#[cfg(any(feature = "approx", test))]
271mod approx_integration {
272 use super::*;
273 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
274
275 impl<T> RelativeEq for Geometry<T>
276 where
277 T: CoordNum + RelativeEq<Epsilon = T>,
278 {
279 #[inline]
280 fn default_max_relative() -> Self::Epsilon {
281 T::default_max_relative()
282 }
283
284 fn relative_eq(
299 &self,
300 other: &Self,
301 epsilon: Self::Epsilon,
302 max_relative: Self::Epsilon,
303 ) -> bool {
304 match (self, other) {
305 (Geometry::Point(g1), Geometry::Point(g2)) => {
306 g1.relative_eq(g2, epsilon, max_relative)
307 }
308 (Geometry::Line(g1), Geometry::Line(g2)) => {
309 g1.relative_eq(g2, epsilon, max_relative)
310 }
311 (Geometry::LineString(g1), Geometry::LineString(g2)) => {
312 g1.relative_eq(g2, epsilon, max_relative)
313 }
314 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => {
315 g1.relative_eq(g2, epsilon, max_relative)
316 }
317 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => {
318 g1.relative_eq(g2, epsilon, max_relative)
319 }
320 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
321 g1.relative_eq(g2, epsilon, max_relative)
322 }
323 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
324 g1.relative_eq(g2, epsilon, max_relative)
325 }
326 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
327 g1.relative_eq(g2, epsilon, max_relative)
328 }
329 (Geometry::Rect(g1), Geometry::Rect(g2)) => {
330 g1.relative_eq(g2, epsilon, max_relative)
331 }
332 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => {
333 g1.relative_eq(g2, epsilon, max_relative)
334 }
335 (_, _) => false,
336 }
337 }
338 }
339
340 impl<T> AbsDiffEq for Geometry<T>
341 where
342 T: CoordNum + AbsDiffEq<Epsilon = T>,
343 {
344 type Epsilon = T;
345
346 #[inline]
347 fn default_epsilon() -> Self::Epsilon {
348 T::default_epsilon()
349 }
350
351 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
365 match (self, other) {
366 (Geometry::Point(g1), Geometry::Point(g2)) => g1.abs_diff_eq(g2, epsilon),
367 (Geometry::Line(g1), Geometry::Line(g2)) => g1.abs_diff_eq(g2, epsilon),
368 (Geometry::LineString(g1), Geometry::LineString(g2)) => g1.abs_diff_eq(g2, epsilon),
369 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => g1.abs_diff_eq(g2, epsilon),
370 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => g1.abs_diff_eq(g2, epsilon),
371 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
372 g1.abs_diff_eq(g2, epsilon)
373 }
374 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
375 g1.abs_diff_eq(g2, epsilon)
376 }
377 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
378 g1.abs_diff_eq(g2, epsilon)
379 }
380 (Geometry::Rect(g1), Geometry::Rect(g2)) => g1.abs_diff_eq(g2, epsilon),
381 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => g1.abs_diff_eq(g2, epsilon),
382 (_, _) => false,
383 }
384 }
385 }
386
387 impl<T> UlpsEq for Geometry<T>
388 where
389 T: CoordNum + UlpsEq<Epsilon = T>,
390 {
391 fn default_max_ulps() -> u32 {
392 T::default_max_ulps()
393 }
394
395 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
423 match (self, other) {
424 (Geometry::Point(g1), Geometry::Point(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
425 (Geometry::Line(g1), Geometry::Line(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
426 (Geometry::LineString(g1), Geometry::LineString(g2)) => {
427 g1.ulps_eq(g2, epsilon, max_ulps)
428 }
429 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
430 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => {
431 g1.ulps_eq(g2, epsilon, max_ulps)
432 }
433 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
434 g1.ulps_eq(g2, epsilon, max_ulps)
435 }
436 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
437 g1.ulps_eq(g2, epsilon, max_ulps)
438 }
439 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
440 g1.ulps_eq(g2, epsilon, max_ulps)
441 }
442 (Geometry::Rect(g1), Geometry::Rect(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
443 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => {
444 g1.ulps_eq(g2, epsilon, max_ulps)
445 }
446 _ => false,
448 }
449 }
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 mod approx_integration {
456 use crate::{Geometry, Point};
457
458 #[test]
459 fn test_abs_diff() {
460 let g = Geometry::from(Point::new(1.0, 1.0));
461 let abs_diff_eq_point =
462 Geometry::from(Point::new(1.0 + f64::EPSILON, 1.0 + f64::EPSILON));
463 assert_ne!(g, abs_diff_eq_point);
464 assert_abs_diff_eq!(g, abs_diff_eq_point);
465
466 let a_little_farther = Geometry::from(Point::new(1.001, 1.001));
467 assert_ne!(g, a_little_farther);
468 assert_abs_diff_ne!(g, a_little_farther);
469 assert_abs_diff_eq!(g, a_little_farther, epsilon = 1e-3);
470 assert_abs_diff_ne!(g, a_little_farther, epsilon = 5e-4);
471 }
472
473 #[test]
474 fn test_relative() {
475 let g = Geometry::from(Point::new(2.0, 2.0));
476
477 let relative_eq_point = Geometry::from(Point::new(
478 2.0 + 2.0 * f64::EPSILON,
479 2.0 + 2.0 * f64::EPSILON,
480 ));
481 assert_ne!(g, relative_eq_point);
482 assert_relative_eq!(g, relative_eq_point);
483
484 let a_little_farther = Geometry::from(Point::new(2.001, 2.001));
485 assert_ne!(g, a_little_farther);
486 assert_relative_ne!(g, a_little_farther);
487 assert_relative_eq!(g, a_little_farther, epsilon = 1e-3);
488 assert_relative_ne!(g, a_little_farther, epsilon = 5e-4);
489 assert_relative_eq!(g, a_little_farther, max_relative = 5e-4);
490
491 let far = Geometry::from(Point::new(4.0, 4.0));
493 assert_relative_eq!(g, far, max_relative = 1.0 / 2.0);
494 assert_relative_ne!(g, far, max_relative = 0.49);
495 }
496
497 #[test]
498 fn test_ulps() {
499 let g = Geometry::from(Point::new(1.0, 1.0));
500
501 let ulps_eq_point = Geometry::from(Point::new(1.0 + f64::EPSILON, 1.0 + f64::EPSILON));
502 assert_ne!(g, ulps_eq_point);
503 assert_ulps_eq!(g, ulps_eq_point);
504 }
505
506 #[test]
507 fn test_ulps_vs_relative() {
508 let a = 1000.000000000001;
517 let b = 1000.0000000000008;
518
519 let p1 = Point::new(a, a);
520 let p2 = Point::new(b, b);
521
522 assert_ne!(p1, p2);
523 assert_relative_ne!(p1, p2);
524 assert_ulps_eq!(p1, p2);
525 }
526 }
527}