parry3d/query/
query_dispatcher.rs

1//! Query dispatcher system for extensible geometric queries.
2//!
3//! # Overview
4//!
5//! This module provides the **query dispatcher** abstraction, which allows Parry to perform
6//! geometric queries (distance, contact, ray casting, etc.) between different shape types in
7//! an extensible and customizable way.
8//!
9//! # What is a Query Dispatcher?
10//!
11//! A query dispatcher is an object that knows how to perform geometric queries between pairs
12//! of shapes. When you ask "what is the distance between shape A and shape B?", the query
13//! dispatcher:
14//!
15//! 1. Examines the types of both shapes (Ball, Cuboid, ConvexMesh, etc.)
16//! 2. Selects the most appropriate algorithm for that shape pair
17//! 3. Executes the query and returns the result
18//!
19//! For example, computing distance between two balls uses a simple formula, while computing
20//! distance between two convex meshes requires the GJK algorithm. The query dispatcher
21//! handles this selection automatically.
22//!
23//! # Why Do Query Dispatchers Exist?
24//!
25//! Query dispatchers provide **extensibility** for several use cases:
26//!
27//! 1. **Custom Shapes**: If you implement a custom shape type (e.g., a superellipsoid or
28//!    implicit surface), you can create a custom query dispatcher that knows how to handle
29//!    queries involving your shape, while delegating other queries to the default dispatcher.
30//!
31//! 2. **Specialized Algorithms**: You might have a faster algorithm for specific shape pairs
32//!    in your application domain. A custom dispatcher lets you override just those cases.
33//!
34//! 3. **Debugging and Profiling**: You can wrap the default dispatcher to log query calls,
35//!    collect statistics, or inject debug visualizations.
36//!
37//! 4. **Fallback Chains**: Multiple dispatchers can be chained together using the `chain()`
38//!    method, so if one dispatcher doesn't support a query, it automatically falls back to
39//!    the next one.
40//!
41//! # When to Use Query Dispatchers
42//!
43//! Most users will never need to directly use or implement query dispatchers. The high-level
44//! query functions in [`crate::query`] use the [`DefaultQueryDispatcher`](crate::query::DefaultQueryDispatcher) automatically.
45//!
46//! You should implement a custom query dispatcher when:
47//!
48//! - You have custom shape types not supported by Parry
49//! - You need specialized algorithms for specific shape pairs
50//! - You're integrating Parry into a larger system that needs to intercept queries
51//! - You want to add logging, profiling, or debugging to queries
52//!
53//! # Basic Usage
54//!
55//! ## Using the Default Dispatcher
56//!
57//! The simplest way is to use the free functions in [`crate::query`], which use the default
58//! dispatcher internally:
59//!
60//! ```
61//! # #[cfg(all(feature = "dim3", feature = "f32"))] {
62//! use parry3d::query;
63//! use parry3d::shape::Ball;
64//! use parry3d::na::Isometry3;
65//!
66//! let ball1 = Ball::new(0.5);
67//! let ball2 = Ball::new(1.0);
68//! let pos1 = Isometry3::identity();
69//! let pos2 = Isometry3::translation(5.0, 0.0, 0.0);
70//!
71//! // Uses DefaultQueryDispatcher automatically
72//! let distance = query::distance(&pos1, &ball1, &pos2, &ball2);
73//! # }
74//! ```
75//!
76//! ## Using a Dispatcher Directly
77//!
78//! If you need explicit control, you can create and use a dispatcher:
79//!
80//! ```
81//! # #[cfg(all(feature = "dim3", feature = "f32"))] {
82//! use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
83//! use parry3d::shape::Ball;
84//! use parry3d::na::Isometry3;
85//!
86//! let dispatcher = DefaultQueryDispatcher;
87//! let ball1 = Ball::new(0.5);
88//! let ball2 = Ball::new(1.0);
89//!
90//! let pos1 = Isometry3::identity();
91//! let pos2 = Isometry3::translation(5.0, 0.0, 0.0);
92//!
93//! // Compute relative position of shape2 in shape1's local space
94//! let pos12 = pos1.inv_mul(&pos2);
95//!
96//! let distance = dispatcher.distance(&pos12, &ball1, &ball2).unwrap();
97//! # }
98//! ```
99//!
100//! ## Chaining Dispatchers
101//!
102//! You can chain multiple dispatchers to create a fallback sequence:
103//!
104//! ```ignore
105//! use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
106//!
107//! // Create a custom dispatcher for your custom shapes
108//! let custom = MyCustomDispatcher::new();
109//!
110//! // Chain it with the default dispatcher as a fallback
111//! let dispatcher = custom.chain(DefaultQueryDispatcher);
112//!
113//! // Now dispatcher will try your custom dispatcher first,
114//! // and fall back to the default if it returns Unsupported
115//! ```
116//!
117//! # Implementing a Custom Query Dispatcher
118//!
119//! To implement a custom query dispatcher, implement the [`QueryDispatcher`] trait:
120//!
121//! ```ignore
122//! use parry3d::query::{QueryDispatcher, Unsupported};
123//! use parry3d::shape::Shape;
124//! use parry3d::math::{Isometry, Real};
125//!
126//! struct MyDispatcher {
127//!     // Your dispatcher state
128//! }
129//!
130//! impl QueryDispatcher for MyDispatcher {
131//!     fn intersection_test(
132//!         &self,
133//!         pos12: &Isometry<Real>,
134//!         g1: &dyn Shape,
135//!         g2: &dyn Shape,
136//!     ) -> Result<bool, Unsupported> {
137//!         // Try to downcast to your custom shape types
138//!         if let (Some(my_shape1), Some(my_shape2)) = (
139//!             g1.as_any().downcast_ref::<MyCustomShape>(),
140//!             g2.as_any().downcast_ref::<MyCustomShape>(),
141//!         ) {
142//!             // Implement your custom intersection test
143//!             Ok(my_custom_intersection_test(my_shape1, my_shape2, pos12))
144//!         } else {
145//!             // Return Unsupported for shape pairs you don't handle
146//!             Err(Unsupported)
147//!         }
148//!     }
149//!
150//!     fn distance(
151//!         &self,
152//!         pos12: &Isometry<Real>,
153//!         g1: &dyn Shape,
154//!         g2: &dyn Shape,
155//!     ) -> Result<Real, Unsupported> {
156//!         // Implement other query methods similarly
157//!         Err(Unsupported)
158//!     }
159//!
160//!     // ... implement other required methods
161//! }
162//! ```
163//!
164//! # Important Notes
165//!
166//! ## The `pos12` Parameter
167//!
168//! All query methods take a `pos12` parameter, which is the **relative position** of shape 2
169//! in shape 1's local coordinate frame. This is computed as:
170//!
171//! ```ignore
172//! let pos12 = pos1.inv_mul(&pos2);  // Transform from g2's space to g1's space
173//! ```
174//!
175//! This convention reduces the number of transformations needed during queries.
176//!
177//! ## Thread Safety
178//!
179//! Query dispatchers must implement `Send + Sync` because they may be shared across threads
180//! in parallel collision detection scenarios (e.g., when using Rapier physics engine).
181//!
182//! ## Error Handling
183//!
184//! Query methods return `Result<T, Unsupported>`. Return `Err(Unsupported)` when:
185//! - The dispatcher doesn't know how to handle the given shape pair
186//! - The shapes cannot be queried with the requested operation
187//!
188//! When chaining dispatchers, returning `Unsupported` allows the next dispatcher in the
189//! chain to try handling the query.
190
191use crate::math::{Isometry, Real, Vector};
192use crate::query::details::ShapeCastOptions;
193#[cfg(feature = "alloc")]
194use crate::query::{
195    contact_manifolds::{ContactManifoldsWorkspace, NormalConstraints},
196    ContactManifold,
197};
198use crate::query::{ClosestPoints, Contact, NonlinearRigidMotion, ShapeCastHit, Unsupported};
199use crate::shape::Shape;
200#[cfg(feature = "alloc")]
201use alloc::vec::Vec;
202
203#[cfg(feature = "alloc")]
204/// A query dispatcher for queries relying on spatial coherence, including contact-manifold computation.
205///
206/// This trait extends [`QueryDispatcher`] with methods that maintain persistent state between
207/// queries to improve performance through **spatial and temporal coherence**.
208///
209/// # What is Spatial Coherence?
210///
211/// Spatial coherence is the principle that objects that are close to each other in one frame
212/// are likely to remain close in subsequent frames. Contact manifolds exploit this by:
213///
214/// 1. Tracking contact points over multiple frames
215/// 2. Reusing previous contact information to accelerate new queries
216/// 3. Maintaining contact IDs for physics solvers to track persistent contacts
217///
218/// # Contact Manifolds vs Single Contacts
219///
220/// - **Single Contact** ([`QueryDispatcher::contact`]): Returns one contact point, suitable
221///   for one-off queries or simple collision detection.
222///
223/// - **Contact Manifold** ([`PersistentQueryDispatcher::contact_manifolds`]): Returns multiple
224///   contact points that persist across frames, essential for stable physics simulation.
225///
226/// # When to Use This Trait
227///
228/// Use `PersistentQueryDispatcher` when:
229/// - Implementing physics simulation that needs stable contact tracking
230/// - Building a custom physics engine on top of Parry
231/// - Optimizing repeated collision queries between the same shape pairs
232///
233/// # Generic Parameters
234///
235/// - `ManifoldData`: Custom data attached to each contact manifold (default: `()`)
236/// - `ContactData`: Custom data attached to each contact point (default: `()`)
237///
238/// These allow physics engines to attach solver-specific data to contacts without modifying
239/// Parry's core types.
240pub trait PersistentQueryDispatcher<ManifoldData = (), ContactData = ()>: QueryDispatcher {
241    /// Compute all the contacts between two shapes.
242    ///
243    /// The output is written into `manifolds` and `context`. Both can persist
244    /// between multiple calls to `contacts` by re-using the result of the previous
245    /// call to `contacts`. This persistence can significantly improve collision
246    /// detection performances by allowing the underlying algorithms to exploit
247    /// spatial and temporal coherence.
248    fn contact_manifolds(
249        &self,
250        pos12: &Isometry<Real>,
251        g1: &dyn Shape,
252        g2: &dyn Shape,
253        prediction: Real,
254        manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
255        workspace: &mut Option<ContactManifoldsWorkspace>,
256    ) -> Result<(), Unsupported>;
257
258    /// Computes the contact-manifold between two convex shapes.
259    fn contact_manifold_convex_convex(
260        &self,
261        pos12: &Isometry<Real>,
262        g1: &dyn Shape,
263        g2: &dyn Shape,
264        normal_constraints1: Option<&dyn NormalConstraints>,
265        normal_constraints2: Option<&dyn NormalConstraints>,
266        prediction: Real,
267        manifold: &mut ContactManifold<ManifoldData, ContactData>,
268    ) -> Result<(), Unsupported>;
269}
270
271/// Dispatcher for pairwise geometric queries between shapes.
272///
273/// This is the core trait for performing geometric queries (distance, intersection, contact, etc.)
274/// between pairs of shapes in Parry. It provides a uniform interface for querying different shape
275/// combinations.
276///
277/// # Purpose
278///
279/// The `QueryDispatcher` trait serves as an abstraction layer that:
280///
281/// 1. **Decouples query algorithms from shape types**: Different shape pairs may require different
282///    algorithms (e.g., sphere-sphere uses simple math, while convex-convex uses GJK/EPA).
283///
284/// 2. **Enables extensibility**: You can implement custom dispatchers to add support for custom
285///    shape types or specialized algorithms without modifying Parry's core code.
286///
287/// 3. **Provides fallback mechanisms**: Dispatchers can be chained together using [`chain()`](Self::chain),
288///    allowing graceful fallback when a query is not supported.
289///
290/// # The `pos12` Parameter Convention
291///
292/// All query methods in this trait take a `pos12` parameter, which represents the **relative
293/// position** of shape 2 (`g2`) in shape 1's (`g1`) local coordinate frame:
294///
295/// ```ignore
296/// pos12 = pos1.inverse() * pos2
297/// ```
298///
299/// This convention is used because:
300/// - It reduces redundant transformations during query execution
301/// - Many algorithms naturally work in one shape's local space
302/// - It's more efficient than passing two separate world-space positions
303///
304/// When using the high-level query functions, this transformation is done automatically.
305///
306/// # Query Methods Overview
307///
308/// The trait provides several categories of queries:
309///
310/// ## Basic Queries
311/// - [`intersection_test`](Self::intersection_test): Boolean intersection check (fastest)
312/// - [`distance`](Self::distance): Minimum separating distance
313/// - [`closest_points`](Self::closest_points): Pair of closest points
314/// - [`contact`](Self::contact): Contact point with penetration depth
315///
316/// ## Motion Queries (Time of Impact)
317/// - [`cast_shapes`](Self::cast_shapes): Linear motion (translation only)
318/// - [`cast_shapes_nonlinear`](Self::cast_shapes_nonlinear): Nonlinear motion (translation + rotation)
319///
320/// # Thread Safety
321///
322/// Query dispatchers must be `Send + Sync` because they're often shared across threads in:
323/// - Parallel collision detection
324/// - Physics simulations with multi-threaded broad phase
325/// - Game engines with parallel scene queries
326///
327/// Ensure your custom dispatcher implementations are thread-safe or use appropriate synchronization.
328///
329/// # Error Handling with `Unsupported`
330///
331/// All query methods return `Result<T, Unsupported>`. The `Unsupported` error indicates:
332///
333/// - The dispatcher doesn't know how to handle the given shape pair
334/// - The shapes don't support this type of query
335/// - The query is mathematically undefined for these shapes
336///
337/// When chaining dispatchers with [`chain()`](Self::chain), returning `Unsupported` causes the
338/// next dispatcher in the chain to be tried.
339///
340/// # Example: Using the Default Dispatcher
341///
342/// ```
343/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
344/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
345/// use parry3d::shape::{Ball, Cuboid};
346/// use parry3d::na::{Isometry3, Vector3};
347///
348/// let dispatcher = DefaultQueryDispatcher;
349///
350/// let ball = Ball::new(1.0);
351/// let cuboid = Cuboid::new(Vector3::new(2.0, 2.0, 2.0));
352///
353/// let pos1 = Isometry3::identity();
354/// let pos2 = Isometry3::translation(5.0, 0.0, 0.0);
355/// let pos12 = pos1.inv_mul(&pos2);
356///
357/// // Test intersection
358/// let intersects = dispatcher.intersection_test(&pos12, &ball, &cuboid).unwrap();
359///
360/// // Compute distance
361/// let dist = dispatcher.distance(&pos12, &ball, &cuboid).unwrap();
362///
363/// println!("Intersects: {}, Distance: {}", intersects, dist);
364/// # }
365/// ```
366///
367/// # Example: Chaining Dispatchers
368///
369/// ```ignore
370/// # {
371/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
372///
373/// struct MyCustomDispatcher;
374///
375/// impl QueryDispatcher for MyCustomDispatcher {
376///     fn distance(
377///         &self,
378///         pos12: &Isometry<Real>,
379///         g1: &dyn Shape,
380///         g2: &dyn Shape,
381///     ) -> Result<Real, Unsupported> {
382///         // Handle custom shape types
383///         if let Some(my_shape) = g1.as_any().downcast_ref::<MyShape>() {
384///             // ... custom distance computation
385///             Ok(computed_distance)
386///         } else {
387///             // Don't know how to handle this, let the next dispatcher try
388///             Err(Unsupported)
389///         }
390///     }
391///
392///     // ... implement other methods
393/// }
394///
395/// // Chain custom dispatcher with default as fallback
396/// let dispatcher = MyCustomDispatcher.chain(DefaultQueryDispatcher);
397///
398/// // Now all queries try custom dispatcher first, then default
399/// let dist = dispatcher.distance(&pos12, shape1, shape2)?;
400/// # }
401/// ```
402///
403/// # See Also
404///
405/// - [`DefaultQueryDispatcher`](crate::query::DefaultQueryDispatcher): The built-in implementation used by Parry
406/// - [`PersistentQueryDispatcher`]: Extended trait for contact manifold queries
407/// - [`crate::query`]: High-level query functions that use dispatchers internally
408pub trait QueryDispatcher: Send + Sync {
409    /// Tests whether two shapes are intersecting.
410    fn intersection_test(
411        &self,
412        pos12: &Isometry<Real>,
413        g1: &dyn Shape,
414        g2: &dyn Shape,
415    ) -> Result<bool, Unsupported>;
416
417    /// Computes the minimum distance separating two shapes.
418    ///
419    /// Returns `0.0` if the objects are touching or penetrating.
420    fn distance(
421        &self,
422        pos12: &Isometry<Real>,
423        g1: &dyn Shape,
424        g2: &dyn Shape,
425    ) -> Result<Real, Unsupported>;
426
427    /// Computes one pair of contact points point between two shapes.
428    ///
429    /// Returns `None` if the objects are separated by a distance greater than `prediction`.
430    fn contact(
431        &self,
432        pos12: &Isometry<Real>,
433        g1: &dyn Shape,
434        g2: &dyn Shape,
435        prediction: Real,
436    ) -> Result<Option<Contact>, Unsupported>;
437
438    /// Computes the pair of closest points between two shapes.
439    ///
440    /// Returns `ClosestPoints::Disjoint` if the objects are separated by a distance greater than `max_dist`.
441    fn closest_points(
442        &self,
443        pos12: &Isometry<Real>,
444        g1: &dyn Shape,
445        g2: &dyn Shape,
446        max_dist: Real,
447    ) -> Result<ClosestPoints, Unsupported>;
448
449    /// Computes the smallest time when two shapes under translational movement are separated by a
450    /// distance smaller or equal to `distance`.
451    ///
452    /// Returns `0.0` if the objects are touching or penetrating.
453    ///
454    /// # Parameters
455    /// - `pos12`: the position of the second shape relative to the first shape.
456    /// - `local_vel12`: the relative velocity between the two shapes, expressed in the local-space
457    ///   of the first shape. In other world: `pos1.inverse() * (vel2 - vel1)`.
458    /// - `g1`: the first shape involved in the shape-cast.
459    /// - `g2`: the second shape involved in the shape-cast.
460    /// - `target_dist`: a hit will be returned as soon as the two shapes get closer than `target_dist`.
461    /// - `max_time_of_impact`: the maximum allowed travel time. This method returns `None` if the time-of-impact
462    ///   detected is theater than this value.
463    fn cast_shapes(
464        &self,
465        pos12: &Isometry<Real>,
466        local_vel12: &Vector<Real>,
467        g1: &dyn Shape,
468        g2: &dyn Shape,
469        options: ShapeCastOptions,
470    ) -> Result<Option<ShapeCastHit>, Unsupported>;
471
472    /// Construct a `QueryDispatcher` that falls back on `other` for cases not handled by `self`
473    fn chain<U: QueryDispatcher>(self, other: U) -> QueryDispatcherChain<Self, U>
474    where
475        Self: Sized,
476    {
477        QueryDispatcherChain(self, other)
478    }
479
480    /// Computes the smallest time of impact of two shapes under translational and rotational movement.
481    ///
482    /// # Parameters
483    /// * `motion1` - The motion of the first shape.
484    /// * `g1` - The first shape involved in the query.
485    /// * `motion2` - The motion of the second shape.
486    /// * `g2` - The second shape involved in the query.
487    /// * `start_time` - The starting time of the interval where the motion takes place.
488    /// * `end_time` - The end time of the interval where the motion takes place.
489    /// * `stop_at_penetration` - If the casted shape starts in a penetration state with any
490    ///   collider, two results are possible. If `stop_at_penetration` is `true` then, the
491    ///   result will have a `time_of_impact` equal to `start_time`. If `stop_at_penetration` is `false`
492    ///   then the nonlinear shape-casting will see if further motion wrt. the penetration normal
493    ///   would result in tunnelling. If it does not (i.e. we have a separating velocity along
494    ///   that normal) then the nonlinear shape-casting will attempt to find another impact,
495    ///   at a time `> start_time` that could result in tunnelling.
496    fn cast_shapes_nonlinear(
497        &self,
498        motion1: &NonlinearRigidMotion,
499        g1: &dyn Shape,
500        motion2: &NonlinearRigidMotion,
501        g2: &dyn Shape,
502        start_time: Real,
503        end_time: Real,
504        stop_at_penetration: bool,
505    ) -> Result<Option<ShapeCastHit>, Unsupported>;
506}
507
508/// A chain of two query dispatchers that provides fallback behavior.
509///
510/// This struct is created by calling [`QueryDispatcher::chain()`] and allows combining multiple
511/// dispatchers into a fallback sequence. When a query is performed:
512///
513/// 1. The first dispatcher (`T`) is tried
514/// 2. If it returns `Err(Unsupported)`, the second dispatcher (`U`) is tried
515/// 3. If the second also returns `Unsupported`, the error is propagated
516///
517/// # Use Cases
518///
519/// Dispatcher chains are useful for:
520///
521/// - **Custom shapes with default fallback**: Handle your custom shapes specifically, but fall
522///   back to Parry's default dispatcher for standard shapes
523///
524/// - **Performance optimization**: Try a fast specialized algorithm first, fall back to a general
525///   but slower algorithm if needed
526///
527/// - **Progressive feature support**: Layer dispatchers that support different feature sets
528///
529/// - **Debugging**: Wrap the default dispatcher with a logging dispatcher that passes through
530///
531/// # Example
532///
533/// ```ignore
534/// # {
535/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
536///
537/// // A dispatcher that handles only custom shapes
538/// struct CustomShapeDispatcher;
539/// impl QueryDispatcher for CustomShapeDispatcher {
540///     fn distance(
541///         &self,
542///         pos12: &Isometry<Real>,
543///         g1: &dyn Shape,
544///         g2: &dyn Shape,
545///     ) -> Result<Real, Unsupported> {
546///         // Try to handle custom shapes
547///         match (g1.as_any().downcast_ref::<MyShape>(),
548///                g2.as_any().downcast_ref::<MyShape>()) {
549///             (Some(s1), Some(s2)) => Ok(custom_distance(s1, s2, pos12)),
550///             _ => Err(Unsupported), // Let the next dispatcher handle it
551///         }
552///     }
553///     // ... other methods return Err(Unsupported)
554/// }
555///
556/// // Chain: try custom first, fall back to default
557/// let dispatcher = CustomShapeDispatcher.chain(DefaultQueryDispatcher);
558///
559/// // This will use CustomShapeDispatcher if both are MyShape,
560/// // otherwise DefaultQueryDispatcher handles it
561/// let dist = dispatcher.distance(&pos12, shape1, shape2)?;
562/// # }
563/// ```
564///
565/// # Performance Note
566///
567/// Chaining has minimal overhead - it's just two function calls in the worst case. The first
568/// dispatcher is always tried first, so place your most likely-to-succeed dispatcher at the
569/// front of the chain for best performance.
570///
571/// # Multiple Chains
572///
573/// You can chain more than two dispatchers by chaining chains:
574///
575/// ```ignore
576/// let dispatcher = custom1
577///     .chain(custom2)
578///     .chain(DefaultQueryDispatcher);
579/// ```
580///
581/// This creates a chain of three dispatchers: `custom1` -> `custom2` -> `DefaultQueryDispatcher`.
582pub struct QueryDispatcherChain<T, U>(T, U);
583
584macro_rules! chain_method {
585    ($name:ident ( $( $arg:ident : $ty:ty,)*) -> $result:ty) => {
586        fn $name(&self, $($arg : $ty,)*
587        ) -> Result<$result, Unsupported> {
588            (self.0).$name($($arg,)*)
589                .or_else(|Unsupported| (self.1).$name($($arg,)*))
590        }
591    }
592}
593
594impl<T, U> QueryDispatcher for QueryDispatcherChain<T, U>
595where
596    T: QueryDispatcher,
597    U: QueryDispatcher,
598{
599    chain_method!(intersection_test(
600        pos12: &Isometry<Real>,
601        g1: &dyn Shape,
602        g2: &dyn Shape,
603    ) -> bool);
604
605    chain_method!(distance(pos12: &Isometry<Real>, g1: &dyn Shape, g2: &dyn Shape,) -> Real);
606
607    chain_method!(contact(
608        pos12: &Isometry<Real>,
609        g1: &dyn Shape,
610        g2: &dyn Shape,
611        prediction: Real,
612    ) -> Option<Contact>);
613
614    chain_method!(closest_points(
615        pos12: &Isometry<Real>,
616        g1: &dyn Shape,
617        g2: &dyn Shape,
618        max_dist: Real,
619    ) -> ClosestPoints);
620
621    chain_method!(cast_shapes(
622        pos12: &Isometry<Real>,
623        vel12: &Vector<Real>,
624        g1: &dyn Shape,
625        g2: &dyn Shape,
626        options: ShapeCastOptions,
627    ) -> Option<ShapeCastHit>);
628
629    chain_method!(cast_shapes_nonlinear(
630        motion1: &NonlinearRigidMotion,
631        g1: &dyn Shape,
632        motion2: &NonlinearRigidMotion,
633        g2: &dyn Shape,
634        start_time: Real,
635        end_time: Real,
636        stop_at_penetration: bool,
637    ) -> Option<ShapeCastHit>);
638}
639
640#[cfg(feature = "alloc")]
641impl<ManifoldData, ContactData, T, U> PersistentQueryDispatcher<ManifoldData, ContactData>
642    for QueryDispatcherChain<T, U>
643where
644    T: PersistentQueryDispatcher<ManifoldData, ContactData>,
645    U: PersistentQueryDispatcher<ManifoldData, ContactData>,
646{
647    chain_method!(contact_manifolds(
648        pos12: &Isometry<Real>,
649        g1: &dyn Shape,
650        g2: &dyn Shape,
651        prediction: Real,
652        manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
653        workspace: &mut Option<ContactManifoldsWorkspace>,
654    ) -> ());
655
656    chain_method!(contact_manifold_convex_convex(
657        pos12: &Isometry<Real>,
658        g1: &dyn Shape,
659        g2: &dyn Shape,
660        normal_constraints1: Option<&dyn NormalConstraints>,
661        normal_constraints2: Option<&dyn NormalConstraints>,
662        prediction: Real,
663        manifold: &mut ContactManifold<ManifoldData, ContactData>,
664    ) -> ());
665}