spatial_join/
validation.rs1use 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 }
32}
33
34impl 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