1use sorted_vec::partial::ReverseSortedVec;
2
3use crate::object;
4use crate::math::*;
5
6use super::Proximity;
7
8#[derive(Clone, Copy, Debug, PartialEq)]
9struct SimplexMinkowski {
10 pub points : [PointMinkowski; 4],
11 pub npoints : u8
12}
13
14#[derive(Clone, Copy, Debug, Default, PartialEq)]
16struct PointMinkowski {
17 pub point_a : Point3 <f64>,
18 pub point_b : Point3 <f64>
19 }
22
23impl SimplexMinkowski {
24 const fn push (&mut self, point : PointMinkowski) {
25 self.points[self.npoints as usize] = point;
26 self.npoints += 1;
27 }
28}
29
30impl PointMinkowski {
31 fn point (self) -> Point3 <f64> {
33 Point3 (self.point_a - self.point_b)
34 }
35
36 fn support <A, B> (direction : NonZero3 <f64>, object_a : &A, object_b : &B)
37 -> (Self, f64)
38 where A : object::Bounded, B : object::Bounded {
39 let (point_a, _) = object_a.to_primitive().support (direction);
40 let (point_b, _) = object_b.to_primitive().support (-direction);
41 let minkowski = PointMinkowski { point_a, point_b };
42 (minkowski, minkowski.point().0.dot (*direction))
43 }
44}
45
46impl Proximity {
47 pub fn query_gjk <A, B> (object_a : &A, object_b : &B) -> Self where
49 A : object::Bounded, B : object::Bounded
50 {
51 const TOLERANCE : f64 = 0.000_000_000_01;
58 const TOLERANCE_SQUARED : f64 = TOLERANCE * TOLERANCE;
59 let mut search_dir = NonZero3::unchecked (vector3 (1.0, 1.0, 1.0));
61 let (support, _) = PointMinkowski::support (search_dir, object_a, object_b);
62 let mut near = support.point();
63 let mut distance_squared = near.0.magnitude_squared();
64 let mut lowest_distance_sq = distance_squared;
65 let mut simplex = SimplexMinkowski {
66 points: [support,
67 PointMinkowski::default(), PointMinkowski::default(), PointMinkowski::default()],
68 npoints: 1
69 };
70 search_dir = -NonZero3::unchecked (support.point().0);
73 let mut lowest_unique_count = 0;
74 let mut last_distance_sq = f64::MAX;
75 let noprogress_limit = 3;
76 let mut noprogress_count = 0;
77 let mut unique_count = 0;
78 loop {
79 let (support, _) = PointMinkowski::support (search_dir, object_a, object_b);
80 let vnew = support.point() - near;
82 let dot_new = vnew.dot (*search_dir);
83 if dot_new <= TOLERANCE {
84 break
86 }
87 simplex.push (support);
89 let mut overlap = false;
90 if simplex.npoints == 4 {
91 let [a, b, c, d] = simplex.points.map (PointMinkowski::point);
93 let ab = b - a;
95 let ac = c - a;
96 let ad = d - a;
97 let da = a - d;
98 let db = b - d;
99 let dc = c - d;
100 let ab_x_ac = ab.cross (ac);
101 let ab_x_ac_dot_ad = ab_x_ac.dot (ad);
102 let nd = -d.0;
103 let (dab, dac, dbc) = if ab_x_ac_dot_ad > 0.0 {
104 ( db.cross (da),
106 da.cross (dc),
107 dc.cross (db) )
108 } else {
109 ( da.cross (db),
111 dc.cross (da),
112 db.cross (dc) )
113 };
114 let check1 = dab.dot (nd) > 0.000000001;
116 let check2 = dac.dot (nd) > 0.000000001;
117 let check3 = dbc.dot (nd) > 0.000000001;
118 if check1 && check2 && check3 {
119 overlap = true
120 } else {
121 let line = geometry::Segment3::noisy (Point3::<f64>::origin(), near).into();
123 if let Some (triangle) = geometry::Triangle3::new (d, a, b)
125 && geometry::intersect::line_triangle (line, triangle).is_some()
126 {
127 simplex.points[2] = simplex.points[3];
129 } else {
130 if let Some (triangle) = geometry::Triangle3::new (d, a, c)
132 && geometry::intersect::line_triangle (line, triangle).is_some()
133 {
134 simplex.points[1] = simplex.points[3];
136 } else {
137 if let Some (triangle) = geometry::Triangle3::new (d, b, c)
139 && geometry::intersect::line_triangle (line, triangle).is_some()
140 {
141 simplex.points[0] = simplex.points[3];
143 } else {
144 unreachable!("should have intersected new simplex")
145 }
146 }
147 }
148 simplex.npoints = 3;
149 }
150 }
151 if !overlap {
152 match simplex.npoints {
154 1 => {
155 near = simplex.points[0].point();
156 distance_squared = near.0.magnitude_squared();
157 if distance_squared < TOLERANCE_SQUARED {
158 overlap = true
159 } else {
160 search_dir = NonZero3::new (-near.0).unwrap()
162 }
163 }
164 2 => {
165 let t;
166 (t, near) = geometry::Segment3::unchecked (
167 simplex.points[0].point(), simplex.points[1].point()
168 ).nearest_point (Point3::origin());
169 distance_squared = near.0.magnitude_squared();
170 if distance_squared < TOLERANCE_SQUARED {
171 overlap = true
172 } else if *t == 1.0 {
173 simplex.points[0] = simplex.points[1];
175 simplex.npoints -= 1;
176 search_dir = NonZero3::unchecked (-simplex.points[0].point().0)
177 } else {
178 search_dir = NonZero3::unchecked (-near.0)
180 }
181 }
182 3 => {
183 let (s, t);
184 ([s, t], near) = geometry::Triangle3::unchecked (
185 simplex.points[0].point(),
186 simplex.points[1].point(),
187 simplex.points[2].point()
188 ).nearest_point (Point3::origin());
189 distance_squared = near.0.magnitude_squared();
190 if distance_squared < TOLERANCE_SQUARED {
191 overlap = true
192 } else {
193 search_dir = NonZero3::unchecked (-near.0);
195 if *s == 0.0 && *t == 0.0 {
196 simplex.npoints = 1;
198 } else if *s == 1.0 && *t == 0.0 {
199 simplex.points[0] = simplex.points[1];
201 simplex.npoints = 1;
202 } else if *s == 0.0 && *t == 1.0 {
203 simplex.points[0] = simplex.points[2];
205 simplex.npoints = 1;
206 } else if (*s + *t - 1.0).abs() < TOLERANCE {
207 simplex.points[0] = simplex.points[1];
209 simplex.points[1] = simplex.points[2];
210 simplex.npoints = 2;
211 } else if *s < TOLERANCE {
212 simplex.points[1] = simplex.points[2];
214 simplex.npoints = 2;
215 } else if *t < TOLERANCE {
216 simplex.npoints = 2;
218 } else {
219 debug_assert!(*s > 0.0);
221 debug_assert!(*s < 1.0);
222 debug_assert!(*t > 0.0);
223 debug_assert!(*t < 1.0);
224 debug_assert!(*s + *t < 1.0);
225 }
226 }
227 }
228 _ => unreachable!()
229 }
230 }
231 if overlap {
232 #[derive(PartialEq)]
235 struct PolytopeFace {
236 pub distance_squared : NonNegative <f64>,
238 pub distance_vector : Vector3 <f64>,
240 pub nearest_a : Point3 <f64>,
241 pub nearest_b : Point3 <f64>,
242 pub points : [PointMinkowski; 3],
243 pub normal : NonZero3 <f64>,
244 pub exterior : bool
245 }
246 impl PartialOrd for PolytopeFace {
247 fn partial_cmp (&self, other : &Self) -> Option <std::cmp::Ordering> {
248 self.distance_squared.partial_cmp (&other.distance_squared)
249 }
250 }
251 let mut node_list = ReverseSortedVec::<PolytopeFace>::new();
252 let add_face = |
253 node_list : &mut ReverseSortedVec <PolytopeFace>,
254 p1 : PointMinkowski, p2 : PointMinkowski, p3 : PointMinkowski
255 | {
256 let triangle = geometry::Triangle3::noisy (p1.point(), p2.point(), p3.point());
257 let ([s, t], nearest) = triangle.nearest_point (Point3::origin());
258 let nearest_a = p1.point_a +
259 (p2.point_a - p1.point_a) * *s + (p3.point_a - p1.point_a) * *t;
260 let nearest_b = p1.point_b +
261 (p2.point_b - p1.point_b) * *s + (p3.point_b - p1.point_b) * *t;
262 let normal = {
263 let mut normal = triangle.normal();
264 if normal.dot (triangle.point_a().0) < 0.0 {
265 normal = -normal
266 }
267 normal
268 };
269 let node = PolytopeFace {
270 distance_squared: nearest.0.norm_squared(),
271 distance_vector: -nearest.0,
272 points: [p1, p2, p3],
273 exterior: false,
274 nearest_a,
275 nearest_b,
276 normal
277 };
278 node_list.insert (node);
279 };
280 let a = simplex.points[0];
281 let b = simplex.points[1];
282 let c = simplex.points[2];
283 let d = simplex.points[3];
284 match simplex.npoints {
285 3 => {
286 let e1 = simplex.points[1].point() - simplex.points[0].point();
288 let e2 = simplex.points[2].point() - simplex.points[0].point();
289 let n1 = NonZero3::noisy (e1.cross (e2));
290 let n2 = -n1;
291 let (p1, dot) = PointMinkowski::support (n1, object_a, object_b);
293 if dot <= TOLERANCE {
294 let half_axis = *n1 * TOLERANCE * 0.5;
295 return Proximity {
296 distance: -TOLERANCE.sqrt(),
297 normal: n1.normalize(),
298 midpoint: p1.point_a + half_axis,
299 half_axis
300 }
301 }
302 add_face (&mut node_list, a, b, p1);
303 add_face (&mut node_list, a, c, p1);
304 add_face (&mut node_list, b, c, p1);
305 let (p2, dot) = PointMinkowski::support (n2, object_a, object_b);
307 if dot <= TOLERANCE {
308 let half_axis = *n2 * TOLERANCE * 0.5;
309 return Proximity {
310 distance: -TOLERANCE.sqrt(),
311 normal: n2.normalize(),
312 midpoint: p2.point_a + half_axis,
313 half_axis
314 }
315 }
316 add_face (&mut node_list, a, b, p2);
317 add_face (&mut node_list, a, c, p2);
318 add_face (&mut node_list, b, c, p2);
319 }
320 4 => {
321 add_face (&mut node_list, a, b, c);
322 add_face (&mut node_list, a, b, d);
323 add_face (&mut node_list, a, c, d);
324 add_face (&mut node_list, b, c, d);
325 }
326 _ => unreachable!()
327 }
328 let mut edges = vec![];
334 let mut edge_in_list = vec![];
335 let mut last_iter_distance = f64::MIN;
336 let exterior_node_proximity = |node : PolytopeFace| {
337 let half_axis = node.distance_vector * 0.5;
338 Proximity {
339 half_axis,
340 distance: -*node.distance_squared.sqrt(),
341 normal: half_axis.normalize(), midpoint: node.nearest_a + half_axis
343 }
344 };
345 let mut iter = 0;
346 let noprogress_limit = 3;
347 let mut noprogress_count = 0;
348 loop {
349 let mut node = node_list.pop().unwrap();
350 if approx::relative_eq!(*node.distance_squared, last_iter_distance,
351 epsilon = 0.000000001
352 ) {
353 noprogress_count += 1;
355 if noprogress_count == noprogress_limit {
356 log::trace!("expanding polytope search no progress after {iter} iterations");
357 return exterior_node_proximity (node)
358 }
359 } else {
360 noprogress_count = 0;
361 }
362 last_iter_distance = *node.distance_squared;
363 let (pa, _) = PointMinkowski::support (node.normal, object_a, object_b);
365 if node.points.contains (&pa) {
366 node.exterior = true;
368 } else {
369 let bpa = pa.point() - node.points[0].point();
371 let normal_unit = node.normal.normalize();
373 if normal_unit.dot (bpa) < TOLERANCE {
374 node.exterior = true;
375 }
376 }
377 if node.exterior {
378 return exterior_node_proximity (node)
380 } else {
381 edges.clear();
384 edge_in_list.clear();
385 edges.extend ([
386 [node.points[0], node.points[1]],
387 [node.points[0], node.points[2]],
388 [node.points[1], node.points[2]]
389 ]);
390 edge_in_list.extend ([true, true, true]);
391 node_list.retain (|node|{
394 let p0_pa = pa.point() - node.points[0].point();
395 if TOLERANCE < node.normal.dot (p0_pa) {
396 let mut add_edge = |i : usize, j : usize| {
398 let mut found = false;
399 for (k, edge) in edges.iter().enumerate()
401 .filter (|(k, _)| edge_in_list[*k])
402 {
403 if node.points[i].point() == edge[0].point()
404 && node.points[j].point() == edge[1].point()
405 || node.points[i].point() == edge[1].point()
406 && node.points[j].point() == edge[0].point()
407 {
408 found = true;
409 edge_in_list[k] = false; break
411 }
412 }
413 if !found {
414 edge_in_list.push (true);
416 edges.push ([node.points[i], node.points[j]]);
417 }
418 };
419 add_edge (0, 1); add_edge (0, 2); add_edge (1, 2); false } else {
424 true }
426 });
427 for (_, edge) in edges.iter().enumerate()
430 .filter (|(i, _)| edge_in_list[*i])
431 {
432 if geometry::Triangle3::new (pa.point(), edge[0].point(), edge[1].point())
433 .is_none()
434 {
435 continue
437 }
438 add_face (&mut node_list, pa, edge[0], edge[1]);
439 }
440 }
441 iter += 1;
442 }
443 } if simplex.points[0].point_a == simplex.points[1].point_a
446 && simplex.points[1].point_a == simplex.points[2].point_a
447 {
448 unique_count += 1;
449 } else if simplex.points[0].point_a == simplex.points[1].point_a
450 || simplex.points[0].point_a == simplex.points[2].point_a
451 || simplex.points[1].point_a == simplex.points[2].point_a
452 {
453 unique_count += 2;
454 } else {
455 debug_assert!(
456 simplex.points[0].point_a != simplex.points[1].point_a &&
457 simplex.points[0].point_a != simplex.points[2].point_a &&
458 simplex.points[1].point_a != simplex.points[2].point_a);
459 unique_count += 3;
460 }
461 if simplex.points[0].point_b == simplex.points[1].point_b
462 && simplex.points[1].point_b == simplex.points[2].point_b
463 {
464 unique_count += 1;
465 } else if simplex.points[0].point_b == simplex.points[1].point_b
466 || simplex.points[0].point_b == simplex.points[2].point_b
467 || simplex.points[1].point_b == simplex.points[2].point_b
468 {
469 unique_count += 2;
470 } else {
471 debug_assert!(
472 simplex.points[0].point_b != simplex.points[1].point_b &&
473 simplex.points[0].point_b != simplex.points[2].point_b &&
474 simplex.points[1].point_b != simplex.points[2].point_b);
475 unique_count += 3;
476 }
477 if distance_squared < lowest_distance_sq ||
479 distance_squared == lowest_distance_sq && unique_count < lowest_unique_count
480 {
481 lowest_distance_sq = distance_squared;
482 lowest_unique_count = unique_count;
483 } else if distance_squared >= last_distance_sq {
484 if noprogress_count < noprogress_limit {
485 noprogress_count += 1;
486 } else {
487 break
489 }
490 }
491 last_distance_sq = distance_squared;
492 }
493 let mut dupe_a_01 = false;
496 let mut dupe_a_02 = false;
497 let mut dupe_a_12 = false;
498 let mut dupe_b_01 = false;
499 let mut dupe_b_02 = false;
500 let mut dupe_b_12 = false;
501 if simplex.npoints >= 2 {
502 dupe_a_01 = simplex.points[0].point_a == simplex.points[1].point_a;
503 dupe_b_01 = simplex.points[0].point_b == simplex.points[1].point_b;
504 }
505 if simplex.npoints >= 3 {
506 dupe_a_02 = simplex.points[0].point_a == simplex.points[2].point_a;
507 dupe_a_12 = simplex.points[1].point_a == simplex.points[2].point_a;
508 dupe_b_02 = simplex.points[0].point_b == simplex.points[2].point_b;
509 dupe_b_12 = simplex.points[1].point_b == simplex.points[2].point_b;
510 }
511 debug_assert!(!(simplex.npoints == 2 && unique_count == 2),
514 "only one unique point: not possible");
515 match simplex.npoints {
517 1 => {
518 let nearest_a = simplex.points[0].point_a;
520 let nearest_b = simplex.points[0].point_b;
521 let a_to_b = nearest_b - nearest_a;
522 let half_axis = a_to_b * 0.5;
523 let midpoint = nearest_a + half_axis;
524 let normal = if !a_to_b.is_approx_zero() {
525 Unit3::normalize (-a_to_b)
526 } else {
527 Unit3::normalize (object_a.position().0 - object_b.position().0)
529 };
530 let distance = a_to_b.magnitude();
531 Proximity { distance, half_axis, midpoint, normal }
532 }
533 2 => {
534 let point0_a = simplex.points[0].point_a;
536 let point1_a = simplex.points[1].point_a;
537 let point0_b = simplex.points[0].point_b;
538 let point1_b = simplex.points[1].point_b;
539 if !dupe_a_01 && !dupe_b_01 {
540 let edge_a = geometry::Segment3::noisy (point0_a, point1_a);
542 let edge_b = geometry::Segment3::noisy (point0_b, point1_b);
543 Proximity::query_segment_segment (&edge_a, &edge_b)
544 } else {
545 if dupe_a_01 {
547 debug_assert!(!dupe_b_01);
549 debug_assert_eq!(point0_a, point1_a);
550 let point_a = point0_a;
551 let edge_b = geometry::Segment3::noisy (point0_b, point1_b);
552 Proximity::query_segment_point (&edge_b, &point_a).flip()
554 } else {
555 debug_assert!(dupe_b_01);
557 let point_b = point0_b;
558 let edge_a = geometry::Segment3::noisy (point0_a, point1_a);
559 Proximity::query_segment_point (&edge_a, &point_b)
560 }
561 }
562 }
563 3 => {
564 let is_edge = |
566 p0 : &mut Point3 <f64>, p1 : &mut Point3 <f64>, p2 : &Point3 <f64>
567 | {
568 let p01 = *p1 - *p0;
569 let p02 = *p2 - *p0;
570 let p01_cross_p02 = p01.cross (p02);
571 if p01_cross_p02.is_approx_zero() {
572 let p12 = *p2 - *p1;
574 let dot_p01 = p01.magnitude_squared();
575 let dot_p02 = p02.magnitude_squared();
576 let dot_p12 = p12.magnitude_squared();
577 if dot_p01 > dot_p02 && dot_p01 > dot_p12 {
579 } else if dot_p02 > dot_p01 && dot_p02 > dot_p12 {
581 *p1 = *p2;
582 } else {
583 debug_assert!(dot_p12 > dot_p01 && dot_p12 > dot_p02);
584 *p0 = *p1;
585 *p1 = *p2;
586 }
587 true
588 } else {
589 false
590 }
591 };
592 debug_assert!(!((dupe_a_01 && dupe_a_12) && (dupe_b_01 && dupe_b_12)));
594 if (!dupe_a_01 && !dupe_a_02 && !dupe_a_12) &&
595 (!dupe_b_01 && !dupe_b_02 && !dupe_b_12)
596 {
597 let mut a0 = simplex.points[0].point_a;
599 let mut a1 = simplex.points[1].point_a;
600 let a2 = simplex.points[2].point_a;
601 let mut b0 = simplex.points[0].point_b;
602 let mut b1 = simplex.points[1].point_b;
603 let b2 = simplex.points[2].point_b;
604 let edge_a = is_edge (&mut a0, &mut a1, &a2);
605 let edge_b = is_edge (&mut b0, &mut b1, &b2);
606 if edge_a && edge_b {
607 let edge_a = geometry::Segment3::noisy (a0, a1);
609 let edge_b = geometry::Segment3::noisy (b0, b1);
610 Proximity::query_segment_segment (&edge_a, &edge_b)
611 } else if edge_a && !edge_b {
612 let edge_a = geometry::Segment3::noisy (a0, a1);
614 let triangle_b = geometry::Triangle3::noisy (b0, b1, b2);
615 Proximity::query_triangle_segment (&triangle_b, &edge_a).flip()
617 } else if !edge_a && edge_b {
618 let edge_b = geometry::Segment3::noisy (b0, b1);
620 let triangle_a = geometry::Triangle3::noisy (a0, a1, a2);
621 Proximity::query_triangle_segment (&triangle_a, &edge_b)
622 } else {
623 debug_assert!(!edge_a);
624 debug_assert!(!edge_b);
625 let triangle_a = geometry::Triangle3::noisy (a0, a1, a2);
627 let triangle_b = geometry::Triangle3::noisy (b0, b1, b2);
628 Proximity::query_triangle_triangle (&triangle_a, &triangle_b)
629 }
630 } else if (dupe_a_01 != dupe_a_02 || dupe_a_01 != dupe_a_12)
631 && (!dupe_b_01 && !dupe_b_02 && !dupe_b_12)
632 {
633 let a0 = simplex.points[0].point_a;
640 let mut a1 = simplex.points[1].point_a;
641 let mut b0 = simplex.points[0].point_b;
642 let mut b1 = simplex.points[1].point_b;
643 let b2 = simplex.points[2].point_b;
644 if dupe_a_01 || dupe_a_12 {
645 a1 = simplex.points[2].point_a;
646 }
647 let edge_b = is_edge (&mut b0, &mut b1, &b2);
648 let edge_a = geometry::Segment3::noisy (a0, a1);
649 if edge_b {
650 let edge_b = geometry::Segment3::noisy (b0, b1);
652 Proximity::query_segment_segment (&edge_a, &edge_b)
653 } else {
654 let triangle_b = geometry::Triangle3::noisy (b0, b1, b2);
656 Proximity::query_triangle_segment (&triangle_b, &edge_a).flip()
658 }
659 } else if (dupe_b_01 != dupe_b_02 || dupe_b_01 != dupe_b_12)
660 && (!dupe_a_01 && !dupe_a_02 && !dupe_a_12)
661 {
662 let mut a0 = simplex.points[0].point_a;
664 let mut a1 = simplex.points[1].point_a;
665 let a2 = simplex.points[2].point_a;
666 let b0 = simplex.points[0].point_b;
667 let b1 = if dupe_b_01 || dupe_b_12 {
668 simplex.points[2].point_b
669 } else {
670 simplex.points[1].point_b
671 };
672 let edge_a = is_edge (&mut a0, &mut a1, &a2);
673 if edge_a {
674 let edge_a = geometry::Segment3::noisy (a0, a1);
676 let edge_b = geometry::Segment3::noisy (b0, b1);
677 Proximity::query_segment_segment (&edge_a, &edge_b)
678 } else {
679 let triangle_a = geometry::Triangle3::noisy (a0, a1, a2);
681 let edge_b = geometry::Segment3::noisy (b0, b1);
682 Proximity::query_triangle_segment (&triangle_a, &edge_b)
683 }
684 } else {
685 if (dupe_a_01 != dupe_a_02 || dupe_a_01 != dupe_a_12)
686 && !(dupe_a_01 && dupe_a_02 && dupe_a_12) {
688 debug_assert!(dupe_b_01 != dupe_b_02 || dupe_b_01 != dupe_b_12);
691 debug_assert!(!(dupe_b_01 && dupe_b_02 && dupe_b_12));
692 debug_assert!(!(dupe_a_01 && dupe_b_01));
693 debug_assert!(!(dupe_a_02 && dupe_b_02));
694 debug_assert!(!(dupe_a_12 && dupe_b_12));
695 if (dupe_a_01 != dupe_a_02) && (dupe_b_01 != dupe_b_02) {
700 if dupe_a_02 {
702 debug_assert!(dupe_b_01);
705 } else {
707 debug_assert!(dupe_a_01);
710 debug_assert!(dupe_b_02);
711 simplex.points.swap(1, 2);
712 }
713 } else if (dupe_a_01 != dupe_a_12) && (dupe_b_01 != dupe_b_12) {
714 let temp = simplex.points[0];
716 simplex.points[0] = simplex.points[1];
717 if dupe_a_01 {
718 debug_assert!(dupe_b_12);
721 simplex.points[1] = simplex.points[2];
722 simplex.points[2] = temp;
723 } else {
724 debug_assert!(dupe_a_12);
727 debug_assert!(dupe_b_01);
728 simplex.points[1] = temp;
729 }
730 } else {
731 debug_assert!(dupe_a_02 != dupe_a_12);
733 debug_assert!(dupe_b_02 != dupe_b_12);
734 let temp = simplex.points[0];
735 simplex.points[0] = simplex.points[2];
736 if dupe_a_02 {
737 debug_assert!(dupe_b_12);
740 simplex.points[2] = temp;
741 } else {
742 debug_assert!(dupe_a_12);
745 debug_assert!(dupe_b_02);
746 simplex.points[2] = simplex.points[1];
747 simplex.points[1] = temp;
748 }
749 }
750 let a0 = simplex.points[0].point_a;
751 let a1 = simplex.points[1].point_a;
752 let b0 = simplex.points[0].point_b;
753 let b2 = simplex.points[2].point_b;
755 let edge_a = geometry::Segment3::noisy (a0, a1);
756 let edge_b = geometry::Segment3::noisy (b0, b2);
757 Proximity::query_segment_segment (&edge_a, &edge_b)
758 } else {
759 debug_assert!((dupe_a_01 && dupe_a_12) != (dupe_b_01 && dupe_b_12));
762 if dupe_a_01 && dupe_a_12 {
763 debug_assert!(dupe_a_02); let point_a = simplex.points[0].point_a;
766 let b0 = simplex.points[0].point_b;
767 let b1 = simplex.points[1].point_b;
768 let b2 = simplex.points[2].point_b;
769 let triangle_b = geometry::Triangle3::noisy (b0, b1, b2);
770 Proximity::query_triangle_point (&triangle_b, &point_a).flip()
772 } else {
773 debug_assert!(dupe_b_01 && dupe_b_12);
775 debug_assert!(dupe_b_02); let point_b = simplex.points[0].point_b;
777 let a0 = simplex.points[0].point_a;
778 let a1 = simplex.points[1].point_a;
779 let a2 = simplex.points[2].point_a;
780 let triangle_a = geometry::Triangle3::noisy (a0, a1, a2);
781 Proximity::query_triangle_point (&triangle_a, &point_b)
782 }
783 }
784 }
785 }
786 _ => unreachable!()
787 }
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use approx;
794 use gl_utils::{mesh, Mesh};
795 use rand;
796 use rand_distr;
797 use rand_xorshift::XorShiftRng;
798 use crate::math::geometry::*;
799 use crate::component;
800 use super::*;
801
802 #[test]
803 fn query_gjk() {
804 use rand::SeedableRng;
805 use rand_distr::Distribution;
806
807 let tetrahedron = |p1 : [f64; 3], p2 : [f64; 3], p3 : [f64; 3], p4 : [f64; 3]|
808 -> (component::Position, component::Bound)
809 {
810 ( component::Position::origin(),
811 Hull3::from_points_with_mesh (
812 &simplex3::Tetrahedron::<f64>::noisy (
813 p1.into(), p2.into(), p3.into(), p4.into()
814 ).points()
815 ).unwrap().into()
816 )
817 };
818 let a = tetrahedron (
819 [-2.0, 2.0, -1.0],
820 [ 2.0, 2.0, -1.0],
821 [ 0.0, -2.0, -1.0],
822 [ 0.0, 0.0, 2.0]);
823 let b = tetrahedron (
824 [-2.0, 2.0, 3.5],
825 [ 2.0, 2.0, 3.5],
826 [ 0.0, -2.0, 3.5],
827 [ 0.0, 0.0, 6.5]);
828 let proximity = Proximity::query_gjk (&a, &b);
829 assert_eq!(proximity.distance, 1.5);
830 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.75].into());
831 assert_eq!(proximity.midpoint, [0.0, 0.0, 2.75].into());
832 assert_eq!(proximity.normal, -Unit3::axis_z());
833 let a = tetrahedron (
834 [-2.0, 2.0, -1.0],
835 [ 2.0, 2.0, -1.0],
836 [ 0.0, -2.0, -1.0],
837 [ 0.0, 0.0, 2.0]);
838 let b = tetrahedron (
839 [-2.0, 2.0, 1.75],
840 [ 2.0, 2.0, 1.75],
841 [ 0.0, -2.0, 1.75],
842 [ 0.0, 0.0, 4.75]);
843 let proximity = Proximity::query_gjk (&a, &b);
844 assert_eq!(proximity.distance, -0.25);
845 assert_eq!(proximity.half_axis, [0.0, 0.0, -0.125].into());
846 assert_eq!(proximity.midpoint, [0.0, 0.0, 1.875].into());
847 assert_eq!(proximity.normal, -Unit3::axis_z());
848 let a = tetrahedron (
849 [ 0.0, 0.0, 3.5],
850 [-2.0, 2.0, 0.5],
851 [ 2.0, 2.0, 0.5],
852 [ 0.0, -2.0, 0.5]);
853 let b = tetrahedron (
854 [-2.0, 2.0, 1.0],
855 [ 2.0, 2.0, 1.0],
856 [ 0.0, -2.0, 1.0],
857 [ 0.0, 0.0, -2.0]);
858 let proximity = Proximity::query_gjk (&a, &b);
859 assert_eq!(proximity.distance, -0.5);
860 approx::assert_abs_diff_eq!(proximity.half_axis, [0.0, 0.0, 0.25].into());
861 assert_eq!(proximity.midpoint, [0.0, 2.0/3.0, 0.75].into());
862 approx::assert_abs_diff_eq!(*proximity.normal, *Unit3::axis_z(),
863 epsilon = f64::EPSILON * 4.0);
864 let hull = |points : &[Point3 <f64>]| -> (component::Position, component::Bound) {
865 ( component::Position::origin(),
866 Hull3::from_points_with_mesh (points).unwrap().into()
867 )
868 };
869 let a = hull (&[
870 [ 0.0, 0.0, 3.5],
871 [ 0.0, 0.0, 0.5],
872 [-2.0, 2.0, 0.5],
873 [ 2.0, 2.0, 0.5],
874 [ 0.0, -2.0, 0.5]].map (Into::into));
875 let b = hull (&[
876 [-2.0, 2.0, 1.0],
877 [ 2.0, 2.0, 1.0],
878 [ 0.0, -2.0, 1.0],
879 [ 0.0, 0.0, 1.0],
880 [ 0.0, 0.0, -2.0]].map (Into::into));
881 let proximity = Proximity::query_gjk (&a, &b);
882 assert_eq!(proximity.distance, -0.5);
883 approx::assert_abs_diff_eq!(proximity.half_axis, [0.0, 0.0, 0.25].into());
884 assert_eq!(proximity.midpoint, [0.0, 2.0/3.0, 0.75].into());
885 approx::assert_abs_diff_eq!(*proximity.normal, *Unit3::axis_z(),
886 epsilon = f64::EPSILON * 4.0);
887
888 {
889 const NPOINTS : usize = 4;
890 let mut rng = XorShiftRng::seed_from_u64 (0);
891 let cauchy = rand_distr::Cauchy::new (0.0, 1.0).unwrap();
892 let randf = |rng : &mut XorShiftRng| cauchy.sample (rng);
893 let aabb = Aabb3::with_minmax (
894 [-5.0, -5.0, -5.0].into(),
895 [ 5.0, 5.0, 5.0].into()).unwrap();
896 let rand_point = |rng : &mut XorShiftRng|
897 aabb.clamp (point3 (randf (rng), randf (rng), randf (rng)));
898 let object = |hull : shape::Hull <f64>|
899 (component::Position::origin(), component::Bound::from (hull));
900 #[expect(unused_variables)]
901 let write_gltf = |
902 (hull, mesh) : &shape::Hull <f64>,
903 filename : &str
904 | {
905 let mut m = mesh::Triangles3dBuilder::empty();
906 for triangle in mesh.triangles().values() {
907 let triangle = hull.triangle (triangle);
908 m.push_face (triangle.points());
909 }
910 Mesh::from (m.build()).write_gltf (filename);
911 };
912 for _i in 0..1000 {
913 let a = {
915 let points = std::iter::repeat_with (|| rand_point (&mut rng)).take (NPOINTS)
916 .collect::<Vec<_>>();
917 let hull = Hull3::from_points_with_mesh (&points).unwrap();
918 object (hull)
920 };
921 let b = {
922 let points = std::iter::repeat_with (|| rand_point (&mut rng)).take (NPOINTS)
923 .collect::<Vec<_>>();
924 let hull = Hull3::from_points_with_mesh (&points).unwrap();
925 object (hull)
927 };
928 let _proximity = Proximity::query_gjk (&a, &b);
931 }
932 }
933 }
934}