1use std::collections::HashMap;
2
3#[derive(Default, Debug, Clone)]
4pub struct Offset {
5 pub contour: Vec<(f64, f64)>,
6 pub area: f64,
7 pub perimeter: f64,
8}
9
10#[derive(Default, Debug, Clone)]
11pub struct Polygon {
12 edges: Vec<Edge>,
13 vertices: HashMap<usize, Vertex>,
14 offset_margin: f64,
15}
16
17#[derive(Default, Debug, Copy, Clone)]
18struct Vertex {
19 x: f64,
20 y: f64,
21 is_intersect: bool
22}
23
24#[derive(Default, Debug, Copy, Clone)]
25struct Edge {
26 p1: usize,
27 p2: usize,
28 index: usize,
29 outward_normal: Vertex,
30}
31
32#[derive(Default, Clone, Debug)]
33struct Segment {
34 p1: (f64, f64),
35 p2: (f64, f64),
36}
37
38#[inline]
39fn compute_area(contours: &Vec<(f64, f64)>) -> f64 {
40 let mut a = 0.0;
41 if contours.len() == 0 { return 0.0 }
42 for i in 0..contours.len() - 1 {
43 a = a + (contours[i].0 * contours[i + 1].1) - (contours[i + 1].0 * contours[i].1);
44 }
45 (a * -0.5).abs()
46}
47
48fn compute_perimeter(contour2d: &Vec<(f64, f64)>) -> f64 {
49 let mut perimeter2d = 0.;
50 for i in 0..(contour2d.len() - 1) {
51 let p1 = &contour2d[i];
52 let p2 = &contour2d[i + 1];
53 perimeter2d += ((p2.0 - p1.0).powi(2) + (p2.1 - p1.1).powi(2)).sqrt();
54 }
55 perimeter2d
56}
57
58#[inline]
59fn get_dist(p1: (f64, f64), p2: (f64, f64)) -> f64 {
60 ((p2.0 - p1.0).powi(2) + (p2.1 - p1.1).powi(2)).sqrt()
61}
62
63#[inline]
64fn vector_sub(v1: (f64, f64), v2: (f64, f64)) -> (f64, f64) {
65 (v1.0 - v2.0, v1.1 - v2.1)
66}
67
68#[inline]
69fn vector_add(v1: (f64, f64), v2: (f64, f64)) -> (f64, f64) {
70 (v1.0 + v2.0, v1.1 + v2.1)
71}
72
73#[inline]
74fn reverse_segments(sgmts: &Vec<Segment>) -> Vec<Segment> {
75 let mut segments: Vec<Segment> = Vec::new();
76
77 for s in sgmts.iter().rev() {
78 segments.push( Segment {
79 p1: s.p2,
80 p2: s.p1,
81 });
82 }
83 segments
84}
85
86impl Polygon {
89 fn append_arc(&self, center: &Vertex, radius: f64, start_vertex: &Vertex, end_vertex: &Vertex, tolerance: f64) -> Vec<Vertex> {
90 let mut start_angle = (start_vertex.y - center.y).atan2(start_vertex.x - center.x);
92 let mut end_angle = (end_vertex.y - center.y).atan2(end_vertex.x - center.x);
93 if start_angle < 0. { start_angle = 2. * std::f64::consts::PI + start_angle }
94 if end_angle <= 0. { end_angle = 2. * std::f64::consts::PI + end_angle }
95
96 let mut angle : f64 = end_angle - start_angle;
98 if angle.abs() > std::f64::consts::PI {
99 angle = -( angle / angle.abs()) * (2. * std::f64::consts::PI - angle.abs());
100 }
101
102 let n_angle = (1. - (4. * radius * tolerance - 2. * tolerance.powi(2) ) / (radius.powi(2)) ).acos();
104 if n_angle == 0.0 {
105 let vect = vector_add((start_vertex.x, start_vertex.y), vector_sub((end_vertex.x, end_vertex.y), (start_vertex.x, start_vertex.y)));
106 return vec![Vertex { x: vect.0, y: vect.1, is_intersect: false }]
107 }
108 let nseg: i64 = ((angle.abs() / n_angle.abs()).round() + 1.) as i64;
109
110 let angular_step = angle / nseg as f64;
112
113 let mut dots = Vec::new();
115 for i in 0..(nseg + 1) {
116 let theta = start_angle + angular_step * i as f64;
117 let x = radius * (theta).cos() + center.x;
118 let y = radius * (theta).sin() + center.y;
119 dots.push(Vertex {x: x, y: y, is_intersect: false});
120 }
121 dots
122 }
123
124 fn edges_intersection(&self, e1: &(Vertex, Vertex), e2: &(Vertex, Vertex), is_inters: bool) -> Option<Vertex> {
125 let den = (e2.1.y - e2.0.y) * (e1.1.x - e1.0.x) - (e2.1.x - e2.0.x) * (e1.1.y - e1.0.y);
126 if den > -0.0001 && den < 0.0001 {
127 return None; }
129
130 let ua = ((e2.1.x - e2.0.x) * (e1.0.y - e2.0.y) - (e2.1.y - e2.0.y) * (e1.0.x - e2.0.x)) / den;
131 let ub = ((e1.1.x - e1.0.x) * (e1.0.y - e2.0.y) - (e1.1.y - e1.0.y) * (e1.0.x - e2.0.x)) / den;
132
133 if ua < 0.0000001 || ub < 0.0000001 || ua > 0.9999999 || ub > 0.9999999 {
134 return None;
135 }
136
137 let v_cross = Some(Vertex {
138 x: e1.0.x + ua * (e1.1.x - e1.0.x),
139 y: e1.0.y + ua * (e1.1.y - e1.0.y),
140 is_intersect: is_inters
141 });
142 v_cross
143 }
144
145 fn create_offset_edge(&self, p1: &Vertex, p2: &Vertex, dx: f64, dy: f64) -> (Vertex, Vertex) {
146 let mut v1: Vertex = Vertex::default();
147 let mut v2: Vertex = Vertex::default();
148 v1.x = p1.x + dx;
149 v1.y = p1.y + dy;
150 v2.x = p2.x + dx;
151 v2.y = p2.y + dy;
152 (v1, v2)
153 }
154
155 fn create_margin_polygon(&mut self, tolerance: f64) -> Polygon {
156 let mut offset_edges: Vec<(Vertex, Vertex)> = Vec::new();
157 let mut vertices: HashMap<usize, Vertex> = HashMap::new();
158 let mut index: usize = 0;
159
160 self.edges.iter().for_each(|edge| {
162 let p1 = self.vertices.get(&edge.p1).unwrap();
163 let p2 = self.vertices.get(&edge.p2).unwrap();
164 let dx = edge.outward_normal.x * self.offset_margin;
165 let dy = edge.outward_normal.y * self.offset_margin;
166 offset_edges.push(self.create_offset_edge(p1, p2, dx, dy));
167 });
168
169
170 for i in 0..offset_edges.len() {
171 let this_edge = &offset_edges[i];
172 let prev_edge = &offset_edges[(i + offset_edges.len() - 1) % offset_edges.len()];
173 let vertex = self.edges_intersection(prev_edge, this_edge, false);
174
175 if vertex.is_none() {
177 let arc_center = &self.vertices.get(&i).unwrap();
178 let arc_vertices = &self.append_arc(arc_center, self.offset_margin, &prev_edge.1, &this_edge.0, tolerance);
179
180 for av in arc_vertices.iter() {
184 vertices.insert(index, *av);
185 index += 1;
186 }
187 } else {
188 vertices.insert(index, vertex.unwrap());
189 index += 1;
190 }
191 }
192
193 let margin_polygon = self.create_polygon(vertices, self.offset_margin, false);
195 margin_polygon
196 }
197
198 fn sort_by_squared_dist(&self, p1: &Vertex, cross: &Vec<usize>, poly: &Polygon) -> Vec<usize> {
199 let mut cross_coord: Vec<(usize, Vertex)> = Vec::new();
200 let mut vp: Vec<(f64, usize)> = Vec::new();
201 let mut crossp = Vec::new();
202
203 for c in cross {
204 cross_coord.push((*c, *poly.vertices.get(&c).unwrap()));
205 }
206
207 for i in 0..cross_coord.len() {
208 let dist = (p1.x - cross_coord[i].1.x).powi(2) + (p1.y - cross_coord[i].1.y).powi(2);
209 vp.push(( dist, cross_coord[i].0));
210 }
211
212 vp.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
213 vp.iter().for_each(|v| {
214 crossp.push(v.1);
215 });
216 crossp
217 }
218
219 fn detect_all_intersect(&mut self, margin_polygon: &mut Polygon) {
220 let mut poly: Polygon = Polygon::default();
221 let mut indices: HashMap<usize, Vec<usize>> = HashMap::new();
222 let mut vertices = margin_polygon.vertices.clone();
223
224 let mut iteration = 0;
225 margin_polygon.edges.iter_mut().for_each(|edge| {
226 indices.insert(edge.index, Vec::new());
227 edge.index = iteration;
228 iteration += 1;
229 });
230
231 let mut max_vertices = 0;
232 margin_polygon.vertices.iter().for_each(|(id, _)| {
233 if id > &max_vertices { max_vertices = *id;}
234 });
235
236 margin_polygon.edges.iter().for_each(|edge1| {
238 margin_polygon.edges.iter().for_each(|edge2| {
239 if edge1.index > edge2.index {
240 let p1: Vertex = *margin_polygon.vertices.get(&edge1.p1).unwrap();
241 let p2: Vertex = *margin_polygon.vertices.get(&edge1.p2).unwrap();
242 let p3: Vertex = *margin_polygon.vertices.get(&edge2.p1).unwrap();
243 let p4: Vertex = *margin_polygon.vertices.get(&edge2.p2).unwrap();
244 let e1: (Vertex, Vertex) = (p1, p2);
245 let e2: (Vertex, Vertex) = (p3, p4);
246
247 let inters = self.edges_intersection(&e1, &e2, true);
248 if !inters.is_none() {
249 vertices.insert(max_vertices + 1, inters.unwrap());
250 max_vertices += 1;
251
252 match indices.get_mut(&edge1.index) {
253 Some(v) => {
254 if !v.contains(&max_vertices) {
255 v.push(max_vertices);
256 }
257 },
258 _ => {}
259 };
260 match indices.get_mut(&edge2.index) {
261 Some(v) => {
262 if !v.contains(&max_vertices) {
263 v.push(max_vertices);
264 }
265 },
266 _ => {}
267 };
268 }
269 }
270 });
271 });
272
273 margin_polygon.vertices = vertices.clone();
275 let mut new_poly: Vec<Edge> = Vec::new();
276 margin_polygon.edges.iter().for_each(|edge| {
277 let idx = edge.index;
278 let p1 = margin_polygon.vertices.get(&edge.p1).unwrap();
279
280 match indices.get(&idx) {
281 Some(cross) => {
282 if cross.len() > 0 {
283 let sorted_cross: Vec<usize> = self.sort_by_squared_dist(p1, &cross.to_vec(), &margin_polygon);
284 let new_edge: Edge = Edge {
285 p1: edge.p1,
286 p2: sorted_cross[0],
287 index: 0,
288 outward_normal: edge.outward_normal
289 };
290 new_poly.push(new_edge);
291
292 for i in 0..sorted_cross.len() - 1 {
293 let new_edge: Edge = Edge {
294 p1: sorted_cross[i],
295 p2: sorted_cross[i + 1],
296 index: 0,
297 outward_normal: edge.outward_normal
298 };
299 new_poly.push(new_edge);
300 }
301 let new_edge: Edge = Edge {
302 p1: sorted_cross[sorted_cross.len() - 1],
303 p2: edge.p2,
304 index: 0,
305 outward_normal: edge.outward_normal
306 };
307 new_poly.push(new_edge);
308 } else {
309 new_poly.push(*edge);
310 }
311 },
312 _ => {}
313 }
314 });
315 let mut iteration = 0;
316 new_poly.iter_mut().for_each(|edge| {
317 edge.index = iteration;
318 iteration += 1;
319 });
320 poly.edges = new_poly;
321 poly.vertices = vertices;
322 *margin_polygon = poly;
323 }
324
325 fn detect_regions(&self, polygon: &Polygon) -> Vec<Polygon> {
326 let mut regions : Vec<Polygon> = Vec::new();
328
329 let mut remaining: Vec<usize> = Vec::new();
331
332 polygon.vertices.iter().for_each(|(id, _)| remaining.push(*id));
333
334 let mut map : HashMap<usize, Vec<usize>> = HashMap::new();
336 polygon.vertices.iter().for_each(|(id, _)| { map.insert(*id, Vec::new()); });
337 polygon.edges.iter().for_each(|edge| {
338 match map.get_mut(&edge.p1) { Some(v) => {if !v.contains(&edge.index) {v.push(edge.index)}}, _ => {} };
339 });
340
341 while remaining.len() > 0 {
343
344 let mut current_region: Polygon = Polygon {
345 edges: Vec::new(),
346 vertices: HashMap::new(),
347 offset_margin: 0.0,
348 };
349
350 let mut idx = remaining[0];
351 let start_idx = idx;
352 let mut prev_edge_indice: usize = 0;
353
354 while idx != start_idx || current_region.vertices.len() == 0 {
355 match polygon.vertices.get(&idx) {
356 Some(v) => {
357 current_region.vertices.insert(idx, *v);
359 remaining.retain(|r| {
360 *r != idx
361 });
362
363 match v.is_intersect {
364 true => {
365 let mut edges: Vec<usize> = map.get(&idx).unwrap().clone();
366 edges.retain(|e| {
367 *e != prev_edge_indice + 1
368 });
369 let edge = edges[0];
370 let new_edge = Edge {
371 p1: idx,
372 p2: polygon.edges[edge].p2,
373 outward_normal: polygon.edges[edge].outward_normal,
374 index: 0
375 };
376 current_region.edges.push(new_edge);
377 idx = polygon.edges[edge].p2;
378 prev_edge_indice = edge;
379 },
380 false => {
381 let edge = map.get(&idx).unwrap()[0];
382 let new_edge = Edge {
383 p1: idx,
384 p2: polygon.edges[edge].p2,
385 outward_normal: polygon.edges[edge].outward_normal,
386 index: 0
387 };
388 current_region.edges.push(new_edge);
389 idx = polygon.edges[edge].p2;
390 prev_edge_indice = edge;
391 }
392 }
393 },
394 _ => panic!("Regions, vertice not found")
395 }
396 }
397 let mut iteration = 0;
398 current_region.edges.iter_mut().for_each(|e| {
399 e.index = iteration;
400 iteration += 1;
401 });
402 regions.push(current_region)
403 }
404 regions
405 }
406
407 fn outward_edge_normal(&self, v1: &Vertex, v2: &Vertex) -> Vertex {
408 let dx = v2.x - v1.x;
409 let dy = v2.y - v1.y;
410 let edge_length = (dx * dx + dy * dy).sqrt();
411 Vertex {
412 is_intersect: false,
413 x: dy / edge_length,
414 y: -dx / edge_length
415 }
416 }
417
418 fn contour_to_vertices(contour: Vec<(f64, f64)>) -> HashMap<usize, Vertex> {
419 let mut vtxs: HashMap<usize, Vertex> = HashMap::new();
420
421 for i in 0..contour.len() - 1 {
422 let mut vertex: Vertex = Vertex::default();
423 vertex.is_intersect = false;
424 vertex.x = contour[i].0;
425 vertex.y = contour[i].1;
426 vtxs.insert(i, vertex);
427 }
428 vtxs
429 }
430
431 fn get_polygon_area<'a>(&self, poly: &'a mut Polygon) -> (f64, &'a Polygon) {
432 let mut contours: Vec<(f64, f64)> = Vec::new();
433
434 let edges = &mut poly.edges;
435 edges.sort_by_key(|k| k.index);
436
437 for i in 0..edges.len() {
438 let v = poly.vertices.get(&edges[i].p1).unwrap();
439 contours.push((v.x, v.y));
440 }
441
442 let mut a = 0.0;
443 for i in 0..contours.len() - 1 {
444 a = a + (contours[i].0 * contours[i + 1].1) - (contours[i + 1].0 * contours[i].1);
445 }
446 a = a + (contours[contours.len() - 1].0 * contours[0].1) - (contours[0].0 * contours[contours.len() - 1].1);
447 ((a * -0.5).abs(), poly)
448 }
449
450 fn tuples_to_segments(contour1: &Vec<(f64, f64)>) -> Vec<Segment> {
452 let mut segments: Vec<Segment> = Vec::new();
453
454 for i in 1..contour1.len() {
455 let mut sgmt: Segment = Segment::default();
456 sgmt.p1.0 = contour1[i - 1].0;
457 sgmt.p1.1 = contour1[i - 1].1;
458 if i == contour1.len() {
459 sgmt.p2.0 = contour1[0].0;
460 sgmt.p2.1 = contour1[0].1;
461 segments.push(sgmt);
462 break ;
463 }
464 sgmt.p2.0 = contour1[i].0;
465 sgmt.p2.1 = contour1[i].1;
466 segments.push(sgmt);
467 }
468 segments
469 }
470
471 fn create_polygon(
472 &mut self,
473 vertices: HashMap<usize, Vertex>,
474 offset_size: f64,
475 is_initial_polygon: bool
476 ) -> Polygon {
477 let mut polygon = Polygon::default();
478 let mut edges: Vec<Edge> = Vec::new();
479 polygon.vertices = vertices;
480 polygon.offset_margin = offset_size;
481
482 for i in 0..polygon.vertices.len() {
484 let mut edge = Edge {
485 p1: i,
486 p2: (i + 1) % polygon.vertices.len(),
487 index: i,
488 outward_normal: Vertex::default(),
489 };
490 if edge.p1 == edge.p2 {
491 continue ;
492 }
493 if is_initial_polygon {
494 edge.outward_normal = self.outward_edge_normal(
495 polygon.vertices.get(&edge.p1).unwrap(),
496 polygon.vertices.get(&edge.p2).unwrap()
497 );
498 }
499 edges.push(edge);
500 }
501
502 polygon.edges = edges;
503 polygon
504 }
505
506 pub fn new(
507 initial_contour: &Vec<(f64, f64)>,
508 offset_size: f64,
509 ) -> Result <Polygon, Box<dyn std::error::Error>> {
510
511 let mut new_segments: Vec<Segment> = Polygon::tuples_to_segments(&initial_contour);
512 new_segments.retain(|s| { get_dist(s.p1, s.p2) != 0. });
514
515 if initial_contour[0] != initial_contour[initial_contour.len() - 1] {
517 return Err(format!("Unclosed polygon").into())
518 }
519
520 let value = new_segments.iter().fold(
522 0.,
523 |acc, seg|
524 acc + (seg.p2.0 - seg.p1.0) * (seg.p2.1 + seg.p1.1)
525 );
526
527 if value > 0. { new_segments = reverse_segments(&new_segments); }
529
530
531 let mut points: Vec<(f64, f64)> = Vec::new();
532 for s in new_segments.iter() {
533 points.push(s.p1);
534 }
535 points.push(points[0]);
536
537 let mut initial_polygon: Polygon = Polygon::default();
538 let vertices: HashMap<usize, Vertex> = Polygon::contour_to_vertices(points.to_vec());
539 Ok(initial_polygon.create_polygon(vertices, offset_size, true))
540 }
541
542 pub fn offsetting(&mut self, tolerance: f64) -> Result <Offset, Box<dyn std::error::Error>> {
543 let mut offsets: Offset = Offset::default();
544 let mut areas: Vec<(f64, &Polygon)> = Vec::new();
545
546 if tolerance <= 0.0 {
547 return Err("The tolerance can't be below or egal to 0".into())
548 }
549
550 if self.offset_margin == 0.0 {
552 let mut points: Vec<(f64, f64)> = Vec::new();
553 self.edges.iter().for_each(|e| {
554 let p1 = self.vertices.get(&e.p1).unwrap();
555 points.push((p1.x, p1.y));
556 });
557 points.push(points[0]);
558
559 let offset = Offset {
560 area: compute_area(&points),
561 perimeter: compute_perimeter(&points),
562 contour: points,
563 };
564 return Ok(offset)
565 }
566
567 let mut margin_polygon: Polygon = self.create_margin_polygon(tolerance);
569
570 self.detect_all_intersect(&mut margin_polygon);
572
573 let mut regions = self.detect_regions(&margin_polygon);
575 regions.iter_mut().for_each(|r| {
576 areas.push(self.get_polygon_area(&mut *r));
577 });
578 areas.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
579
580 let offset_polygon: &Polygon = areas[areas.len() - 1].1;
582 offsets.area = areas[areas.len() - 1].0;
583
584 offset_polygon.edges.iter().for_each(|edge| {
585 offsets.contour.push((
586 offset_polygon.vertices.get(&edge.p1).unwrap().x,
587 offset_polygon.vertices.get(&edge.p1).unwrap().y
588 ));
589 });
590 offsets.contour.push(offsets.contour[0]);
591 offsets.perimeter = compute_perimeter(&offsets.contour);
592
593 Ok(offsets)
594 }
595}
596
597
598
599
600
601