parry3d_f64/transformation/
convex_hull2.rs1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4use crate::math::Real;
5use crate::transformation::convex_hull_utils::{indexed_support_point_id, support_point_id};
6use na::{self, Point2, Vector2};
7use num_traits::Zero;
8
9#[cfg(feature = "dim2")]
13pub fn convex_hull2(points: &[Point2<Real>]) -> Vec<Point2<Real>> {
14 convex_hull2_idx(points)
15 .into_iter()
16 .map(|id| points[id])
17 .collect()
18}
19
20pub fn convex_hull2_idx(points: &[Point2<Real>]) -> Vec<usize> {
25 let mut undecidable_points = Vec::new();
26 let mut segments = get_initial_polyline(points, &mut undecidable_points);
27
28 let mut i = 0;
29 while i != segments.len() {
30 if !segments[i].valid {
31 i += 1;
32 continue;
33 }
34
35 let pt_id = indexed_support_point_id(
36 &segments[i].normal,
37 points,
38 segments[i].visible_points.iter().copied(),
39 );
40
41 if let Some(point) = pt_id {
42 segments[i].valid = false;
43
44 attach_and_push_facets2(
45 segments[i].prev,
46 segments[i].next,
47 point,
48 points,
49 &mut segments,
50 i,
51 &mut undecidable_points,
52 );
53 }
54
55 i += 1;
56 }
57
58 let mut idx = Vec::new();
59 let mut curr_facet = 0;
60
61 while !segments[curr_facet].valid {
62 curr_facet += 1
63 }
64
65 let first_facet = curr_facet;
66
67 loop {
68 let curr = &segments[curr_facet];
69
70 if curr.valid {
71 idx.push(curr.pts[0]);
72 }
73
74 curr_facet = curr.next;
75
76 if curr_facet == first_facet {
77 break;
78 }
79 }
80
81 idx
82}
83
84fn get_initial_polyline(
85 points: &[Point2<Real>],
86 undecidable: &mut Vec<usize>,
87) -> Vec<SegmentFacet> {
88 let mut res = Vec::new();
89
90 assert!(points.len() >= 2);
91
92 let p1 = support_point_id(&Vector2::x(), points).unwrap();
93 let mut p2 = p1;
94
95 let direction = [-Vector2::x(), -Vector2::y(), Vector2::y()];
96
97 for dir in direction.iter() {
98 p2 = support_point_id(dir, points).unwrap();
99
100 let p1p2 = points[p2] - points[p1];
101
102 if !p1p2.norm_squared().is_zero() {
103 break;
104 }
105 }
106
107 assert!(
108 p1 != p2,
109 "Failed to build the 2d convex hull of this point cloud."
110 );
111
112 let mut f1 = SegmentFacet::new(p1, p2, 1, 1, points);
114 let mut f2 = SegmentFacet::new(p2, p1, 0, 0, points);
115
116 for i in 0..points.len() {
118 if i == p1 || i == p2 {
119 continue;
120 }
121 if f1.can_be_seen_by(i, points) {
122 f1.visible_points.push(i);
123 } else if f2.can_be_seen_by(i, points) {
124 f2.visible_points.push(i);
125 } else {
126 undecidable.push(i);
128 }
129 }
130
131 res.push(f1);
132 res.push(f2);
133
134 res
135}
136
137fn attach_and_push_facets2(
138 prev_facet: usize,
139 next_facet: usize,
140 point: usize,
141 points: &[Point2<Real>],
142 segments: &mut Vec<SegmentFacet>,
143 removed_facet: usize,
144 undecidable: &mut Vec<usize>,
145) {
146 let new_facet1_id = segments.len();
147 let new_facet2_id = new_facet1_id + 1;
148 let prev_pt = segments[prev_facet].pts[1];
149 let next_pt = segments[next_facet].pts[0];
150
151 let mut new_facet1 = SegmentFacet::new(prev_pt, point, prev_facet, new_facet2_id, points);
152 let mut new_facet2 = SegmentFacet::new(point, next_pt, new_facet1_id, next_facet, points);
153
154 segments[prev_facet].next = new_facet1_id;
155 segments[next_facet].prev = new_facet2_id;
156
157 for visible_point in segments[removed_facet].visible_points.iter() {
159 if *visible_point == point {
160 continue;
161 }
162
163 if new_facet1.can_be_seen_by(*visible_point, points) {
164 new_facet1.visible_points.push(*visible_point);
165 } else if new_facet2.can_be_seen_by(*visible_point, points) {
166 new_facet2.visible_points.push(*visible_point);
167 }
168 }
170
171 let mut i = 0;
173
174 while i != undecidable.len() {
175 if new_facet1.can_be_seen_by(undecidable[i], points) {
176 new_facet1.visible_points.push(undecidable[i]);
177 let _ = undecidable.swap_remove(i);
178 } else if new_facet2.can_be_seen_by(undecidable[i], points) {
179 new_facet2.visible_points.push(undecidable[i]);
180 let _ = undecidable.swap_remove(i);
181 } else {
182 i += 1;
183 }
184 }
185
186 segments.push(new_facet1);
187 segments.push(new_facet2);
188}
189
190struct SegmentFacet {
191 pub valid: bool,
192 pub normal: Vector2<Real>,
193 pub next: usize,
194 pub prev: usize,
195 pub pts: [usize; 2],
196 pub visible_points: Vec<usize>,
197 pt_type: PhantomData<Point2<Real>>,
198}
199
200impl SegmentFacet {
201 pub fn new(
202 p1: usize,
203 p2: usize,
204 prev: usize,
205 next: usize,
206 points: &[Point2<Real>],
207 ) -> SegmentFacet {
208 let p1p2 = points[p2] - points[p1];
209
210 let mut normal = Vector2::new(p1p2.y, -p1p2.x);
211 let norm = normal.normalize_mut();
212
213 SegmentFacet {
214 valid: norm != 0.0,
215 normal,
216 prev,
217 next,
218 pts: [p1, p2],
219 visible_points: Vec::new(),
220 pt_type: PhantomData,
221 }
222 }
223
224 pub fn can_be_seen_by(&self, point: usize, points: &[Point2<Real>]) -> bool {
225 let p0 = &points[self.pts[0]];
226 let pt = &points[point];
227
228 let _eps = crate::math::DEFAULT_EPSILON;
229
230 (*pt - *p0).dot(&self.normal) > _eps * na::convert::<f64, Real>(100.0f64)
231 }
232}