1use crate::math::{Isometry, Point, Real, Vector};
4use crate::query::gjk::{self, CSOPoint, ConstantOrigin, VoronoiSimplex};
5use crate::query::PointQueryWithLocation;
6use crate::shape::{SupportMap, Triangle, TrianglePointLocation};
7use crate::utils;
8use alloc::collections::BinaryHeap;
9use alloc::vec::Vec;
10use core::cmp::Ordering;
11use na::{self, Unit};
12use num::Bounded;
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; 3],
55 adj: [usize; 3],
56 normal: Unit<Vector<Real>>,
57 bcoords: [Real; 3],
58 deleted: bool,
59}
60
61impl Face {
62 pub fn new_with_proj(
63 vertices: &[CSOPoint],
64 bcoords: [Real; 3],
65 pts: [usize; 3],
66 adj: [usize; 3],
67 ) -> Self {
68 let normal;
69
70 if let Some(n) = utils::ccw_face_normal([
71 &vertices[pts[0]].point,
72 &vertices[pts[1]].point,
73 &vertices[pts[2]].point,
74 ]) {
75 normal = n;
76 } else {
77 normal = Unit::new_unchecked(na::zero());
82 }
83
84 Face {
85 pts,
86 bcoords,
87 adj,
88 normal,
89 deleted: false,
90 }
91 }
92
93 pub fn new(vertices: &[CSOPoint], pts: [usize; 3], adj: [usize; 3]) -> (Self, bool) {
94 let tri = Triangle::new(
95 vertices[pts[0]].point,
96 vertices[pts[1]].point,
97 vertices[pts[2]].point,
98 );
99 let (proj, loc) = tri.project_local_point_and_get_location(&Point::<Real>::origin(), true);
100
101 match loc {
102 TrianglePointLocation::OnVertex(_) | TrianglePointLocation::OnEdge(_, _) => {
103 let eps_tol = crate::math::DEFAULT_EPSILON * 100.0; (
105 Self::new_with_proj(vertices, loc.barycentric_coordinates().unwrap(), pts, adj),
107 proj.is_inside_eps(&Point::<Real>::origin(), eps_tol),
108 )
109 }
110 TrianglePointLocation::OnFace(_, bcoords) => {
111 (Self::new_with_proj(vertices, bcoords, pts, adj), true)
112 }
113 _ => (Self::new_with_proj(vertices, [0.0; 3], pts, adj), false),
114 }
115 }
116
117 pub fn closest_points(&self, vertices: &[CSOPoint]) -> (Point<Real>, Point<Real>) {
118 (
119 vertices[self.pts[0]].orig1 * self.bcoords[0]
120 + vertices[self.pts[1]].orig1.coords * self.bcoords[1]
121 + vertices[self.pts[2]].orig1.coords * self.bcoords[2],
122 vertices[self.pts[0]].orig2 * self.bcoords[0]
123 + vertices[self.pts[1]].orig2.coords * self.bcoords[1]
124 + vertices[self.pts[2]].orig2.coords * self.bcoords[2],
125 )
126 }
127
128 pub fn contains_point(&self, id: usize) -> bool {
129 self.pts[0] == id || self.pts[1] == id || self.pts[2] == id
130 }
131
132 pub fn next_ccw_pt_id(&self, id: usize) -> usize {
133 if self.pts[0] == id {
134 1
135 } else if self.pts[1] == id {
136 2
137 } else {
138 if self.pts[2] != id {
139 log::debug!(
140 "Hit unexpected state in EPA: found index {}, expected: {}.",
141 self.pts[2],
142 id
143 );
144 }
145
146 0
147 }
148 }
149
150 pub fn can_be_seen_by(&self, vertices: &[CSOPoint], point: usize, opp_pt_id: usize) -> bool {
151 let p0 = &vertices[self.pts[opp_pt_id]].point;
152 let p1 = &vertices[self.pts[(opp_pt_id + 1) % 3]].point;
153 let p2 = &vertices[self.pts[(opp_pt_id + 2) % 3]].point;
154 let pt = &vertices[point].point;
155
156 (*pt - *p0).dot(&self.normal) >= -gjk::eps_tol()
162 || Triangle::new(*p1, *p2, *pt).is_affinely_dependent()
163 }
164}
165
166struct SilhouetteEdge {
167 face_id: usize,
168 opp_pt_id: usize,
169}
170
171impl SilhouetteEdge {
172 pub fn new(face_id: usize, opp_pt_id: usize) -> Self {
173 SilhouetteEdge { face_id, opp_pt_id }
174 }
175}
176
177#[derive(Default)]
179pub struct EPA {
180 vertices: Vec<CSOPoint>,
181 faces: Vec<Face>,
182 silhouette: Vec<SilhouetteEdge>,
183 heap: BinaryHeap<FaceId>,
184}
185
186impl EPA {
187 pub fn new() -> Self {
189 Self::default()
190 }
191
192 fn reset(&mut self) {
193 self.vertices.clear();
194 self.faces.clear();
195 self.heap.clear();
196 self.silhouette.clear();
197 }
198
199 pub fn project_origin<G: ?Sized + SupportMap>(
208 &mut self,
209 m: &Isometry<Real>,
210 g: &G,
211 simplex: &VoronoiSimplex,
212 ) -> Option<Point<Real>> {
213 self.closest_points(&m.inverse(), g, &ConstantOrigin, simplex)
214 .map(|(p, _, _)| p)
215 }
216
217 pub fn closest_points<G1, G2>(
222 &mut self,
223 pos12: &Isometry<Real>,
224 g1: &G1,
225 g2: &G2,
226 simplex: &VoronoiSimplex,
227 ) -> Option<(Point<Real>, Point<Real>, Unit<Vector<Real>>)>
228 where
229 G1: ?Sized + SupportMap,
230 G2: ?Sized + SupportMap,
231 {
232 let _eps = crate::math::DEFAULT_EPSILON;
233 let _eps_tol = _eps * 100.0;
234
235 self.reset();
236
237 for i in 0..simplex.dimension() + 1 {
241 self.vertices.push(*simplex.point(i));
242 }
243
244 if simplex.dimension() == 0 {
245 let mut n: Vector<Real> = na::zero();
246 n[1] = 1.0;
247 return Some((Point::origin(), Point::origin(), Unit::new_unchecked(n)));
248 } else if simplex.dimension() == 3 {
249 let dp1 = self.vertices[1] - self.vertices[0];
250 let dp2 = self.vertices[2] - self.vertices[0];
251 let dp3 = self.vertices[3] - self.vertices[0];
252
253 if dp1.cross(&dp2).dot(&dp3) > 0.0 {
254 self.vertices.swap(1, 2)
255 }
256
257 let pts1 = [0, 1, 2];
258 let pts2 = [1, 3, 2];
259 let pts3 = [0, 2, 3];
260 let pts4 = [0, 3, 1];
261
262 let adj1 = [3, 1, 2];
263 let adj2 = [3, 2, 0];
264 let adj3 = [0, 1, 3];
265 let adj4 = [2, 1, 0];
266
267 let (face1, proj_inside1) = Face::new(&self.vertices, pts1, adj1);
268 let (face2, proj_inside2) = Face::new(&self.vertices, pts2, adj2);
269 let (face3, proj_inside3) = Face::new(&self.vertices, pts3, adj3);
270 let (face4, proj_inside4) = Face::new(&self.vertices, pts4, adj4);
271
272 self.faces.push(face1);
273 self.faces.push(face2);
274 self.faces.push(face3);
275 self.faces.push(face4);
276
277 if proj_inside1 {
278 let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
279 self.heap.push(FaceId::new(0, -dist1)?);
280 }
281
282 if proj_inside2 {
283 let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);
284 self.heap.push(FaceId::new(1, -dist2)?);
285 }
286
287 if proj_inside3 {
288 let dist3 = self.faces[2].normal.dot(&self.vertices[2].point.coords);
289 self.heap.push(FaceId::new(2, -dist3)?);
290 }
291
292 if proj_inside4 {
293 let dist4 = self.faces[3].normal.dot(&self.vertices[3].point.coords);
294 self.heap.push(FaceId::new(3, -dist4)?);
295 }
296
297 if !(proj_inside1 || proj_inside2 || proj_inside3 || proj_inside4) {
298 log::debug!("Hit unexpected state in EPA: failed to project the origin on the initial simplex.");
302 return None;
303 }
304 } else {
305 if simplex.dimension() == 1 {
306 let dpt = self.vertices[1] - self.vertices[0];
307
308 Vector::orthonormal_subspace_basis(&[dpt], |dir| {
309 let dir = Unit::new_unchecked(*dir);
311 self.vertices
312 .push(CSOPoint::from_shapes(pos12, g1, g2, &dir));
313 false
314 });
315 }
316
317 let pts1 = [0, 1, 2];
318 let pts2 = [0, 2, 1];
319
320 let adj1 = [1, 1, 1];
321 let adj2 = [0, 0, 0];
322
323 let (face1, _) = Face::new(&self.vertices, pts1, adj1);
324 let (face2, _) = Face::new(&self.vertices, pts2, adj2);
325 self.faces.push(face1);
326 self.faces.push(face2);
327
328 self.heap.push(FaceId::new(0, 0.0)?);
329 self.heap.push(FaceId::new(1, 0.0)?);
330 }
331
332 let mut niter = 0;
333 let mut max_dist = Real::max_value();
334 let mut best_face_id = *self.heap.peek()?;
335 let mut old_dist = 0.0;
336
337 while let Some(face_id) = self.heap.pop() {
341 let face = self.faces[face_id.id].clone();
343
344 if face.deleted {
345 continue;
346 }
347
348 let cso_point = CSOPoint::from_shapes(pos12, g1, g2, &face.normal);
349 let support_point_id = self.vertices.len();
350 self.vertices.push(cso_point);
351
352 let candidate_max_dist = cso_point.point.coords.dot(&face.normal);
353
354 if candidate_max_dist < max_dist {
355 best_face_id = face_id;
356 max_dist = candidate_max_dist;
357 }
358
359 let curr_dist = -face_id.neg_dist;
360
361 if max_dist - curr_dist < _eps_tol ||
362 ((curr_dist - old_dist).abs() < _eps && candidate_max_dist < max_dist)
365 {
366 let best_face = &self.faces[best_face_id.id];
367 let points = best_face.closest_points(&self.vertices);
368 return Some((points.0, points.1, best_face.normal));
369 }
370
371 old_dist = curr_dist;
372
373 self.faces[face_id.id].deleted = true;
374
375 let adj_opp_pt_id1 = self.faces[face.adj[0]].next_ccw_pt_id(face.pts[0]);
376 let adj_opp_pt_id2 = self.faces[face.adj[1]].next_ccw_pt_id(face.pts[1]);
377 let adj_opp_pt_id3 = self.faces[face.adj[2]].next_ccw_pt_id(face.pts[2]);
378
379 self.compute_silhouette(support_point_id, face.adj[0], adj_opp_pt_id1);
380 self.compute_silhouette(support_point_id, face.adj[1], adj_opp_pt_id2);
381 self.compute_silhouette(support_point_id, face.adj[2], adj_opp_pt_id3);
382
383 let first_new_face_id = self.faces.len();
384
385 if self.silhouette.is_empty() {
386 return None;
388 }
389
390 for edge in &self.silhouette {
391 if !self.faces[edge.face_id].deleted {
392 let new_face_id = self.faces.len();
393
394 let face_adj = &mut self.faces[edge.face_id];
395 let pt_id1 = face_adj.pts[(edge.opp_pt_id + 2) % 3];
396 let pt_id2 = face_adj.pts[(edge.opp_pt_id + 1) % 3];
397
398 let pts = [pt_id1, pt_id2, support_point_id];
399 let adj = [edge.face_id, new_face_id + 1, new_face_id - 1];
400 let new_face = Face::new(&self.vertices, pts, adj);
401
402 face_adj.adj[(edge.opp_pt_id + 1) % 3] = new_face_id;
403
404 self.faces.push(new_face.0);
405
406 if new_face.1 {
407 let pt = self.vertices[self.faces[new_face_id].pts[0]].point.coords;
408 let dist = self.faces[new_face_id].normal.dot(&pt);
409 if dist < curr_dist {
410 let points = face.closest_points(&self.vertices);
413 return Some((points.0, points.1, face.normal));
414 }
415
416 self.heap.push(FaceId::new(new_face_id, -dist)?);
417 }
418 }
419 }
420
421 if first_new_face_id == self.faces.len() {
422 return None;
425 }
426
427 self.faces[first_new_face_id].adj[2] = self.faces.len() - 1;
428 self.faces.last_mut().unwrap().adj[1] = first_new_face_id;
429
430 self.silhouette.clear();
431 niter += 1;
434 if niter > 100 {
435 break;
438 }
439 }
440
441 let best_face = &self.faces[best_face_id.id];
442 let points = best_face.closest_points(&self.vertices);
443 Some((points.0, points.1, best_face.normal))
444 }
445
446 fn compute_silhouette(&mut self, point: usize, id: usize, opp_pt_id: usize) {
447 if !self.faces[id].deleted {
448 if !self.faces[id].can_be_seen_by(&self.vertices, point, opp_pt_id) {
449 self.silhouette.push(SilhouetteEdge::new(id, opp_pt_id));
450 } else {
451 self.faces[id].deleted = true;
452
453 let adj_pt_id1 = (opp_pt_id + 2) % 3;
454 let adj_pt_id2 = opp_pt_id;
455
456 let adj1 = self.faces[id].adj[adj_pt_id1];
457 let adj2 = self.faces[id].adj[adj_pt_id2];
458
459 let adj_opp_pt_id1 =
460 self.faces[adj1].next_ccw_pt_id(self.faces[id].pts[adj_pt_id1]);
461 let adj_opp_pt_id2 =
462 self.faces[adj2].next_ccw_pt_id(self.faces[id].pts[adj_pt_id2]);
463
464 self.compute_silhouette(point, adj1, adj_opp_pt_id1);
465 self.compute_silhouette(point, adj2, adj_opp_pt_id2);
466 }
467 }
468 }
469
470 #[allow(dead_code)]
471 #[cfg(feature = "std")]
472 fn print_silhouette(&self) {
473 use std::{print, println};
474
475 print!("Silhouette points: ");
476 for i in 0..self.silhouette.len() {
477 let edge = &self.silhouette[i];
478 let face = &self.faces[edge.face_id];
479
480 if !face.deleted {
481 print!(
482 "({}, {}) ",
483 face.pts[(edge.opp_pt_id + 2) % 3],
484 face.pts[(edge.opp_pt_id + 1) % 3]
485 );
486 }
487 }
488 println!();
489 }
490
491 #[allow(dead_code)]
492 fn check_topology(&self) {
493 for i in 0..self.faces.len() {
494 let face = &self.faces[i];
495 if face.deleted {
496 continue;
497 }
498
499 let adj1 = &self.faces[face.adj[0]];
501 let adj2 = &self.faces[face.adj[1]];
502 let adj3 = &self.faces[face.adj[2]];
503
504 assert!(!adj1.deleted);
505 assert!(!adj2.deleted);
506 assert!(!adj3.deleted);
507
508 assert!(face.pts[0] != face.pts[1]);
509 assert!(face.pts[0] != face.pts[2]);
510 assert!(face.pts[1] != face.pts[2]);
511
512 assert!(adj1.contains_point(face.pts[0]));
513 assert!(adj1.contains_point(face.pts[1]));
514
515 assert!(adj2.contains_point(face.pts[1]));
516 assert!(adj2.contains_point(face.pts[2]));
517
518 assert!(adj3.contains_point(face.pts[2]));
519 assert!(adj3.contains_point(face.pts[0]));
520
521 let opp_pt_id1 = adj1.next_ccw_pt_id(face.pts[0]);
522 let opp_pt_id2 = adj2.next_ccw_pt_id(face.pts[1]);
523 let opp_pt_id3 = adj3.next_ccw_pt_id(face.pts[2]);
524
525 assert!(!face.contains_point(adj1.pts[opp_pt_id1]));
526 assert!(!face.contains_point(adj2.pts[opp_pt_id2]));
527 assert!(!face.contains_point(adj3.pts[opp_pt_id3]));
528
529 assert!(adj1.adj[(opp_pt_id1 + 1) % 3] == i);
530 assert!(adj2.adj[(opp_pt_id2 + 1) % 3] == i);
531 assert!(adj3.adj[(opp_pt_id3 + 1) % 3] == i);
532 }
533 }
534}