Skip to main content

parry2d/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::math::Pose;
65//!
66//! let ball1 = Ball::new(0.5);
67//! let ball2 = Ball::new(1.0);
68//! let pos1 = Pose::identity();
69//! let pos2 = Pose::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::math::Pose;
85//!
86//! let dispatcher = DefaultQueryDispatcher;
87//! let ball1 = Ball::new(0.5);
88//! let ball2 = Ball::new(1.0);
89//!
90//! let pos1 = Pose::identity();
91//! let pos2 = Pose::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::{Pose, Real};
125//!
126//! struct MyDispatcher {
127//!     // Your dispatcher state
128//! }
129//!
130//! impl QueryDispatcher for MyDispatcher {
131//!     fn intersection_test(
132//!         &self,
133//!         pos12: &Pose,
134//!         g1: &dyn Shape,
135//!         g2: &dyn Shape,
136//!     ) -> Result<ShapeIntersection, 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: &Pose,
153//!         g1: &dyn Shape,
154//!         g2: &dyn Shape,
155//!     ) -> Result<ShapeDistance, 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::{Pose, 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::{
199    ClosestPoints, Contact, NonlinearRigidMotion, ShapeCastHit, ShapeDistance, ShapeIntersection,
200    Unsupported,
201};
202use crate::shape::Shape;
203#[cfg(feature = "alloc")]
204use alloc::vec::Vec;
205
206#[cfg(feature = "alloc")]
207/// A query dispatcher for queries relying on spatial coherence, including contact-manifold computation.
208///
209/// This trait extends [`QueryDispatcher`] with methods that maintain persistent state between
210/// queries to improve performance through **spatial and temporal coherence**.
211///
212/// # What is Spatial Coherence?
213///
214/// Spatial coherence is the principle that objects that are close to each other in one frame
215/// are likely to remain close in subsequent frames. Contact manifolds exploit this by:
216///
217/// 1. Tracking contact points over multiple frames
218/// 2. Reusing previous contact information to accelerate new queries
219/// 3. Maintaining contact IDs for physics solvers to track persistent contacts
220///
221/// # Contact Manifolds vs Single Contacts
222///
223/// - **Single Contact** ([`QueryDispatcher::contact`]): Returns one contact point, suitable
224///   for one-off queries or simple collision detection.
225///
226/// - **Contact Manifold** ([`PersistentQueryDispatcher::contact_manifolds`]): Returns multiple
227///   contact points that persist across frames, essential for stable physics simulation.
228///
229/// # When to Use This Trait
230///
231/// Use `PersistentQueryDispatcher` when:
232/// - Implementing physics simulation that needs stable contact tracking
233/// - Building a custom physics engine on top of Parry
234/// - Optimizing repeated collision queries between the same shape pairs
235///
236/// # Generic Parameters
237///
238/// - `ManifoldData`: Custom data attached to each contact manifold (default: `()`)
239/// - `ContactData`: Custom data attached to each contact point (default: `()`)
240///
241/// These allow physics engines to attach solver-specific data to contacts without modifying
242/// Parry's core types.
243pub trait PersistentQueryDispatcher<ManifoldData = (), ContactData = ()>: QueryDispatcher {
244    /// Compute all the contacts between two shapes.
245    ///
246    /// The output is written into `manifolds` and `context`. Both can persist
247    /// between multiple calls to `contacts` by re-using the result of the previous
248    /// call to `contacts`. This persistence can significantly improve collision
249    /// detection performances by allowing the underlying algorithms to exploit
250    /// spatial and temporal coherence.
251    fn contact_manifolds(
252        &self,
253        pos12: &Pose,
254        g1: &dyn Shape,
255        g2: &dyn Shape,
256        prediction: Real,
257        manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
258        workspace: &mut Option<ContactManifoldsWorkspace>,
259    ) -> Result<(), Unsupported>;
260
261    /// Computes the contact-manifold between two convex shapes.
262    fn contact_manifold_convex_convex(
263        &self,
264        pos12: &Pose,
265        g1: &dyn Shape,
266        g2: &dyn Shape,
267        normal_constraints1: Option<&dyn NormalConstraints>,
268        normal_constraints2: Option<&dyn NormalConstraints>,
269        prediction: Real,
270        manifold: &mut ContactManifold<ManifoldData, ContactData>,
271    ) -> Result<(), Unsupported>;
272}
273
274/// Dispatcher for pairwise geometric queries between shapes.
275///
276/// This is the core trait for performing geometric queries (distance, intersection, contact, etc.)
277/// between pairs of shapes in Parry. It provides a uniform interface for querying different shape
278/// combinations.
279///
280/// # Purpose
281///
282/// The `QueryDispatcher` trait serves as an abstraction layer that:
283///
284/// 1. **Decouples query algorithms from shape types**: Different shape pairs may require different
285///    algorithms (e.g., sphere-sphere uses simple math, while convex-convex uses GJK/EPA).
286///
287/// 2. **Enables extensibility**: You can implement custom dispatchers to add support for custom
288///    shape types or specialized algorithms without modifying Parry's core code.
289///
290/// 3. **Provides fallback mechanisms**: Dispatchers can be chained together using [`chain()`](Self::chain),
291///    allowing graceful fallback when a query is not supported.
292///
293/// # The `pos12` Parameter Convention
294///
295/// All query methods in this trait take a `pos12` parameter, which represents the **relative
296/// position** of shape 2 (`g2`) in shape 1's (`g1`) local coordinate frame:
297///
298/// ```ignore
299/// pos12 = pos1.inverse() * pos2
300/// ```
301///
302/// This convention is used because:
303/// - It reduces redundant transformations during query execution
304/// - Many algorithms naturally work in one shape's local space
305/// - It's more efficient than passing two separate world-space positions
306///
307/// When using the high-level query functions, this transformation is done automatically.
308///
309/// # Query Methods Overview
310///
311/// The trait provides several categories of queries:
312///
313/// ## Basic Queries
314/// - [`intersection_test`](Self::intersection_test): Boolean intersection check (fastest)
315/// - [`distance`](Self::distance): Minimum separating distance
316/// - [`closest_points`](Self::closest_points): Pair of closest points
317/// - [`contact`](Self::contact): Contact point with penetration depth
318///
319/// ## Motion Queries (Time of Impact)
320/// - [`cast_shapes`](Self::cast_shapes): Linear motion (translation only)
321/// - [`cast_shapes_nonlinear`](Self::cast_shapes_nonlinear): Nonlinear motion (translation + rotation)
322///
323/// # Thread Safety
324///
325/// Query dispatchers must be `Send + Sync` because they're often shared across threads in:
326/// - Parallel collision detection
327/// - Physics simulations with multi-threaded broad phase
328/// - Game engines with parallel scene queries
329///
330/// Ensure your custom dispatcher implementations are thread-safe or use appropriate synchronization.
331///
332/// # Error Handling with `Unsupported`
333///
334/// All query methods return `Result<T, Unsupported>`. The `Unsupported` error indicates:
335///
336/// - The dispatcher doesn't know how to handle the given shape pair
337/// - The shapes don't support this type of query
338/// - The query is mathematically undefined for these shapes
339///
340/// When chaining dispatchers with [`chain()`](Self::chain), returning `Unsupported` causes the
341/// next dispatcher in the chain to be tried.
342///
343/// # Example: Using the Default Dispatcher
344///
345/// ```
346/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
347/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
348/// use parry3d::shape::{Ball, Cuboid};
349/// use parry3d::math::{Pose, Vector};
350///
351/// let dispatcher = DefaultQueryDispatcher;
352///
353/// let ball = Ball::new(1.0);
354/// let cuboid = Cuboid::new(Vector::splat(2.0));
355///
356/// let pos1 = Pose::identity();
357/// let pos2 = Pose::translation(5.0, 0.0, 0.0);
358/// let pos12 = pos1.inv_mul(&pos2);
359///
360/// // Test intersection
361/// let intersects = dispatcher.intersection_test(&pos12, &ball, &cuboid).unwrap().intersecting;
362///
363/// // Compute distance
364/// let dist = dispatcher.distance(&pos12, &ball, &cuboid).unwrap().distance;
365///
366/// println!("Intersects: {}, Distance: {}", intersects, dist);
367/// # }
368/// ```
369///
370/// # Example: Chaining Dispatchers
371///
372/// ```ignore
373/// # {
374/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
375///
376/// struct MyCustomDispatcher;
377///
378/// impl QueryDispatcher for MyCustomDispatcher {
379///     fn distance(
380///         &self,
381///         pos12: &Pose,
382///         g1: &dyn Shape,
383///         g2: &dyn Shape,
384///     ) -> Result<ShapeDistance, Unsupported> {
385///         // Handle custom shape types
386///         if let Some(my_shape) = g1.as_any().downcast_ref::<MyShape>() {
387///             // ... custom distance computation
388///             Ok(computed_distance)
389///         } else {
390///             // Don't know how to handle this, let the next dispatcher try
391///             Err(Unsupported)
392///         }
393///     }
394///
395///     // ... implement other methods
396/// }
397///
398/// // Chain custom dispatcher with default as fallback
399/// let dispatcher = MyCustomDispatcher.chain(DefaultQueryDispatcher);
400///
401/// // Now all queries try custom dispatcher first, then default
402/// let dist = dispatcher.distance(pos12, shape1, shape2)?;
403/// # }
404/// ```
405///
406/// # See Also
407///
408/// - [`DefaultQueryDispatcher`](crate::query::DefaultQueryDispatcher): The built-in implementation used by Parry
409/// - [`PersistentQueryDispatcher`]: Extended trait for contact manifold queries
410/// - [`crate::query`]: High-level query functions that use dispatchers internally
411pub trait QueryDispatcher: Send + Sync {
412    /// Tests whether two shapes are intersecting.
413    fn intersection_test(
414        &self,
415        pos12: &Pose,
416        g1: &dyn Shape,
417        g2: &dyn Shape,
418    ) -> Result<ShapeIntersection, Unsupported>;
419
420    /// Computes the minimum distance separating two shapes.
421    ///
422    /// Returns `0.0` if the objects are touching or penetrating.
423    fn distance(
424        &self,
425        pos12: &Pose,
426        g1: &dyn Shape,
427        g2: &dyn Shape,
428    ) -> Result<ShapeDistance, Unsupported>;
429
430    /// Computes one pair of contact points point between two shapes.
431    ///
432    /// Returns `None` if the objects are separated by a distance greater than `prediction`.
433    fn contact(
434        &self,
435        pos12: &Pose,
436        g1: &dyn Shape,
437        g2: &dyn Shape,
438        prediction: Real,
439    ) -> Result<Option<Contact>, Unsupported>;
440
441    /// Computes the pair of closest points between two shapes.
442    ///
443    /// Returns `ClosestPoints::Disjoint` if the objects are separated by a distance greater than `max_dist`.
444    fn closest_points(
445        &self,
446        pos12: &Pose,
447        g1: &dyn Shape,
448        g2: &dyn Shape,
449        max_dist: Real,
450    ) -> Result<ClosestPoints, Unsupported>;
451
452    /// Computes the smallest time when two shapes under translational movement are separated by a
453    /// distance smaller or equal to `distance`.
454    ///
455    /// Returns `0.0` if the objects are touching or penetrating.
456    ///
457    /// # Parameters
458    /// - `pos12`: the position of the second shape relative to the first shape.
459    /// - `local_vel12`: the relative velocity between the two shapes, expressed in the local-space
460    ///   of the first shape. In other world: `pos1.inverse() * (vel2 - vel1)`.
461    /// - `g1`: the first shape involved in the shape-cast.
462    /// - `g2`: the second shape involved in the shape-cast.
463    /// - `target_dist`: a hit will be returned as soon as the two shapes get closer than `target_dist`.
464    /// - `max_time_of_impact`: the maximum allowed travel time. This method returns `None` if the time-of-impact
465    ///   detected is theater than this value.
466    fn cast_shapes(
467        &self,
468        pos12: &Pose,
469        local_vel12: Vector,
470        g1: &dyn Shape,
471        g2: &dyn Shape,
472        options: ShapeCastOptions,
473    ) -> Result<Option<ShapeCastHit>, Unsupported>;
474
475    /// Construct a `QueryDispatcher` that falls back on `other` for cases not handled by `self`
476    fn chain<U: QueryDispatcher>(self, other: U) -> QueryDispatcherChain<Self, U>
477    where
478        Self: Sized,
479    {
480        QueryDispatcherChain(self, other)
481    }
482
483    /// Computes the smallest time of impact of two shapes under translational and rotational movement.
484    ///
485    /// # Parameters
486    /// * `motion1` - The motion of the first shape.
487    /// * `g1` - The first shape involved in the query.
488    /// * `motion2` - The motion of the second shape.
489    /// * `g2` - The second shape involved in the query.
490    /// * `start_time` - The starting time of the interval where the motion takes place.
491    /// * `end_time` - The end time of the interval where the motion takes place.
492    /// * `stop_at_penetration` - If the casted shape starts in a penetration state with any
493    ///   collider, two results are possible. If `stop_at_penetration` is `true` then, the
494    ///   result will have a `time_of_impact` equal to `start_time`. If `stop_at_penetration` is `false`
495    ///   then the nonlinear shape-casting will see if further motion wrt. the penetration normal
496    ///   would result in tunnelling. If it does not (i.e. we have a separating velocity along
497    ///   that normal) then the nonlinear shape-casting will attempt to find another impact,
498    ///   at a time `> start_time` that could result in tunnelling.
499    fn cast_shapes_nonlinear(
500        &self,
501        motion1: &NonlinearRigidMotion,
502        g1: &dyn Shape,
503        motion2: &NonlinearRigidMotion,
504        g2: &dyn Shape,
505        start_time: Real,
506        end_time: Real,
507        stop_at_penetration: bool,
508    ) -> Result<Option<ShapeCastHit>, Unsupported>;
509}
510
511/// A chain of two query dispatchers that provides fallback behavior.
512///
513/// This struct is created by calling [`QueryDispatcher::chain()`] and allows combining multiple
514/// dispatchers into a fallback sequence. When a query is performed:
515///
516/// 1. The first dispatcher (`T`) is tried
517/// 2. If it returns `Err(Unsupported)`, the second dispatcher (`U`) is tried
518/// 3. If the second also returns `Unsupported`, the error is propagated
519///
520/// # Use Cases
521///
522/// Dispatcher chains are useful for:
523///
524/// - **Custom shapes with default fallback**: Handle your custom shapes specifically, but fall
525///   back to Parry's default dispatcher for standard shapes
526///
527/// - **Performance optimization**: Try a fast specialized algorithm first, fall back to a general
528///   but slower algorithm if needed
529///
530/// - **Progressive feature support**: Layer dispatchers that support different feature sets
531///
532/// - **Debugging**: Wrap the default dispatcher with a logging dispatcher that passes through
533///
534/// # Example
535///
536/// ```ignore
537/// # {
538/// use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
539///
540/// // A dispatcher that handles only custom shapes
541/// struct CustomShapeDispatcher;
542/// impl QueryDispatcher for CustomShapeDispatcher {
543///     fn distance(
544///         &self,
545///         pos12: &Pose,
546///         g1: &dyn Shape,
547///         g2: &dyn Shape,
548///     ) -> Result<ShapeDistance, Unsupported> {
549///         // Try to handle custom shapes
550///         match (g1.as_any().downcast_ref::<MyShape>(),
551///                g2.as_any().downcast_ref::<MyShape>()) {
552///             (Some(s1), Some(s2)) => Ok(custom_distance(s1, s2, pos12)),
553///             _ => Err(Unsupported), // Let the next dispatcher handle it
554///         }
555///     }
556///     // ... other methods return Err(Unsupported)
557/// }
558///
559/// // Chain: try custom first, fall back to default
560/// let dispatcher = CustomShapeDispatcher.chain(DefaultQueryDispatcher);
561///
562/// // This will use CustomShapeDispatcher if both are MyShape,
563/// // otherwise DefaultQueryDispatcher handles it
564/// let dist = dispatcher.distance(pos12, shape1, shape2)?;
565/// # }
566/// ```
567///
568/// # Performance Note
569///
570/// Chaining has minimal overhead - it's just two function calls in the worst case. The first
571/// dispatcher is always tried first, so place your most likely-to-succeed dispatcher at the
572/// front of the chain for best performance.
573///
574/// # Multiple Chains
575///
576/// You can chain more than two dispatchers by chaining chains:
577///
578/// ```ignore
579/// let dispatcher = custom1
580///     .chain(custom2)
581///     .chain(DefaultQueryDispatcher);
582/// ```
583///
584/// This creates a chain of three dispatchers: `custom1` -> `custom2` -> `DefaultQueryDispatcher`.
585pub struct QueryDispatcherChain<T, U>(T, U);
586
587macro_rules! chain_method {
588    ($name:ident ( $( $arg:ident : $ty:ty,)*) -> $result:ty) => {
589        fn $name(&self, $($arg : $ty,)*
590        ) -> Result<$result, Unsupported> {
591            (self.0).$name($($arg,)*)
592                .or_else(|Unsupported| (self.1).$name($($arg,)*))
593        }
594    }
595}
596
597impl<T, U> QueryDispatcher for QueryDispatcherChain<T, U>
598where
599    T: QueryDispatcher,
600    U: QueryDispatcher,
601{
602    chain_method!(intersection_test(
603        pos12: &Pose,
604        g1: &dyn Shape,
605        g2: &dyn Shape,
606    ) -> ShapeIntersection);
607
608    chain_method!(distance(pos12: &Pose, g1: &dyn Shape, g2: &dyn Shape,) -> ShapeDistance);
609
610    chain_method!(contact(
611        pos12: &Pose,
612        g1: &dyn Shape,
613        g2: &dyn Shape,
614        prediction: Real,
615    ) -> Option<Contact>);
616
617    chain_method!(closest_points(
618        pos12: &Pose,
619        g1: &dyn Shape,
620        g2: &dyn Shape,
621        max_dist: Real,
622    ) -> ClosestPoints);
623
624    chain_method!(cast_shapes(
625        pos12: &Pose,
626        vel12: Vector,
627        g1: &dyn Shape,
628        g2: &dyn Shape,
629        options: ShapeCastOptions,
630    ) -> Option<ShapeCastHit>);
631
632    chain_method!(cast_shapes_nonlinear(
633        motion1: &NonlinearRigidMotion,
634        g1: &dyn Shape,
635        motion2: &NonlinearRigidMotion,
636        g2: &dyn Shape,
637        start_time: Real,
638        end_time: Real,
639        stop_at_penetration: bool,
640    ) -> Option<ShapeCastHit>);
641}
642
643#[cfg(feature = "alloc")]
644impl<ManifoldData, ContactData, T, U> PersistentQueryDispatcher<ManifoldData, ContactData>
645    for QueryDispatcherChain<T, U>
646where
647    T: PersistentQueryDispatcher<ManifoldData, ContactData>,
648    U: PersistentQueryDispatcher<ManifoldData, ContactData>,
649{
650    chain_method!(contact_manifolds(
651        pos12: &Pose,
652        g1: &dyn Shape,
653        g2: &dyn Shape,
654        prediction: Real,
655        manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
656        workspace: &mut Option<ContactManifoldsWorkspace>,
657    ) -> ());
658
659    chain_method!(contact_manifold_convex_convex(
660        pos12: &Pose,
661        g1: &dyn Shape,
662        g2: &dyn Shape,
663        normal_constraints1: Option<&dyn NormalConstraints>,
664        normal_constraints2: Option<&dyn NormalConstraints>,
665        prediction: Real,
666        manifold: &mut ContactManifold<ManifoldData, ContactData>,
667    ) -> ());
668}