Skip to main content

QueryDispatcher

Trait QueryDispatcher 

Source
pub trait QueryDispatcher: Send + Sync {
    // Required methods
    fn intersection_test(
        &self,
        pos12: &Pose,
        g1: &dyn Shape,
        g2: &dyn Shape,
    ) -> Result<bool, Unsupported>;
    fn distance(
        &self,
        pos12: &Pose,
        g1: &dyn Shape,
        g2: &dyn Shape,
    ) -> Result<f32, Unsupported>;
    fn contact(
        &self,
        pos12: &Pose,
        g1: &dyn Shape,
        g2: &dyn Shape,
        prediction: f32,
    ) -> Result<Option<Contact>, Unsupported>;
    fn closest_points(
        &self,
        pos12: &Pose,
        g1: &dyn Shape,
        g2: &dyn Shape,
        max_dist: f32,
    ) -> Result<ClosestPoints, Unsupported>;
    fn cast_shapes(
        &self,
        pos12: &Pose,
        local_vel12: Vector,
        g1: &dyn Shape,
        g2: &dyn Shape,
        options: ShapeCastOptions,
    ) -> Result<Option<ShapeCastHit>, Unsupported>;
    fn cast_shapes_nonlinear(
        &self,
        motion1: &NonlinearRigidMotion,
        g1: &dyn Shape,
        motion2: &NonlinearRigidMotion,
        g2: &dyn Shape,
        start_time: f32,
        end_time: f32,
        stop_at_penetration: bool,
    ) -> Result<Option<ShapeCastHit>, Unsupported>;

    // Provided method
    fn chain<U: QueryDispatcher>(
        self,
        other: U,
    ) -> QueryDispatcherChain<Self, U>
       where Self: Sized { ... }
}
Expand description

Dispatcher for pairwise geometric queries between shapes.

This is the core trait for performing geometric queries (distance, intersection, contact, etc.) between pairs of shapes in Parry. It provides a uniform interface for querying different shape combinations.

§Purpose

The QueryDispatcher trait serves as an abstraction layer that:

  1. Decouples query algorithms from shape types: Different shape pairs may require different algorithms (e.g., sphere-sphere uses simple math, while convex-convex uses GJK/EPA).

  2. Enables extensibility: You can implement custom dispatchers to add support for custom shape types or specialized algorithms without modifying Parry’s core code.

  3. Provides fallback mechanisms: Dispatchers can be chained together using chain(), allowing graceful fallback when a query is not supported.

§The pos12 Parameter Convention

All query methods in this trait take a pos12 parameter, which represents the relative position of shape 2 (g2) in shape 1’s (g1) local coordinate frame:

pos12 = pos1.inverse() * pos2

This convention is used because:

  • It reduces redundant transformations during query execution
  • Many algorithms naturally work in one shape’s local space
  • It’s more efficient than passing two separate world-space positions

When using the high-level query functions, this transformation is done automatically.

§Query Methods Overview

The trait provides several categories of queries:

§Basic Queries

§Motion Queries (Time of Impact)

§Thread Safety

Query dispatchers must be Send + Sync because they’re often shared across threads in:

  • Parallel collision detection
  • Physics simulations with multi-threaded broad phase
  • Game engines with parallel scene queries

Ensure your custom dispatcher implementations are thread-safe or use appropriate synchronization.

§Error Handling with Unsupported

All query methods return Result<T, Unsupported>. The Unsupported error indicates:

  • The dispatcher doesn’t know how to handle the given shape pair
  • The shapes don’t support this type of query
  • The query is mathematically undefined for these shapes

When chaining dispatchers with chain(), returning Unsupported causes the next dispatcher in the chain to be tried.

§Example: Using the Default Dispatcher

use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
use parry3d::shape::{Ball, Cuboid};
use parry3d::math::{Pose, Vector};

let dispatcher = DefaultQueryDispatcher;

let ball = Ball::new(1.0);
let cuboid = Cuboid::new(Vector::splat(2.0));

let pos1 = Pose::identity();
let pos2 = Pose::translation(5.0, 0.0, 0.0);
let pos12 = pos1.inv_mul(&pos2);

// Test intersection
let intersects = dispatcher.intersection_test(&pos12, &ball, &cuboid).unwrap();

// Compute distance
let dist = dispatcher.distance(&pos12, &ball, &cuboid).unwrap();

