1use geo::algorithm::winding_order::Winding;
2use geo::{Coordinate, Geometry, GeometryCollection, LineString, MultiPolygon, Polygon};
3use num_traits;
4
5pub trait Normalized<T: num_traits::Float> {
6 fn normalized(&self) -> Self;
40}
41
42impl<T: num_traits::Float> Normalized<T> for GeometryCollection<T> {
45 fn normalized(&self) -> Self {
46 GeometryCollection(
47 self.0
48 .iter()
49 .map(|p| match p {
50 Geometry::Polygon { .. } => {
51 Geometry::Polygon(p.clone().into_polygon().unwrap().normalized())
52 }
53 Geometry::MultiPolygon { .. } => {
54 Geometry::MultiPolygon(p.clone().into_multi_polygon().unwrap().normalized())
55 }
56 _ => p.clone(),
57 })
58 .collect::<Vec<Geometry<T>>>(),
59 )
60 }
61}
62
63impl<T: num_traits::Float> Normalized<T> for MultiPolygon<T> {
66 fn normalized(&self) -> Self {
67 MultiPolygon::from(
68 self.0
69 .iter()
70 .map(|x| x.normalized())
71 .collect::<Vec<Polygon<T>>>(),
72 )
73 }
74}
75
76impl<T: num_traits::Float> Normalized<T> for Polygon<T> {
77 fn normalized(&self) -> Self {
78 normalized_polygon(self)
79 }
80}
81
82fn normalized_polygon<T: num_traits::Float>(poly: &Polygon<T>) -> Polygon<T> {
86 Polygon::new(
87 LineString::from(
88 poly.exterior()
89 .points_cw()
90 .map(|x| x.0)
91 .collect::<Vec<Coordinate<T>>>(),
92 ),
93 poly.interiors()
94 .iter()
95 .map(|ring| {
96 LineString::from(
97 ring.clone()
98 .points_ccw()
99 .map(|x| x.0)
100 .collect::<Vec<Coordinate<T>>>(),
101 )
102 })
103 .collect(),
104 )
105}
106
107#[cfg(test)]
110mod tests {
111 use super::*;
112 use geo::{line_string, point, polygon};
113
114 #[test]
115 fn does_not_change_good_polygon() {
116 let (good, _) = get_bad_outer_poly();
117 let norm = good.normalized();
118 assert_eq!(norm, good);
119 }
120
121 #[test]
122 fn can_normalize_bad_outer_polygon() {
123 let (good, bad) = get_bad_outer_poly();
124 let norm = bad.normalized();
125 assert_eq!(norm, good);
126 }
127
128 #[test]
129 fn can_normalize_good_outer_bad_inner_polygon() {
130 let (good, bad) = get_good_outer_bad_inner_poly();
131 let norm = bad.normalized();
132 assert_eq!(norm, good);
133 }
134
135 #[test]
136 fn can_normalize_bad_outer_bad_inner_polygon() {
137 let (good, bad) = get_bad_outer_bad_inner_poly();
138 let norm = bad.normalized();
139 assert_eq!(norm, good);
140 }
141
142 #[test]
143 fn can_normalize_bad_outer_good_inner_polygon() {
144 let (good, bad) = get_bad_outer_good_inner_poly();
145 let norm = bad.normalized();
146 assert_eq!(norm, good);
147 }
148
149 #[test]
150 fn can_process_multi_polygon() {
151 let (good, bad) = get_bad_outer_good_inner_poly();
152 let mp = MultiPolygon(vec![good.clone(), bad]);
153 let norm = mp.normalized();
154 for poly in norm {
155 assert_eq!(good, poly);
156 }
157 }
158
159 fn get_bad_outer_poly() -> (Polygon<f64>, Polygon<f64>) {
160 let bad = polygon![
161 (x: 1.0, y: 1.0),
162 (x: 4.0, y: 1.0),
163 (x: 4.0, y: 4.0),
164 (x: 1.0, y: 4.0),
165 (x: 1.0, y: 1.0),
166 ];
167 let good = polygon![
168 (x: 1.0, y: 1.0),
169 (x: 1.0, y: 4.0),
170 (x: 4.0, y: 4.0),
171 (x: 4.0, y: 1.0),
172 (x: 1.0, y: 1.0),
173 ];
174 (good, bad)
175 }
176
177 fn get_good_outer_bad_inner_poly() -> (Polygon<f64>, Polygon<f64>) {
178 let bad = polygon!(
179 exterior: [
180 (x: 0., y: 0.),
181 (x: 0., y: 50.),
182 (x: 50., y: 50.),
183 (x: 50., y: 0.),
184 ],
185 interiors: [
186 [
187 (x: 10., y: 10.),
188 (x: 10., y: 20.),
189 (x: 20., y: 20.),
190 (x: 20., y: 10.),
191 ],
192 ],
193 );
194 let good = polygon!(
195 exterior: [
196 (x: 0., y: 0.),
197 (x: 0., y: 50.),
198 (x: 50., y: 50.),
199 (x: 50., y: 0.),
200 ],
201 interiors: [
202 [
203 (x: 10., y: 10.),
204 (x: 20., y: 10.),
205 (x: 20., y: 20.),
206 (x: 10., y: 20.),
207 ],
208 ],
209 );
210 (good, bad)
211 }
212
213 fn get_bad_outer_bad_inner_poly() -> (Polygon<f64>, Polygon<f64>) {
214 let bad = polygon!(
215 exterior: [
216 (x: 0., y: 0.),
217 (x: 50., y: 0.),
218 (x: 50., y: 50.),
219 (x: 0., y: 50.),
220 ],
221 interiors: [
222 [
223 (x: 10., y: 10.),
224 (x: 10., y: 20.),
225 (x: 20., y: 20.),
226 (x: 20., y: 10.),
227 ],
228 ],
229 );
230 let good = polygon!(
231 exterior: [
232 (x: 0., y: 0.),
233 (x: 0., y: 50.),
234 (x: 50., y: 50.),
235 (x: 50., y: 0.),
236 ],
237 interiors: [
238 [
239 (x: 10., y: 10.),
240 (x: 20., y: 10.),
241 (x: 20., y: 20.),
242 (x: 10., y: 20.),
243 ],
244 ],
245 );
246 (good, bad)
247 }
248
249 fn get_bad_outer_good_inner_poly() -> (Polygon<f64>, Polygon<f64>) {
250 let bad = polygon!(
251 exterior: [
252 (x: 0., y: 0.),
253 (x: 50., y: 0.),
254 (x: 50., y: 50.),
255 (x: 0., y: 50.),
256 ],
257 interiors: [
258 [
259 (x: 10., y: 10.),
260 (x: 20., y: 10.),
261 (x: 20., y: 20.),
262 (x: 10., y: 20.),
263 ],
264 ],
265 );
266 let good = polygon!(
267 exterior: [
268 (x: 0., y: 0.),
269 (x: 0., y: 50.),
270 (x: 50., y: 50.),
271 (x: 50., y: 0.),
272 ],
273 interiors: [
274 [
275 (x: 10., y: 10.),
276 (x: 20., y: 10.),
277 (x: 20., y: 20.),
278 (x: 10., y: 20.),
279 ],
280 ],
281 );
282 (good, bad)
283 }
284}