1use crate::math::{Isometry, Vector};
2use crate::pipeline::narrow_phase::{ContactDispatcher, ContactManifoldGenerator};
3use crate::query::{
4 self, visitors::AABBSetsInterferencesCollector, Contact, ContactKinematic, ContactManifold,
5 ContactPrediction, ContactPreprocessor, ContactTrackingMode, NeighborhoodGeometry,
6};
7use crate::shape::{
8 ClippingCache, CompositeShape, ConvexPolygonalFeature, FeatureId, Segment,
9 SegmentPointLocation, Shape, TriMesh, Triangle,
10};
11use na::{self, RealField, Unit};
12use std::mem;
13
14pub struct TriMeshTriMeshManifoldGenerator<N: RealField + Copy> {
16 clip_cache: ClippingCache<N>,
17 new_contacts: Vec<(Contact<N>, FeatureId, FeatureId)>,
18 convex_feature1: ConvexPolygonalFeature<N>,
19 convex_feature2: ConvexPolygonalFeature<N>,
20 interferences: Vec<(usize, usize)>,
21}
22
23impl<N: RealField + Copy> TriMeshTriMeshManifoldGenerator<N> {
24 pub fn new() -> TriMeshTriMeshManifoldGenerator<N> {
26 TriMeshTriMeshManifoldGenerator {
27 clip_cache: ClippingCache::new(),
28 new_contacts: Vec::new(),
29 convex_feature1: ConvexPolygonalFeature::with_size(3),
30 convex_feature2: ConvexPolygonalFeature::with_size(3),
31 interferences: Vec::new(),
32 }
33 }
34}
35
36impl<N: RealField + Copy> TriMeshTriMeshManifoldGenerator<N> {
37 fn compute_faces_closest_points(
38 &mut self,
39 m12: &Isometry<N>,
40 m21: &Isometry<N>,
41 m1: &Isometry<N>,
42 mesh1: &TriMesh<N>,
43 i1: usize,
44 proc1: Option<&dyn ContactPreprocessor<N>>,
45 m2: &Isometry<N>,
46 mesh2: &TriMesh<N>,
47 i2: usize,
48 proc2: Option<&dyn ContactPreprocessor<N>>,
49 prediction: &ContactPrediction<N>,
50 manifold: &mut ContactManifold<N>,
51 ) {
52 let face1 = &mesh1.faces()[i1];
53 let face2 = &mesh2.faces()[i2];
54
55 let pts1 = mesh1.points();
56 let pts2 = mesh2.points();
57 let t1 = Triangle::new(
58 pts1[face1.indices.x],
59 pts1[face1.indices.y],
60 pts1[face1.indices.z],
61 );
62 let t2 = Triangle::new(
63 m12 * pts2[face2.indices.x],
64 m12 * pts2[face2.indices.y],
65 m12 * pts2[face2.indices.z],
66 );
67
68 if let (Some(n1), Some(n2)) = (face1.normal, face2.normal) {
69 let n2 = m12 * n2;
70
71 #[inline(always)]
75 fn penetration<N: RealField + Copy>(a: (N, N), b: (N, N)) -> Option<(N, bool)> {
76 assert!(a.0 <= a.1 && b.0 <= b.1);
77 if a.0 > b.1 || b.0 > a.1 {
78 None
80 } else {
81 let depth1 = b.1 - a.0;
82 let depth2 = a.1 - b.0;
83
84 if depth1 < depth2 {
85 Some((depth1, true))
86 } else {
87 Some((depth2, false))
88 }
89 }
90 }
91
92 #[inline(always)]
93 fn sort2<N: RealField + Copy>(a: N, b: N) -> (N, N) {
94 if a > b {
95 (b, a)
96 } else {
97 (a, b)
98 }
99 }
100
101 'search: loop {
105 let _big: N = na::convert(10000000.0);
106 let mut penetration_depth = (N::max_value().unwrap(), false);
107 let mut penetration_dir = Vector::y_axis();
108
109 let proj1 = t1.a.coords.dot(&n1);
111 let mut interval1 = (proj1, proj1);
112 let interval2 = t2.extents_on_dir(&n1);
113
114 if mesh1.oriented() {
115 interval1.0 = -_big;
116 }
117
118 if let Some(overlap) = penetration(interval1, interval2) {
119 if overlap.0 < penetration_depth.0 {
120 penetration_depth = overlap;
121 penetration_dir = n1;
122 }
123 } else {
124 break;
126 }
127
128 let proj2 = t2.a.coords.dot(&n2);
129 let mut interval2 = (proj2, proj2);
130 let interval1 = t1.extents_on_dir(&n2);
131
132 if mesh2.oriented() {
133 interval2.0 = -_big;
134 }
135
136 if let Some(overlap) = penetration(interval1, interval2) {
137 if overlap.0 < penetration_depth.0 {
138 penetration_depth = overlap;
139 penetration_dir = n2;
140 }
141 } else {
142 break;
144 }
145
146 let edge_dirs_a = t1.edges_scaled_directions();
147 let edge_dirs_b = t2.edges_scaled_directions();
148
149 for (i, e1) in edge_dirs_a.iter().enumerate() {
151 for (j, e2) in edge_dirs_b.iter().enumerate() {
152 if let Some(dir) = Unit::try_new(e1.cross(e2), N::default_epsilon()) {
153 let mut interval1 = sort2(
154 dir.dot(&t1.vertices()[i].coords),
155 dir.dot(&t1.vertices()[(i + 2) % 3].coords),
156 );
157 let mut interval2 = sort2(
158 dir.dot(&t2.vertices()[j].coords),
159 dir.dot(&t2.vertices()[(j + 2) % 3].coords),
160 );
161
162 let eid1 = face1.edges[i];
163 let eid2 = face2.edges[j];
164
165 if mesh1.oriented() {
166 if mesh1.edge_tangent_cone_contains_dir(eid1, None, &dir) {
167 interval1.0 = -_big;
168 } else if mesh1.edge_tangent_cone_contains_dir(eid1, None, &-dir) {
169 interval1.1 = _big;
170 }
171 }
172
173 if mesh2.oriented() {
174 if mesh2.edge_tangent_cone_contains_dir(eid2, None, &(m21 * dir)) {
175 interval2.0 = -_big;
176 } else if mesh2.edge_tangent_cone_contains_dir(
177 eid2,
178 None,
179 &-(m21 * dir),
180 ) {
181 interval2.1 = _big;
182 }
183 }
184
185 if let Some(overlap) = penetration(interval1, interval2) {
186 if overlap.0 < penetration_depth.0 {
187 penetration_depth = overlap;
188 penetration_dir = dir;
189 }
190 } else {
191 break 'search;
193 }
194 }
195 }
196 }
197
198 if let (Some(side_normals1), Some(side_normals2)) =
200 (face1.side_normals.as_ref(), face2.side_normals.as_ref())
201 {
202 for i in 0..3 {
203 self.convex_feature1.vertices[i] = m1 * t1.vertices()[i];
204 self.convex_feature1.edge_normals[i] = m1 * *side_normals1[i];
205 self.convex_feature1.vertices_id[i] = FeatureId::Vertex(face1.indices[i]);
206 self.convex_feature1.edges_id[i] = FeatureId::Edge(face1.edges[i]);
207
208 self.convex_feature2.vertices[i] = m1 * t2.vertices()[i]; self.convex_feature2.edge_normals[i] = m2 * *side_normals2[i];
210 self.convex_feature2.vertices_id[i] = FeatureId::Vertex(face2.indices[i]);
211 self.convex_feature2.edges_id[i] = FeatureId::Edge(face2.edges[i]);
212 }
213
214 let normal = if !penetration_depth.1 {
215 m1 * penetration_dir
216 } else {
217 m1 * -penetration_dir
218 };
219
220 self.convex_feature1.normal = face1.normal.map(|n| m1 * n);
221 self.convex_feature1.feature_id = FeatureId::Face(i1);
222
223 if let Some(normal_f1) = self.convex_feature1.normal.as_mut() {
225 if normal_f1.dot(&normal) < N::zero() {
226 *normal_f1 = -*normal_f1;
227 self.convex_feature1.feature_id =
228 FeatureId::Face(i1 + mesh1.faces().len());
229 self.convex_feature1.vertices.swap(0, 1);
230 self.convex_feature1.edge_normals.swap(1, 2);
231 self.convex_feature1.vertices_id.swap(0, 1);
232 self.convex_feature1.edges_id.swap(1, 2);
233 }
234 }
235
236 self.convex_feature2.normal = face2.normal.map(|n| m2 * n);
237 self.convex_feature2.feature_id = FeatureId::Face(i2);
238
239 if let Some(normal_f2) = self.convex_feature2.normal.as_mut() {
240 if -normal_f2.dot(&normal) < N::zero() {
241 *normal_f2 = -*normal_f2;
242 self.convex_feature2.feature_id =
243 FeatureId::Face(i2 + mesh2.faces().len());
244 self.convex_feature2.vertices.swap(0, 1);
245 self.convex_feature2.edge_normals.swap(1, 2);
246 self.convex_feature2.vertices_id.swap(0, 1);
247 self.convex_feature2.edges_id.swap(1, 2);
248 }
249 }
250
251 self.convex_feature1.clip(
252 &self.convex_feature2,
253 &normal,
254 prediction,
255 &mut self.clip_cache,
256 &mut self.new_contacts,
257 );
258
259 for (c, f1, f2) in self.new_contacts.drain(..) {
260 self.convex_feature1.add_contact_to_manifold(
261 &self.convex_feature2,
262 c,
263 m1,
264 f1,
265 None,
266 m2,
267 f2,
268 None,
269 manifold,
270 );
271 }
272 }
273
274 return;
275 }
276
277 for i in 0..3 {
282 let id_e1 = face1.edges[i];
283 let e1 = &mesh1.edges()[id_e1];
284 let seg1 = Segment::new(pts1[e1.indices.x], pts1[e1.indices.y]);
285
286 for j in 0..3 {
287 let id_e2 = face2.edges[j];
288 let e2 = &mesh2.edges()[id_e2];
289 let seg2 = Segment::new(m12 * pts2[e2.indices.x], m12 * pts2[e2.indices.y]);
292
293 let locs = query::closest_points_segment_segment_with_locations_nD(
294 (&seg1.a, &seg1.b),
295 (&seg2.a, &seg2.b),
296 );
297 let p1 = seg1.point_at(&locs.0);
298 let p2 = seg2.point_at(&locs.1);
299 if let Some(dir) = Unit::try_new(p2 - p1, N::default_epsilon()) {
300 match locs {
301 (
302 SegmentPointLocation::OnVertex(i),
303 SegmentPointLocation::OnVertex(j),
304 ) => {
305 let ip1 = e1.indices[i];
306 let ip2 = e2.indices[j];
307 if mesh1.vertex_tangent_cone_polar_contains_dir(
308 ip1,
309 &dir,
310 prediction.sin_angular1(),
311 ) && mesh2.vertex_tangent_cone_polar_contains_dir(
312 ip2,
313 &(m21 * -dir),
314 prediction.sin_angular2(),
315 ) {
316 let contact = Contact::new_wo_depth(m1 * p1, m1 * p2, m1 * dir);
318 let mut kinematic = ContactKinematic::new();
319 kinematic.set_approx1(
320 FeatureId::Vertex(ip1),
321 pts1[ip1],
322 NeighborhoodGeometry::Point,
323 );
324 kinematic.set_approx2(
325 FeatureId::Vertex(ip2),
326 pts2[ip2],
327 NeighborhoodGeometry::Point,
328 );
329 let _ = manifold.push(contact, kinematic, p1, proc1, proc2);
330 }
331 }
332 (
333 SegmentPointLocation::OnVertex(i),
334 SegmentPointLocation::OnEdge(_),
335 ) => {
336 let ip1 = e1.indices[i];
337 if mesh1.vertex_tangent_cone_polar_contains_dir(
338 ip1,
339 &dir,
340 prediction.sin_angular1(),
341 ) && mesh2.edge_tangent_cone_polar_contains_orthogonal_dir(
342 id_e2,
343 &(m21 * -dir),
344 prediction.sin_angular2(),
345 ) {
346 let contact = Contact::new_wo_depth(m1 * p1, m1 * p2, m1 * dir);
348 let mut kinematic = ContactKinematic::new();
349 kinematic.set_approx1(
350 FeatureId::Vertex(ip1),
351 pts1[ip1],
352 NeighborhoodGeometry::Point,
353 );
354 kinematic.set_approx2(
355 FeatureId::Edge(id_e2),
356 pts2[e2.indices.x],
357 NeighborhoodGeometry::Line(m21 * seg2.direction().unwrap()),
358 );
359 let _ = manifold.push(contact, kinematic, p1, proc1, proc2);
360 }
361 }
362 (
363 SegmentPointLocation::OnEdge(_),
364 SegmentPointLocation::OnVertex(j),
365 ) => {
366 let ip2 = e2.indices[j];
367 if mesh1.edge_tangent_cone_polar_contains_orthogonal_dir(
368 id_e1,
369 &dir,
370 prediction.sin_angular1(),
371 ) && mesh2.vertex_tangent_cone_polar_contains_dir(
372 ip2,
373 &(m21 * -dir),
374 prediction.sin_angular2(),
375 ) {
376 let contact = Contact::new_wo_depth(m1 * p1, m1 * p2, m1 * dir);
378 let mut kinematic = ContactKinematic::new();
379 kinematic.set_approx1(
380 FeatureId::Edge(id_e1),
381 pts1[e1.indices.x],
382 NeighborhoodGeometry::Line(seg1.direction().unwrap()),
383 );
384 kinematic.set_approx2(
385 FeatureId::Vertex(ip2),
386 pts2[ip2],
387 NeighborhoodGeometry::Point,
388 );
389
390 let _ = manifold.push(contact, kinematic, p1, proc1, proc2);
391 }
392 }
393 (SegmentPointLocation::OnEdge(_), SegmentPointLocation::OnEdge(_)) => {
394 if mesh1.edge_tangent_cone_polar_contains_orthogonal_dir(
395 id_e1,
396 &dir,
397 prediction.sin_angular1(),
398 ) && mesh2.edge_tangent_cone_polar_contains_orthogonal_dir(
399 id_e2,
400 &(m21 * -dir),
401 prediction.sin_angular2(),
402 ) {
403 let contact = Contact::new_wo_depth(m1 * p1, m1 * p2, m1 * dir);
405 let mut kinematic = ContactKinematic::new();
406 kinematic.set_approx1(
407 FeatureId::Edge(id_e1),
408 pts1[e1.indices.x],
409 NeighborhoodGeometry::Line(seg1.direction().unwrap()),
410 );
411 kinematic.set_approx2(
412 FeatureId::Edge(id_e2),
413 pts2[e2.indices.x],
414 NeighborhoodGeometry::Line(m21 * seg2.direction().unwrap()),
415 );
416 let _ = manifold.push(contact, kinematic, p1, proc1, proc2);
417 }
418 }
419 }
420 }
421 }
422 }
423
424 'vloop1: for iv in face1.indices.iter() {
426 let p1 = pts1[*iv];
427
428 for (side2, ref_pt2) in face2
429 .side_normals
430 .as_ref()
431 .unwrap()
432 .iter()
433 .zip(t2.vertices().iter())
434 {
435 let dpt = p1 - ref_pt2;
437 if dpt.dot(&(m12 * side2)) >= N::zero() {
438 continue 'vloop1;
439 }
440 }
441
442 let dpt = p1 - t2.a;
443 let dist = dpt.dot(&n2);
444
445 if dist >= N::zero()
446 && mesh1.vertex_tangent_cone_polar_contains_dir(
447 *iv,
448 &-n2,
449 prediction.sin_angular1(),
450 )
451 {
452 let proj = p1 + *n2 * -dist;
453
454 let contact = Contact::new(m1 * p1, m1 * proj, m1 * -n2, -dist);
456 let mut kinematic = ContactKinematic::new();
457 kinematic.set_approx1(FeatureId::Vertex(*iv), p1, NeighborhoodGeometry::Point);
458 kinematic.set_approx2(
459 FeatureId::Face(i2),
460 pts2[face2.indices.x],
461 NeighborhoodGeometry::Plane(face2.normal.unwrap()),
462 );
463 let _ = manifold.push(contact, kinematic, p1, proc1, proc2);
464 }
465 }
466
467 'vloop2: for iv in face2.indices.iter() {
469 let p2 = m12 * pts2[*iv];
472
473 for (side1, ref_pt1) in face1
474 .side_normals
475 .as_ref()
476 .unwrap()
477 .iter()
478 .zip(t1.vertices().iter())
479 {
480 let dpt = p2 - ref_pt1;
481 if dpt.dot(side1) >= N::zero() {
482 continue 'vloop2;
483 }
484 }
485
486 let dpt = p2 - t1.a;
487 let dist = dpt.dot(&n1);
488
489 if dist >= N::zero()
490 && mesh2.vertex_tangent_cone_polar_contains_dir(
491 *iv,
492 &(m21 * -n1),
493 prediction.sin_angular2(),
494 )
495 {
496 let proj = p2 + *n1 * -dist;
497
498 let contact = Contact::new(m1 * proj, m1 * p2, m1 * n1, -dist);
500 let mut kinematic = ContactKinematic::new();
501 kinematic.set_approx1(
502 FeatureId::Face(i1),
503 t1.a,
504 NeighborhoodGeometry::Plane(n1),
505 );
506 kinematic.set_approx2(
507 FeatureId::Vertex(*iv),
508 m21 * p2,
509 NeighborhoodGeometry::Point,
510 );
511 let _ = manifold.push(contact, kinematic, proj, proc1, proc2);
512 }
513 }
514 }
515 }
516}
517
518impl<N: RealField + Copy> ContactManifoldGenerator<N> for TriMeshTriMeshManifoldGenerator<N> {
519 fn generate_contacts(
520 &mut self,
521 _: &dyn ContactDispatcher<N>,
522 m1: &Isometry<N>,
523 g1: &dyn Shape<N>,
524 proc1: Option<&dyn ContactPreprocessor<N>>,
525 m2: &Isometry<N>,
526 g2: &dyn Shape<N>,
527 proc2: Option<&dyn ContactPreprocessor<N>>,
528 prediction: &ContactPrediction<N>,
529 manifold: &mut ContactManifold<N>,
530 ) -> bool {
531 if let (Some(mesh1), Some(mesh2)) =
532 (g1.as_shape::<TriMesh<N>>(), g2.as_shape::<TriMesh<N>>())
533 {
534 let m12 = m1.inverse() * m2;
536 let m21 = m12.inverse();
537
538 let m12_abs_rot = m12.rotation.to_rotation_matrix().matrix().abs();
540
541 {
542 let mut visitor = AABBSetsInterferencesCollector::new(
543 prediction.linear(),
544 &m12,
545 &m12_abs_rot,
546 &mut self.interferences,
547 );
548 mesh1.bvh().visit_bvtt(mesh2.bvh(), &mut visitor);
549 }
550
551 let mut interferences = mem::replace(&mut self.interferences, Vec::new());
552 for id in interferences.drain(..) {
553 self.compute_faces_closest_points(
554 &m12, &m21, m1, mesh1, id.0, proc1, m2, mesh2, id.1, proc2, prediction,
555 manifold,
556 );
557 }
558 self.interferences = interferences;
559
560 true
561 } else {
562 false
563 }
564 }
565
566 fn init_manifold(&self) -> ContactManifold<N> {
567 let mut res = ContactManifold::new();
568 res.set_tracking_mode(ContactTrackingMode::FeatureBased);
569 res
570 }
571}