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}