1use alloc::{collections::BinaryHeap, vec::Vec};
4use core::cmp::Ordering;
5
6use na::{self, Unit};
7use num::Bounded;
8
9use crate::math::{Isometry, Point, Real, Vector};
10use crate::query::gjk::{self, CSOPoint, ConstantOrigin, VoronoiSimplex};
11use crate::shape::SupportMap;
12use crate::utils;
13
14#[derive(Copy, Clone, PartialEq)]
15struct FaceId {
16 id: usize,
17 neg_dist: Real,
18}
19
20impl FaceId {
21 fn new(id: usize, neg_dist: Real) -> Option<Self> {
22 if neg_dist > gjk::eps_tol() {
23 None
24 } else {
25 Some(FaceId { id, neg_dist })
26 }
27 }
28}
29
30impl Eq for FaceId {}
31
32impl PartialOrd for FaceId {
33 #[inline]
34 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
35 Some(self.cmp(other))
36 }
37}
38
39impl Ord for FaceId {
40 #[inline]
41 fn cmp(&self, other: &Self) -> Ordering {
42 if self.neg_dist < other.neg_dist {
43 Ordering::Less
44 } else if self.neg_dist > other.neg_dist {
45 Ordering::Greater
46 } else {
47 Ordering::Equal
48 }
49 }
50}
51
52#[derive(Clone, Debug)]
53struct Face {
54 pts: [usize; 2],
55 normal: Unit<Vector<Real>>,
56 proj: Point<Real>,
57 bcoords: [Real; 2],
58 deleted: bool,
59}
60
61impl Face {
62 pub fn new(vertices: &[CSOPoint], pts: [usize; 2]) -> (Self, bool) {
63 if let Some((proj, bcoords)) =
64 project_origin(&vertices[pts[0]].point, &vertices[pts[1]].point)
65 {
66 (Self::new_with_proj(vertices, proj, bcoords, pts), true)
67 } else {
68 (
69 Self::new_with_proj(vertices, Point::origin(), [0.0; 2], pts),
70 false,
71 )
72 }
73 }
74
75 pub fn new_with_proj(
76 vertices: &[CSOPoint],
77 proj: Point<Real>,
78 bcoords: [Real; 2],
79 pts: [usize; 2],
80 ) -> Self {
81 let normal;
82 let deleted;
83
84 if let Some(n) = utils::ccw_face_normal([&vertices[pts[0]].point, &vertices[pts[1]].point])
85 {
86 normal = n;
87 deleted = false;
88 } else {
89 normal = Unit::new_unchecked(na::zero());
90 deleted = true;
91 }
92
93 Face {
94 pts,
95 normal,
96 proj,
97 bcoords,
98 deleted,
99 }
100 }
101
102 pub fn closest_points(&self, vertices: &[CSOPoint]) -> (Point<Real>, Point<Real>) {
103 (
104 vertices[self.pts[0]].orig1 * self.bcoords[0]
105 + vertices[self.pts[1]].orig1.coords * self.bcoords[1],
106 vertices[self.pts[0]].orig2 * self.bcoords[0]
107 + vertices[self.pts[1]].orig2.coords * self.bcoords[1],
108 )
109 }
110}
111
112#[derive(Default)]
114pub struct EPA {
115 vertices: Vec<CSOPoint>,
116 faces: Vec<Face>,
117 heap: BinaryHeap<FaceId>,
118}
119
120impl EPA {
121 pub fn new() -> Self {
123 EPA::default()
124 }
125
126 fn reset(&mut self) {
127 self.vertices.clear();
128 self.faces.clear();
129 self.heap.clear();
130 }
131
132 pub fn project_origin<G: ?Sized + SupportMap>(
142 &mut self,
143 m: &Isometry<Real>,
144 g: &G,
145 simplex: &VoronoiSimplex,
146 ) -> Option<Point<Real>> {
147 self.closest_points(&m.inverse(), g, &ConstantOrigin, simplex)
148 .map(|(p, _, _)| p)
149 }
150
151 pub fn closest_points<G1, G2>(
156 &mut self,
157 pos12: &Isometry<Real>,
158 g1: &G1,
159 g2: &G2,
160 simplex: &VoronoiSimplex,
161 ) -> Option<(Point<Real>, Point<Real>, Unit<Vector<Real>>)>
162 where
163 G1: ?Sized + SupportMap,
164 G2: ?Sized + SupportMap,
165 {
166 let _eps: Real = crate::math::DEFAULT_EPSILON;
167 let _eps_tol = _eps * 100.0;
168
169 self.reset();
170
171 for i in 0..simplex.dimension() + 1 {
175 self.vertices.push(*simplex.point(i));
176 }
177
178 if simplex.dimension() == 0 {
179 const MAX_ITERS: usize = 100; let mut n = Vector::y_axis();
185
186 let orig1 = self.vertices[0].orig1;
188 for _ in 0..MAX_ITERS {
189 let supp1 = g1.local_support_point(&n);
190 if let Some(tangent) = Unit::try_new(supp1 - orig1, _eps_tol) {
191 if n.dot(&tangent) < _eps_tol {
192 break;
193 }
194
195 n = Unit::new_unchecked(Vector::new(-tangent.y, tangent.x));
196 } else {
197 break;
198 }
199 }
200
201 let orig2 = self.vertices[0].orig2;
203 for _ in 0..MAX_ITERS {
204 let supp2 = g2.support_point(pos12, &-n);
205 if let Some(tangent) = Unit::try_new(supp2 - orig2, _eps_tol) {
206 if (-n).dot(&tangent) < _eps_tol {
207 break;
208 }
209
210 n = Unit::new_unchecked(Vector::new(-tangent.y, tangent.x));
211 } else {
212 break;
213 }
214 }
215
216 return Some((Point::origin(), Point::origin(), n));
217 } else if simplex.dimension() == 2 {
218 let dp1 = self.vertices[1] - self.vertices[0];
219 let dp2 = self.vertices[2] - self.vertices[0];
220
221 if dp1.perp(&dp2) < 0.0 {
222 self.vertices.swap(1, 2)
223 }
224
225 let pts1 = [0, 1];
226 let pts2 = [1, 2];
227 let pts3 = [2, 0];
228
229 let (face1, proj_inside1) = Face::new(&self.vertices, pts1);
230 let (face2, proj_inside2) = Face::new(&self.vertices, pts2);
231 let (face3, proj_inside3) = Face::new(&self.vertices, pts3);
232
233 self.faces.push(face1);
234 self.faces.push(face2);
235 self.faces.push(face3);
236
237 if proj_inside1 {
238 let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
239 self.heap.push(FaceId::new(0, -dist1)?);
240 }
241
242 if proj_inside2 {
243 let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);
244 self.heap.push(FaceId::new(1, -dist2)?);
245 }
246
247 if proj_inside3 {
248 let dist3 = self.faces[2].normal.dot(&self.vertices[2].point.coords);
249 self.heap.push(FaceId::new(2, -dist3)?);
250 }
251
252 if !(proj_inside1 || proj_inside2 || proj_inside3) {
253 log::debug!("Hit unexpected state in EPA: failed to project the origin on the initial simplex.");
257 return None;
258 }
259 } else {
260 let pts1 = [0, 1];
261 let pts2 = [1, 0];
262
263 self.faces.push(Face::new_with_proj(
264 &self.vertices,
265 Point::origin(),
266 [1.0, 0.0],
267 pts1,
268 ));
269 self.faces.push(Face::new_with_proj(
270 &self.vertices,
271 Point::origin(),
272 [1.0, 0.0],
273 pts2,
274 ));
275
276 let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
277 let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);
278
279 self.heap.push(FaceId::new(0, dist1)?);
280 self.heap.push(FaceId::new(1, dist2)?);
281 }
282
283 let mut niter = 0;
284 let mut max_dist = Real::max_value();
285 let mut best_face_id = *self.heap.peek().unwrap();
286 let mut old_dist = 0.0;
287
288 while let Some(face_id) = self.heap.pop() {
292 let face = self.faces[face_id.id].clone();
294
295 if face.deleted {
296 continue;
297 }
298
299 let cso_point = CSOPoint::from_shapes(pos12, g1, g2, &face.normal);
300 let support_point_id = self.vertices.len();
301 self.vertices.push(cso_point);
302
303 let candidate_max_dist = cso_point.point.coords.dot(&face.normal);
304
305 if candidate_max_dist < max_dist {
306 best_face_id = face_id;
307 max_dist = candidate_max_dist;
308 }
309
310 let curr_dist = -face_id.neg_dist;
311
312 if max_dist - curr_dist < _eps_tol ||
313 ((curr_dist - old_dist).abs() < _eps && candidate_max_dist < max_dist)
316 {
317 let best_face = &self.faces[best_face_id.id];
318 let cpts = best_face.closest_points(&self.vertices);
319 return Some((cpts.0, cpts.1, best_face.normal));
320 }
321
322 old_dist = curr_dist;
323
324 let pts1 = [face.pts[0], support_point_id];
325 let pts2 = [support_point_id, face.pts[1]];
326
327 let new_faces = [
328 Face::new(&self.vertices, pts1),
329 Face::new(&self.vertices, pts2),
330 ];
331
332 for f in new_faces.iter() {
333 if f.1 {
334 let dist = f.0.normal.dot(&f.0.proj.coords);
335 if dist < curr_dist {
336 let cpts = f.0.closest_points(&self.vertices);
339 return Some((cpts.0, cpts.1, f.0.normal));
340 }
341
342 if !f.0.deleted {
343 self.heap.push(FaceId::new(self.faces.len(), -dist)?);
344 }
345 }
346
347 self.faces.push(f.0.clone());
348 }
349
350 niter += 1;
351 if niter > 100 {
352 break;
355 }
356 }
357
358 let best_face = &self.faces[best_face_id.id];
359 let cpts = best_face.closest_points(&self.vertices);
360 Some((cpts.0, cpts.1, best_face.normal))
361 }
362}
363
364fn project_origin(a: &Point<Real>, b: &Point<Real>) -> Option<(Point<Real>, [Real; 2])> {
365 let ab = *b - *a;
366 let ap = -a.coords;
367 let ab_ap = ab.dot(&ap);
368 let sqnab = ab.norm_squared();
369
370 if sqnab == 0.0 {
371 return None;
372 }
373
374 let position_on_segment;
375
376 let _eps: Real = gjk::eps_tol();
377
378 if ab_ap < -_eps || ab_ap > sqnab + _eps {
379 None
381 } else {
382 position_on_segment = ab_ap / sqnab;
384
385 let res = *a + ab * position_on_segment;
386
387 Some((res, [1.0 - position_on_segment, position_on_segment]))
388 }
389}