Skip to main content

spatial_join/
validation.rs

1use geo::{Geometry, Line, LineString, Point, Polygon, Rect, Triangle};
2
3use crate::Error;
4
5pub(crate) trait IsSafe {
6    fn is_safe(&self, position: usize) -> Result<(), Error>;
7}
8
9impl IsSafe for Point<f64> {
10    fn is_safe(&self, position: usize) -> Result<(), Error> {
11        if self.x().is_finite() && self.y().is_finite() {
12            Ok(())
13        } else {
14            Err(Error::BadCoordinateValue(position, Geometry::Point(*self)))
15        }
16    }
17}
18
19impl IsSafe for Line<f64> {
20    fn is_safe(&self, position: usize) -> Result<(), Error> {
21        let r = self
22            .start_point()
23            .is_safe(position)
24            .and(self.end_point().is_safe(position));
25        if r.is_err() {
26            Err(Error::BadCoordinateValue(position, Geometry::Line(*self)))
27        } else {
28            Ok(())
29        }
30        //            .map_err(|_| Box::new(Error::BadCoordinateValue((*self).into())))
31    }
32}
33
34// Our Relates impls that use all() rely on the length checks for
35// LineString and Polygon here since all(empty()) returns true. If we
36// ever change those length checks, we have to review all uses of
37// all() in Relates impls.
38
39impl IsSafe for LineString<f64> {
40    fn is_safe(&self, position: usize) -> Result<(), Error> {
41        if self.0.len() < 2 {
42            return Err(Error::LineStringTooSmall(position));
43        }
44        for pt in self.points_iter() {
45            if pt.is_safe(position).is_err() {
46                return Err(Error::BadCoordinateValue(
47                    position,
48                    Geometry::LineString(self.clone()),
49                ));
50            }
51        }
52        Ok(())
53    }
54}
55
56impl IsSafe for Rect<f64> {
57    fn is_safe(&self, position: usize) -> Result<(), Error> {
58        let min: Point<f64> = self.min().into();
59        let max: Point<f64> = self.max().into();
60        let r = min.is_safe(position).and(max.is_safe(position));
61        if r.is_err() {
62            Err(Error::BadCoordinateValue(position, Geometry::Rect(*self)))
63        } else {
64            Ok(())
65        }
66    }
67}
68
69impl IsSafe for Triangle<f64> {
70    fn is_safe(&self, position: usize) -> Result<(), Error> {
71        let [a, b, c] = self.to_array();
72        let a: Point<f64> = a.into();
73        let b: Point<f64> = b.into();
74        let c: Point<f64> = c.into();
75        let r = a
76            .is_safe(position)
77            .and(b.is_safe(position))
78            .and(c.is_safe(position));
79        if r.is_err() {
80            Err(Error::BadCoordinateValue(
81                position,
82                Geometry::Triangle(*self),
83            ))
84        } else {
85            Ok(())
86        }
87    }
88}
89
90impl IsSafe for Polygon<f64> {
91    fn is_safe(&self, position: usize) -> Result<(), Error> {
92        if self.exterior().num_coords() < 3 {
93            return Err(Error::PolygonExteriorTooSmall(position));
94        }
95        for line_string in std::iter::once(self.exterior()).chain(self.interiors().iter()) {
96            if line_string.is_safe(position).is_err() {
97                return Err(Error::BadCoordinateValue(
98                    position,
99                    Geometry::Polygon(self.clone()),
100                ));
101            }
102        }
103        Ok(())
104    }
105}
106
107// //<T as TryInto<SplitGeoSeq>>::Error
108// impl From<std::convert::Infallible> for Error {
109//     fn from(t: std::convert::Infallible) -> Self {
110//         Error::Sigh()
111//     }
112// }