1use crate::math::{Isometry, Point, Real, Vector};
2use crate::query::details::ShapeCastOptions;
3use crate::query::{
4 self, details::NonlinearShapeCastMode, ClosestPoints, Contact, NonlinearRigidMotion,
5 QueryDispatcher, ShapeCastHit, Unsupported,
6};
7#[cfg(feature = "alloc")]
8use crate::query::{
9 contact_manifolds::{ContactManifoldsWorkspace, NormalConstraints},
10 query_dispatcher::PersistentQueryDispatcher,
11 ContactManifold,
12};
13use crate::shape::{HalfSpace, Segment, Shape, ShapeType};
14#[cfg(feature = "alloc")]
15use alloc::vec::Vec;
16
17#[derive(Debug, Clone)]
19pub struct DefaultQueryDispatcher;
20
21impl QueryDispatcher for DefaultQueryDispatcher {
22 fn intersection_test(
23 &self,
24 pos12: &Isometry<Real>,
25 shape1: &dyn Shape,
26 shape2: &dyn Shape,
27 ) -> Result<bool, Unsupported> {
28 if let (Some(b1), Some(b2)) = (shape1.as_ball(), shape2.as_ball()) {
29 let p12 = Point::from(pos12.translation.vector);
30 Ok(query::details::intersection_test_ball_ball(&p12, b1, b2))
31 } else if let (Some(c1), Some(c2)) = (shape1.as_cuboid(), shape2.as_cuboid()) {
32 Ok(query::details::intersection_test_cuboid_cuboid(
33 pos12, c1, c2,
34 ))
35 } else if let (Some(t1), Some(c2)) = (shape1.as_triangle(), shape2.as_cuboid()) {
36 Ok(query::details::intersection_test_triangle_cuboid(
37 pos12, t1, c2,
38 ))
39 } else if let (Some(c1), Some(t2)) = (shape1.as_cuboid(), shape2.as_triangle()) {
40 Ok(query::details::intersection_test_cuboid_triangle(
41 pos12, c1, t2,
42 ))
43 } else if let Some(b1) = shape1.as_ball() {
44 Ok(query::details::intersection_test_ball_point_query(
45 pos12, b1, shape2,
46 ))
47 } else if let Some(b2) = shape2.as_ball() {
48 Ok(query::details::intersection_test_point_query_ball(
49 pos12, shape1, b2,
50 ))
51 } else if let (Some(p1), Some(s2)) =
52 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
53 {
54 Ok(query::details::intersection_test_halfspace_support_map(
55 pos12, p1, s2,
56 ))
57 } else if let (Some(s1), Some(p2)) =
58 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
59 {
60 Ok(query::details::intersection_test_support_map_halfspace(
61 pos12, s1, p2,
62 ))
63 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
64 Ok(query::details::intersection_test_support_map_support_map(
65 pos12, s1, s2,
66 ))
67 } else {
68 #[cfg(feature = "alloc")]
69 if let Some(c1) = shape1.as_composite_shape() {
70 return Ok(query::details::intersection_test_composite_shape_shape(
71 self, pos12, c1, shape2,
72 ));
73 } else if let Some(c2) = shape2.as_composite_shape() {
74 return Ok(query::details::intersection_test_shape_composite_shape(
75 self, pos12, shape1, c2,
76 ));
77 }
78
79 Err(Unsupported)
80 }
81 }
82
83 fn distance(
87 &self,
88 pos12: &Isometry<Real>,
89 shape1: &dyn Shape,
90 shape2: &dyn Shape,
91 ) -> Result<Real, Unsupported> {
92 let ball1 = shape1.as_ball();
93 let ball2 = shape2.as_ball();
94
95 if let (Some(b1), Some(b2)) = (ball1, ball2) {
96 let p2 = Point::from(pos12.translation.vector);
97 Ok(query::details::distance_ball_ball(b1, &p2, b2))
98 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
99 Ok(query::details::distance_ball_convex_polyhedron(
100 pos12, b1, shape2,
101 ))
102 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
103 Ok(query::details::distance_convex_polyhedron_ball(
104 pos12, shape1, b2,
105 ))
106 } else if let (Some(c1), Some(c2)) = (shape1.as_cuboid(), shape2.as_cuboid()) {
107 Ok(query::details::distance_cuboid_cuboid(pos12, c1, c2))
108 } else if let (Some(s1), Some(s2)) = (shape1.as_segment(), shape2.as_segment()) {
109 Ok(query::details::distance_segment_segment(pos12, s1, s2))
110 } else if let (Some(p1), Some(s2)) =
111 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
112 {
113 Ok(query::details::distance_halfspace_support_map(
114 pos12, p1, s2,
115 ))
116 } else if let (Some(s1), Some(p2)) =
117 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
118 {
119 Ok(query::details::distance_support_map_halfspace(
120 pos12, s1, p2,
121 ))
122 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
123 Ok(query::details::distance_support_map_support_map(
124 pos12, s1, s2,
125 ))
126 } else {
127 #[cfg(feature = "alloc")]
128 if let Some(c1) = shape1.as_composite_shape() {
129 return Ok(query::details::distance_composite_shape_shape(
130 self, pos12, c1, shape2,
131 ));
132 } else if let Some(c2) = shape2.as_composite_shape() {
133 return Ok(query::details::distance_shape_composite_shape(
134 self, pos12, shape1, c2,
135 ));
136 }
137
138 Err(Unsupported)
139 }
140 }
141
142 fn contact(
143 &self,
144 pos12: &Isometry<Real>,
145 shape1: &dyn Shape,
146 shape2: &dyn Shape,
147 prediction: Real,
148 ) -> Result<Option<Contact>, Unsupported> {
149 let ball1 = shape1.as_ball();
150 let ball2 = shape2.as_ball();
151
152 if let (Some(b1), Some(b2)) = (ball1, ball2) {
153 Ok(query::details::contact_ball_ball(pos12, b1, b2, prediction))
154 } else if let (Some(p1), Some(s2)) =
159 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
160 {
161 Ok(query::details::contact_halfspace_support_map(
162 pos12, p1, s2, prediction,
163 ))
164 } else if let (Some(s1), Some(p2)) =
165 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
166 {
167 Ok(query::details::contact_support_map_halfspace(
168 pos12, s1, p2, prediction,
169 ))
170 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
171 Ok(query::details::contact_ball_convex_polyhedron(
172 pos12, b1, shape2, prediction,
173 ))
174 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
175 Ok(query::details::contact_convex_polyhedron_ball(
176 pos12, shape1, b2, prediction,
177 ))
178 } else {
179 #[cfg(feature = "alloc")]
180 if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
181 return Ok(query::details::contact_support_map_support_map(
182 pos12, s1, s2, prediction,
183 ));
184 } else if let Some(c1) = shape1.as_composite_shape() {
185 return Ok(query::details::contact_composite_shape_shape(
186 self, pos12, c1, shape2, prediction,
187 ));
188 } else if let Some(c2) = shape2.as_composite_shape() {
189 return Ok(query::details::contact_shape_composite_shape(
190 self, pos12, shape1, c2, prediction,
191 ));
192 }
193
194 Err(Unsupported)
195 }
196 }
197
198 fn closest_points(
199 &self,
200 pos12: &Isometry<Real>,
201 shape1: &dyn Shape,
202 shape2: &dyn Shape,
203 max_dist: Real,
204 ) -> Result<ClosestPoints, Unsupported> {
205 let ball1 = shape1.as_ball();
206 let ball2 = shape2.as_ball();
207
208 if let (Some(b1), Some(b2)) = (ball1, ball2) {
209 Ok(query::details::closest_points_ball_ball(
210 pos12, b1, b2, max_dist,
211 ))
212 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
213 Ok(query::details::closest_points_ball_convex_polyhedron(
214 pos12, b1, shape2, max_dist,
215 ))
216 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
217 Ok(query::details::closest_points_convex_polyhedron_ball(
218 pos12, shape1, b2, max_dist,
219 ))
220 } else if let (Some(s1), Some(s2)) =
221 (shape1.as_shape::<Segment>(), shape2.as_shape::<Segment>())
222 {
223 Ok(query::details::closest_points_segment_segment(
224 pos12, s1, s2, max_dist,
225 ))
226 } else if let (Some(s1), Some(s2)) = (shape1.as_segment(), shape2.as_segment()) {
231 Ok(query::details::closest_points_segment_segment(
232 pos12, s1, s2, max_dist,
233 ))
234 } else if let (Some(t1), Some(c2)) = (shape1.as_triangle(), shape2.as_cuboid()) {
239 Ok(query::details::closest_points_triangle_cuboid(
240 pos12, t1, c2, max_dist,
241 ))
242 } else if let (Some(p1), Some(s2)) =
243 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
244 {
245 Ok(query::details::closest_points_halfspace_support_map(
246 pos12, p1, s2, max_dist,
247 ))
248 } else if let (Some(s1), Some(p2)) =
249 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
250 {
251 Ok(query::details::closest_points_support_map_halfspace(
252 pos12, s1, p2, max_dist,
253 ))
254 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
255 Ok(query::details::closest_points_support_map_support_map(
256 pos12, s1, s2, max_dist,
257 ))
258 } else {
259 #[cfg(feature = "alloc")]
260 if let Some(c1) = shape1.as_composite_shape() {
261 return Ok(query::details::closest_points_composite_shape_shape(
262 self, pos12, c1, shape2, max_dist,
263 ));
264 } else if let Some(c2) = shape2.as_composite_shape() {
265 return Ok(query::details::closest_points_shape_composite_shape(
266 self, pos12, shape1, c2, max_dist,
267 ));
268 }
269
270 Err(Unsupported)
271 }
272 }
273
274 fn cast_shapes(
275 &self,
276 pos12: &Isometry<Real>,
277 local_vel12: &Vector<Real>,
278 shape1: &dyn Shape,
279 shape2: &dyn Shape,
280 options: ShapeCastOptions,
281 ) -> Result<Option<ShapeCastHit>, Unsupported> {
282 if let (Some(b1), Some(b2)) = (shape1.as_ball(), shape2.as_ball()) {
283 Ok(query::details::cast_shapes_ball_ball(
284 pos12,
285 local_vel12,
286 b1,
287 b2,
288 options,
289 ))
290 } else if let (Some(p1), Some(s2)) =
291 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
292 {
293 Ok(query::details::cast_shapes_halfspace_support_map(
294 pos12,
295 local_vel12,
296 p1,
297 s2,
298 options,
299 ))
300 } else if let (Some(s1), Some(p2)) =
301 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
302 {
303 Ok(query::details::cast_shapes_support_map_halfspace(
304 pos12,
305 local_vel12,
306 s1,
307 p2,
308 options,
309 ))
310 } else {
311 #[cfg(feature = "alloc")]
312 if let Some(heightfield1) = shape1.as_heightfield() {
313 return query::details::cast_shapes_heightfield_shape(
314 self,
315 pos12,
316 local_vel12,
317 heightfield1,
318 shape2,
319 options,
320 );
321 } else if let Some(heightfield2) = shape2.as_heightfield() {
322 return query::details::cast_shapes_shape_heightfield(
323 self,
324 pos12,
325 local_vel12,
326 shape1,
327 heightfield2,
328 options,
329 );
330 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map())
331 {
332 return Ok(query::details::cast_shapes_support_map_support_map(
333 pos12,
334 local_vel12,
335 s1,
336 s2,
337 options,
338 ));
339 } else if let Some(c1) = shape1.as_composite_shape() {
340 return Ok(query::details::cast_shapes_composite_shape_shape(
341 self,
342 pos12,
343 local_vel12,
344 c1,
345 shape2,
346 options,
347 ));
348 } else if let Some(c2) = shape2.as_composite_shape() {
349 return Ok(query::details::cast_shapes_shape_composite_shape(
350 self,
351 pos12,
352 local_vel12,
353 shape1,
354 c2,
355 options,
356 ));
357 } else if let Some(v1) = shape1.as_voxels() {
358 return Ok(query::details::cast_shapes_voxels_shape(
359 self,
360 pos12,
361 local_vel12,
362 v1,
363 shape2,
364 options,
365 ));
366 } else if let Some(v2) = shape2.as_voxels() {
367 return Ok(query::details::cast_shapes_shape_voxels(
368 self,
369 pos12,
370 local_vel12,
371 shape1,
372 v2,
373 options,
374 ));
375 }
376
377 Err(Unsupported)
378 }
379 }
380
381 fn cast_shapes_nonlinear(
382 &self,
383 motion1: &NonlinearRigidMotion,
384 shape1: &dyn Shape,
385 motion2: &NonlinearRigidMotion,
386 shape2: &dyn Shape,
387 start_time: Real,
388 end_time: Real,
389 stop_at_penetration: bool,
390 ) -> Result<Option<ShapeCastHit>, Unsupported> {
391 if let (Some(sm1), Some(sm2)) = (shape1.as_support_map(), shape2.as_support_map()) {
392 let mode = if stop_at_penetration {
393 NonlinearShapeCastMode::StopAtPenetration
394 } else {
395 NonlinearShapeCastMode::directional_toi(shape1, shape2)
396 };
397
398 Ok(
399 query::details::cast_shapes_nonlinear_support_map_support_map(
400 self, motion1, sm1, shape1, motion2, sm2, shape2, start_time, end_time, mode,
401 ),
402 )
403 } else {
404 #[cfg(feature = "alloc")]
405 if let Some(c1) = shape1.as_composite_shape() {
406 return Ok(query::details::cast_shapes_nonlinear_composite_shape_shape(
407 self,
408 motion1,
409 c1,
410 motion2,
411 shape2,
412 start_time,
413 end_time,
414 stop_at_penetration,
415 ));
416 } else if let Some(c2) = shape2.as_composite_shape() {
417 return Ok(query::details::cast_shapes_nonlinear_shape_composite_shape(
418 self,
419 motion1,
420 shape1,
421 motion2,
422 c2,
423 start_time,
424 end_time,
425 stop_at_penetration,
426 ));
427 } else if let Some(c1) = shape1.as_voxels() {
428 return Ok(query::details::cast_shapes_nonlinear_voxels_shape(
429 self,
430 motion1,
431 c1,
432 motion2,
433 shape2,
434 start_time,
435 end_time,
436 stop_at_penetration,
437 ));
438 } else if let Some(c2) = shape2.as_voxels() {
439 return Ok(query::details::cast_shapes_nonlinear_shape_voxels(
440 self,
441 motion1,
442 shape1,
443 motion2,
444 c2,
445 start_time,
446 end_time,
447 stop_at_penetration,
448 ));
449 }
450 Err(Unsupported)
458 }
459 }
460}
461
462#[cfg(feature = "alloc")]
463impl<ManifoldData, ContactData> PersistentQueryDispatcher<ManifoldData, ContactData>
464 for DefaultQueryDispatcher
465where
466 ManifoldData: Default + Clone,
467 ContactData: Default + Copy,
468{
469 fn contact_manifolds(
470 &self,
471 pos12: &Isometry<Real>,
472 shape1: &dyn Shape,
473 shape2: &dyn Shape,
474 prediction: Real,
475 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
476 workspace: &mut Option<ContactManifoldsWorkspace>,
477 ) -> Result<(), Unsupported> {
478 use crate::query::contact_manifolds::*;
479
480 let composite1 = shape1.as_composite_shape();
481 let composite2 = shape2.as_composite_shape();
482
483 if let (Some(composite1), Some(composite2)) = (composite1, composite2) {
484 contact_manifolds_composite_shape_composite_shape(
485 self, pos12, composite1, composite2, prediction, manifolds, workspace,
486 );
487
488 return Ok(());
489 }
490
491 match (shape1.shape_type(), shape2.shape_type()) {
492 (ShapeType::TriMesh, _) | (_, ShapeType::TriMesh) => {
493 contact_manifolds_trimesh_shape_shapes(
494 self, pos12, shape1, shape2, prediction, manifolds, workspace,
495 );
496 }
497 (ShapeType::HeightField, _) => {
498 if let Some(composite2) = composite2 {
499 contact_manifolds_heightfield_composite_shape(
500 self,
501 pos12,
502 &pos12.inverse(),
503 shape1.as_heightfield().unwrap(),
504 composite2,
505 prediction,
506 manifolds,
507 workspace,
508 false,
509 )
510 } else {
511 contact_manifolds_heightfield_shape_shapes(
512 self, pos12, shape1, shape2, prediction, manifolds, workspace,
513 );
514 }
515 }
516 (_, ShapeType::HeightField) => {
517 if let Some(composite1) = composite1 {
518 contact_manifolds_heightfield_composite_shape(
519 self,
520 &pos12.inverse(),
521 pos12,
522 shape2.as_heightfield().unwrap(),
523 composite1,
524 prediction,
525 manifolds,
526 workspace,
527 true,
528 )
529 } else {
530 contact_manifolds_heightfield_shape_shapes(
531 self, pos12, shape1, shape2, prediction, manifolds, workspace,
532 );
533 }
534 }
535 (ShapeType::Voxels, ShapeType::Ball) | (ShapeType::Ball, ShapeType::Voxels) => {
536 contact_manifolds_voxels_ball_shapes(pos12, shape1, shape2, prediction, manifolds)
537 }
538 (ShapeType::Voxels, _) | (_, ShapeType::Voxels) => {
539 contact_manifolds_voxels_shape_shapes(
540 self, pos12, shape1, shape2, prediction, manifolds, workspace,
541 )
542 }
543 _ => {
544 if let Some(composite1) = composite1 {
545 contact_manifolds_composite_shape_shape(
546 self, pos12, composite1, shape2, prediction, manifolds, workspace, false,
547 );
548 } else if let Some(composite2) = composite2 {
549 contact_manifolds_composite_shape_shape(
550 self,
551 &pos12.inverse(),
552 composite2,
553 shape1,
554 prediction,
555 manifolds,
556 workspace,
557 true,
558 );
559 } else {
560 if manifolds.is_empty() {
561 manifolds.push(ContactManifold::new());
562 }
563
564 return self.contact_manifold_convex_convex(
565 pos12,
566 shape1,
567 shape2,
568 None,
569 None,
570 prediction,
571 &mut manifolds[0],
572 );
573 }
574 }
575 }
576
577 Ok(())
578 }
579
580 fn contact_manifold_convex_convex(
581 &self,
582 pos12: &Isometry<Real>,
583 shape1: &dyn Shape,
584 shape2: &dyn Shape,
585 normal_constraints1: Option<&dyn NormalConstraints>,
586 normal_constraints2: Option<&dyn NormalConstraints>,
587 prediction: Real,
588 manifold: &mut ContactManifold<ManifoldData, ContactData>,
589 ) -> Result<(), Unsupported> {
590 use crate::query::contact_manifolds::*;
591
592 match (shape1.shape_type(), shape2.shape_type()) {
593 (ShapeType::Ball, ShapeType::Ball) => {
594 contact_manifold_ball_ball_shapes(pos12, shape1, shape2, prediction, manifold)
595 }
596 (ShapeType::Cuboid, ShapeType::Cuboid) =>
597 contact_manifold_cuboid_cuboid_shapes(pos12, shape1, shape2, prediction, manifold)
598 ,
599 (ShapeType::Capsule, ShapeType::Capsule) => {
607 contact_manifold_capsule_capsule_shapes(pos12, shape1, shape2, prediction, manifold)
608 }
609 (_, ShapeType::Ball) | (ShapeType::Ball, _) => {
610 contact_manifold_convex_ball_shapes(pos12, shape1, shape2, normal_constraints1, normal_constraints2, prediction, manifold)
611 }
612 (ShapeType::Triangle, ShapeType::Cuboid) | (ShapeType::Cuboid, ShapeType::Triangle) => {
615 contact_manifold_cuboid_triangle_shapes(pos12, shape1, shape2, normal_constraints1, normal_constraints2, prediction, manifold)
616 }
617 (ShapeType::HalfSpace, _) => {
618 if let Some((pfm2, border_radius2)) = shape2.as_polygonal_feature_map() {
619 contact_manifold_halfspace_pfm(
620 pos12,
621 shape1.as_halfspace().unwrap(),
622 pfm2,
623 border_radius2,
624 prediction,
625 manifold,
626 false
627 )
628 } else {
629 return Err(Unsupported)
630 }
631 }
632 (_, ShapeType::HalfSpace) => {
633 if let Some((pfm1, border_radius1)) = shape1.as_polygonal_feature_map() {
634 contact_manifold_halfspace_pfm(
635 &pos12.inverse(),
636 shape2.as_halfspace().unwrap(),
637 pfm1,
638 border_radius1,
639 prediction,
640 manifold,
641 true
642 )
643 } else {
644 return Err(Unsupported)
645 }
646 }
647 _ => {
648 if let (Some(pfm1), Some(pfm2)) = (
649 shape1.as_polygonal_feature_map(),
650 shape2.as_polygonal_feature_map(),
651 ) {
652 contact_manifold_pfm_pfm(
653 pos12, pfm1.0, pfm1.1, normal_constraints1, pfm2.0, pfm2.1, normal_constraints2, prediction, manifold,
654 )
655 } else {
656 return Err(Unsupported);
657 }
658 }
659 }
660
661 Ok(())
662 }
663}