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 pub fn static_name(&self) -> &'static str {
216 match self {
217 Geometry::Point(_) => "Point",
218 Geometry::Line(_) => "Line",
219 Geometry::LineString(_) => "LineString",
220 Geometry::Polygon(_) => "Polygon",
221 Geometry::MultiPoint(_) => "MultiPoint",
222 Geometry::MultiLineString(_) => "MultiLineString",
223 Geometry::MultiPolygon(_) => "MultiPolygon",
224 Geometry::GeometryCollection(_) => "GeometryCollection",
225 Geometry::Rect(_) => "Rect",
226 Geometry::Triangle(_) => "Triangle",
227 }
228 }
229}
230
231macro_rules! try_from_geometry_impl {
232 ($($type: ident),+) => {
233 $(
234 impl <T: CoordNum> TryFrom<Geometry<T>> for $type<T> {
238 type Error = Error;
239
240 fn try_from(geom: Geometry<T>) -> Result<Self, Self::Error> {
241 match geom {
242 Geometry::$type(g) => Ok(g),
243 other => Err(Error::MismatchedGeometry {
244 expected: type_name::<$type<T>>(),
245 found: inner_type_name(other)
246 })
247 }
248 }
249 }
250 )+
251 }
252}
253
254try_from_geometry_impl!(
255 Point,
256 Line,
257 LineString,
258 Polygon,
259 MultiPoint,
260 MultiLineString,
261 MultiPolygon,
262 Rect,
265 Triangle
266);
267
268fn inner_type_name<T>(geometry: Geometry<T>) -> &'static str
269where
270 T: CoordNum,
271{
272 match geometry {
273 Geometry::Point(_) => type_name::<Point<T>>(),
274 Geometry::Line(_) => type_name::<Line<T>>(),
275 Geometry::LineString(_) => type_name::<LineString<T>>(),
276 Geometry::Polygon(_) => type_name::<Polygon<T>>(),
277 Geometry::MultiPoint(_) => type_name::<MultiPoint<T>>(),
278 Geometry::MultiLineString(_) => type_name::<MultiLineString<T>>(),
279 Geometry::MultiPolygon(_) => type_name::<MultiPolygon<T>>(),
280 Geometry::GeometryCollection(_) => type_name::<GeometryCollection<T>>(),
281 Geometry::Rect(_) => type_name::<Rect<T>>(),
282 Geometry::Triangle(_) => type_name::<Triangle<T>>(),
283 }
284}
285
286#[cfg(any(feature = "approx", test))]
287mod approx_integration {
288 use super::*;
289 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
290
291 impl<T> RelativeEq for Geometry<T>
292 where
293 T: CoordNum + RelativeEq<Epsilon = T>,
294 {
295 #[inline]
296 fn default_max_relative() -> Self::Epsilon {
297 T::default_max_relative()
298 }
299
300 fn relative_eq(
315 &self,
316 other: &Self,
317 epsilon: Self::Epsilon,
318 max_relative: Self::Epsilon,
319 ) -> bool {
320 match (self, other) {
321 (Geometry::Point(g1), Geometry::Point(g2)) => {
322 g1.relative_eq(g2, epsilon, max_relative)
323 }
324 (Geometry::Line(g1), Geometry::Line(g2)) => {
325 g1.relative_eq(g2, epsilon, max_relative)
326 }
327 (Geometry::LineString(g1), Geometry::LineString(g2)) => {
328 g1.relative_eq(g2, epsilon, max_relative)
329 }
330 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => {
331 g1.relative_eq(g2, epsilon, max_relative)
332 }
333 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => {
334 g1.relative_eq(g2, epsilon, max_relative)
335 }
336 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
337 g1.relative_eq(g2, epsilon, max_relative)
338 }
339 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
340 g1.relative_eq(g2, epsilon, max_relative)
341 }
342 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
343 g1.relative_eq(g2, epsilon, max_relative)
344 }
345 (Geometry::Rect(g1), Geometry::Rect(g2)) => {
346 g1.relative_eq(g2, epsilon, max_relative)
347 }
348 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => {
349 g1.relative_eq(g2, epsilon, max_relative)
350 }
351 (_, _) => false,
352 }
353 }
354 }
355
356 impl<T> AbsDiffEq for Geometry<T>
357 where
358 T: CoordNum + AbsDiffEq<Epsilon = T>,
359 {
360 type Epsilon = T;
361
362 #[inline]
363 fn default_epsilon() -> Self::Epsilon {
364 T::default_epsilon()
365 }
366
367 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
381 match (self, other) {
382 (Geometry::Point(g1), Geometry::Point(g2)) => g1.abs_diff_eq(g2, epsilon),
383 (Geometry::Line(g1), Geometry::Line(g2)) => g1.abs_diff_eq(g2, epsilon),
384 (Geometry::LineString(g1), Geometry::LineString(g2)) => g1.abs_diff_eq(g2, epsilon),
385 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => g1.abs_diff_eq(g2, epsilon),
386 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => g1.abs_diff_eq(g2, epsilon),
387 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
388 g1.abs_diff_eq(g2, epsilon)
389 }
390 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
391 g1.abs_diff_eq(g2, epsilon)
392 }
393 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
394 g1.abs_diff_eq(g2, epsilon)
395 }
396 (Geometry::Rect(g1), Geometry::Rect(g2)) => g1.abs_diff_eq(g2, epsilon),
397 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => g1.abs_diff_eq(g2, epsilon),
398 (_, _) => false,
399 }
400 }
401 }
402
403 impl<T> UlpsEq for Geometry<T>
404 where
405 T: CoordNum + UlpsEq<Epsilon = T>,
406 {
407 fn default_max_ulps() -> u32 {
408 T::default_max_ulps()
409 }
410
411 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
439 match (self, other) {
440 (Geometry::Point(g1), Geometry::Point(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
441 (Geometry::Line(g1), Geometry::Line(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
442 (Geometry::LineString(g1), Geometry::LineString(g2)) => {
443 g1.ulps_eq(g2, epsilon, max_ulps)
444 }
445 (Geometry::Polygon(g1), Geometry::Polygon(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
446 (Geometry::MultiPoint(g1), Geometry::MultiPoint(g2)) => {
447 g1.ulps_eq(g2, epsilon, max_ulps)
448 }
449 (Geometry::MultiLineString(g1), Geometry::MultiLineString(g2)) => {
450 g1.ulps_eq(g2, epsilon, max_ulps)
451 }
452 (Geometry::MultiPolygon(g1), Geometry::MultiPolygon(g2)) => {
453 g1.ulps_eq(g2, epsilon, max_ulps)
454 }
455 (Geometry::GeometryCollection(g1), Geometry::GeometryCollection(g2)) => {
456 g1.ulps_eq(g2, epsilon, max_ulps)
457 }
458 (Geometry::Rect(g1), Geometry::Rect(g2)) => g1.ulps_eq(g2, epsilon, max_ulps),
459 (Geometry::Triangle(g1), Geometry::Triangle(g2)) => {
460 g1.ulps_eq(g2, epsilon, max_ulps)
461 }
462 _ => false,
464 }
465 }
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 mod approx_integration {
472 use crate::{Geometry, Point};
473
474 #[test]
475 fn test_abs_diff() {
476 let g = Geometry::from(Point::new(1.0, 1.0));
477 let abs_diff_eq_point =
478 Geometry::from(Point::new(1.0 + f64::EPSILON, 1.0 + f64::EPSILON));
479 assert_ne!(g, abs_diff_eq_point);
480 assert_abs_diff_eq!(g, abs_diff_eq_point);
481
482 let a_little_farther = Geometry::from(Point::new(1.001, 1.001));
483 assert_ne!(g, a_little_farther);
484 assert_abs_diff_ne!(g, a_little_farther);
485 assert_abs_diff_eq!(g, a_little_farther, epsilon = 1e-3);
486 assert_abs_diff_ne!(g, a_little_farther, epsilon = 5e-4);
487 }
488
489 #[test]
490 fn test_relative() {
491 let g = Geometry::from(Point::new(2.0, 2.0));
492
493 let relative_eq_point = Geometry::from(Point::new(
494 2.0 + 2.0 * f64::EPSILON,
495 2.0 + 2.0 * f64::EPSILON,
496 ));
497 assert_ne!(g, relative_eq_point);
498 assert_relative_eq!(g, relative_eq_point);
499
500 let a_little_farther = Geometry::from(Point::new(2.001, 2.001));
501 assert_ne!(g, a_little_farther);
502 assert_relative_ne!(g, a_little_farther);
503 assert_relative_eq!(g, a_little_farther, epsilon = 1e-3);
504 assert_relative_ne!(g, a_little_farther, epsilon = 5e-4);
505 assert_relative_eq!(g, a_little_farther, max_relative = 5e-4);
506
507 let far = Geometry::from(Point::new(4.0, 4.0));
509 assert_relative_eq!(g, far, max_relative = 1.0 / 2.0);
510 assert_relative_ne!(g, far, max_relative = 0.49);
511 }
512
513 #[test]
514 fn test_ulps() {
515 let g = Geometry::from(Point::new(1.0, 1.0));
516
517 let ulps_eq_point = Geometry::from(Point::new(1.0 + f64::EPSILON, 1.0 + f64::EPSILON));
518 assert_ne!(g, ulps_eq_point);
519 assert_ulps_eq!(g, ulps_eq_point);
520 }
521
522 #[test]
523 fn test_ulps_vs_relative() {
524 let a = 1000.000000000001;
533 let b = 1000.0000000000008;
534
535 let p1 = Point::new(a, a);
536 let p2 = Point::new(b, b);
537
538 assert_ne!(p1, p2);
539 assert_relative_ne!(p1, p2);
540 assert_ulps_eq!(p1, p2);
541 }
542 }
543}