visioncortex/path/
simplify.rs1use crate::{PathI32, PointI32};
2
3use super::util::signed_area;
4
5pub(crate) struct PathSimplify;
6
7#[derive(Copy, Clone, Debug)]
8pub enum PathSimplifyMode {
9 None,
10 Polygon,
11 Spline,
12}
13
14#[derive(Copy, Clone)]
15pub enum Dir {
16 Up,
17 Right,
18 Down,
19 Left
20}
21
22impl Default for PathSimplifyMode {
23 fn default() -> Self {
24 Self::None
25 }
26}
27
28impl PathSimplify {
29
30 pub fn remove_staircase(path: &PathI32, clockwise: bool) -> PathI32 {
34 let path = &path.path;
35 let len = path.len();
36
37 let segment_length = |i: usize, j: usize| -> i32 {
38 (path[i].x - path[j].x).abs() + (path[i].y - path[j].y).abs()
39 };
40
41 let mut result = PathI32::new();
42 if len == 0 {
43 return result;
44 }
45 for i in 0..len {
46 let j = (i + 1) % len;
47 let h = if i > 0 { i - 1 } else { len - 1 };
48 let keep = if i == 0 || i == len - 1 {
49 true
50 } else if segment_length(i, h) == 1 || segment_length(i, j) == 1 {
51 let area = signed_area(path[h], path[i], path[j]);
52 area != 0 && (area > 0) == clockwise
53 } else {
54 true
55 };
56 if keep {
57 result.add(path[i]);
58 }
59 }
60 result
61 }
62
63 pub fn limit_penalties(path: &PathI32) -> PathI32 {
64 let tolerance = 1.0;
65 let path = &path.path;
66 let len = path.len();
67 let past_delta = |from: usize, to: usize| -> f64 {
68 (from..to).skip(1).map(|i| {
69 Self::evaluate_penalty(path[from], path[i], path[to])
70 }).fold(0.0, |a, b| a.max(b)) };
72
73 let mut result = PathI32::new();
74 if len == 0 {
75 return result;
76 }
77 let mut last = 0;
78 for i in 0..len {
79 if i == 0 {
80 result.add(path[i]);
81 } else if i == last + 1 {
82 continue;
83 } else if past_delta(last, i) >= tolerance {
84 last = i - 1;
85 result.add(path[i-1]);
86 }
87 if i == len - 1 {
88 result.add(path[i]);
89 }
90 }
91 result
92 }
93
94 fn evaluate_penalty(a: PointI32, b: PointI32, c: PointI32) -> f64 {
95 let sq = |x| { (x * x) as f64 };
96 let l1 = (sq(a.x - b.x) + sq(a.y - b.y)).sqrt();
97 let l2 = (sq(b.x - c.x) + sq(b.y - c.y)).sqrt();
98 let l3 = (sq(c.x - a.x) + sq(c.y - a.y)).sqrt();
99 let p = (l1 + l2 + l3) / 2.0;
100 let area = (p * (p - l1) * (p - l2) * (p - l3)).sqrt();
101 area * area / l3
102 }
103}