bevy_rapier2d/dynamics/
generic_joint.rs

1use crate::dynamics::{FixedJoint, PrismaticJoint, RevoluteJoint, RopeJoint};
2use crate::math::{Real, Rot, Vect};
3use rapier::dynamics::{
4    GenericJoint as RapierGenericJoint, JointAxesMask, JointAxis, JointLimits, JointMotor,
5    MotorModel,
6};
7
8#[cfg(feature = "dim3")]
9use crate::dynamics::SphericalJoint;
10
11/// The description of any joint.
12#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
13#[derive(Copy, Clone, Debug, PartialEq, Default)]
14#[repr(transparent)]
15pub struct GenericJoint {
16    /// The raw Rapier description of the joint.
17    pub raw: RapierGenericJoint,
18}
19
20impl GenericJoint {
21    /// Converts this joint into a Rapier joint.
22    pub fn into_rapier(self) -> RapierGenericJoint {
23        self.raw
24    }
25}
26
27/*
28 * NOTE: the following are copy-pasted from Rapier’s GenericJoint, to match its
29 *       construction methods, but using glam types.
30 */
31
32impl GenericJoint {
33    /// Creates a new generic joint that locks the specified degrees of freedom.
34    #[must_use]
35    pub fn new(locked_axes: JointAxesMask) -> Self {
36        Self {
37            raw: RapierGenericJoint::new(locked_axes),
38        }
39    }
40
41    /// The set of axes locked by this joint.
42    pub fn locked_axes(&self) -> JointAxesMask {
43        self.raw.locked_axes
44    }
45
46    /// Add the specified axes to the set of axes locked by this joint.
47    pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
48        self.raw.lock_axes(axes);
49        self
50    }
51
52    /// The basis of this joint, expressed in the first rigid-body’s local-space.
53    #[must_use]
54    pub fn local_basis1(&self) -> Rot {
55        #[cfg(feature = "dim2")]
56        return self.raw.local_frame1.rotation.angle();
57        #[cfg(feature = "dim3")]
58        return self.raw.local_frame1.rotation.into();
59    }
60
61    /// Sets the joint’s frame, expressed in the first rigid-body’s local-space.
62    pub fn set_local_basis1(&mut self, local_basis: Rot) -> &mut Self {
63        #[cfg(feature = "dim2")]
64        {
65            self.raw.local_frame1.rotation = na::UnitComplex::new(local_basis);
66        }
67        #[cfg(feature = "dim3")]
68        {
69            self.raw.local_frame1.rotation = local_basis.into();
70        }
71        self
72    }
73
74    /// The basis of this joint, expressed in the second rigid-body’s local-space.
75    #[must_use]
76    pub fn local_basis2(&self) -> Rot {
77        #[cfg(feature = "dim2")]
78        return self.raw.local_frame2.rotation.angle();
79        #[cfg(feature = "dim3")]
80        return self.raw.local_frame2.rotation.into();
81    }
82
83    /// Sets the joint’s frame, expressed in the second rigid-body’s local-space.
84    pub fn set_local_basis2(&mut self, local_basis: Rot) -> &mut Self {
85        #[cfg(feature = "dim2")]
86        {
87            self.raw.local_frame2.rotation = na::UnitComplex::new(local_basis);
88        }
89        #[cfg(feature = "dim3")]
90        {
91            self.raw.local_frame2.rotation = local_basis.into();
92        }
93        self
94    }
95
96    /// The principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
97    #[must_use]
98    pub fn local_axis1(&self) -> Vect {
99        (*self.raw.local_axis1()).into()
100    }
101
102    /// Sets the principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
103    pub fn set_local_axis1(&mut self, local_axis: Vect) -> &mut Self {
104        self.raw.set_local_axis1(local_axis.try_into().unwrap());
105        self
106    }
107
108    /// The principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
109    #[must_use]
110    pub fn local_axis2(&self) -> Vect {
111        (*self.raw.local_axis2()).into()
112    }
113
114    /// Sets the principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
115    pub fn set_local_axis2(&mut self, local_axis: Vect) -> &mut Self {
116        self.raw.set_local_axis2(local_axis.try_into().unwrap());
117        self
118    }
119
120    /// The anchor of this joint, expressed in the first rigid-body’s local-space.
121    #[must_use]
122    pub fn local_anchor1(&self) -> Vect {
123        self.raw.local_anchor1().into()
124    }
125
126    /// Sets anchor of this joint, expressed in the first rigid-body’s local-space.
127    pub fn set_local_anchor1(&mut self, anchor1: Vect) -> &mut Self {
128        self.raw.set_local_anchor1(anchor1.into());
129        self
130    }
131
132    /// The anchor of this joint, expressed in the second rigid-body’s local-space.
133    #[must_use]
134    pub fn local_anchor2(&self) -> Vect {
135        self.raw.local_anchor2().into()
136    }
137
138    /// Sets anchor of this joint, expressed in the second rigid-body’s local-space.
139    pub fn set_local_anchor2(&mut self, anchor2: Vect) -> &mut Self {
140        self.raw.set_local_anchor2(anchor2.into());
141        self
142    }
143
144    /// Are contacts between the attached rigid-bodies enabled?
145    pub fn contacts_enabled(&self) -> bool {
146        self.raw.contacts_enabled
147    }
148
149    /// Sets whether contacts between the attached rigid-bodies are enabled.
150    pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
151        self.raw.set_contacts_enabled(enabled);
152        self
153    }
154
155    /// The joint limits along the specified axis.
156    #[must_use]
157    pub fn limits(&self, axis: JointAxis) -> Option<&JointLimits<Real>> {
158        self.raw.limits(axis)
159    }
160
161    /// Sets the joint limits along the specified axis.
162    pub fn set_limits(&mut self, axis: JointAxis, limits: [Real; 2]) -> &mut Self {
163        self.raw.set_limits(axis, limits);
164        self
165    }
166
167    /// Sets the coupled degrees of freedom for this joint’s limits and motor.
168    pub fn set_coupled_axes(&mut self, axes: JointAxesMask) -> &mut Self {
169        self.raw.coupled_axes = axes;
170        self
171    }
172
173    /// The spring-like motor model along the specified axis of this joint.
174    #[must_use]
175    pub fn motor_model(&self, axis: JointAxis) -> Option<MotorModel> {
176        self.raw.motor_model(axis)
177    }
178
179    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
180    pub fn set_motor_model(&mut self, axis: JointAxis, model: MotorModel) -> &mut Self {
181        self.raw.set_motor_model(axis, model);
182        self
183    }
184
185    /// Sets the target velocity this motor needs to reach.
186    pub fn set_motor_velocity(
187        &mut self,
188        axis: JointAxis,
189        target_vel: Real,
190        factor: Real,
191    ) -> &mut Self {
192        self.raw.set_motor_velocity(axis, target_vel, factor);
193        self
194    }
195
196    /// Sets the target angle this motor needs to reach.
197    pub fn set_motor_position(
198        &mut self,
199        axis: JointAxis,
200        target_pos: Real,
201        stiffness: Real,
202        damping: Real,
203    ) -> &mut Self {
204        self.raw
205            .set_motor_position(axis, target_pos, stiffness, damping);
206        self
207    }
208
209    /// Sets the maximum force the motor can deliver along the specified axis.
210    pub fn set_motor_max_force(&mut self, axis: JointAxis, max_force: Real) -> &mut Self {
211        self.raw.set_motor_max_force(axis, max_force);
212        self
213    }
214
215    /// The motor affecting the joint’s degree of freedom along the specified axis.
216    #[must_use]
217    pub fn motor(&self, axis: JointAxis) -> Option<&JointMotor> {
218        self.raw.motor(axis)
219    }
220
221    /// Configure both the target angle and target velocity of the motor.
222    pub fn set_motor(
223        &mut self,
224        axis: JointAxis,
225        target_pos: Real,
226        target_vel: Real,
227        stiffness: Real,
228        damping: Real,
229    ) -> &mut Self {
230        self.raw
231            .set_motor(axis, target_pos, target_vel, stiffness, damping);
232        self
233    }
234}
235
236macro_rules! joint_conversion_methods(
237    ($as_joint: ident, $as_joint_mut: ident, $Joint: ty, $axes: expr) => {
238        /// Converts the joint to its specific variant, if it is one.
239        #[must_use]
240        pub fn $as_joint(&self) -> Option<&$Joint> {
241            if self.locked_axes() == $axes {
242                // SAFETY: this is OK because the target joint type is
243                //         a `repr(transparent)` newtype of `Joint`.
244                Some(unsafe { std::mem::transmute::<&Self, &$Joint>(self) })
245            } else {
246                None
247            }
248        }
249
250        /// Converts the joint to its specific mutable variant, if it is one.
251        #[must_use]
252        pub fn $as_joint_mut(&mut self) -> Option<&mut $Joint> {
253            if self.locked_axes() == $axes {
254                // SAFETY: this is OK because the target joint type is
255                //         a `repr(transparent)` newtype of `Joint`.
256                Some(unsafe { std::mem::transmute::<&mut Self, &mut $Joint>(self) })
257            } else {
258                None
259            }
260        }
261    }
262);
263
264impl GenericJoint {
265    joint_conversion_methods!(
266        as_revolute,
267        as_revolute_mut,
268        RevoluteJoint,
269        JointAxesMask::LOCKED_REVOLUTE_AXES
270    );
271    joint_conversion_methods!(
272        as_fixed,
273        as_fixed_mut,
274        FixedJoint,
275        JointAxesMask::LOCKED_FIXED_AXES
276    );
277    joint_conversion_methods!(
278        as_prismatic,
279        as_prismatic_mut,
280        PrismaticJoint,
281        JointAxesMask::LOCKED_PRISMATIC_AXES
282    );
283    joint_conversion_methods!(
284        as_rope,
285        as_rope_mut,
286        RopeJoint,
287        JointAxesMask::FREE_FIXED_AXES
288    );
289
290    #[cfg(feature = "dim3")]
291    joint_conversion_methods!(
292        as_spherical,
293        as_spherical_mut,
294        SphericalJoint,
295        JointAxesMask::LOCKED_SPHERICAL_AXES
296    );
297}
298
299/// Create generic joints using the builder pattern.
300#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
301#[derive(Copy, Clone, Debug)]
302pub struct GenericJointBuilder(GenericJoint);
303
304impl GenericJointBuilder {
305    /// Creates a new generic joint builder.
306    #[must_use]
307    pub fn new(locked_axes: JointAxesMask) -> Self {
308        Self(GenericJoint::new(locked_axes))
309    }
310
311    /// Sets the degrees of freedom locked by the joint.
312    #[must_use]
313    pub fn locked_axes(mut self, axes: JointAxesMask) -> Self {
314        self.0.lock_axes(axes);
315        self
316    }
317
318    /// Sets the joint’s frame, expressed in the first rigid-body’s local-space.
319    #[must_use]
320    pub fn local_basis1(mut self, local_basis: Rot) -> Self {
321        self.0.set_local_basis1(local_basis);
322        self
323    }
324
325    /// Sets the joint’s frame, expressed in the second rigid-body’s local-space.
326    #[must_use]
327    pub fn local_basis2(mut self, local_basis: Rot) -> Self {
328        self.0.set_local_basis2(local_basis);
329        self
330    }
331
332    /// Sets the principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
333    #[must_use]
334    pub fn local_axis1(mut self, local_axis: Vect) -> Self {
335        self.0.set_local_axis1(local_axis);
336        self
337    }
338
339    /// Sets the principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
340    #[must_use]
341    pub fn local_axis2(mut self, local_axis: Vect) -> Self {
342        self.0.set_local_axis2(local_axis);
343        self
344    }
345
346    /// Sets the anchor of this joint, expressed in the first rigid-body’s local-space.
347    #[must_use]
348    pub fn local_anchor1(mut self, anchor1: Vect) -> Self {
349        self.0.set_local_anchor1(anchor1);
350        self
351    }
352
353    /// Sets the anchor of this joint, expressed in the second rigid-body’s local-space.
354    #[must_use]
355    pub fn local_anchor2(mut self, anchor2: Vect) -> Self {
356        self.0.set_local_anchor2(anchor2);
357        self
358    }
359
360    /// Sets the joint limits along the specified axis.
361    #[must_use]
362    pub fn limits(mut self, axis: JointAxis, limits: [Real; 2]) -> Self {
363        self.0.set_limits(axis, limits);
364        self
365    }
366
367    /// Sets the coupled degrees of freedom for this joint’s limits and motor.
368    #[must_use]
369    pub fn coupled_axes(mut self, axes: JointAxesMask) -> Self {
370        self.0.set_coupled_axes(axes);
371        self
372    }
373
374    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
375    #[must_use]
376    pub fn motor_model(mut self, axis: JointAxis, model: MotorModel) -> Self {
377        self.0.set_motor_model(axis, model);
378        self
379    }
380
381    /// Sets the target velocity this motor needs to reach.
382    #[must_use]
383    pub fn motor_velocity(mut self, axis: JointAxis, target_vel: Real, factor: Real) -> Self {
384        self.0.set_motor_velocity(axis, target_vel, factor);
385        self
386    }
387
388    /// Sets the target angle this motor needs to reach.
389    #[must_use]
390    pub fn motor_position(
391        mut self,
392        axis: JointAxis,
393        target_pos: Real,
394        stiffness: Real,
395        damping: Real,
396    ) -> Self {
397        self.0
398            .set_motor_position(axis, target_pos, stiffness, damping);
399        self
400    }
401
402    /// Configure both the target angle and target velocity of the motor.
403    #[must_use]
404    pub fn set_motor(
405        mut self,
406        axis: JointAxis,
407        target_pos: Real,
408        target_vel: Real,
409        stiffness: Real,
410        damping: Real,
411    ) -> Self {
412        self.0
413            .set_motor(axis, target_pos, target_vel, stiffness, damping);
414        self
415    }
416
417    /// Sets the maximum force the motor can deliver along the specified axis.
418    #[must_use]
419    pub fn motor_max_force(mut self, axis: JointAxis, max_force: Real) -> Self {
420        self.0.set_motor_max_force(axis, max_force);
421        self
422    }
423
424    /// Builds the generic joint.
425    #[must_use]
426    pub fn build(self) -> GenericJoint {
427        self.0
428    }
429}
430
431impl From<GenericJointBuilder> for GenericJoint {
432    fn from(joint: GenericJointBuilder) -> GenericJoint {
433        joint.0
434    }
435}