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