1use crate::impl_mesh::ManifoldImpl;
20use crate::linalg::{cross, distance2, dot, Mat3x4, Vec3};
21use crate::sort::{get_face_box_morton, morton_code};
22use crate::types::Box as BBox;
23
24const K_ROOT: i32 = 1;
29
30fn leaf_to_node(leaf: i32) -> i32 {
31 leaf * 2
32}
33fn node_to_leaf(node: i32) -> i32 {
34 node / 2
35}
36fn internal_to_node(internal: i32) -> i32 {
37 internal * 2 + 1
38}
39fn node_to_internal(node: i32) -> i32 {
40 node / 2
41}
42fn is_leaf(node: i32) -> bool {
43 node % 2 == 0
44}
45fn is_internal(node: i32) -> bool {
46 node % 2 == 1
47}
48
49#[derive(Clone, Debug, Default)]
50pub struct Collider {
51 leaf_bbox: Vec<BBox>,
52 leaf_morton: Vec<u32>,
53 sorted_to_original: Vec<usize>, node_bbox: Vec<BBox>, internal_children: Vec<[i32; 2]>, }
58
59impl Collider {
60 pub fn new(leaf_bbox: Vec<BBox>, leaf_morton: Vec<u32>) -> Self {
63 debug_assert_eq!(leaf_bbox.len(), leaf_morton.len());
64 let n = leaf_bbox.len();
65 let mut order: Vec<usize> = (0..n).collect();
67 order.sort_by_key(|&i| leaf_morton[i]);
68 let sorted_bbox: Vec<BBox> = order.iter().map(|&i| leaf_bbox[i]).collect();
69 let sorted_morton: Vec<u32> = order.iter().map(|&i| leaf_morton[i]).collect();
70 let sorted_to_original = order;
71
72 let mut collider = Self {
73 leaf_bbox: sorted_bbox,
74 leaf_morton: sorted_morton,
75 sorted_to_original,
76 node_bbox: Vec::new(),
77 internal_children: Vec::new(),
78 };
79 collider.build_bvh();
80 collider
81 }
82
83
84 fn build_bvh(&mut self) {
85 let num_leaves = self.leaf_bbox.len();
86 if num_leaves == 0 {
87 return;
88 }
89 if num_leaves == 1 {
90 self.node_bbox = vec![BBox::default(); 2];
92 self.node_bbox[0] = self.leaf_bbox[0]; self.node_bbox[1] = self.leaf_bbox[0]; self.internal_children = vec![[0, 0]; 1]; return;
96 }
97
98 let num_internal = num_leaves - 1;
99 let num_nodes = 2 * num_leaves - 1;
100 self.node_bbox = vec![BBox::default(); num_nodes];
101 self.internal_children = vec![[-1, -1]; num_internal];
102
103 for i in 0..num_leaves {
105 self.node_bbox[leaf_to_node(i as i32) as usize] = self.leaf_bbox[i];
106 }
107
108 self.create_radix_tree();
110
111 self.build_internal_boxes();
113 }
114
115 fn create_radix_tree(&mut self) {
117 let num_leaves = self.leaf_bbox.len();
118 if num_leaves <= 1 {
119 return;
120 }
121 let num_internal = num_leaves - 1;
122
123 const K_INITIAL_LENGTH: i32 = 128;
124 const K_LENGTH_MULTIPLE: i32 = 4;
125
126 let prefix_length = |i: i32, j: i32| -> i32 {
128 if j < 0 || j >= num_leaves as i32 {
129 return -1;
130 }
131 let mi = self.leaf_morton[i as usize];
132 let mj = self.leaf_morton[j as usize];
133 let xor = mi ^ mj;
134 if xor == 0 {
135 32 + ((i as u32 ^ j as u32).leading_zeros() as i32)
137 } else {
138 xor.leading_zeros() as i32
139 }
140 };
141
142 let range_end = |i: i32| -> i32 {
144 let dir_val = prefix_length(i, i + 1) - prefix_length(i, i - 1);
145 let dir = if dir_val > 0 { 1i32 } else if dir_val < 0 { -1i32 } else { -1i32 };
146 let common_prefix = prefix_length(i, i - dir);
147 let mut max_length = K_INITIAL_LENGTH;
148 while prefix_length(i, i + dir * max_length) > common_prefix {
149 max_length *= K_LENGTH_MULTIPLE;
150 }
151 let mut length = 0i32;
152 let mut step = max_length / 2;
153 while step > 0 {
154 if prefix_length(i, i + dir * (length + step)) > common_prefix {
155 length += step;
156 }
157 step /= 2;
158 }
159 i + dir * length
160 };
161
162 let find_split = |first: i32, last: i32| -> i32 {
164 let common_prefix = prefix_length(first, last);
165 let mut split = first;
166 let mut step = last - first;
167 loop {
168 step = (step + 1) >> 1; let new_split = split + step;
170 if new_split < last {
171 let split_prefix = prefix_length(first, new_split);
172 if split_prefix > common_prefix {
173 split = new_split;
174 }
175 }
176 if step <= 1 { break; }
177 }
178 split
179 };
180
181 let mut node_parent = vec![-1i32; 2 * num_leaves - 1];
183
184 for internal in 0..num_internal {
185 let i = internal as i32;
186 let mut first = i;
187 let mut last = range_end(i);
188 if first > last {
189 std::mem::swap(&mut first, &mut last);
190 }
191
192 let split = find_split(first, last);
193
194 let child1 = if split == first {
196 leaf_to_node(split)
197 } else {
198 internal_to_node(split)
199 };
200 let split2 = split + 1;
202 let child2 = if split2 == last {
203 leaf_to_node(split2)
204 } else if (split2 as usize) < num_internal {
205 internal_to_node(split2)
206 } else {
207 child1
211 };
212
213 self.internal_children[internal] = [child1, child2];
214 let node = internal_to_node(i);
215 node_parent[child1 as usize] = node;
216 node_parent[child2 as usize] = node;
217 }
218
219 let mut counter = vec![0u32; num_internal];
222
223 for leaf in 0..num_leaves {
224 let mut node = leaf_to_node(leaf as i32);
225 loop {
226 let parent = node_parent[node as usize];
227 if parent < 0 {
228 break; }
230 let internal = node_to_internal(parent);
231 if internal < 0 || internal >= num_internal as i32 {
232 break;
233 }
234 let idx = internal as usize;
235 counter[idx] += 1;
236 if counter[idx] < 2 {
237 break; }
239 let [c1, c2] = self.internal_children[idx];
241 let b1 = self.node_bbox[c1 as usize];
242 let b2 = self.node_bbox[c2 as usize];
243 self.node_bbox[parent as usize] = b1.union_box(&b2);
244 node = parent;
245 }
246 }
247 }
248
249 fn build_internal_boxes(&mut self) {
251 }
254
255 pub fn collisions_one<R: FnMut(usize, usize)>(
260 &self,
261 query: &BBox,
262 query_idx: usize,
263 mut record: R,
264 ) {
265 if query.is_empty() {
266 return;
267 }
268 if self.internal_children.is_empty() {
269 if self.leaf_bbox.len() == 1 {
270 let original_idx = self.sorted_to_original[0];
271 if query.does_overlap_box(&self.leaf_bbox[0]) {
272 record(query_idx, original_idx);
273 }
274 }
275 return;
276 }
277 self.traverse_bvh(query, query_idx, false, &mut record);
278 }
279
280 pub fn collisions_fn<F, R>(
284 &self,
285 query_box_fn: F,
286 n: usize,
287 mut record: R,
288 ) where
289 F: Fn(usize) -> BBox,
290 R: FnMut(usize, usize),
291 {
292 if self.internal_children.is_empty() {
293 if self.leaf_bbox.len() == 1 {
295 let original_idx = self.sorted_to_original[0];
296 for query_idx in 0..n {
297 let query = query_box_fn(query_idx);
298 if !query.is_empty() && query.does_overlap_box(&self.leaf_bbox[0]) {
299 record(query_idx, original_idx);
300 }
301 }
302 }
303 return;
304 }
305
306 for query_idx in 0..n {
307 let query = query_box_fn(query_idx);
308 if query.is_empty() {
309 continue;
310 }
311 self.traverse_bvh(&query, query_idx, false, &mut record);
312 }
313 }
314
315 pub fn collisions_with_boxes<F: FnMut(usize, usize)>(
317 &self,
318 queries: &[BBox],
319 self_collision: bool,
320 mut record: F,
321 ) {
322 if self.internal_children.is_empty() {
323 if self.leaf_bbox.len() == 1 {
325 let original_idx = self.sorted_to_original[0];
326 for (qi, q) in queries.iter().enumerate() {
327 if !(self_collision && qi == original_idx) && q.does_overlap_box(&self.leaf_bbox[0]) {
328 record(qi, original_idx);
329 }
330 }
331 }
332 return;
333 }
334
335 for (query_idx, query) in queries.iter().enumerate() {
336 if query.is_empty() {
337 continue;
338 }
339 self.traverse_bvh(query, query_idx, self_collision, &mut record);
340 }
341 }
342
343 pub fn collisions_point<F, R>(
345 &self,
346 point_fn: F,
347 n: usize,
348 mut record: R,
349 ) where
350 F: Fn(usize) -> Vec3,
351 R: FnMut(usize, usize),
352 {
353 if self.internal_children.is_empty() {
354 if self.leaf_bbox.len() == 1 {
355 let original_idx = self.sorted_to_original[0];
356 for query_idx in 0..n {
357 let pt = point_fn(query_idx);
358 let query = BBox::from_point(pt);
359 if query.does_overlap_box(&self.leaf_bbox[0]) {
360 record(query_idx, original_idx);
361 }
362 }
363 }
364 return;
365 }
366
367 for query_idx in 0..n {
368 let pt = point_fn(query_idx);
369 let query = BBox::from_point(pt);
370 self.traverse_bvh(&query, query_idx, false, &mut record);
371 }
372 }
373
374 fn traverse_bvh<F: FnMut(usize, usize)>(
376 &self,
377 query: &BBox,
378 query_idx: usize,
379 self_collision: bool,
380 record: &mut F,
381 ) {
382 let mut stack = [0i32; 64];
383 let mut top: i32 = -1;
384 let mut node = K_ROOT;
385
386 loop {
387 let internal = node_to_internal(node);
388 if internal < 0 || internal as usize >= self.internal_children.len() {
389 if top < 0 { break; }
390 node = stack[top as usize];
391 top -= 1;
392 continue;
393 }
394 let [child1, child2] = self.internal_children[internal as usize];
395
396 let traverse1 = self.check_node(query, child1, query_idx, self_collision, record);
397 let traverse2 = self.check_node(query, child2, query_idx, self_collision, record);
398
399 if !traverse1 && !traverse2 {
400 if top < 0 {
401 break;
402 }
403 node = stack[top as usize];
404 top -= 1;
405 } else {
406 node = if traverse1 { child1 } else { child2 };
407 if traverse1 && traverse2 {
408 top += 1;
409 debug_assert!((top as usize) < 64, "BVH stack overflow");
410 stack[top as usize] = child2;
411 }
412 }
413 }
414 }
415
416 #[inline]
419 fn check_node<F: FnMut(usize, usize)>(
420 &self,
421 query: &BBox,
422 node: i32,
423 query_idx: usize,
424 self_collision: bool,
425 record: &mut F,
426 ) -> bool {
427 if node < 0 || node as usize >= self.node_bbox.len() {
428 return false;
429 }
430 let node_box = &self.node_bbox[node as usize];
431 let overlaps = query.does_overlap_box(node_box);
432 if overlaps && is_leaf(node) {
433 let sorted_idx = node_to_leaf(node) as usize;
434 let original_idx = self.sorted_to_original[sorted_idx];
435 if !self_collision || original_idx != query_idx {
436 record(query_idx, original_idx);
437 }
438 }
439 overlaps && is_internal(node)
440 }
441
442 pub fn update_boxes(&mut self, leaf_bbox: Vec<BBox>) {
443 debug_assert_eq!(leaf_bbox.len(), self.leaf_bbox.len());
444 for (sorted_idx, &orig_idx) in self.sorted_to_original.iter().enumerate() {
447 self.leaf_bbox[sorted_idx] = leaf_bbox[orig_idx];
448 }
449 self.build_bvh();
451 }
452
453 pub fn transform(&mut self, transform: &Mat3x4) {
454 debug_assert!(Self::is_axis_aligned(transform));
455 for bbox in &mut self.leaf_bbox {
456 *bbox = bbox.transform(transform);
457 }
458 self.build_bvh();
460 }
461
462 pub fn leaf_count(&self) -> usize {
463 self.leaf_bbox.len()
464 }
465
466 pub fn leaf_bbox(&self) -> &[BBox] {
467 &self.leaf_bbox
468 }
469
470 pub fn morton_code(position: Vec3, bbox: &BBox) -> u32 {
471 morton_code(position, bbox)
472 }
473
474 pub fn is_axis_aligned(transform: &Mat3x4) -> bool {
475 for row in 0..3 {
476 let mut zero_count = 0;
477 for col in 0..3 {
478 if transform[col][row] == 0.0 {
479 zero_count += 1;
480 }
481 }
482 if zero_count != 2 {
483 return false;
484 }
485 }
486 true
487 }
488
489 pub fn leaf_morton(&self) -> &[u32] {
490 &self.leaf_morton
491 }
492}
493
494pub fn edge_edge_dist(p: Vec3, a: Vec3, q: Vec3, b: Vec3) -> (Vec3, Vec3) {
495 let t_vec = q - p;
496 let a_dot_a = dot(a, a);
497 let b_dot_b = dot(b, b);
498 let a_dot_b = dot(a, b);
499 let a_dot_t = dot(a, t_vec);
500 let b_dot_t = dot(b, t_vec);
501
502 let denom = a_dot_a * b_dot_b - a_dot_b * a_dot_b;
503 let mut t = if denom != 0.0 {
504 ((a_dot_t * b_dot_b - b_dot_t * a_dot_b) / denom).clamp(0.0, 1.0)
505 } else {
506 0.0
507 };
508
509 let u = if b_dot_b != 0.0 {
510 let u = (t * a_dot_b - b_dot_t) / b_dot_b;
511 if u < 0.0 {
512 t = if a_dot_a != 0.0 { (a_dot_t / a_dot_a).clamp(0.0, 1.0) } else { 0.0 };
513 0.0
514 } else if u > 1.0 {
515 t = if a_dot_a != 0.0 {
516 ((a_dot_b + a_dot_t) / a_dot_a).clamp(0.0, 1.0)
517 } else {
518 0.0
519 };
520 1.0
521 } else {
522 u
523 }
524 } else {
525 t = if a_dot_a != 0.0 { (a_dot_t / a_dot_a).clamp(0.0, 1.0) } else { 0.0 };
526 0.0
527 };
528
529 (p + a * t, q + b * u)
530}
531
532pub fn distance_triangle_triangle_squared(p: [Vec3; 3], q: [Vec3; 3]) -> f64 {
533 let sv = [p[1] - p[0], p[2] - p[1], p[0] - p[2]];
534 let tv = [q[1] - q[0], q[2] - q[1], q[0] - q[2]];
535
536 let mut shown_disjoint = false;
537 let mut mindd = f64::MAX;
538
539 for i in 0..3 {
540 for j in 0..3 {
541 let (cp, cq) = edge_edge_dist(p[i], sv[i], q[j], tv[j]);
542 let v = cq - cp;
543 let dd = dot(v, v);
544
545 if dd <= mindd {
546 mindd = dd;
547
548 let mut id = i + 2;
549 if id >= 3 { id -= 3; }
550 let z = p[id] - cp;
551 let mut a = dot(z, v);
552
553 id = j + 2;
554 if id >= 3 { id -= 3; }
555 let z = q[id] - cq;
556 let mut b = dot(z, v);
557
558 if a <= 0.0 && b >= 0.0 {
559 return dot(v, v);
560 }
561
562 if a <= 0.0 { a = 0.0; } else if b > 0.0 { b = 0.0; }
563
564 if mindd - a + b > 0.0 {
565 shown_disjoint = true;
566 }
567 }
568 }
569 }
570
571 let sn = cross(sv[0], sv[1]);
572 let snl = dot(sn, sn);
573 if snl > 1e-15 {
574 let tp = Vec3::new(dot(p[0] - q[0], sn), dot(p[0] - q[1], sn), dot(p[0] - q[2], sn));
575 let mut index = None;
576 if tp.x > 0.0 && tp.y > 0.0 && tp.z > 0.0 {
577 let mut idx = if tp.x < tp.y { 0 } else { 1 };
578 if tp.z < tp[idx] { idx = 2; }
579 index = Some(idx);
580 } else if tp.x < 0.0 && tp.y < 0.0 && tp.z < 0.0 {
581 let mut idx = if tp.x > tp.y { 0 } else { 1 };
582 if tp.z > tp[idx] { idx = 2; }
583 index = Some(idx);
584 }
585
586 if let Some(index) = index {
587 shown_disjoint = true;
588 let q_index = q[index];
589 let v = q_index - p[0];
590 let z = cross(sn, sv[0]);
591 if dot(v, z) > 0.0 {
592 let v = q_index - p[1];
593 let z = cross(sn, sv[1]);
594 if dot(v, z) > 0.0 {
595 let v = q_index - p[2];
596 let z = cross(sn, sv[2]);
597 if dot(v, z) > 0.0 {
598 let cp = q_index + sn * (tp[index] / snl);
599 let cq = q_index;
600 return dot(cp - cq, cp - cq);
601 }
602 }
603 }
604 }
605 }
606
607 let tn = cross(tv[0], tv[1]);
608 let tnl = dot(tn, tn);
609 if tnl > 1e-15 {
610 let sp = Vec3::new(dot(q[0] - p[0], tn), dot(q[0] - p[1], tn), dot(q[0] - p[2], tn));
611 let mut index = None;
612 if sp.x > 0.0 && sp.y > 0.0 && sp.z > 0.0 {
613 let mut idx = if sp.x < sp.y { 0 } else { 1 };
614 if sp.z < sp[idx] { idx = 2; }
615 index = Some(idx);
616 } else if sp.x < 0.0 && sp.y < 0.0 && sp.z < 0.0 {
617 let mut idx = if sp.x > sp.y { 0 } else { 1 };
618 if sp.z > sp[idx] { idx = 2; }
619 index = Some(idx);
620 }
621
622 if let Some(index) = index {
623 shown_disjoint = true;
624 let p_index = p[index];
625 let v = p_index - q[0];
626 let z = cross(tn, tv[0]);
627 if dot(v, z) > 0.0 {
628 let v = p_index - q[1];
629 let z = cross(tn, tv[1]);
630 if dot(v, z) > 0.0 {
631 let v = p_index - q[2];
632 let z = cross(tn, tv[2]);
633 if dot(v, z) > 0.0 {
634 let cp = p_index;
635 let cq = p_index + tn * (sp[index] / tnl);
636 return dot(cp - cq, cp - cq);
637 }
638 }
639 }
640 }
641 }
642
643 if shown_disjoint { mindd } else { 0.0 }
644}
645
646pub fn ray_triangle_intersection(
647 origin: Vec3,
648 direction: Vec3,
649 tri: [Vec3; 3],
650) -> Option<f64> {
651 let eps = 1e-9;
652 let edge1 = tri[1] - tri[0];
653 let edge2 = tri[2] - tri[0];
654 let h = cross(direction, edge2);
655 let a = dot(edge1, h);
656 if a.abs() < eps {
657 return None;
658 }
659 let f = 1.0 / a;
660 let s = origin - tri[0];
661 let u = f * dot(s, h);
662 if !(0.0..=1.0).contains(&u) {
663 return None;
664 }
665 let q = cross(s, edge1);
666 let v = f * dot(direction, q);
667 if v < 0.0 || u + v > 1.0 {
668 return None;
669 }
670 let t = f * dot(edge2, q);
671 if t > eps { Some(t) } else { None }
672}
673
674impl ManifoldImpl {
675 pub fn is_self_intersecting(&self) -> bool {
676 let ep = 2.0 * self.epsilon;
677 let epsilon_sq = ep * ep;
678 let (face_box, face_morton) = get_face_box_morton(self);
679 let collider = Collider::new(face_box.clone(), face_morton);
680 let mut intersecting = false;
681
682 collider.collisions_with_boxes(&face_box, true, |tri0, tri1| {
683 if intersecting {
684 return;
685 }
686 let tri_verts0 = self.face_triangle_vertices(tri0);
687 let tri_verts1 = self.face_triangle_vertices(tri1);
688
689 for a in &tri_verts0 {
690 for b in &tri_verts1 {
691 if distance2(*a, *b) <= epsilon_sq {
692 return;
693 }
694 }
695 }
696
697 if distance_triangle_triangle_squared(tri_verts0, tri_verts1) == 0.0 {
698 let mut tmp0 = tri_verts0;
699 let mut tmp1 = tri_verts1;
700 for i in 0..3 {
701 tmp0[i] = tri_verts0[i] + self.face_normal[tri1] * ep;
702 }
703 if distance_triangle_triangle_squared(tmp0, tri_verts1) > 0.0 {
704 return;
705 }
706 for i in 0..3 {
707 tmp0[i] = tri_verts0[i] - self.face_normal[tri1] * ep;
708 }
709 if distance_triangle_triangle_squared(tmp0, tri_verts1) > 0.0 {
710 return;
711 }
712 for i in 0..3 {
713 tmp1[i] = tri_verts1[i] + self.face_normal[tri0] * ep;
714 }
715 if distance_triangle_triangle_squared(tri_verts0, tmp1) > 0.0 {
716 return;
717 }
718 for i in 0..3 {
719 tmp1[i] = tri_verts1[i] - self.face_normal[tri0] * ep;
720 }
721 if distance_triangle_triangle_squared(tri_verts0, tmp1) > 0.0 {
722 return;
723 }
724 intersecting = true;
725 }
726 });
727
728 intersecting
729 }
730
731 pub fn min_gap(&self, other: &ManifoldImpl, search_length: f64) -> f64 {
732 let (self_box, self_morton) = get_face_box_morton(self);
733 let (mut other_box, _) = get_face_box_morton(other);
734 for bbox in &mut other_box {
735 bbox.min = bbox.min - Vec3::splat(search_length);
736 bbox.max = bbox.max + Vec3::splat(search_length);
737 }
738
739 let collider = Collider::new(self_box, self_morton);
740 let mut min_distance = f64::INFINITY;
741 collider.collisions_with_boxes(&other_box, false, |tri_other, tri| {
742 let p = self.face_triangle_vertices(tri);
743 let q = other.face_triangle_vertices(tri_other);
744 min_distance = min_distance.min(distance_triangle_triangle_squared(p, q));
745 });
746
747 min_distance.min(search_length * search_length).sqrt()
748 }
749
750 fn face_triangle_vertices(&self, tri: usize) -> [Vec3; 3] {
751 [
752 self.vert_pos[self.halfedge[3 * tri].start_vert as usize],
753 self.vert_pos[self.halfedge[3 * tri + 1].start_vert as usize],
754 self.vert_pos[self.halfedge[3 * tri + 2].start_vert as usize],
755 ]
756 }
757}
758
759#[cfg(test)]
760mod tests {
761 use super::*;
762 use crate::linalg::{mat4_to_mat3x4, translation_matrix};
763
764 #[test]
765 fn test_collider_box_overlap() {
766 let boxes = vec![
767 BBox::from_points(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0)),
768 BBox::from_points(Vec3::new(2.0, 2.0, 2.0), Vec3::new(3.0, 3.0, 3.0)),
769 ];
770 let collider = Collider::new(boxes.clone(), vec![0, 1]);
771 let mut hits = Vec::new();
772 collider.collisions_with_boxes(&boxes, true, |a, b| hits.push((a, b)));
773 assert!(hits.is_empty());
774
775 let queries = vec![BBox::from_points(Vec3::new(0.5, 0.5, 0.5), Vec3::new(2.5, 2.5, 2.5))];
776 collider.collisions_with_boxes(&queries, false, |a, b| hits.push((a, b)));
777 assert_eq!(hits, vec![(0, 0), (0, 1)]);
778 }
779
780 #[test]
781 fn test_ray_triangle_intersection() {
782 let tri = [
783 Vec3::new(0.0, 0.0, 0.0),
784 Vec3::new(1.0, 0.0, 0.0),
785 Vec3::new(0.0, 1.0, 0.0),
786 ];
787 let hit = ray_triangle_intersection(Vec3::new(0.25, 0.25, -1.0), Vec3::new(0.0, 0.0, 1.0), tri);
788 assert!(hit.is_some());
789 }
790
791 #[test]
792 fn test_triangle_triangle_distance_zero_for_intersection() {
793 let a = [
794 Vec3::new(0.0, 0.0, 0.0),
795 Vec3::new(1.0, 0.0, 0.0),
796 Vec3::new(0.0, 1.0, 0.0),
797 ];
798 let b = [
799 Vec3::new(0.25, 0.25, -1.0),
800 Vec3::new(0.25, 0.25, 1.0),
801 Vec3::new(0.75, 0.25, 0.0),
802 ];
803 assert_eq!(distance_triangle_triangle_squared(a, b), 0.0);
804 }
805
806 #[test]
807 fn test_cube_not_self_intersecting() {
808 let m = ManifoldImpl::cube(&Mat3x4::identity());
809 assert!(!m.is_self_intersecting());
810 }
811
812 #[test]
813 fn test_min_gap_between_cubes() {
814 let a = ManifoldImpl::cube(&Mat3x4::identity());
815 let b = ManifoldImpl::cube(&mat4_to_mat3x4(translation_matrix(Vec3::new(2.0, 0.0, 0.0))));
816 let gap = a.min_gap(&b, 5.0);
817 assert!((gap - 1.0).abs() < 1e-8, "gap = {}", gap);
818 }
819
820 #[test]
821 fn test_bvh_many_boxes() {
822 let n = 100;
824 let mut boxes = Vec::new();
825 let mut mortons = Vec::new();
826 for i in 0..n {
827 let x = i as f64 * 3.0;
828 boxes.push(BBox::from_points(
829 Vec3::new(x, 0.0, 0.0),
830 Vec3::new(x + 1.0, 1.0, 1.0),
831 ));
832 mortons.push(i as u32);
833 }
834 let collider = Collider::new(boxes.clone(), mortons);
835
836 let query = vec![BBox::from_points(
838 Vec3::new(150.5, 0.5, 0.5),
839 Vec3::new(150.6, 0.6, 0.6),
840 )];
841 let mut hits = Vec::new();
842 collider.collisions_with_boxes(&query, false, |a, b| hits.push((a, b)));
843 assert_eq!(hits, vec![(0, 50)]);
844 }
845}