gistools/geometry/tools/polys/
inside.rs1use crate::geometry::orient2d;
2use alloc::vec::Vec;
3use s2json::{
4 Feature, Geometry, GetXY, MultiLineString, MultiLineString3D, MultiLineString3DGeometry,
5 MultiLineStringGeometry, MultiPoint, MultiPoint3D, MultiPoint3DGeometry, MultiPointGeometry,
6 MultiPolygon, MultiPolygon3D, MultiPolygon3DGeometry, MultiPolygonGeometry, Point, Point3D,
7 Point3DGeometry, PointGeometry, VectorFeature, VectorGeometry, VectorMultiLineString,
8 VectorMultiLineStringGeometry, VectorMultiPoint, VectorMultiPointGeometry, VectorMultiPolygon,
9 VectorMultiPolygonGeometry, VectorPoint, VectorPointGeometry,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq)]
14pub enum InsideResult {
15 Inside,
17 Outside,
19 Boundary,
21}
22impl InsideResult {
23 pub fn get_dominant(&self, other: InsideResult) -> InsideResult {
29 if *self == other {
30 *self
31 } else {
32 match (self, other) {
33 (InsideResult::Inside, _) => InsideResult::Inside,
34 (_, InsideResult::Inside) => InsideResult::Inside,
35 (InsideResult::Boundary, _) => InsideResult::Boundary,
36 (_, InsideResult::Boundary) => InsideResult::Boundary,
37 _ => InsideResult::Outside,
38 }
39 }
40 }
41}
42
43pub trait Inside {
75 fn inside<P: GetXY>(&self, b: &P) -> InsideResult;
83}
84
85impl<P: GetXY> Inside for &Vec<Vec<P>> {
88 fn inside<B: GetXY>(&self, b: &B) -> InsideResult {
89 point_in_polygon(b, self)
90 }
91}
92impl<P: GetXY> Inside for &[Vec<P>] {
93 fn inside<B: GetXY>(&self, b: &B) -> InsideResult {
94 point_in_polygon(b, self)
95 }
96}
97
98impl<M, P: Clone + Default, D: Clone + Default> Inside for Feature<M, P, D> {
99 fn inside<B: GetXY>(&self, b: &B) -> InsideResult {
100 self.geometry.inside(b)
101 }
102}
103impl<M: Clone + Default> Inside for Geometry<M> {
104 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
105 match self {
106 Geometry::Point(g) => g.inside(b),
107 Geometry::MultiPoint(g) => g.inside(b),
108 Geometry::LineString(g) => g.inside(b),
109 Geometry::MultiLineString(g) => g.inside(b),
110 Geometry::Polygon(g) => g.inside(b),
111 Geometry::MultiPolygon(g) => g.inside(b),
112 Geometry::Point3D(g) => g.inside(b),
113 Geometry::MultiPoint3D(g) => g.inside(b),
114 Geometry::LineString3D(g) => g.inside(b),
115 Geometry::MultiLineString3D(g) => g.inside(b),
116 Geometry::Polygon3D(g) => g.inside(b),
117 Geometry::MultiPolygon3D(g) => g.inside(b),
118 }
119 }
120}
121impl<M: Clone + Default> Inside for PointGeometry<M> {
122 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
123 self.coordinates.inside(b)
124 }
125}
126impl<M: Clone + Default> Inside for MultiPointGeometry<M> {
127 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
128 self.coordinates.inside(b)
129 }
130}
131impl<M: Clone + Default> Inside for MultiLineStringGeometry<M> {
132 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
133 self.coordinates.inside(b)
134 }
135}
136impl<M: Clone + Default> Inside for MultiPolygonGeometry<M> {
137 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
138 self.coordinates.inside(b)
139 }
140}
141impl<M: Clone + Default> Inside for Point3DGeometry<M> {
142 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
143 self.coordinates.inside(b)
144 }
145}
146impl<M: Clone + Default> Inside for MultiPoint3DGeometry<M> {
147 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
148 self.coordinates.inside(b)
149 }
150}
151impl<M: Clone + Default> Inside for MultiLineString3DGeometry<M> {
152 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
153 self.coordinates.inside(b)
154 }
155}
156impl<M: Clone + Default> Inside for MultiPolygon3DGeometry<M> {
157 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
158 self.coordinates.inside(b)
159 }
160}
161
162impl Inside for Point {
165 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
166 if self.x() == b.x() && self.y() == b.y() {
167 InsideResult::Inside
168 } else {
169 InsideResult::Outside
170 }
171 }
172}
173impl Inside for MultiPoint {
174 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
175 point_in_polyline(b, self)
176 }
177}
178impl Inside for MultiLineString {
179 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
180 point_in_polygon(b, self)
181 }
182}
183impl Inside for MultiPolygon {
184 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
185 let mut res = InsideResult::Outside;
186 for poly in self {
187 res = res.get_dominant(poly.inside(b));
188 }
189 res
190 }
191}
192impl Inside for Point3D {
193 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
194 if self.x() == b.x() && self.y() == b.y() {
195 InsideResult::Inside
196 } else {
197 InsideResult::Outside
198 }
199 }
200}
201impl Inside for MultiPoint3D {
202 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
203 point_in_polyline(b, self)
204 }
205}
206impl Inside for MultiLineString3D {
207 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
208 point_in_polygon(b, self)
209 }
210}
211impl Inside for MultiPolygon3D {
212 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
213 let mut res = InsideResult::Outside;
214 for poly in self {
215 res = res.get_dominant(poly.inside(b));
216 }
217 res
218 }
219}
220
221impl<M, P: Clone + Default, D: Clone + Default> Inside for VectorFeature<M, P, D> {
224 fn inside<B: GetXY>(&self, b: &B) -> InsideResult {
225 self.geometry.inside(b)
226 }
227}
228impl<M: Clone + Default> Inside for VectorGeometry<M> {
229 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
230 match self {
231 VectorGeometry::Point(g) => g.inside(b),
232 VectorGeometry::MultiPoint(g) => g.inside(b),
233 VectorGeometry::LineString(g) => g.inside(b),
234 VectorGeometry::MultiLineString(g) => g.inside(b),
235 VectorGeometry::Polygon(g) => g.inside(b),
236 VectorGeometry::MultiPolygon(g) => g.inside(b),
237 }
238 }
239}
240impl<M: Clone + Default> Inside for VectorPointGeometry<M> {
241 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
242 self.coordinates.inside(b)
243 }
244}
245impl<M: Clone + Default> Inside for VectorMultiPointGeometry<M> {
246 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
247 self.coordinates.inside(b)
248 }
249}
250impl<M: Clone + Default> Inside for VectorMultiLineStringGeometry<M> {
251 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
252 self.coordinates.inside(b)
253 }
254}
255impl<M: Clone + Default> Inside for VectorMultiPolygonGeometry<M> {
256 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
257 self.coordinates.inside(b)
258 }
259}
260
261impl<M: Clone + Default> Inside for VectorPoint<M> {
264 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
265 if self.x() == b.x() && self.y() == b.y() {
266 InsideResult::Inside
267 } else {
268 InsideResult::Outside
269 }
270 }
271}
272impl<M: Clone + Default> Inside for VectorMultiPoint<M> {
273 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
274 point_in_polyline(b, self)
275 }
276}
277impl<M: Clone + Default> Inside for VectorMultiLineString<M> {
278 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
279 point_in_polygon(b, self)
280 }
281}
282impl<M: Clone + Default> Inside for VectorMultiPolygon<M> {
283 fn inside<P: GetXY>(&self, b: &P) -> InsideResult {
284 let mut res = InsideResult::Outside;
285 for poly in self {
286 res = res.get_dominant(poly.inside(b));
287 }
288 res
289 }
290}
291
292pub fn point_in_polygon<P1: GetXY, P2: GetXY>(point: &P1, polygon: &[Vec<P2>]) -> InsideResult {
301 let mut k = 0;
302 let mut f;
303 let mut u1;
304 let mut v1;
305 let mut u2;
306 let mut v2;
307 let mut current_p: &P2;
308 let mut next_p: &P2;
309
310 let x = point.x();
311 let y = point.y();
312 for contour in polygon {
313 let contour_len = contour.len() - 1;
314
315 current_p = &contour[0];
316 if current_p.x() != contour[contour_len].x() && current_p.y() != contour[contour_len].y() {
317 return InsideResult::Outside;
319 }
320
321 u1 = current_p.x() - x;
322 v1 = current_p.y() - y;
323
324 for ii in 0..contour_len {
325 next_p = &contour[ii + 1];
326
327 u2 = next_p.x() - x;
328 v2 = next_p.y() - y;
329
330 if v1 == 0. && v2 == 0. {
331 if (u2 <= 0. && u1 >= 0.) || (u1 <= 0. && u2 >= 0.) {
332 return InsideResult::Boundary;
333 }
334 } else if (v2 >= 0. && v1 <= 0.) || (v2 <= 0. && v1 >= 0.) {
335 f = orient2d(u1, u2, v1, v2, 0., 0.);
336 if f == 0. {
337 return InsideResult::Boundary;
338 }
339 if (f > 0. && v2 > 0. && v1 <= 0.) || (f < 0. && v2 <= 0. && v1 > 0.) {
340 k += 1;
341 }
342 }
343 v1 = v2;
345 u1 = u2;
346 }
347 }
348
349 if k % 2 == 0 { InsideResult::Outside } else { InsideResult::Inside }
350}
351
352pub fn point_in_polyline<P1: GetXY, P2: GetXY>(point: &P1, contour: &[P2]) -> InsideResult {
361 let mut k = 0;
362 let mut f;
363 let mut u1;
364 let mut v1;
365 let mut u2;
366 let mut v2;
367 let mut next_p: &P2;
368
369 let x = point.x();
370 let y = point.y();
371 let contour_len = contour.len() - 1;
372
373 let current_p = &contour[0];
374 if current_p.x() != contour[contour_len].x() && current_p.y() != contour[contour_len].y() {
375 return InsideResult::Outside;
377 }
378
379 u1 = current_p.x() - x;
380 v1 = current_p.y() - y;
381
382 for ii in 0..contour_len {
383 next_p = &contour[ii + 1];
384
385 u2 = next_p.x() - x;
386 v2 = next_p.y() - y;
387
388 if v1 == 0. && v2 == 0. {
389 if (u2 <= 0. && u1 >= 0.) || (u1 <= 0. && u2 >= 0.) {
390 return InsideResult::Boundary;
391 }
392 } else if (v2 >= 0. && v1 <= 0.) || (v2 <= 0. && v1 >= 0.) {
393 f = orient2d(u1, u2, v1, v2, 0., 0.);
394 if f == 0. {
395 return InsideResult::Boundary;
396 }
397 if (f > 0. && v2 > 0. && v1 <= 0.) || (f < 0. && v2 <= 0. && v1 > 0.) {
398 k += 1;
399 }
400 }
401 v1 = v2;
403 u1 = u2;
404 }
405
406 if k % 2 == 0 { InsideResult::Outside } else { InsideResult::Inside }
407}
408
409pub fn polyline_in_polyline<P: GetXY>(hole: &[P], outer: &[P]) -> bool {
418 for point in hole {
419 match point_in_polyline(point, outer) {
420 InsideResult::Inside => return true,
421 InsideResult::Outside => return false,
422 InsideResult::Boundary => continue,
423 }
424 }
425 true
427}