geo/algorithm/validation/
multi_polygon.rs1use super::{GeometryIndex, InvalidPolygon, Validation};
2use crate::coordinate_position::CoordPos;
3use crate::dimensions::Dimensions;
4use crate::{GeoFloat, MultiPolygon, Relate};
5
6use std::fmt;
7
8#[derive(Debug, Clone, PartialEq)]
13pub enum InvalidMultiPolygon {
14 InvalidPolygon(GeometryIndex, InvalidPolygon),
16 ElementsOverlaps(GeometryIndex, GeometryIndex),
18 ElementsTouchOnALine(GeometryIndex, GeometryIndex),
20}
21
22impl fmt::Display for InvalidMultiPolygon {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match self {
25 InvalidMultiPolygon::InvalidPolygon(idx, err) => {
26 write!(f, "polygon at index {} is invalid: {}", idx.0, err)
27 }
28 InvalidMultiPolygon::ElementsOverlaps(idx1, idx2) => {
29 write!(f, "polygons at indices {} and {} overlap", idx1.0, idx2.0)
30 }
31 InvalidMultiPolygon::ElementsTouchOnALine(idx1, idx2) => {
32 write!(
33 f,
34 "polygons at indices {} and {} touch on a line",
35 idx1.0, idx2.0
36 )
37 }
38 }
39 }
40}
41
42impl std::error::Error for InvalidMultiPolygon {}
43
44impl<F: GeoFloat> Validation for MultiPolygon<F> {
45 type Error = InvalidMultiPolygon;
46
47 fn visit_validation<T>(
48 &self,
49 mut handle_validation_error: Box<dyn FnMut(Self::Error) -> Result<(), T> + '_>,
50 ) -> Result<(), T> {
51 for (i, polygon) in self.0.iter().enumerate() {
52 polygon.visit_validation(Box::new(&mut |invalid_polygon| {
53 handle_validation_error(InvalidMultiPolygon::InvalidPolygon(
54 GeometryIndex(i),
55 invalid_polygon,
56 ))
57 }))?;
58
59 for (j, pol2) in self.0.iter().enumerate().skip(i + 1) {
61 let im = polygon.relate(pol2);
62 if im.get(CoordPos::Inside, CoordPos::Inside) == Dimensions::TwoDimensional {
63 let err =
64 InvalidMultiPolygon::ElementsOverlaps(GeometryIndex(i), GeometryIndex(j));
65 handle_validation_error(err)?;
66 }
67 if im.get(CoordPos::OnBoundary, CoordPos::OnBoundary) == Dimensions::OneDimensional
68 {
69 let err = InvalidMultiPolygon::ElementsTouchOnALine(
70 GeometryIndex(i),
71 GeometryIndex(j),
72 );
73 handle_validation_error(err)?;
74 }
75 }
76 }
77 Ok(())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::super::assert_validation_errors;
84 use super::*;
85 use crate::algorithm::validation::RingRole;
86 use crate::wkt;
87
88 #[test]
89 fn test_multipolygon_invalid() {
90 let multi_polygon = wkt!(
94 MULTIPOLYGON (
95 (
96 (0.5 0.5, 3.0 0.5, 3.0 2.5, 0.5 2.5, 0.5 0.5),
97 (1.0 1.0, 1.0 2.0, 2.5 2.0, 3.5 1.0, 1.0 1.0)
98 ),
99 (
100 (0.5 0.5, 3.0 0.5, 3.0 2.5, 0.5 2.5, 0.5 0.5),
101 (1.0 1.0, 1.0 2.0, 2.5 2.0, 3.5 1.0, 1.0 1.0)
102 )
103 )
104 );
105 assert_validation_errors!(
106 &multi_polygon,
107 vec![
108 InvalidMultiPolygon::InvalidPolygon(
109 GeometryIndex(0),
110 InvalidPolygon::InteriorRingNotContainedInExteriorRing(RingRole::Interior(0))
111 ),
112 InvalidMultiPolygon::ElementsOverlaps(GeometryIndex(0), GeometryIndex(1)),
113 InvalidMultiPolygon::ElementsTouchOnALine(GeometryIndex(0), GeometryIndex(1)),
114 InvalidMultiPolygon::InvalidPolygon(
115 GeometryIndex(1),
116 InvalidPolygon::InteriorRingNotContainedInExteriorRing(RingRole::Interior(0))
117 ),
118 ]
119 );
120 }
121}