parry3d/query/contact/
contact.rs

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