rapier2d/dynamics/joint/
rope_joint.rs

1use crate::dynamics::integration_parameters::SpringCoefficients;
2use crate::dynamics::joint::{GenericJoint, GenericJointBuilder, JointAxesMask};
3use crate::dynamics::{JointAxis, MotorModel};
4use crate::math::{Point, Real};
5
6use super::JointMotor;
7
8#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
9#[derive(Copy, Clone, Debug, PartialEq)]
10#[repr(transparent)]
11/// A distance-limiting joint (like a rope or cable connecting two objects).
12///
13/// Rope joints keep two bodies from getting too far apart, but allow them to get closer.
14/// They only apply force when stretched to their maximum length. Use for:
15/// - Ropes and chains
16/// - Cables and tethers
17/// - Leashes
18/// - Grappling hooks
19/// - Maximum distance constraints
20///
21/// Unlike spring joints, rope joints are inelastic - they don't bounce or stretch smoothly,
22/// they just enforce a hard maximum distance.
23pub struct RopeJoint {
24    /// The underlying joint data.
25    pub data: GenericJoint,
26}
27
28impl RopeJoint {
29    /// Creates a new rope joint limiting the max distance between two bodies.
30    ///
31    /// The `max_dist` must be strictly greater than 0.0.
32    pub fn new(max_dist: Real) -> Self {
33        let data = GenericJointBuilder::new(JointAxesMask::empty())
34            .coupled_axes(JointAxesMask::LIN_AXES)
35            .build();
36        let mut result = Self { data };
37        result.set_max_distance(max_dist);
38        result
39    }
40
41    /// The underlying generic joint.
42    pub fn data(&self) -> &GenericJoint {
43        &self.data
44    }
45
46    /// Are contacts between the attached rigid-bodies enabled?
47    pub fn contacts_enabled(&self) -> bool {
48        self.data.contacts_enabled
49    }
50
51    /// Sets whether contacts between the attached rigid-bodies are enabled.
52    pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
53        self.data.set_contacts_enabled(enabled);
54        self
55    }
56
57    /// The joint’s anchor, expressed in the local-space of the first rigid-body.
58    #[must_use]
59    pub fn local_anchor1(&self) -> Point<Real> {
60        self.data.local_anchor1()
61    }
62
63    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
64    pub fn set_local_anchor1(&mut self, anchor1: Point<Real>) -> &mut Self {
65        self.data.set_local_anchor1(anchor1);
66        self
67    }
68
69    /// The joint’s anchor, expressed in the local-space of the second rigid-body.
70    #[must_use]
71    pub fn local_anchor2(&self) -> Point<Real> {
72        self.data.local_anchor2()
73    }
74
75    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
76    pub fn set_local_anchor2(&mut self, anchor2: Point<Real>) -> &mut Self {
77        self.data.set_local_anchor2(anchor2);
78        self
79    }
80
81    /// The motor affecting the joint’s translational degree of freedom.
82    #[must_use]
83    pub fn motor(&self, axis: JointAxis) -> Option<&JointMotor> {
84        self.data.motor(axis)
85    }
86
87    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
88    pub fn set_motor_model(&mut self, model: MotorModel) -> &mut Self {
89        self.data.set_motor_model(JointAxis::LinX, model);
90        self
91    }
92
93    /// Sets the target velocity this motor needs to reach.
94    pub fn set_motor_velocity(&mut self, target_vel: Real, factor: Real) -> &mut Self {
95        self.data
96            .set_motor_velocity(JointAxis::LinX, target_vel, factor);
97        self
98    }
99
100    /// Sets the target angle this motor needs to reach.
101    pub fn set_motor_position(
102        &mut self,
103        target_pos: Real,
104        stiffness: Real,
105        damping: Real,
106    ) -> &mut Self {
107        self.data
108            .set_motor_position(JointAxis::LinX, target_pos, stiffness, damping);
109        self
110    }
111
112    /// Configure both the target angle and target velocity of the motor.
113    pub fn set_motor(
114        &mut self,
115        target_pos: Real,
116        target_vel: Real,
117        stiffness: Real,
118        damping: Real,
119    ) -> &mut Self {
120        self.data
121            .set_motor(JointAxis::LinX, target_pos, target_vel, stiffness, damping);
122        self
123    }
124
125    /// Sets the maximum force the motor can deliver.
126    pub fn set_motor_max_force(&mut self, max_force: Real) -> &mut Self {
127        self.data.set_motor_max_force(JointAxis::LinX, max_force);
128        self
129    }
130
131    /// The maximum rope length (distance between anchor points).
132    ///
133    /// Bodies can get closer but not farther than this distance.
134    #[must_use]
135    pub fn max_distance(&self) -> Real {
136        self.data
137            .limits(JointAxis::LinX)
138            .map(|l| l.max)
139            .unwrap_or(Real::MAX)
140    }
141
142    /// Changes the maximum rope length.
143    ///
144    /// Must be greater than 0.0. Bodies will be pulled together if farther apart.
145    ///
146    /// # Example
147    /// ```
148    /// # use rapier3d::prelude::*;
149    /// # use rapier3d::dynamics::RopeJoint;
150    /// # let mut rope_joint = RopeJoint::new(5.0);
151    /// rope_joint.set_max_distance(10.0);  // Max 10 units apart
152    /// ```
153    pub fn set_max_distance(&mut self, max_dist: Real) -> &mut Self {
154        self.data.set_limits(JointAxis::LinX, [0.0, max_dist]);
155        self
156    }
157
158    /// Gets the softness of this joint’s locked degrees of freedom.
159    #[must_use]
160    pub fn softness(&self) -> SpringCoefficients<Real> {
161        self.data.softness
162    }
163
164    /// Sets the softness of this joint’s locked degrees of freedom.
165    #[must_use]
166    pub fn set_softness(&mut self, softness: SpringCoefficients<Real>) -> &mut Self {
167        self.data.softness = softness;
168        self
169    }
170}
171
172impl From<RopeJoint> for GenericJoint {
173    fn from(val: RopeJoint) -> GenericJoint {
174        val.data
175    }
176}
177
178/// Create rope joints using the builder pattern.
179///
180/// A rope joint, limits the maximum distance between two bodies.
181#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
182#[derive(Copy, Clone, Debug, PartialEq)]
183pub struct RopeJointBuilder(pub RopeJoint);
184
185impl RopeJointBuilder {
186    /// Creates a new builder for rope joints.
187    pub fn new(max_dist: Real) -> Self {
188        Self(RopeJoint::new(max_dist))
189    }
190
191    /// Sets whether contacts between the attached rigid-bodies are enabled.
192    #[must_use]
193    pub fn contacts_enabled(mut self, enabled: bool) -> Self {
194        self.0.set_contacts_enabled(enabled);
195        self
196    }
197
198    /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body.
199    #[must_use]
200    pub fn local_anchor1(mut self, anchor1: Point<Real>) -> Self {
201        self.0.set_local_anchor1(anchor1);
202        self
203    }
204
205    /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body.
206    #[must_use]
207    pub fn local_anchor2(mut self, anchor2: Point<Real>) -> Self {
208        self.0.set_local_anchor2(anchor2);
209        self
210    }
211
212    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
213    #[must_use]
214    pub fn motor_model(mut self, model: MotorModel) -> Self {
215        self.0.set_motor_model(model);
216        self
217    }
218
219    /// Sets the target velocity this motor needs to reach.
220    #[must_use]
221    pub fn motor_velocity(mut self, target_vel: Real, factor: Real) -> Self {
222        self.0.set_motor_velocity(target_vel, factor);
223        self
224    }
225
226    /// Sets the target angle this motor needs to reach.
227    #[must_use]
228    pub fn motor_position(mut self, target_pos: Real, stiffness: Real, damping: Real) -> Self {
229        self.0.set_motor_position(target_pos, stiffness, damping);
230        self
231    }
232
233    /// Configure both the target angle and target velocity of the motor.
234    #[must_use]
235    pub fn set_motor(
236        mut self,
237        target_pos: Real,
238        target_vel: Real,
239        stiffness: Real,
240        damping: Real,
241    ) -> Self {
242        self.0.set_motor(target_pos, target_vel, stiffness, damping);
243        self
244    }
245
246    /// Sets the maximum force the motor can deliver.
247    #[must_use]
248    pub fn motor_max_force(mut self, max_force: Real) -> Self {
249        self.0.set_motor_max_force(max_force);
250        self
251    }
252
253    /// Sets the maximum allowed distance between the attached bodies.
254    ///
255    /// The `max_dist` must be strictly greater than 0.0.
256    #[must_use]
257    pub fn max_distance(mut self, max_dist: Real) -> Self {
258        self.0.set_max_distance(max_dist);
259        self
260    }
261
262    /// Sets the softness of this joint’s locked degrees of freedom.
263    #[must_use]
264    pub fn softness(mut self, softness: SpringCoefficients<Real>) -> Self {
265        self.0.data.softness = softness;
266        self
267    }
268
269    /// Builds the rope joint.
270    #[must_use]
271    pub fn build(self) -> RopeJoint {
272        self.0
273    }
274}
275
276impl From<RopeJointBuilder> for GenericJoint {
277    fn from(val: RopeJointBuilder) -> GenericJoint {
278        val.0.into()
279    }
280}