rapier3d/dynamics/joint/
spring_joint.rs

1use crate::dynamics::joint::{GenericJoint, GenericJointBuilder, JointAxesMask};
2use crate::dynamics::{JointAxis, MotorModel};
3use crate::math::{Point, Real};
4
5#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
6#[derive(Copy, Clone, Debug, PartialEq)]
7#[repr(transparent)]
8/// A spring-damper joint, applies a force proportional to the distance between two objects.
9///
10/// The spring is integrated implicitly, implying that even an undamped spring will be subject to some
11/// amount of numerical damping (so it will eventually come to a rest). More solver iterations, or smaller
12/// timesteps, will lower the effect of numerical damping, providing a more realistic result.
13pub struct SpringJoint {
14    /// The underlying joint data.
15    pub data: GenericJoint,
16}
17
18impl SpringJoint {
19    /// Creates a new spring joint limiting the max distance between two bodies.
20    ///
21    /// The `max_dist` must be strictly greater than 0.0.
22    pub fn new(rest_length: Real, stiffness: Real, damping: Real) -> Self {
23        let data = GenericJointBuilder::new(JointAxesMask::empty())
24            .coupled_axes(JointAxesMask::LIN_AXES)
25            .motor_position(JointAxis::LinX, rest_length, stiffness, damping)
26            .motor_model(JointAxis::LinX, MotorModel::ForceBased)
27            .build();
28        Self { data }
29    }
30
31    /// The underlying generic joint.
32    pub fn data(&self) -> &GenericJoint {
33        &self.data
34    }
35
36    /// Are contacts between the attached rigid-bodies enabled?
37    pub fn contacts_enabled(&self) -> bool {
38        self.data.contacts_enabled
39    }
40
41    /// Sets whether contacts between the attached rigid-bodies are enabled.
42    pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
43        self.data.set_contacts_enabled(enabled);
44        self
45    }
46
47    /// The joint’s anchor, expressed in the local-space of the first rigid-body.
48    #[must_use]
49    pub fn local_anchor1(&self) -> Point<Real> {
50        self.data.local_anchor1()
51    }
52
53    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
54    pub fn set_local_anchor1(&mut self, anchor1: Point<Real>) -> &mut Self {
55        self.data.set_local_anchor1(anchor1);
56        self
57    }
58
59    /// The joint’s anchor, expressed in the local-space of the second rigid-body.
60    #[must_use]
61    pub fn local_anchor2(&self) -> Point<Real> {
62        self.data.local_anchor2()
63    }
64
65    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
66    pub fn set_local_anchor2(&mut self, anchor2: Point<Real>) -> &mut Self {
67        self.data.set_local_anchor2(anchor2);
68        self
69    }
70
71    /// Set the spring model used by this joint to reach the desired target velocity and position.
72    ///
73    /// Setting this to `MotorModel::ForceBased` (which is the default value for this joint) makes the spring constants
74    /// (stiffness and damping) parameter understood as in the regular spring-mass-damper system. With
75    /// `MotorModel::AccelerationBased`, the spring constants will be automatically scaled by the attached masses,
76    /// making the spring more mass-independent.
77    pub fn set_spring_model(&mut self, model: MotorModel) -> &mut Self {
78        self.data.set_motor_model(JointAxis::LinX, model);
79        self
80    }
81
82    // /// The maximum distance allowed between the attached objects.
83    // #[must_use]
84    // pub fn rest_length(&self) -> Option<Real> {
85    //     self.data.limits(JointAxis::X).map(|l| l.max)
86    // }
87    //
88    // /// Sets the maximum allowed distance between the attached objects.
89    // ///
90    // /// The `max_dist` must be strictly greater than 0.0.
91    // pub fn set_rest_length(&mut self, max_dist: Real) -> &mut Self {
92    //     self.data.set_limits(JointAxis::X, [0.0, max_dist]);
93    //     self
94    // }
95}
96
97impl From<SpringJoint> for GenericJoint {
98    fn from(val: SpringJoint) -> GenericJoint {
99        val.data
100    }
101}
102
103/// A [SpringJoint] joint using the builder pattern.
104///
105/// This builds a spring-damper joint which applies a force proportional to the distance between two objects.
106/// See the documentation of [SpringJoint] for more information on its behavior.
107#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
108#[derive(Copy, Clone, Debug, PartialEq)]
109pub struct SpringJointBuilder(pub SpringJoint);
110
111impl SpringJointBuilder {
112    /// Creates a new builder for spring joints.
113    ///
114    /// This axis is expressed in the local-space of both rigid-bodies.
115    pub fn new(rest_length: Real, stiffness: Real, damping: Real) -> Self {
116        Self(SpringJoint::new(rest_length, stiffness, damping))
117    }
118
119    /// Sets whether contacts between the attached rigid-bodies are enabled.
120    #[must_use]
121    pub fn contacts_enabled(mut self, enabled: bool) -> Self {
122        self.0.set_contacts_enabled(enabled);
123        self
124    }
125
126    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
127    #[must_use]
128    pub fn local_anchor1(mut self, anchor1: Point<Real>) -> Self {
129        self.0.set_local_anchor1(anchor1);
130        self
131    }
132
133    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
134    #[must_use]
135    pub fn local_anchor2(mut self, anchor2: Point<Real>) -> Self {
136        self.0.set_local_anchor2(anchor2);
137        self
138    }
139
140    /// Set the spring used by this joint to reach the desired target velocity and position.
141    ///
142    /// Setting this to `MotorModel::ForceBased` (which is the default value for this joint) makes the spring constants
143    /// (stiffness and damping) parameter understood as in the regular spring-mass-damper system. With
144    /// `MotorModel::AccelerationBased`, the spring constants will be automatically scaled by the attached masses,
145    /// making the spring more mass-independent.
146    #[must_use]
147    pub fn spring_model(mut self, model: MotorModel) -> Self {
148        self.0.set_spring_model(model);
149        self
150    }
151
152    // /// Sets the maximum allowed distance between the attached bodies.
153    // ///
154    // /// The `max_dist` must be strictly greater than 0.0.
155    // #[must_use]
156    // pub fn max_distance(mut self, max_dist: Real) -> Self {
157    //     self.0.set_max_distance(max_dist);
158    //     self
159    // }
160
161    /// Builds the spring joint.
162    #[must_use]
163    pub fn build(self) -> SpringJoint {
164        self.0
165    }
166}
167
168impl From<SpringJointBuilder> for GenericJoint {
169    fn from(val: SpringJointBuilder) -> GenericJoint {
170        val.0.into()
171    }
172}