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