Skip to main content

bevy_rapier3d/dynamics/
generic_joint.rs

1use crate::dynamics::{FixedJoint, PrismaticJoint, RevoluteJoint, RopeJoint, TypedJoint};
2use crate::math::{Real, Rot, Vect};
3use rapier::dynamics::{
4    GenericJoint as RapierGenericJoint, JointAxesMask, JointAxis, JointLimits, JointMotor,
5    MotorModel, SpringCoefficients,
6};
7use rapier::math::Pose;
8
9#[cfg(feature = "dim2")]
10use crate::dynamics::PinSlotJoint;
11
12#[cfg(feature = "dim3")]
13use crate::dynamics::SphericalJoint;
14
15/// The description of any joint.
16#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
17#[derive(Copy, Clone, Debug, PartialEq, Default)]
18#[repr(transparent)]
19pub struct GenericJoint {
20    /// The raw Rapier description of the joint.
21    pub raw: RapierGenericJoint,
22}
23
24impl GenericJoint {
25    /// Converts this joint into a Rapier joint.
26    pub fn into_rapier(self) -> RapierGenericJoint {
27        self.raw
28    }
29}
30
31/*
32 * NOTE: the following are copy-pasted from Rapier’s GenericJoint, to match its
33 *       construction methods, but using glam types.
34 */
35
36impl GenericJoint {
37    /// Creates a new generic joint that locks the specified degrees of freedom.
38    #[must_use]
39    pub fn new(locked_axes: JointAxesMask) -> Self {
40        Self {
41            raw: RapierGenericJoint::new(locked_axes),
42        }
43    }
44
45    /// The set of axes locked by this joint.
46    pub fn locked_axes(&self) -> JointAxesMask {
47        self.raw.locked_axes
48    }
49
50    /// Add the specified axes to the set of axes locked by this joint.
51    pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
52        self.raw.lock_axes(axes);
53        self
54    }
55
56    /// The basis of this joint, expressed in the first rigid-body’s local-space.
57    #[must_use]
58    pub fn local_basis1(&self) -> Rot {
59        #[cfg(feature = "dim2")]
60        return self.raw.local_frame1.rotation.angle();
61        #[cfg(feature = "dim3")]
62        return self.raw.local_frame1.rotation;
63    }
64
65    /// Sets the joint’s frame, expressed in the first rigid-body’s local-space.
66    pub fn set_local_basis1(&mut self, local_basis: Rot) -> &mut Self {
67        #[cfg(feature = "dim2")]
68        {
69            self.raw.local_frame1.rotation = rapier::math::Rot2::new(local_basis);
70        }
71        #[cfg(feature = "dim3")]
72        {
73            self.raw.local_frame1.rotation = local_basis;
74        }
75        self
76    }
77
78    /// The basis of this joint, expressed in the second rigid-body’s local-space.
79    #[must_use]
80    pub fn local_basis2(&self) -> Rot {
81        #[cfg(feature = "dim2")]
82        return self.raw.local_frame2.rotation.angle();
83        #[cfg(feature = "dim3")]
84        return self.raw.local_frame2.rotation;
85    }
86
87    /// Sets the joint’s frame, expressed in the second rigid-body’s local-space.
88    pub fn set_local_basis2(&mut self, local_basis: Rot) -> &mut Self {
89        #[cfg(feature = "dim2")]
90        {
91            self.raw.local_frame2.rotation = rapier::math::Rot2::new(local_basis);
92        }
93        #[cfg(feature = "dim3")]
94        {
95            self.raw.local_frame2.rotation = local_basis;
96        }
97        self
98    }
99
100    /// The principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
101    #[must_use]
102    pub fn local_axis1(&self) -> Vect {
103        self.raw.local_axis1()
104    }
105
106    /// Sets the principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
107    pub fn set_local_axis1(&mut self, local_axis: Vect) -> &mut Self {
108        self.raw.set_local_axis1(local_axis.normalize());
109        self
110    }
111
112    /// The principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
113    #[must_use]
114    pub fn local_axis2(&self) -> Vect {
115        self.raw.local_axis2()
116    }
117
118    /// Sets the principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
119    pub fn set_local_axis2(&mut self, local_axis: Vect) -> &mut Self {
120        self.raw.set_local_axis2(local_axis.normalize());
121        self
122    }
123
124    /// The anchor of this joint, expressed in the first rigid-body’s local-space.
125    #[must_use]
126    pub fn local_anchor1(&self) -> Vect {
127        self.raw.local_anchor1()
128    }
129
130    /// Sets anchor of this joint, expressed in the first rigid-body’s local-space.
131    pub fn set_local_anchor1(&mut self, anchor1: Vect) -> &mut Self {
132        self.raw.set_local_anchor1(anchor1);
133        self
134    }
135
136    /// The anchor of this joint, expressed in the second rigid-body’s local-space.
137    #[must_use]
138    pub fn local_anchor2(&self) -> Vect {
139        self.raw.local_anchor2()
140    }
141
142    /// Sets anchor of this joint, expressed in the second rigid-body’s local-space.
143    pub fn set_local_anchor2(&mut self, anchor2: Vect) -> &mut Self {
144        self.raw.set_local_anchor2(anchor2);
145        self
146    }
147
148    /// The joint’s frame (anchor and basis), expressed in the first rigid-body’s local-space.
149    #[must_use]
150    pub fn local_frame1(&self) -> Pose {
151        self.raw.local_frame1
152    }
153
154    /// Sets the joint’s frame (anchor and basis), expressed in the first rigid-body’s local-space.
155    pub fn set_local_frame1(&mut self, local_frame: Pose) -> &mut Self {
156        self.raw.set_local_frame1(local_frame);
157        self
158    }
159
160    /// The joint’s frame (anchor and basis), expressed in the second rigid-body’s local-space.
161    #[must_use]
162    pub fn local_frame2(&self) -> Pose {
163        self.raw.local_frame2
164    }
165
166    /// Sets the joint’s frame (anchor and basis), expressed in the second rigid-body’s local-space.
167    pub fn set_local_frame2(&mut self, local_frame: Pose) -> &mut Self {
168        self.raw.set_local_frame2(local_frame);
169        self
170    }
171
172    /// Are contacts between the attached rigid-bodies enabled?
173    pub fn contacts_enabled(&self) -> bool {
174        self.raw.contacts_enabled
175    }
176
177    /// Sets whether contacts between the attached rigid-bodies are enabled.
178    pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
179        self.raw.set_contacts_enabled(enabled);
180        self
181    }
182
183    /// Is this joint enabled?
184    ///
185    /// This only reflects the value set on this joint description. See
186    /// [`ImpulseJointDisabled`](crate::dynamics::ImpulseJointDisabled) for a marker component
187    /// disabling an impulse joint.
188    pub fn is_enabled(&self) -> bool {
189        self.raw.is_enabled()
190    }
191
192    /// Sets whether this joint is enabled.
193    ///
194    /// A disabled impulse joint is ignored by the solver but stays attached to its rigid-bodies.
195    /// Multibody joints ignore this flag, except for filtering contacts between attached bodies.
196    pub fn set_enabled(&mut self, enabled: bool) -> &mut Self {
197        self.raw.set_enabled(enabled);
198        self
199    }
200
201    /// The spring coefficients controlling the softness of this joint’s locked degrees of freedom.
202    #[must_use]
203    pub fn softness(&self) -> SpringCoefficients<Real> {
204        self.raw.softness
205    }
206
207    /// Sets the spring coefficients controlling the softness of this joint’s locked degrees of freedom.
208    pub fn set_softness(&mut self, softness: SpringCoefficients<Real>) -> &mut Self {
209        self.raw.softness = softness;
210        self
211    }
212
213    /// Flips the orientation of the joint, swapping its two frames and negating its limits and motor targets.
214    ///
215    /// This is useful to keep the joint’s behavior unchanged after swapping its two attached rigid-bodies.
216    pub fn flip(&mut self) -> &mut Self {
217        self.raw.flip();
218        self
219    }
220
221    /// The joint limits along the specified axis.
222    #[must_use]
223    pub fn limits(&self, axis: JointAxis) -> Option<&JointLimits<Real>> {
224        self.raw.limits(axis)
225    }
226
227    /// Sets the joint limits along the specified axis.
228    pub fn set_limits(&mut self, axis: JointAxis, limits: [Real; 2]) -> &mut Self {
229        self.raw.set_limits(axis, limits);
230        self
231    }
232
233    /// Sets the coupled degrees of freedom for this joint’s limits and motor.
234    pub fn set_coupled_axes(&mut self, axes: JointAxesMask) -> &mut Self {
235        self.raw.coupled_axes = axes;
236        self
237    }
238
239    /// The spring-like motor model along the specified axis of this joint.
240    #[must_use]
241    pub fn motor_model(&self, axis: JointAxis) -> Option<MotorModel> {
242        self.raw.motor_model(axis)
243    }
244
245    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
246    pub fn set_motor_model(&mut self, axis: JointAxis, model: MotorModel) -> &mut Self {
247        self.raw.set_motor_model(axis, model);
248        self
249    }
250
251    /// Sets the target velocity this motor needs to reach.
252    pub fn set_motor_velocity(
253        &mut self,
254        axis: JointAxis,
255        target_vel: Real,
256        factor: Real,
257    ) -> &mut Self {
258        self.raw.set_motor_velocity(axis, target_vel, factor);
259        self
260    }
261
262    /// Sets the target angle this motor needs to reach.
263    pub fn set_motor_position(
264        &mut self,
265        axis: JointAxis,
266        target_pos: Real,
267        stiffness: Real,
268        damping: Real,
269    ) -> &mut Self {
270        self.raw
271            .set_motor_position(axis, target_pos, stiffness, damping);
272        self
273    }
274
275    /// Sets the maximum force the motor can deliver along the specified axis.
276    pub fn set_motor_max_force(&mut self, axis: JointAxis, max_force: Real) -> &mut Self {
277        self.raw.set_motor_max_force(axis, max_force);
278        self
279    }
280
281    /// The motor affecting the joint’s degree of freedom along the specified axis.
282    #[must_use]
283    pub fn motor(&self, axis: JointAxis) -> Option<&JointMotor> {
284        self.raw.motor(axis)
285    }
286
287    /// Configure both the target angle and target velocity of the motor.
288    pub fn set_motor(
289        &mut self,
290        axis: JointAxis,
291        target_pos: Real,
292        target_vel: Real,
293        stiffness: Real,
294        damping: Real,
295    ) -> &mut Self {
296        self.raw
297            .set_motor(axis, target_pos, target_vel, stiffness, damping);
298        self
299    }
300}
301
302macro_rules! joint_conversion_methods(
303    ($as_joint: ident, $as_joint_mut: ident, $Joint: ty, $axes: expr) => {
304        /// Converts the joint to its specific variant, if it is one.
305        #[must_use]
306        pub fn $as_joint(&self) -> Option<&$Joint> {
307            if self.locked_axes() == $axes {
308                // SAFETY: this is OK because the target joint type is
309                //         a `repr(transparent)` newtype of `Joint`.
310                Some(unsafe { std::mem::transmute::<&Self, &$Joint>(self) })
311            } else {
312                None
313            }
314        }
315
316        /// Converts the joint to its specific mutable variant, if it is one.
317        #[must_use]
318        pub fn $as_joint_mut(&mut self) -> Option<&mut $Joint> {
319            if self.locked_axes() == $axes {
320                // SAFETY: this is OK because the target joint type is
321                //         a `repr(transparent)` newtype of `Joint`.
322                Some(unsafe { std::mem::transmute::<&mut Self, &mut $Joint>(self) })
323            } else {
324                None
325            }
326        }
327    }
328);
329
330impl GenericJoint {
331    joint_conversion_methods!(
332        as_revolute,
333        as_revolute_mut,
334        RevoluteJoint,
335        JointAxesMask::LOCKED_REVOLUTE_AXES
336    );
337    joint_conversion_methods!(
338        as_fixed,
339        as_fixed_mut,
340        FixedJoint,
341        JointAxesMask::LOCKED_FIXED_AXES
342    );
343    joint_conversion_methods!(
344        as_prismatic,
345        as_prismatic_mut,
346        PrismaticJoint,
347        JointAxesMask::LOCKED_PRISMATIC_AXES
348    );
349    joint_conversion_methods!(
350        as_rope,
351        as_rope_mut,
352        RopeJoint,
353        JointAxesMask::FREE_FIXED_AXES
354    );
355
356    #[cfg(feature = "dim3")]
357    joint_conversion_methods!(
358        as_spherical,
359        as_spherical_mut,
360        SphericalJoint,
361        JointAxesMask::LOCKED_SPHERICAL_AXES
362    );
363
364    #[cfg(feature = "dim2")]
365    joint_conversion_methods!(
366        as_pin_slot,
367        as_pin_slot_mut,
368        PinSlotJoint,
369        JointAxesMask::LOCKED_PIN_SLOT_AXES
370    );
371}
372
373/// Create generic joints using the builder pattern.
374#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
375#[derive(Copy, Clone, Debug)]
376pub struct GenericJointBuilder(GenericJoint);
377
378impl GenericJointBuilder {
379    /// Creates a new generic joint builder.
380    #[must_use]
381    pub fn new(locked_axes: JointAxesMask) -> Self {
382        Self(GenericJoint::new(locked_axes))
383    }
384
385    /// Sets the degrees of freedom locked by the joint.
386    #[must_use]
387    pub fn locked_axes(mut self, axes: JointAxesMask) -> Self {
388        self.0.lock_axes(axes);
389        self
390    }
391
392    /// Sets the joint’s frame, expressed in the first rigid-body’s local-space.
393    #[must_use]
394    pub fn local_basis1(mut self, local_basis: Rot) -> Self {
395        self.0.set_local_basis1(local_basis);
396        self
397    }
398
399    /// Sets the joint’s frame, expressed in the second rigid-body’s local-space.
400    #[must_use]
401    pub fn local_basis2(mut self, local_basis: Rot) -> Self {
402        self.0.set_local_basis2(local_basis);
403        self
404    }
405
406    /// Sets the principal (local X) axis of this joint, expressed in the first rigid-body’s local-space.
407    #[must_use]
408    pub fn local_axis1(mut self, local_axis: Vect) -> Self {
409        self.0.set_local_axis1(local_axis);
410        self
411    }
412
413    /// Sets the principal (local X) axis of this joint, expressed in the second rigid-body’s local-space.
414    #[must_use]
415    pub fn local_axis2(mut self, local_axis: Vect) -> Self {
416        self.0.set_local_axis2(local_axis);
417        self
418    }
419
420    /// Sets the anchor of this joint, expressed in the first rigid-body’s local-space.
421    #[must_use]
422    pub fn local_anchor1(mut self, anchor1: Vect) -> Self {
423        self.0.set_local_anchor1(anchor1);
424        self
425    }
426
427    /// Sets the anchor of this joint, expressed in the second rigid-body’s local-space.
428    #[must_use]
429    pub fn local_anchor2(mut self, anchor2: Vect) -> Self {
430        self.0.set_local_anchor2(anchor2);
431        self
432    }
433
434    /// Sets the joint’s frame (anchor and basis), expressed in the first rigid-body’s local-space.
435    #[must_use]
436    pub fn local_frame1(mut self, local_frame: Pose) -> Self {
437        self.0.set_local_frame1(local_frame);
438        self
439    }
440
441    /// Sets the joint’s frame (anchor and basis), expressed in the second rigid-body’s local-space.
442    #[must_use]
443    pub fn local_frame2(mut self, local_frame: Pose) -> Self {
444        self.0.set_local_frame2(local_frame);
445        self
446    }
447
448    /// Sets whether contacts between the attached rigid-bodies are enabled.
449    #[must_use]
450    pub fn contacts_enabled(mut self, enabled: bool) -> Self {
451        self.0.set_contacts_enabled(enabled);
452        self
453    }
454
455    /// Sets whether the joint is enabled.
456    #[must_use]
457    pub fn enabled(mut self, enabled: bool) -> Self {
458        self.0.set_enabled(enabled);
459        self
460    }
461
462    /// Sets the spring coefficients controlling the softness of this joint’s locked degrees of freedom.
463    #[must_use]
464    pub fn softness(mut self, softness: SpringCoefficients<Real>) -> Self {
465        self.0.set_softness(softness);
466        self
467    }
468
469    /// Sets the joint limits along the specified axis.
470    #[must_use]
471    pub fn limits(mut self, axis: JointAxis, limits: [Real; 2]) -> Self {
472        self.0.set_limits(axis, limits);
473        self
474    }
475
476    /// Sets the coupled degrees of freedom for this joint’s limits and motor.
477    #[must_use]
478    pub fn coupled_axes(mut self, axes: JointAxesMask) -> Self {
479        self.0.set_coupled_axes(axes);
480        self
481    }
482
483    /// Set the spring-like model used by the motor to reach the desired target velocity and position.
484    #[must_use]
485    pub fn motor_model(mut self, axis: JointAxis, model: MotorModel) -> Self {
486        self.0.set_motor_model(axis, model);
487        self
488    }
489
490    /// Sets the target velocity this motor needs to reach.
491    #[must_use]
492    pub fn motor_velocity(mut self, axis: JointAxis, target_vel: Real, factor: Real) -> Self {
493        self.0.set_motor_velocity(axis, target_vel, factor);
494        self
495    }
496
497    /// Sets the target angle this motor needs to reach.
498    #[must_use]
499    pub fn motor_position(
500        mut self,
501        axis: JointAxis,
502        target_pos: Real,
503        stiffness: Real,
504        damping: Real,
505    ) -> Self {
506        self.0
507            .set_motor_position(axis, target_pos, stiffness, damping);
508        self
509    }
510
511    /// Configure both the target angle and target velocity of the motor.
512    #[must_use]
513    pub fn set_motor(
514        mut self,
515        axis: JointAxis,
516        target_pos: Real,
517        target_vel: Real,
518        stiffness: Real,
519        damping: Real,
520    ) -> Self {
521        self.0
522            .set_motor(axis, target_pos, target_vel, stiffness, damping);
523        self
524    }
525
526    /// Sets the maximum force the motor can deliver along the specified axis.
527    #[must_use]
528    pub fn motor_max_force(mut self, axis: JointAxis, max_force: Real) -> Self {
529        self.0.set_motor_max_force(axis, max_force);
530        self
531    }
532
533    /// Builds the generic joint.
534    #[must_use]
535    pub fn build(self) -> GenericJoint {
536        self.0
537    }
538}
539
540impl From<GenericJointBuilder> for GenericJoint {
541    fn from(joint: GenericJointBuilder) -> GenericJoint {
542        joint.0
543    }
544}
545
546impl From<GenericJointBuilder> for TypedJoint {
547    fn from(joint: GenericJointBuilder) -> TypedJoint {
548        joint.0.into()
549    }
550}
551
552impl From<GenericJoint> for TypedJoint {
553    fn from(joint: GenericJoint) -> TypedJoint {
554        TypedJoint::GenericJoint(joint)
555    }
556}