println!("Intersects: {}, Distance: {}", intersects, dist);

§Example: Chaining Dispatchers

use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};

struct MyCustomDispatcher;

impl QueryDispatcher for MyCustomDispatcher {
    fn distance(
        &self,
        pos12: &Pose,
        g1: &dyn Shape,
        g2: &dyn Shape,
    ) -> Result<Real, Unsupported> {
        // Handle custom shape types
        if let Some(my_shape) = g1.as_any().downcast_ref::<MyShape>() {
            // ... custom distance computation
            Ok(computed_distance)
        } else {
            // Don't know how to handle this, let the next dispatcher try
            Err(Unsupported)
        }
    }

    // ... implement other methods
}

// Chain custom dispatcher with default as fallback
let dispatcher = MyCustomDispatcher.chain(DefaultQueryDispatcher);

// Now all queries try custom dispatcher first, then default
let dist = dispatcher.distance(pos12, shape1, shape2)?;

§See Also

Required Methods§

Source

fn intersection_test( &self, pos12: &Pose, g1: &dyn Shape, g2: &dyn Shape, ) -> Result<bool, Unsupported>

Tests whether two shapes are intersecting.

Source

fn distance( &self, pos12: &Pose, g1: &dyn Shape, g2: &dyn Shape, ) -> Result<f32, Unsupported>

Computes the minimum distance separating two shapes.

Returns 0.0 if the objects are touching or penetrating.

Source

fn contact( &self, pos12: &Pose, g1: &dyn Shape, g2: &dyn Shape, prediction: f32, ) -> Result<Option<Contact>, Unsupported>

Computes one pair of contact points point between two shapes.

Returns None if the objects are separated by a distance greater than prediction.

Source

fn closest_points( &self, pos12: &Pose, g1: &dyn Shape, g2: &dyn Shape, max_dist: f32, ) -> Result<ClosestPoints, Unsupported>

Computes the pair of closest points between two shapes.

Returns ClosestPoints::Disjoint if the objects are separated by a distance greater than max_dist.

Source

fn cast_shapes( &self, pos12: &Pose, local_vel12: Vector, g1: &dyn Shape, g2: &dyn Shape, options: ShapeCastOptions, ) -> Result<Option<ShapeCastHit>, Unsupported>

Computes the smallest time when two shapes under translational movement are separated by a distance smaller or equal to distance.

Returns 0.0 if the objects are touching or penetrating.

§Parameters
  • pos12: the position of the second shape relative to the first shape.
  • local_vel12: the relative velocity between the two shapes, expressed in the local-space of the first shape. In other world: pos1.inverse() * (vel2 - vel1).
  • g1: the first shape involved in the shape-cast.
  • g2: the second shape involved in the shape-cast.
  • target_dist: a hit will be returned as soon as the two shapes get closer than target_dist.
  • max_time_of_impact: the maximum allowed travel time. This method returns None if the time-of-impact detected is theater than this value.
Source

fn cast_shapes_nonlinear( &self, motion1: &NonlinearRigidMotion, g1: &dyn Shape, motion2: &NonlinearRigidMotion, g2: &dyn Shape, start_time: f32, end_time: f32, stop_at_penetration: bool, ) -> Result<Option<ShapeCastHit>, Unsupported>

Computes the smallest time of impact of two shapes under translational and rotational movement.

§Parameters
  • motion1 - The motion of the first shape.
  • g1 - The first shape involved in the query.
  • motion2 - The motion of the second shape.
  • g2 - The second shape involved in the query.
  • start_time - The starting time of the interval where the motion takes place.
  • end_time - The end time of the interval where the motion takes place.
  • stop_at_penetration - If the casted shape starts in a penetration state with any collider, two results are possible. If stop_at_penetration is true then, the result will have a time_of_impact equal to start_time. If stop_at_penetration is false then the nonlinear shape-casting will see if further motion wrt. the penetration normal would result in tunnelling. If it does not (i.e. we have a separating velocity along that normal) then the nonlinear shape-casting will attempt to find another impact, at a time > start_time that could result in tunnelling.

Provided Methods§

Source

fn chain<U: QueryDispatcher>(self, other: U) -> QueryDispatcherChain<Self, U>
where Self: Sized,

Construct a QueryDispatcher that falls back on other for cases not handled by self

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§