1use crate::{Coord, GeoFloat, Line, LineString, MultiLineString, MultiPolygon, Polygon};
2use crate::{CoordsIter, EuclideanDistance};
3
4const LINE_STRING_INITIAL_MIN: usize = 2;
5const POLYGON_INITIAL_MIN: usize = 4;
6
7#[derive(Copy, Clone)]
11struct RdpIndex<T>
12where
13 T: GeoFloat,
14{
15 index: usize,
16 coord: Coord<T>,
17}
18
19fn rdp<T, I: Iterator<Item = Coord<T>>, const INITIAL_MIN: usize>(
21 coords: I,
22 epsilon: &T,
23) -> Vec<Coord<T>>
24where
25 T: GeoFloat,
26{
27 if *epsilon <= T::zero() {
29 return coords.collect::<Vec<Coord<T>>>();
30 }
31 let rdp_indices = &coords
32 .enumerate()
33 .map(|(idx, coord)| RdpIndex { index: idx, coord })
34 .collect::<Vec<RdpIndex<T>>>();
35 let mut simplified_len = rdp_indices.len();
36 let simplified_coords: Vec<_> =
37 compute_rdp::<T, INITIAL_MIN>(rdp_indices, &mut simplified_len, epsilon)
38 .into_iter()
39 .map(|rdpindex| rdpindex.coord)
40 .collect();
41 debug_assert_eq!(simplified_coords.len(), simplified_len);
42 simplified_coords
43}
44
45fn calculate_rdp_indices<T, const INITIAL_MIN: usize>(
47 rdp_indices: &[RdpIndex<T>],
48 epsilon: &T,
49) -> Vec<usize>
50where
51 T: GeoFloat,
52{
53 if *epsilon <= T::zero() {
54 return rdp_indices
55 .iter()
56 .map(|rdp_index| rdp_index.index)
57 .collect();
58 }
59
60 let mut simplified_len = rdp_indices.len();
61 let simplified_coords =
62 compute_rdp::<T, INITIAL_MIN>(rdp_indices, &mut simplified_len, epsilon)
63 .into_iter()
64 .map(|rdpindex| rdpindex.index)
65 .collect::<Vec<usize>>();
66 debug_assert_eq!(simplified_len, simplified_coords.len());
67 simplified_coords
68}
69
70fn compute_rdp<T, const INITIAL_MIN: usize>(
74 rdp_indices: &[RdpIndex<T>],
75 simplified_len: &mut usize,
76 epsilon: &T,
77) -> Vec<RdpIndex<T>>
78where
79 T: GeoFloat,
80{
81 if rdp_indices.is_empty() {
82 return vec![];
83 }
84
85 let first = rdp_indices[0];
86 let last = rdp_indices[rdp_indices.len() - 1];
87 if rdp_indices.len() == 2 {
88 return vec![first, last];
89 }
90
91 let first_last_line = Line::new(first.coord, last.coord);
92
93 let (farthest_index, farthest_distance) = rdp_indices
95 .iter()
96 .enumerate()
97 .take(rdp_indices.len() - 1) .skip(1) .map(|(index, rdp_index)| (index, rdp_index.coord.euclidean_distance(&first_last_line)))
100 .fold(
101 (0usize, T::zero()),
102 |(farthest_index, farthest_distance), (index, distance)| {
103 if distance >= farthest_distance {
104 (index, distance)
105 } else {
106 (farthest_index, farthest_distance)
107 }
108 },
109 );
110 debug_assert_ne!(farthest_index, 0);
111
112 if farthest_distance > *epsilon {
113 let mut intermediate =
116 compute_rdp::<T, INITIAL_MIN>(&rdp_indices[..=farthest_index], simplified_len, epsilon);
117
118 intermediate.pop(); intermediate.extend_from_slice(&compute_rdp::<T, INITIAL_MIN>(
121 &rdp_indices[farthest_index..],
122 simplified_len,
123 epsilon,
124 ));
125 return intermediate;
126 }
127
128 let number_culled = rdp_indices.len() - 2;
134 let new_length = *simplified_len - number_culled;
135
136 if new_length < INITIAL_MIN {
139 return rdp_indices.to_owned();
140 }
141 *simplified_len = new_length;
142
143 vec![first, last]
145}
146
147pub trait Simplify<T, Epsilon = T> {
158 fn simplify(&self, epsilon: &T) -> Self
186 where
187 T: GeoFloat;
188}
189
190pub trait SimplifyIdx<T, Epsilon = T> {
197 fn simplify_idx(&self, epsilon: &T) -> Vec<usize>
225 where
226 T: GeoFloat;
227}
228
229impl<T> Simplify<T> for LineString<T>
230where
231 T: GeoFloat,
232{
233 fn simplify(&self, epsilon: &T) -> Self {
234 LineString::from(rdp::<_, _, LINE_STRING_INITIAL_MIN>(
235 self.coords_iter(),
236 epsilon,
237 ))
238 }
239}
240
241impl<T> SimplifyIdx<T> for LineString<T>
242where
243 T: GeoFloat,
244{
245 fn simplify_idx(&self, epsilon: &T) -> Vec<usize> {
246 calculate_rdp_indices::<_, LINE_STRING_INITIAL_MIN>(
247 &self
248 .0
249 .iter()
250 .enumerate()
251 .map(|(idx, coord)| RdpIndex {
252 index: idx,
253 coord: *coord,
254 })
255 .collect::<Vec<RdpIndex<T>>>(),
256 epsilon,
257 )
258 }
259}
260
261impl<T> Simplify<T> for MultiLineString<T>
262where
263 T: GeoFloat,
264{
265 fn simplify(&self, epsilon: &T) -> Self {
266 MultiLineString::new(self.iter().map(|l| l.simplify(epsilon)).collect())
267 }
268}
269
270impl<T> Simplify<T> for Polygon<T>
271where
272 T: GeoFloat,
273{
274 fn simplify(&self, epsilon: &T) -> Self {
275 Polygon::new(
276 LineString::from(rdp::<_, _, POLYGON_INITIAL_MIN>(
277 self.exterior().coords_iter(),
278 epsilon,
279 )),
280 self.interiors()
281 .iter()
282 .map(|l| {
283 LineString::from(rdp::<_, _, POLYGON_INITIAL_MIN>(l.coords_iter(), epsilon))
284 })
285 .collect(),
286 )
287 }
288}
289
290impl<T> Simplify<T> for MultiPolygon<T>
291where
292 T: GeoFloat,
293{
294 fn simplify(&self, epsilon: &T) -> Self {
295 MultiPolygon::new(self.iter().map(|p| p.simplify(epsilon)).collect())
296 }
297}
298
299#[cfg(test)]
300mod test {
301 use super::*;
302 use crate::geo_types::coord;
303 use crate::{line_string, polygon};
304
305 #[test]
306 fn recursion_test() {
307 let input = [
308 coord! { x: 8.0, y: 100.0 },
309 coord! { x: 9.0, y: 100.0 },
310 coord! { x: 12.0, y: 100.0 },
311 ];
312 let actual = rdp::<_, _, 2>(input.into_iter(), &1.0);
313 let expected = [coord! { x: 8.0, y: 100.0 }, coord! { x: 12.0, y: 100.0 }];
314 assert_eq!(actual, expected);
315 }
316
317 #[test]
318 fn rdp_test() {
319 let vec = vec![
320 coord! { x: 0.0, y: 0.0 },
321 coord! { x: 5.0, y: 4.0 },
322 coord! { x: 11.0, y: 5.5 },
323 coord! { x: 17.3, y: 3.2 },
324 coord! { x: 27.8, y: 0.1 },
325 ];
326 let compare = vec![
327 coord! { x: 0.0, y: 0.0 },
328 coord! { x: 5.0, y: 4.0 },
329 coord! { x: 11.0, y: 5.5 },
330 coord! { x: 27.8, y: 0.1 },
331 ];
332 let simplified = rdp::<_, _, 2>(vec.into_iter(), &1.0);
333 assert_eq!(simplified, compare);
334 }
335 #[test]
336 fn rdp_test_empty_linestring() {
337 let vec = Vec::new();
338 let compare = Vec::new();
339 let simplified = rdp::<_, _, 2>(vec.into_iter(), &1.0);
340 assert_eq!(simplified, compare);
341 }
342 #[test]
343 fn rdp_test_two_point_linestring() {
344 let vec = vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 27.8, y: 0.1 }];
345 let compare = vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 27.8, y: 0.1 }];
346 let simplified = rdp::<_, _, 2>(vec.into_iter(), &1.0);
347 assert_eq!(simplified, compare);
348 }
349
350 #[test]
351 fn multilinestring() {
352 let mline = MultiLineString::new(vec![LineString::from(vec![
353 (0.0, 0.0),
354 (5.0, 4.0),
355 (11.0, 5.5),
356 (17.3, 3.2),
357 (27.8, 0.1),
358 ])]);
359
360 let mline2 = mline.simplify(&1.0);
361
362 assert_eq!(
363 mline2,
364 MultiLineString::new(vec![LineString::from(vec![
365 (0.0, 0.0),
366 (5.0, 4.0),
367 (11.0, 5.5),
368 (27.8, 0.1),
369 ])])
370 );
371 }
372
373 #[test]
374 fn polygon() {
375 let poly = polygon![
376 (x: 0., y: 0.),
377 (x: 0., y: 10.),
378 (x: 5., y: 11.),
379 (x: 10., y: 10.),
380 (x: 10., y: 0.),
381 (x: 0., y: 0.),
382 ];
383
384 let poly2 = poly.simplify(&2.);
385
386 assert_eq!(
387 poly2,
388 polygon![
389 (x: 0., y: 0.),
390 (x: 0., y: 10.),
391 (x: 10., y: 10.),
392 (x: 10., y: 0.),
393 (x: 0., y: 0.),
394 ],
395 );
396 }
397
398 #[test]
399 fn multipolygon() {
400 let mpoly = MultiPolygon::new(vec![polygon![
401 (x: 0., y: 0.),
402 (x: 0., y: 10.),
403 (x: 5., y: 11.),
404 (x: 10., y: 10.),
405 (x: 10., y: 0.),
406 (x: 0., y: 0.),
407 ]]);
408
409 let mpoly2 = mpoly.simplify(&2.);
410
411 assert_eq!(
412 mpoly2,
413 MultiPolygon::new(vec![polygon![
414 (x: 0., y: 0.),
415 (x: 0., y: 10.),
416 (x: 10., y: 10.),
417 (x: 10., y: 0.),
418 (x: 0., y: 0.)
419 ]]),
420 );
421 }
422
423 #[test]
424 fn simplify_negative_epsilon() {
425 let ls = line_string![
426 (x: 0., y: 0.),
427 (x: 0., y: 10.),
428 (x: 5., y: 11.),
429 (x: 10., y: 10.),
430 (x: 10., y: 0.),
431 ];
432 let simplified = ls.simplify(&-1.0);
433 assert_eq!(ls, simplified);
434 }
435
436 #[test]
437 fn simplify_idx_negative_epsilon() {
438 let ls = line_string![
439 (x: 0., y: 0.),
440 (x: 0., y: 10.),
441 (x: 5., y: 11.),
442 (x: 10., y: 10.),
443 (x: 10., y: 0.),
444 ];
445 let indices = ls.simplify_idx(&-1.0);
446 assert_eq!(vec![0usize, 1, 2, 3, 4], indices);
447 }
448
449 #[test]
451 fn simplify_line_string_polygon_initial_min() {
452 let ls = line_string![
453 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
454 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
455 ( x: -5.9730447e26, y: 1.5590374e-27 ),
456 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
457 ];
458 let epsilon: f64 = 3.46e-43;
459
460 let result = ls.simplify(&epsilon);
462 assert_eq!(
463 line_string![
464 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
465 ( x: -5.9730447e26, y: 1.5590374e-27 ),
466 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
467 ],
468 result
469 );
470
471 let result = Polygon::new(ls, vec![]).simplify(&epsilon);
473 assert_eq!(
474 polygon![
475 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
476 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
477 ( x: -5.9730447e26, y: 1.5590374e-27 ),
478 ( x: 1.4324054e-16, y: 1.4324054e-16 ),
479 ],
480 result,
481 );
482 }
483
484 #[test]
486 fn dont_oversimplify() {
487 let unsimplified = line_string![
488 (x: 0.0, y: 0.0),
489 (x: 5.0, y: 4.0),
490 (x: 11.0, y: 5.5),
491 (x: 17.3, y: 3.2),
492 (x: 27.8, y: 0.1)
493 ];
494 let actual = unsimplified.simplify(&30.0);
495 let expected = line_string![
496 (x: 0.0, y: 0.0),
497 (x: 27.8, y: 0.1)
498 ];
499 assert_eq!(actual, expected);
500 }
501}