1use alloc::vec;
2use alloc::vec::Vec;
3use i_float::int::point::IntPoint;
4use crate::int::shape::{IntContour, IntShape, IntShapes};
5
6pub trait DeSpike {
8 fn remove_spikes(&mut self) -> bool;
15}
16
17pub trait DeSpikeContour {
18 fn has_no_spikes(&self) -> bool;
28
29 fn despiked_contour(&self) -> Option<IntContour>;
36}
37
38pub trait DeSpikeShape {
39 fn has_no_spikes(&self) -> bool;
49
50 fn despiked_shape(&self) -> Option<IntShape>;
57}
58
59pub trait DeSpikeShapes {
60 fn has_no_spikes(&self) -> bool;
70
71 fn despiked_shapes(&self) -> IntShapes;
77}
78
79impl DeSpike for IntContour {
80 fn remove_spikes(&mut self) -> bool {
81 if self.has_no_spikes() {
82 return false;
83 }
84 if let Some(contour) = self.despiked_contour() {
85 *self = contour;
86 } else {
87 self.clear()
88 }
89 true
90 }
91}
92
93impl DeSpikeContour for IntContour {
94 fn has_no_spikes(&self) -> bool {
95 let count = self.len();
96
97 if count < 3 { return false; }
98
99 let mut p0 = self[count - 2];
100 let p1 = self[count - 1];
101
102 let mut v0 = p1.subtract(p0);
103 p0 = p1;
104
105 for &pi in self.iter() {
106 let vi = pi.subtract(p0);
107 let cross = vi.cross_product(v0);
108 let dot = vi.dot_product(v0);
109 if cross == 0 && dot < 0 {
110 return false;
111 }
112 v0 = vi;
113 p0 = pi;
114 }
115
116 true
117 }
118
119 fn despiked_contour(&self) -> Option<IntContour> {
120 if self.len() < 3 {
121 return None;
122 }
123
124 let mut n = self.len();
125 let mut nodes: Vec<Node> = vec![Node { next: 0, index: 0, prev: 0 }; n];
126 let mut validated: Vec<bool> = vec![false; n];
127
128 let mut i0 = n - 2;
129 let mut i1 = n - 1;
130 for i2 in 0..n {
131 nodes[i1] = Node { next: i2, index: i1, prev: i0 };
132 i0 = i1;
133 i1 = i2;
134 }
135
136 let mut first: usize = 0;
137 let mut node = nodes[first];
138 let mut i = 0;
139 while i < n {
140 if validated[node.index] {
141 node = nodes[node.next];
142 continue;
143 }
144
145 let p0 = self[node.prev];
146 let p1 = self[node.index];
147 let p2 = self[node.next];
148
149 let v10 = p1.subtract(p0);
150 let v21 = p2.subtract(p1);
151 let cross = v10.cross_product(v21);
152 let dot = v10.dot_product(v21);
153
154 if cross == 0 && dot < 0 {
155 n -= 1;
156 if n < 3 {
157 return None;
158 }
159
160 nodes[node.prev].next = node.next;
162 nodes[node.next].prev = node.prev;
163
164 if node.index == first {
165 first = node.next
166 }
167
168 node = nodes[node.prev];
169
170 if validated[node.prev] {
171 i -= 1;
172 validated[node.prev] = false
173 }
174
175 if validated[node.next] {
176 i -= 1;
177 validated[node.next] = false
178 }
179
180 if validated[node.index] {
181 i -= 1;
182 validated[node.index] = false
183 }
184 } else {
185 validated[node.index] = true;
186 i += 1;
187 node = nodes[node.next];
188 }
189 }
190
191 let mut buffer = vec![IntPoint::ZERO; n];
192 node = nodes[first];
193
194 for item in buffer.iter_mut().take(n) {
195 *item = self[node.index];
196 node = nodes[node.next];
197 }
198
199 Some(buffer)
200 }
201}
202
203impl DeSpike for IntShape {
204 fn remove_spikes(&mut self) -> bool {
205 let mut any_simplified = false;
206 let mut any_empty = false;
207
208 for (index, contour) in self.iter_mut().enumerate() {
209 if contour.has_no_spikes() { continue; }
210 any_simplified = true;
211
212 if let Some(simple_contour) = contour.despiked_contour() {
213 *contour = simple_contour;
214 } else if index == 0 {
215 self.clear();
217 return true;
218 } else {
219 contour.clear();
220 any_empty = true;
221 }
222 }
223
224 if any_empty {
225 self.retain(|contour| !contour.is_empty());
226 }
227
228 any_simplified
229 }
230}
231
232impl DeSpikeShape for IntShape {
233 fn has_no_spikes(&self) -> bool {
234 for contour in self.iter() {
235 if !contour.has_no_spikes() {
236 return false;
237 }
238 }
239 true
240 }
241
242 fn despiked_shape(&self) -> Option<IntShape> {
243 let mut contours = Vec::with_capacity(self.len());
244 for (i, contour) in self.iter().enumerate() {
245 if contour.has_no_spikes() {
246 contours.push(contour.clone());
247 } else if let Some(simple) = contour.despiked_contour() {
248 contours.push(simple);
249 } else if i == 0 {
250 return None;
251 }
252 }
253
254 Some(contours)
255 }
256}
257
258impl DeSpike for IntShapes {
259 fn remove_spikes(&mut self) -> bool {
260 let mut any_simplified = false;
261 let mut any_empty = false;
262
263 for shape in self.iter_mut() {
264 if shape.has_no_spikes() { continue; }
265 any_simplified = true;
266 if let Some(simple_shape) = shape.despiked_shape() {
267 *shape = simple_shape;
268 } else {
269 shape.clear();
270 any_empty = true;
271 }
272 }
273
274 if any_empty {
275 self.retain(|contour| !contour.is_empty());
276 }
277
278 any_simplified
279 }
280}
281
282impl DeSpikeShapes for IntShapes {
283 fn has_no_spikes(&self) -> bool {
284 for shape in self.iter() {
285 if !shape.has_no_spikes() {
286 return false;
287 }
288 }
289 true
290 }
291
292 fn despiked_shapes(&self) -> IntShapes {
293 let mut shapes = Vec::with_capacity(self.len());
294 for shape in self.iter() {
295 if shape.has_no_spikes() {
296 shapes.push(shape.clone());
297 } else if let Some(simple) = shape.despiked_shape() {
298 shapes.push(simple);
299 }
300 }
301
302 shapes
303 }
304}
305
306#[derive(Clone, Copy)]
307struct Node {
308 next: usize,
309 index: usize,
310 prev: usize,
311}
312
313#[cfg(test)]
314mod tests {
315 use alloc::vec;
316 use i_float::int::point::IntPoint;
317 use crate::int::despike::DeSpike;
318
319 #[test]
320 fn test_0() {
321 let mut contour =
322 vec![
323 IntPoint::new(0, 0),
324 IntPoint::new(1, 0),
325 IntPoint::new(1, 1),
326 IntPoint::new(0, 1),
327 ];
328
329 let modified = contour.remove_spikes();
330
331 assert_eq!(contour.len(), 4);
332 assert_eq!(modified, false);
333 }
334
335 #[test]
336 fn test_1() {
337 let mut contour =
338 vec![
339 IntPoint::new(0, -1),
340 IntPoint::new(0, 1),
341 IntPoint::new(1, 1),
342 IntPoint::new(1, 0),
343 IntPoint::new(0, 0),
344 ];
345
346 let modified = contour.remove_spikes();
347
348 assert_eq!(contour.len(), 4);
349 assert_eq!(modified, true);
350 }
351
352 #[test]
353 fn test_2() {
354 let mut contour =
355 vec![
356 IntPoint::new(0, -1),
357 IntPoint::new(0, 1),
358 IntPoint::new(1, 1),
359 IntPoint::new(1, 0),
360 IntPoint::new(0, 0),
361 ];
362
363 let modified = contour.remove_spikes();
364
365 assert_eq!(contour.len(), 4);
366 assert_eq!(modified, true);
367 }
368
369 #[test]
370 fn test_3() {
371 let mut contour =
372 vec![
373 IntPoint::new(0, 0),
374 IntPoint::new(0, 2),
375 IntPoint::new(1, 2),
376 IntPoint::new(3, 2),
377 IntPoint::new(4, 2),
378 IntPoint::new(2, 2),
379 IntPoint::new(2, 0),
380 ];
381
382 let modified = contour.remove_spikes();
383
384 assert_eq!(contour.len(), 5);
385 assert_eq!(modified, true);
386 }
387
388 #[test]
389 fn test_4() {
390 let mut contour =
391 vec![
392 IntPoint::new(0, 0),
393 IntPoint::new(0, 2),
394 IntPoint::new(1, 2),
395 IntPoint::new(4, 2),
396 IntPoint::new(3, 2),
397 IntPoint::new(2, 2),
398 IntPoint::new(2, 0),
399 ];
400
401 let modified = contour.remove_spikes();
402
403 assert_eq!(contour.len(), 5);
404 assert_eq!(modified, true);
405 }
406
407 #[test]
408 fn test_5() {
409 let mut contour =
410 vec![
411 IntPoint::new(-10, 10),
412 IntPoint::new(-10, 0),
413 IntPoint::new(-10, -10),
414 IntPoint::new(0, -10),
415 IntPoint::new(10, -10),
416 IntPoint::new(10, 0),
417 IntPoint::new(10, 10),
418 IntPoint::new(0, 10),
419 ];
420
421 let modified = contour.remove_spikes();
422
423 assert_eq!(contour.len(), 8);
424 assert_eq!(modified, false);
425 }
426}