1use crate::math::{Pose, 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};
14#[cfg(feature = "alloc")]
15use alloc::vec::Vec;
16
17#[cfg(any(feature = "std", feature = "alloc"))]
18use crate::shape::ShapeType;
19
20#[derive(Debug, Clone)]
174pub struct DefaultQueryDispatcher;
175
176impl QueryDispatcher for DefaultQueryDispatcher {
177 fn intersection_test(
178 &self,
179 pos12: &Pose,
180 shape1: &dyn Shape,
181 shape2: &dyn Shape,
182 ) -> Result<bool, Unsupported> {
183 if let (Some(b1), Some(b2)) = (shape1.as_ball(), shape2.as_ball()) {
184 let p12 = pos12.translation;
185 Ok(query::details::intersection_test_ball_ball(p12, b1, b2))
186 } else if let (Some(c1), Some(c2)) = (shape1.as_cuboid(), shape2.as_cuboid()) {
187 Ok(query::details::intersection_test_cuboid_cuboid(
188 pos12, c1, c2,
189 ))
190 } else if let (Some(t1), Some(c2)) = (shape1.as_triangle(), shape2.as_cuboid()) {
191 Ok(query::details::intersection_test_triangle_cuboid(
192 pos12, t1, c2,
193 ))
194 } else if let (Some(c1), Some(t2)) = (shape1.as_cuboid(), shape2.as_triangle()) {
195 Ok(query::details::intersection_test_cuboid_triangle(
196 pos12, c1, t2,
197 ))
198 } else if let Some(b1) = shape1.as_ball() {
199 Ok(query::details::intersection_test_ball_point_query(
200 pos12, b1, shape2,
201 ))
202 } else if let Some(b2) = shape2.as_ball() {
203 Ok(query::details::intersection_test_point_query_ball(
204 pos12, shape1, b2,
205 ))
206 } else if let (Some(p1), Some(s2)) =
207 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
208 {
209 Ok(query::details::intersection_test_halfspace_support_map(
210 pos12, p1, s2,
211 ))
212 } else if let (Some(s1), Some(p2)) =
213 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
214 {
215 Ok(query::details::intersection_test_support_map_halfspace(
216 pos12, s1, p2,
217 ))
218 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
219 Ok(query::details::intersection_test_support_map_support_map(
220 pos12, s1, s2,
221 ))
222 } else {
223 #[cfg(feature = "alloc")]
224 if let Some(c1) = shape1.as_composite_shape() {
225 return Ok(query::details::intersection_test_composite_shape_shape(
226 self, pos12, c1, shape2,
227 ));
228 } else if let Some(c2) = shape2.as_composite_shape() {
229 return Ok(query::details::intersection_test_shape_composite_shape(
230 self, pos12, shape1, c2,
231 ));
232 } else if let Some(v1) = shape1.as_voxels() {
233 return Ok(query::details::intersection_test_voxels_shape(
234 self, pos12, v1, shape2,
235 ));
236 } else if let Some(v2) = shape2.as_voxels() {
237 return Ok(query::details::intersection_test_shape_voxels(
238 self, pos12, shape1, v2,
239 ));
240 }
241
242 Err(Unsupported)
243 }
244 }
245
246 fn distance(
250 &self,
251 pos12: &Pose,
252 shape1: &dyn Shape,
253 shape2: &dyn Shape,
254 ) -> Result<Real, Unsupported> {
255 let ball1 = shape1.as_ball();
256 let ball2 = shape2.as_ball();
257
258 if let (Some(b1), Some(b2)) = (ball1, ball2) {
259 let p2 = pos12.translation;
260 Ok(query::details::distance_ball_ball(b1, p2, b2))
261 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
262 Ok(query::details::distance_ball_convex_polyhedron(
263 pos12, b1, shape2,
264 ))
265 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
266 Ok(query::details::distance_convex_polyhedron_ball(
267 pos12, shape1, b2,
268 ))
269 } else if let (Some(c1), Some(c2)) = (shape1.as_cuboid(), shape2.as_cuboid()) {
270 Ok(query::details::distance_cuboid_cuboid(pos12, c1, c2))
271 } else if let (Some(s1), Some(s2)) = (shape1.as_segment(), shape2.as_segment()) {
272 Ok(query::details::distance_segment_segment(pos12, s1, s2))
273 } else if let (Some(p1), Some(s2)) =
274 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
275 {
276 Ok(query::details::distance_halfspace_support_map(
277 pos12, p1, s2,
278 ))
279 } else if let (Some(s1), Some(p2)) =
280 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
281 {
282 Ok(query::details::distance_support_map_halfspace(
283 pos12, s1, p2,
284 ))
285 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
286 Ok(query::details::distance_support_map_support_map(
287 pos12, s1, s2,
288 ))
289 } else {
290 #[cfg(feature = "alloc")]
291 if let Some(c1) = shape1.as_composite_shape() {
292 return Ok(query::details::distance_composite_shape_shape(
293 self, pos12, c1, shape2,
294 ));
295 } else if let Some(c2) = shape2.as_composite_shape() {
296 return Ok(query::details::distance_shape_composite_shape(
297 self, pos12, shape1, c2,
298 ));
299 }
300
301 Err(Unsupported)
302 }
303 }
304
305 fn contact(
306 &self,
307 pos12: &Pose,
308 shape1: &dyn Shape,
309 shape2: &dyn Shape,
310 prediction: Real,
311 ) -> Result<Option<Contact>, Unsupported> {
312 let ball1 = shape1.as_ball();
313 let ball2 = shape2.as_ball();
314
315 if let (Some(b1), Some(b2)) = (ball1, ball2) {
316 Ok(query::details::contact_ball_ball(pos12, b1, b2, prediction))
317 } else if let (Some(p1), Some(s2)) =
322 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
323 {
324 Ok(query::details::contact_halfspace_support_map(
325 pos12, p1, s2, prediction,
326 ))
327 } else if let (Some(s1), Some(p2)) =
328 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
329 {
330 Ok(query::details::contact_support_map_halfspace(
331 pos12, s1, p2, prediction,
332 ))
333 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
334 Ok(query::details::contact_ball_convex_polyhedron(
335 pos12, b1, shape2, prediction,
336 ))
337 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
338 Ok(query::details::contact_convex_polyhedron_ball(
339 pos12, shape1, b2, prediction,
340 ))
341 } else {
342 #[cfg(feature = "alloc")]
343 if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
344 return Ok(query::details::contact_support_map_support_map(
345 pos12, s1, s2, prediction,
346 ));
347 } else if let Some(hf1) = shape1.as_heightfield() {
348 return Ok(query::details::contact_heightfield_shape(
349 self, pos12, hf1, shape2, prediction,
350 ));
351 } else if let Some(hf2) = shape2.as_heightfield() {
352 return Ok(query::details::contact_shape_heightfield(
353 self, pos12, shape1, hf2, prediction,
354 ));
355 } else if let Some(c1) = shape1.as_composite_shape() {
356 return Ok(query::details::contact_composite_shape_shape(
357 self, pos12, c1, shape2, prediction,
358 ));
359 } else if let Some(c2) = shape2.as_composite_shape() {
360 return Ok(query::details::contact_shape_composite_shape(
361 self, pos12, shape1, c2, prediction,
362 ));
363 }
364
365 Err(Unsupported)
366 }
367 }
368
369 fn closest_points(
370 &self,
371 pos12: &Pose,
372 shape1: &dyn Shape,
373 shape2: &dyn Shape,
374 max_dist: Real,
375 ) -> Result<ClosestPoints, Unsupported> {
376 let ball1 = shape1.as_ball();
377 let ball2 = shape2.as_ball();
378
379 if let (Some(b1), Some(b2)) = (ball1, ball2) {
380 Ok(query::details::closest_points_ball_ball(
381 pos12, b1, b2, max_dist,
382 ))
383 } else if let (Some(b1), true) = (ball1, shape2.is_convex()) {
384 Ok(query::details::closest_points_ball_convex_polyhedron(
385 pos12, b1, shape2, max_dist,
386 ))
387 } else if let (true, Some(b2)) = (shape1.is_convex(), ball2) {
388 Ok(query::details::closest_points_convex_polyhedron_ball(
389 pos12, shape1, b2, max_dist,
390 ))
391 } else if let (Some(s1), Some(s2)) =
392 (shape1.as_shape::<Segment>(), shape2.as_shape::<Segment>())
393 {
394 Ok(query::details::closest_points_segment_segment(
395 pos12, s1, s2, max_dist,
396 ))
397 } else if let (Some(s1), Some(s2)) = (shape1.as_segment(), shape2.as_segment()) {
402 Ok(query::details::closest_points_segment_segment(
403 pos12, s1, s2, max_dist,
404 ))
405 } else if let (Some(t1), Some(c2)) = (shape1.as_triangle(), shape2.as_cuboid()) {
410 Ok(query::details::closest_points_triangle_cuboid(
411 pos12, t1, c2, max_dist,
412 ))
413 } else if let (Some(p1), Some(s2)) =
414 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
415 {
416 Ok(query::details::closest_points_halfspace_support_map(
417 pos12, p1, s2, max_dist,
418 ))
419 } else if let (Some(s1), Some(p2)) =
420 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
421 {
422 Ok(query::details::closest_points_support_map_halfspace(
423 pos12, s1, p2, max_dist,
424 ))
425 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map()) {
426 Ok(query::details::closest_points_support_map_support_map(
427 pos12, s1, s2, max_dist,
428 ))
429 } else {
430 #[cfg(feature = "alloc")]
431 if let Some(c1) = shape1.as_composite_shape() {
432 return Ok(query::details::closest_points_composite_shape_shape(
433 self, pos12, c1, shape2, max_dist,
434 ));
435 } else if let Some(c2) = shape2.as_composite_shape() {
436 return Ok(query::details::closest_points_shape_composite_shape(
437 self, pos12, shape1, c2, max_dist,
438 ));
439 }
440
441 Err(Unsupported)
442 }
443 }
444
445 fn cast_shapes(
446 &self,
447 pos12: &Pose,
448 local_vel12: Vector,
449 shape1: &dyn Shape,
450 shape2: &dyn Shape,
451 options: ShapeCastOptions,
452 ) -> Result<Option<ShapeCastHit>, Unsupported> {
453 if let (Some(b1), Some(b2)) = (shape1.as_ball(), shape2.as_ball()) {
454 Ok(query::details::cast_shapes_ball_ball(
455 pos12,
456 local_vel12,
457 b1,
458 b2,
459 options,
460 ))
461 } else if let (Some(p1), Some(s2)) =
462 (shape1.as_shape::<HalfSpace>(), shape2.as_support_map())
463 {
464 Ok(query::details::cast_shapes_halfspace_support_map(
465 pos12,
466 local_vel12,
467 p1,
468 s2,
469 options,
470 ))
471 } else if let (Some(s1), Some(p2)) =
472 (shape1.as_support_map(), shape2.as_shape::<HalfSpace>())
473 {
474 Ok(query::details::cast_shapes_support_map_halfspace(
475 pos12,
476 local_vel12,
477 s1,
478 p2,
479 options,
480 ))
481 } else {
482 #[cfg(feature = "alloc")]
483 if let Some(heightfield1) = shape1.as_heightfield() {
484 return query::details::cast_shapes_heightfield_shape(
485 self,
486 pos12,
487 local_vel12,
488 heightfield1,
489 shape2,
490 options,
491 );
492 } else if let Some(heightfield2) = shape2.as_heightfield() {
493 return query::details::cast_shapes_shape_heightfield(
494 self,
495 pos12,
496 local_vel12,
497 shape1,
498 heightfield2,
499 options,
500 );
501 } else if let (Some(s1), Some(s2)) = (shape1.as_support_map(), shape2.as_support_map())
502 {
503 return Ok(query::details::cast_shapes_support_map_support_map(
504 pos12,
505 local_vel12,
506 s1,
507 s2,
508 options,
509 ));
510 } else if let Some(c1) = shape1.as_composite_shape() {
511 return Ok(query::details::cast_shapes_composite_shape_shape(
512 self,
513 pos12,
514 local_vel12,
515 c1,
516 shape2,
517 options,
518 ));
519 } else if let Some(c2) = shape2.as_composite_shape() {
520 return Ok(query::details::cast_shapes_shape_composite_shape(
521 self,
522 pos12,
523 local_vel12,
524 shape1,
525 c2,
526 options,
527 ));
528 } else if let Some(v1) = shape1.as_voxels() {
529 return Ok(query::details::cast_shapes_voxels_shape(
530 self,
531 pos12,
532 local_vel12,
533 v1,
534 shape2,
535 options,
536 ));
537 } else if let Some(v2) = shape2.as_voxels() {
538 return Ok(query::details::cast_shapes_shape_voxels(
539 self,
540 pos12,
541 local_vel12,
542 shape1,
543 v2,
544 options,
545 ));
546 }
547
548 Err(Unsupported)
549 }
550 }
551
552 fn cast_shapes_nonlinear(
553 &self,
554 motion1: &NonlinearRigidMotion,
555 shape1: &dyn Shape,
556 motion2: &NonlinearRigidMotion,
557 shape2: &dyn Shape,
558 start_time: Real,
559 end_time: Real,
560 stop_at_penetration: bool,
561 ) -> Result<Option<ShapeCastHit>, Unsupported> {
562 if let (Some(sm1), Some(sm2)) = (shape1.as_support_map(), shape2.as_support_map()) {
563 let mode = if stop_at_penetration {
564 NonlinearShapeCastMode::StopAtPenetration
565 } else {
566 NonlinearShapeCastMode::directional_toi(shape1, shape2)
567 };
568
569 Ok(
570 query::details::cast_shapes_nonlinear_support_map_support_map(
571 self, motion1, sm1, shape1, motion2, sm2, shape2, start_time, end_time, mode,
572 ),
573 )
574 } else {
575 #[cfg(feature = "alloc")]
576 if let Some(c1) = shape1.as_composite_shape() {
577 return Ok(query::details::cast_shapes_nonlinear_composite_shape_shape(
578 self,
579 motion1,
580 c1,
581 motion2,
582 shape2,
583 start_time,
584 end_time,
585 stop_at_penetration,
586 ));
587 } else if let Some(c2) = shape2.as_composite_shape() {
588 return Ok(query::details::cast_shapes_nonlinear_shape_composite_shape(
589 self,
590 motion1,
591 shape1,
592 motion2,
593 c2,
594 start_time,
595 end_time,
596 stop_at_penetration,
597 ));
598 } else if let Some(c1) = shape1.as_voxels() {
599 return Ok(query::details::cast_shapes_nonlinear_voxels_shape(
600 self,
601 motion1,
602 c1,
603 motion2,
604 shape2,
605 start_time,
606 end_time,
607 stop_at_penetration,
608 ));
609 } else if let Some(c2) = shape2.as_voxels() {
610 return Ok(query::details::cast_shapes_nonlinear_shape_voxels(
611 self,
612 motion1,
613 shape1,
614 motion2,
615 c2,
616 start_time,
617 end_time,
618 stop_at_penetration,
619 ));
620 }
621 Err(Unsupported)
629 }
630 }
631}
632
633#[cfg(feature = "alloc")]
634impl<ManifoldData, ContactData> PersistentQueryDispatcher<ManifoldData, ContactData>
635 for DefaultQueryDispatcher
636where
637 ManifoldData: Default + Clone,
638 ContactData: Default + Copy,
639{
640 fn contact_manifolds(
641 &self,
642 pos12: &Pose,
643 shape1: &dyn Shape,
644 shape2: &dyn Shape,
645 prediction: Real,
646 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
647 workspace: &mut Option<ContactManifoldsWorkspace>,
648 ) -> Result<(), Unsupported> {
649 use crate::query::contact_manifolds::*;
650
651 let composite1 = shape1.as_composite_shape();
652 let composite2 = shape2.as_composite_shape();
653
654 if let (Some(composite1), Some(composite2)) = (composite1, composite2) {
655 contact_manifolds_composite_shape_composite_shape(
656 self, pos12, composite1, composite2, prediction, manifolds, workspace,
657 );
658
659 return Ok(());
660 }
661
662 match (shape1.shape_type(), shape2.shape_type()) {
663 (ShapeType::TriMesh, _) | (_, ShapeType::TriMesh) => {
664 contact_manifolds_trimesh_shape_shapes(
665 self, pos12, shape1, shape2, prediction, manifolds, workspace,
666 );
667 }
668 (ShapeType::HeightField, _) => {
669 if let Some(composite2) = composite2 {
670 contact_manifolds_heightfield_composite_shape(
671 self,
672 pos12,
673 &pos12.inverse(),
674 shape1.as_heightfield().unwrap(),
675 composite2,
676 prediction,
677 manifolds,
678 workspace,
679 false,
680 )
681 } else {
682 contact_manifolds_heightfield_shape_shapes(
683 self, pos12, shape1, shape2, prediction, manifolds, workspace,
684 );
685 }
686 }
687 (_, ShapeType::HeightField) => {
688 if let Some(composite1) = composite1 {
689 contact_manifolds_heightfield_composite_shape(
690 self,
691 &pos12.inverse(),
692 pos12,
693 shape2.as_heightfield().unwrap(),
694 composite1,
695 prediction,
696 manifolds,
697 workspace,
698 true,
699 )
700 } else {
701 contact_manifolds_heightfield_shape_shapes(
702 self, pos12, shape1, shape2, prediction, manifolds, workspace,
703 );
704 }
705 }
706 (ShapeType::Voxels, ShapeType::Voxels) => contact_manifolds_voxels_voxels_shapes(
707 self, pos12, shape1, shape2, prediction, manifolds, workspace,
708 ),
709 (ShapeType::Voxels, ShapeType::Ball) | (ShapeType::Ball, ShapeType::Voxels) => {
710 contact_manifolds_voxels_ball_shapes(pos12, shape1, shape2, prediction, manifolds)
711 }
712 (ShapeType::Voxels, _) | (_, ShapeType::Voxels) => {
713 if composite1.is_some() || composite2.is_some() {
714 contact_manifolds_voxels_composite_shape_shapes(
715 self, pos12, shape1, shape2, prediction, manifolds, workspace,
716 )
717 } else {
718 contact_manifolds_voxels_shape_shapes(
719 self, pos12, shape1, shape2, prediction, manifolds, workspace,
720 )
721 }
722 }
723 _ => {
724 if let Some(composite1) = composite1 {
725 contact_manifolds_composite_shape_shape(
726 self, pos12, composite1, shape2, prediction, manifolds, workspace, false,
727 );
728 } else if let Some(composite2) = composite2 {
729 contact_manifolds_composite_shape_shape(
730 self,
731 &pos12.inverse(),
732 composite2,
733 shape1,
734 prediction,
735 manifolds,
736 workspace,
737 true,
738 );
739 } else {
740 if manifolds.is_empty() {
741 manifolds.push(ContactManifold::new());
742 }
743
744 return self.contact_manifold_convex_convex(
745 pos12,
746 shape1,
747 shape2,
748 None,
749 None,
750 prediction,
751 &mut manifolds[0],
752 );
753 }
754 }
755 }
756
757 Ok(())
758 }
759
760 fn contact_manifold_convex_convex(
761 &self,
762 pos12: &Pose,
763 shape1: &dyn Shape,
764 shape2: &dyn Shape,
765 normal_constraints1: Option<&dyn NormalConstraints>,
766 normal_constraints2: Option<&dyn NormalConstraints>,
767 prediction: Real,
768 manifold: &mut ContactManifold<ManifoldData, ContactData>,
769 ) -> Result<(), Unsupported> {
770 use crate::query::contact_manifolds::*;
771
772 match (shape1.shape_type(), shape2.shape_type()) {
773 (ShapeType::Ball, ShapeType::Ball) => {
774 contact_manifold_ball_ball_shapes(pos12, shape1, shape2, prediction, manifold)
775 }
776 (ShapeType::Cuboid, ShapeType::Cuboid) =>
777 contact_manifold_cuboid_cuboid_shapes(pos12, shape1, shape2, prediction, manifold)
778 ,
779 (ShapeType::Capsule, ShapeType::Capsule) => {
787 contact_manifold_capsule_capsule_shapes(pos12, shape1, shape2, prediction, manifold)
788 }
789 (_, ShapeType::Ball) | (ShapeType::Ball, _) => {
790 contact_manifold_convex_ball_shapes(pos12, shape1, shape2, normal_constraints1, normal_constraints2, prediction, manifold)
791 }
792 (ShapeType::Triangle, ShapeType::Cuboid) | (ShapeType::Cuboid, ShapeType::Triangle) => {
795 contact_manifold_cuboid_triangle_shapes(pos12, shape1, shape2, normal_constraints1, normal_constraints2, prediction, manifold)
796 }
797 (ShapeType::HalfSpace, _) => {
798 if let Some((pfm2, border_radius2)) = shape2.as_polygonal_feature_map() {
799 contact_manifold_halfspace_pfm(
800 pos12,
801 shape1.as_halfspace().unwrap(),
802 pfm2,
803 border_radius2,
804 prediction,
805 manifold,
806 false
807 )
808 } else {
809 return Err(Unsupported)
810 }
811 }
812 (_, ShapeType::HalfSpace) => {
813 if let Some((pfm1, border_radius1)) = shape1.as_polygonal_feature_map() {
814 contact_manifold_halfspace_pfm(
815 &pos12.inverse(),
816 shape2.as_halfspace().unwrap(),
817 pfm1,
818 border_radius1,
819 prediction,
820 manifold,
821 true
822 )
823 } else {
824 return Err(Unsupported)
825 }
826 }
827 _ => {
828 if let (Some(pfm1), Some(pfm2)) = (
829 shape1.as_polygonal_feature_map(),
830 shape2.as_polygonal_feature_map(),
831 ) {
832 contact_manifold_pfm_pfm(
833 pos12, pfm1.0, pfm1.1, normal_constraints1, pfm2.0, pfm2.1, normal_constraints2, prediction, manifold,
834 )
835 } else {
836 return Err(Unsupported);
837 }
838 }
839 }
840
841 Ok(())
842 }
843}