rapier2d/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}