1use std::fmt;
16
17use geo_types::{Coord, Geometry};
18
19use crate::algorithm::interior_point::dimension_non_empty;
20use crate::algorithm::locate::simple_point_in_area_locator::locate;
21use crate::geom::location::{BOUNDARY, INTERIOR};
22use crate::geometry_adapter::coordinates_at_dimension;
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum Verification {
34 Interior,
36 OnGeometry,
39 OffGeometry,
41 Unverifiable,
43}
44
45impl fmt::Display for Verification {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.write_str(match self {
52 Self::Interior => "interior",
53 Self::OnGeometry => "on-geometry",
54 Self::OffGeometry => "off-geometry",
55 Self::Unverifiable => "unverifiable",
56 })
57 }
58}
59
60pub fn verify_interior_point(
73 point: Option<Coord<f64>>,
74 geometry: Option<&Geometry<f64>>,
75) -> Verification {
76 let (Some(point), Some(geometry)) = (point, geometry) else {
77 return Verification::Unverifiable;
78 };
79 let dim = dimension_non_empty(geometry);
80 if dim < 0 {
81 return Verification::Unverifiable;
82 }
83 if dim == 2 {
84 let location = locate(point, geometry);
85 if location == INTERIOR {
86 return Verification::Interior;
87 }
88 if location == BOUNDARY {
89 return Verification::OnGeometry;
90 }
91 return Verification::OffGeometry;
92 }
93 if coordinates_at_dimension(geometry, dim)
101 .iter()
102 .any(|c| c.x == point.x && c.y == point.y)
103 {
104 Verification::OnGeometry
105 } else {
106 Verification::OffGeometry
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::{Verification, verify_interior_point};
113 use crate::interior_point;
114 use geo_types::{
115 Coord, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, Point,
116 Polygon,
117 };
118
119 fn polygon(ring: &[(f64, f64)]) -> Geometry<f64> {
120 Geometry::Polygon(Polygon::new(LineString::from(ring.to_vec()), vec![]))
121 }
122
123 fn verify_computed(geometry: &Geometry<f64>) -> Verification {
125 verify_interior_point(interior_point(geometry), Some(geometry))
126 }
127
128 #[test]
129 fn reports_interior_for_a_point_inside_an_areal_geometry() {
130 let square = polygon(&[
131 (0.0, 0.0),
132 (10.0, 0.0),
133 (10.0, 10.0),
134 (0.0, 10.0),
135 (0.0, 0.0),
136 ]);
137 assert_eq!(interior_point(&square), Some(Coord { x: 5.0, y: 5.0 }));
138 assert_eq!(verify_computed(&square), Verification::Interior);
139 }
140
141 #[test]
142 fn reports_on_geometry_for_a_zero_area_polygon() {
143 let collapsed = polygon(&[(10.0, 10.0), (10.0, 10.0), (10.0, 10.0), (10.0, 10.0)]);
144 assert_eq!(verify_computed(&collapsed), Verification::OnGeometry);
145 }
146
147 #[test]
148 fn reports_on_geometry_for_a_polygon_collapsed_to_a_segment() {
149 let collapsed = polygon(&[(0.0, 0.0), (10.0, 0.0), (0.0, 0.0)]);
150 assert_eq!(verify_computed(&collapsed), Verification::OnGeometry);
151 }
152
153 #[test]
154 fn reports_on_geometry_for_a_point() {
155 let point = Geometry::Point(Point::new(5.0, 5.0));
156 assert_eq!(verify_computed(&point), Verification::OnGeometry);
157 }
158
159 #[test]
160 fn reports_on_geometry_for_a_line_string() {
161 let line = Geometry::LineString(LineString::from(vec![(0.0, 0.0), (10.0, 10.0)]));
162 assert_eq!(interior_point(&line), Some(Coord { x: 0.0, y: 0.0 }));
163 assert_eq!(verify_computed(&line), Verification::OnGeometry);
164 }
165
166 #[test]
167 fn reports_on_geometry_for_a_multi_point() {
168 let points = Geometry::MultiPoint(MultiPoint(vec![
169 Point::new(0.0, 0.0),
170 Point::new(10.0, 10.0),
171 ]));
172 assert_eq!(verify_computed(&points), Verification::OnGeometry);
173 }
174
175 #[test]
176 fn reports_on_geometry_for_a_collection_of_a_point_and_a_line() {
177 let collection = Geometry::GeometryCollection(GeometryCollection(vec![
178 Geometry::Point(Point::new(5.0, 5.0)),
179 Geometry::LineString(LineString::from(vec![(0.0, 0.0), (10.0, 10.0)])),
180 ]));
181 assert_eq!(verify_computed(&collection), Verification::OnGeometry);
182 }
183
184 #[test]
191 fn follows_the_non_empty_dimension_for_a_collection_holding_an_empty_line() {
192 let collection = Geometry::GeometryCollection(GeometryCollection(vec![
193 Geometry::Point(Point::new(5.0, 5.0)),
194 Geometry::LineString(LineString(vec![])),
195 ]));
196 assert_eq!(interior_point(&collection), Some(Coord { x: 5.0, y: 5.0 }));
197 assert_eq!(verify_computed(&collection), Verification::OnGeometry);
198 }
199
200 #[test]
204 fn reports_off_geometry_for_a_fabricated_point_outside_an_areal_geometry() {
205 let square = polygon(&[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)]);
206 assert_eq!(
207 verify_interior_point(Some(Coord { x: 100.0, y: 100.0 }), Some(&square)),
208 Verification::OffGeometry
209 );
210 }
211
212 #[test]
213 fn reports_off_geometry_for_a_fabricated_point_off_a_line_string() {
214 let line = Geometry::LineString(LineString::from(vec![(0.0, 0.0), (10.0, 10.0)]));
215 assert_eq!(
216 verify_interior_point(Some(Coord { x: 100.0, y: 100.0 }), Some(&line)),
217 Verification::OffGeometry
218 );
219 }
220
221 #[test]
222 fn reports_unverifiable_for_an_empty_geometry() {
223 let empty = Geometry::Polygon(Polygon::new(LineString(vec![]), vec![]));
224 assert_eq!(interior_point(&empty), None);
225 assert_eq!(verify_computed(&empty), Verification::Unverifiable);
226 }
227
228 #[test]
229 fn reports_unverifiable_for_a_multi_line_string_of_one_empty_line() {
230 let empty = Geometry::MultiLineString(MultiLineString::new(vec![LineString(vec![])]));
231 assert_eq!(verify_computed(&empty), Verification::Unverifiable);
232 }
233
234 #[test]
235 fn reports_unverifiable_when_either_argument_is_absent() {
236 let square = polygon(&[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)]);
237 assert_eq!(
238 verify_interior_point(None, Some(&square)),
239 Verification::Unverifiable
240 );
241 assert_eq!(
242 verify_interior_point(Some(Coord { x: 0.0, y: 0.0 }), None),
243 Verification::Unverifiable
244 );
245 assert_eq!(
246 verify_interior_point(None, None),
247 Verification::Unverifiable
248 );
249 }
250
251 #[test]
252 fn prints_the_four_outcome_words() {
253 assert_eq!(Verification::Interior.to_string(), "interior");
254 assert_eq!(Verification::OnGeometry.to_string(), "on-geometry");
255 assert_eq!(Verification::OffGeometry.to_string(), "off-geometry");
256 assert_eq!(Verification::Unverifiable.to_string(), "unverifiable");
257 }
258}