Skip to main content

parry3d/query/contact/
contact.rs

1use crate::math::{Pose, Real, Vector};
2use crate::shape::SubShapeId;
3use core::mem;
4
5/// Geometric description of a contact between two shapes.
6///
7/// A contact represents the point(s) where two shapes touch or penetrate. This structure
8/// contains all the information needed to resolve collisions: contact points, surface normals,
9/// and penetration depth.
10///
11/// # Contact States
12///
13/// A `Contact` can represent different collision states:
14///
15/// - **Touching** (`dist ≈ 0.0`): Shapes are just barely in contact
16/// - **Penetrating** (`dist < 0.0`): Shapes are overlapping (negative distance = penetration depth)
17/// - **Separated** (`dist > 0.0`): Shapes are close but not touching (rarely used; see `closest_points` instead)
18///
19/// # Coordinate Systems
20///
21/// Contact data can be expressed in different coordinate systems:
22///
23/// - **World space**: Both shapes' transformations applied; `normal2 = -normal1`
24/// - **Local space**: Relative to one shape's coordinate system
25///
26/// # Use Cases
27///
28/// - **Physics simulation**: Compute collision response forces
29/// - **Collision resolution**: Push objects apart when penetrating
30/// - **Trigger detection**: Detect when objects touch without resolving
31///
32/// # Example
33///
34/// ```rust
35/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
36/// use parry3d::query::contact;
37/// use parry3d::shape::Ball;
38/// use parry3d::math::{Pose, Vector};
39///
40/// let ball1 = Ball::new(1.0);
41/// let ball2 = Ball::new(1.0);
42///
43/// // Overlapping balls (centers 1.5 units apart, combined radii = 2.0)
44/// let pos1 = Pose::translation(0.0, 0.0, 0.0);
45/// let pos2 = Pose::translation(1.5, 0.0, 0.0);
46///
47/// if let Ok(Some(contact)) = contact(&pos1, &ball1, &pos2, &ball2, 0.0) {
48///     // Penetration depth (negative distance)
49///     assert!(contact.dist < 0.0);
50///     println!("Penetration: {}", -contact.dist); // 0.5 units
51///
52///     // Normal points from shape 1 toward shape 2
53///     println!("Normal: {:?}", contact.normal1);
54///
55///     // Contact points are on each shape's surface
56///     println!("Vector on ball1: {:?}", contact.point1);
57///     println!("Vector on ball2: {:?}", contact.point2);
58/// }
59/// # }
60/// ```
61#[derive(Debug, PartialEq, Copy, Clone)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(
64    feature = "rkyv",
65    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
66)]
67pub struct Contact {
68    /// Position of the contact point on the first shape's surface.
69    ///
70    /// This is the point on shape 1 that is closest to (or penetrating into) shape 2.
71    /// Expressed in the same coordinate system as the contact (world or local space).
72    pub point1: Vector,
73
74    /// Position of the contact point on the second shape's surface.
75    ///
76    /// This is the point on shape 2 that is closest to (or penetrating into) shape 1.
77    /// When shapes are penetrating, this point may be inside shape 1.
78    pub point2: Vector,
79
80    /// Contact normal pointing outward from the first shape.
81    ///
82    /// This unit vector points from shape 1 toward shape 2, perpendicular to the
83    /// contact surface. Used to compute separation direction and collision response
84    /// forces for shape 1.
85    pub normal1: Vector,
86
87    /// Contact normal pointing outward from the second shape.
88    ///
89    /// In world space, this is always equal to `-normal1`. In local space coordinates,
90    /// it may differ due to different shape orientations.
91    pub normal2: Vector,
92
93    /// Signed distance between the two contact points.
94    ///
95    /// - **Positive**: Shapes are separated (distance between surfaces)
96    /// - **Zero**: Shapes are exactly touching
97    /// - **Negative**: Shapes are penetrating (absolute value = penetration depth)
98    ///
99    /// For collision resolution, use `-dist` as the penetration depth when `dist < 0.0`.
100    pub dist: Real,
101
102    /// The sub-shape of the first shape this contact is on.
103    ///
104    /// Always `0` for a shape with no sub-shapes.
105    pub subshape1: SubShapeId,
106
107    /// The sub-shape of the second shape this contact is on.
108    ///
109    /// Always `0` for a shape with no sub-shapes.
110    pub subshape2: SubShapeId,
111}
112
113impl Contact {
114    /// Creates a new contact with the given parameters.
115    ///
116    /// # Arguments
117    ///
118    /// * `point1` - Contact point on the first shape's surface
119    /// * `point2` - Contact point on the second shape's surface
120    /// * `normal1` - Unit normal pointing outward from shape 1
121    /// * `normal2` - Unit normal pointing outward from shape 2
122    /// * `dist` - Signed distance (negative = penetration depth)
123    ///
124    /// # Example
125    ///
126    /// ```
127    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
128    /// use parry3d::query::Contact;
129    /// use parry3d::math::Vector;
130    ///
131    /// // Create a contact representing two spheres touching
132    /// let point1 = Vector::new(1.0, 0.0, 0.0);
133    /// let point2 = Vector::new(2.0, 0.0, 0.0);
134    /// let normal1 = Vector::new(1.0, 0.0, 0.0).normalize();
135    /// let normal2 = Vector::new(-1.0, 0.0, 0.0).normalize();
136    ///
137    /// let contact = Contact::new(point1, point2, normal1, normal2, 0.0);
138    /// assert_eq!(contact.dist, 0.0); // Touching, not penetrating
139    /// # }
140    /// ```
141    #[inline]
142    pub fn new(
143        point1: Vector,
144        point2: Vector,
145        normal1: Vector,
146        normal2: Vector,
147        dist: Real,
148    ) -> Self {
149        Contact {
150            point1,
151            point2,
152            normal1,
153            normal2,
154            dist,
155            subshape1: 0,
156            subshape2: 0,
157        }
158    }
159
160    /// Sets the sub-shapes this contact is between.
161    #[inline]
162    pub fn with_subshapes(mut self, subshape1: SubShapeId, subshape2: SubShapeId) -> Self {
163        self.subshape1 = subshape1;
164        self.subshape2 = subshape2;
165        self
166    }
167}
168
169impl Contact {
170    /// Swaps the points and normals of this contact.
171    #[inline]
172    pub fn flip(&mut self) {
173        mem::swap(&mut self.point1, &mut self.point2);
174        mem::swap(&mut self.normal1, &mut self.normal2);
175        mem::swap(&mut self.subshape1, &mut self.subshape2);
176    }
177
178    /// Returns a new contact containing the swapped points and normals of `self`.
179    #[inline]
180    pub fn flipped(mut self) -> Self {
181        self.flip();
182        self
183    }
184
185    /// Transform the points and normals from this contact by
186    /// the given transformations.
187    #[inline]
188    pub fn transform_by_mut(&mut self, pos1: &Pose, pos2: &Pose) {
189        self.point1 = pos1 * self.point1;
190        self.point2 = pos2 * self.point2;
191        self.normal1 = pos1.rotation * self.normal1;
192        self.normal2 = pos2.rotation * self.normal2;
193    }
194
195    /// Transform `self.point1` and `self.normal1` by the `pos`.
196    pub fn transform1_by_mut(&mut self, pos: &Pose) {
197        self.point1 = pos * self.point1;
198        self.normal1 = pos.rotation * self.normal1;
199    }
200}