parry2d/query/
error.rs

1use core::fmt;
2
3/// Error indicating that a geometric query is not supported between certain shape combinations.
4///
5/// Many geometric queries in Parry (like distance calculation, contact detection, or time-of-impact)
6/// are implemented using specialized algorithms for specific pairs of shapes. When you attempt a
7/// query between two shapes for which no implementation exists, this error is returned.
8///
9/// # When This Error Occurs
10///
11/// This error typically occurs in two situations:
12///
13/// 1. **Missing Implementation**: The query has not been implemented for the specific pair of shapes.
14///    For example, some advanced queries might not support all combinations of composite shapes.
15///
16/// 2. **Complex Shape Combinations**: Certain queries involving composite shapes (like [`Compound`],
17///    [`TriMesh`], or [`HeightField`]) may not be fully supported, especially for less common operations.
18///
19/// # Common Scenarios
20///
21/// - Computing contact manifolds between two custom shapes that don't have a specialized implementation
22/// - Using non-linear shape casting with certain composite shapes
23/// - Querying distance between shapes that require more complex algorithms not yet implemented
24///
25/// # How to Handle This Error
26///
27/// When you encounter this error, you have several options:
28///
29/// ## 1. Use a Different Query Type
30///
31/// Try a more basic query that's more widely supported:
32///
33/// ```no_run
34/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
35/// # use parry3d::query::{contact, distance};
36/// # use parry3d::shape::{Ball, Cuboid};
37/// # use parry3d::na::{Isometry3, Vector3};
38/// # let shape1 = Ball::new(1.0);
39/// # let shape2 = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
40/// # let pos1 = Isometry3::identity();
41/// # let pos2 = Isometry3::identity();
42/// // If contact manifolds are unsupported, try basic contact:
43/// if let Ok(contact) = contact(&pos1, &shape1, &pos2, &shape2, 0.0) {
44///     // Process the contact point
45/// }
46///
47/// // Or try distance computation:
48/// let dist = distance(&pos1, &shape1, &pos2, &shape2);
49/// # }
50/// ```
51///
52/// ## 2. Decompose Complex Shapes
53///
54/// Break down complex shapes into simpler components:
55///
56/// ```no_run
57/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
58/// # use parry3d::shape::{TriMesh, Ball, Compound, SharedShape};
59/// # use parry3d::query::distance;
60/// # use parry3d::na::{Isometry3, Vector3};
61/// # let mesh = TriMesh::new(vec![], vec![]).unwrap();
62/// # let ball = Ball::new(1.0);
63/// # let pos1 = Isometry3::identity();
64/// # let pos2 = Isometry3::identity();
65/// // Instead of querying against a complex mesh directly,
66/// // iterate through its triangles:
67/// for triangle in mesh.triangles() {
68///     let dist = distance(&pos1, &triangle, &pos2, &ball);
69///     // Process each triangle-ball pair
70/// }
71/// # }
72/// ```
73///
74/// ## 3. Use the BVH for Composite Shapes
75///
76/// For shapes with BVH acceleration structures (like [`TriMesh`]), use specialized traversal methods:
77///
78/// ```no_run
79/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
80/// # use parry3d::shape::TriMesh;
81/// # use parry3d::bounding_volume::Aabb;
82/// # use parry3d::na::Point3;
83/// # let mesh = TriMesh::new(vec![Point3::origin()], vec![[0, 0, 0]]).unwrap();
84/// # let query_aabb = Aabb::new(Point3::origin(), Point3::origin());
85/// // Use BVH queries instead of direct shape queries:
86/// for leaf_id in mesh.bvh().intersect_aabb(&query_aabb) {
87///     let triangle = mesh.triangle(leaf_id);
88///     // Process the triangle
89/// }
90/// # }
91/// ```
92///
93/// ## 4. Implement a Custom Query Dispatcher
94///
95/// For advanced use cases, implement the [`QueryDispatcher`] trait to add support for your specific
96/// shape combinations:
97///
98/// ```no_run
99/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
100/// # use parry3d::query::{QueryDispatcher, DefaultQueryDispatcher};
101/// # use parry3d::shape::Shape;
102/// # use parry3d::math::{Isometry, Real};
103/// struct MyQueryDispatcher {
104///     default: DefaultQueryDispatcher,
105/// }
106///
107/// // Implement QueryDispatcher and add your custom query implementations
108/// # }
109/// ```
110///
111/// # Example: Catching and Handling the Error
112///
113/// ```
114/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
115/// # use parry3d::query::{contact, Unsupported};
116/// # use parry3d::shape::{Ball, Cuboid};
117/// # use parry3d::na::{Isometry3, Vector3};
118/// let ball = Ball::new(1.0);
119/// let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
120/// let pos1 = Isometry3::identity();
121/// let pos2 = Isometry3::identity();
122///
123/// // Most queries return Result<T, Unsupported>
124/// match contact(&pos1, &ball, &pos2, &cuboid, 0.0) {
125///     Ok(Some(contact)) => {
126///         // Query succeeded and found a contact
127///         println!("Contact found at distance: {}", contact.dist);
128///     }
129///     Ok(None) => {
130///         // Query succeeded but no contact found
131///         println!("No contact");
132///     }
133///     Err(Unsupported) => {
134///         // Query not supported for this shape combination
135///         println!("This query is not supported between these shapes");
136///         // Fall back to an alternative approach
137///     }
138/// }
139/// # }
140/// ```
141///
142/// [`Compound`]: crate::shape::Compound
143/// [`TriMesh`]: crate::shape::TriMesh
144/// [`HeightField`]: crate::shape::HeightField
145/// [`QueryDispatcher`]: crate::query::QueryDispatcher
146#[derive(Debug, Copy, Clone, Eq, PartialEq)]
147pub struct Unsupported;
148
149impl fmt::Display for Unsupported {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        f.pad("query not supported between these shapes")
152    }
153}
154
155#[cfg(feature = "alloc")]
156impl core::error::Error for Unsupported {}