avian3d/dynamics/solver/joints/
distance.rs

1//! [`DistanceJoint`] component.
2
3use crate::{dynamics::solver::xpbd::*, prelude::*};
4use bevy::{
5    ecs::{
6        entity::{EntityMapper, MapEntities},
7        reflect::ReflectMapEntities,
8    },
9    prelude::*,
10};
11
12/// A distance joint keeps the attached bodies at a certain distance from each other while while allowing rotation around all axes.
13///
14/// Distance joints can be useful for things like springs, muscles, and mass-spring networks.
15#[derive(Component, Clone, Copy, Debug, PartialEq, Reflect)]
16#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
17#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
18#[reflect(Debug, Component, MapEntities, PartialEq)]
19pub struct DistanceJoint {
20    /// First entity constrained by the joint.
21    pub entity1: Entity,
22    /// Second entity constrained by the joint.
23    pub entity2: Entity,
24    /// Attachment point on the first body.
25    pub local_anchor1: Vector,
26    /// Attachment point on the second body.
27    pub local_anchor2: Vector,
28    /// The distance the attached bodies will be kept relative to each other.
29    pub rest_length: Scalar,
30    /// The extents of the allowed relative translation between the attached bodies.
31    pub length_limits: Option<DistanceLimit>,
32    /// Linear damping applied by the joint.
33    pub damping_linear: Scalar,
34    /// Angular damping applied by the joint.
35    pub damping_angular: Scalar,
36    /// Lagrange multiplier for the positional correction.
37    pub lagrange: Scalar,
38    /// The joint's compliance, the inverse of stiffness, has the unit meters / Newton.
39    pub compliance: Scalar,
40    /// The force exerted by the joint.
41    pub force: Vector,
42}
43
44impl XpbdConstraint<2> for DistanceJoint {
45    fn entities(&self) -> [Entity; 2] {
46        [self.entity1, self.entity2]
47    }
48
49    fn clear_lagrange_multipliers(&mut self) {
50        self.lagrange = 0.0;
51    }
52
53    fn solve(&mut self, bodies: [&mut RigidBodyQueryItem; 2], dt: Scalar) {
54        self.force = self.constrain_length(bodies, dt);
55    }
56}
57
58impl Joint for DistanceJoint {
59    fn new(entity1: Entity, entity2: Entity) -> Self {
60        Self {
61            entity1,
62            entity2,
63            local_anchor1: Vector::ZERO,
64            local_anchor2: Vector::ZERO,
65            rest_length: 0.0,
66            length_limits: None,
67            damping_linear: 0.0,
68            damping_angular: 0.0,
69            lagrange: 0.0,
70            compliance: 0.0,
71            force: Vector::ZERO,
72        }
73    }
74
75    fn with_compliance(self, compliance: Scalar) -> Self {
76        Self { compliance, ..self }
77    }
78
79    fn with_local_anchor_1(self, anchor: Vector) -> Self {
80        Self {
81            local_anchor1: anchor,
82            ..self
83        }
84    }
85
86    fn with_local_anchor_2(self, anchor: Vector) -> Self {
87        Self {
88            local_anchor2: anchor,
89            ..self
90        }
91    }
92
93    fn with_linear_velocity_damping(self, damping: Scalar) -> Self {
94        Self {
95            damping_linear: damping,
96            ..self
97        }
98    }
99
100    fn with_angular_velocity_damping(self, damping: Scalar) -> Self {
101        Self {
102            damping_angular: damping,
103            ..self
104        }
105    }
106
107    fn local_anchor_1(&self) -> Vector {
108        self.local_anchor1
109    }
110
111    fn local_anchor_2(&self) -> Vector {
112        self.local_anchor2
113    }
114
115    fn damping_linear(&self) -> Scalar {
116        self.damping_linear
117    }
118
119    fn damping_angular(&self) -> Scalar {
120        self.damping_angular
121    }
122}
123
124impl DistanceJoint {
125    /// Constrains the distance the bodies with no constraint on their rotation.
126    ///
127    /// Returns the force exerted by this constraint.
128    fn constrain_length(&mut self, bodies: [&mut RigidBodyQueryItem; 2], dt: Scalar) -> Vector {
129        let [body1, body2] = bodies;
130        let world_r1 = *body1.rotation * self.local_anchor1;
131        let world_r2 = *body2.rotation * self.local_anchor2;
132
133        // If min and max limits aren't specified, use rest length
134        // TODO: Remove rest length, just use min/max limits.
135        let limits = self
136            .length_limits
137            .unwrap_or(DistanceLimit::new(self.rest_length, self.rest_length));
138
139        // Compute the direction and magnitude of the positional correction required
140        // to keep the bodies within a certain distance from each other.
141        let (dir, distance) = limits.compute_correction(
142            body1.current_position() + world_r1,
143            body2.current_position() + world_r2,
144        );
145
146        // Avoid division by zero and unnecessary computation
147        if distance.abs() < Scalar::EPSILON {
148            return Vector::ZERO;
149        }
150
151        // Compute generalized inverse masses (method from PositionConstraint)
152        let w1 = PositionConstraint::compute_generalized_inverse_mass(self, body1, world_r1, dir);
153        let w2 = PositionConstraint::compute_generalized_inverse_mass(self, body2, world_r2, dir);
154        let w = [w1, w2];
155
156        // Compute Lagrange multiplier update, essentially the signed magnitude of the correction
157        let delta_lagrange =
158            self.compute_lagrange_update(self.lagrange, distance, &w, self.compliance, dt);
159        self.lagrange += delta_lagrange;
160
161        // Apply positional correction (method from PositionConstraint)
162        self.apply_positional_lagrange_update(
163            body1,
164            body2,
165            delta_lagrange,
166            dir,
167            world_r1,
168            world_r2,
169        );
170
171        // Return constraint force
172        self.compute_force(self.lagrange, dir, dt)
173    }
174
175    /// Sets the minimum and maximum distances between the attached bodies.
176    pub fn with_limits(self, min: Scalar, max: Scalar) -> Self {
177        Self {
178            length_limits: Some(DistanceLimit::new(min, max)),
179            ..self
180        }
181    }
182
183    /// Sets the joint's rest length, or distance the bodies will be kept at.
184    pub fn with_rest_length(self, rest_length: Scalar) -> Self {
185        Self {
186            rest_length,
187            ..self
188        }
189    }
190}
191
192impl PositionConstraint for DistanceJoint {}
193
194impl AngularConstraint for DistanceJoint {}
195
196impl MapEntities for DistanceJoint {
197    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
198        self.entity1 = entity_mapper.get_mapped(self.entity1);
199        self.entity2 = entity_mapper.get_mapped(self.entity2);
200    }
201}