1#![allow(clippy::bad_bit_mask)] #![allow(clippy::unnecessary_cast)] use crate::dynamics::integration_parameters::SpringCoefficients;
5use crate::dynamics::solver::MotorParameters;
6use crate::dynamics::{
7 FixedJoint, MotorModel, PrismaticJoint, RevoluteJoint, RigidBody, RopeJoint,
8};
9use crate::math::{Isometry, Point, Real, Rotation, SPATIAL_DIM, UnitVector, Vector};
10use crate::utils::{SimdBasis, SimdRealCopy};
11
12#[cfg(feature = "dim3")]
13use crate::dynamics::SphericalJoint;
14
15#[cfg(feature = "dim3")]
16bitflags::bitflags! {
17 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
19 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
20 pub struct JointAxesMask: u8 {
21 const LIN_X = 1 << 0;
23 const LIN_Y = 1 << 1;
25 const LIN_Z = 1 << 2;
27 const ANG_X = 1 << 3;
29 const ANG_Y = 1 << 4;
31 const ANG_Z = 1 << 5;
33 const LOCKED_REVOLUTE_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::LIN_Z.bits() | Self::ANG_Y.bits() | Self::ANG_Z.bits();
35 const LOCKED_PRISMATIC_AXES = Self::LIN_Y.bits() | Self::LIN_Z.bits() | Self::ANG_X.bits() | Self::ANG_Y.bits() | Self::ANG_Z.bits();
37 const LOCKED_FIXED_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::LIN_Z.bits() | Self::ANG_X.bits() | Self::ANG_Y.bits() | Self::ANG_Z.bits();
39 const LOCKED_SPHERICAL_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::LIN_Z.bits();
41 const FREE_REVOLUTE_AXES = Self::ANG_X.bits();
43 const FREE_PRISMATIC_AXES = Self::LIN_X.bits();
45 const FREE_FIXED_AXES = 0;
47 const FREE_SPHERICAL_AXES = Self::ANG_X.bits() | Self::ANG_Y.bits() | Self::ANG_Z.bits();
49 const LIN_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::LIN_Z.bits();
51 const ANG_AXES = Self::ANG_X.bits() | Self::ANG_Y.bits() | Self::ANG_Z.bits();
53 }
54}
55
56#[cfg(feature = "dim2")]
57bitflags::bitflags! {
58 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
60 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
61 pub struct JointAxesMask: u8 {
62 const LIN_X = 1 << 0;
64 const LIN_Y = 1 << 1;
66 const ANG_X = 1 << 2;
68 const LOCKED_REVOLUTE_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits();
70 const LOCKED_PRISMATIC_AXES = Self::LIN_Y.bits() | Self::ANG_X.bits();
72 const LOCKED_PIN_SLOT_AXES = Self::LIN_Y.bits();
74 const LOCKED_FIXED_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::ANG_X.bits();
76 const FREE_REVOLUTE_AXES = Self::ANG_X.bits();
78 const FREE_PRISMATIC_AXES = Self::LIN_X.bits();
80 const FREE_FIXED_AXES = 0;
82 const LIN_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits();
84 const ANG_AXES = Self::ANG_X.bits();
86 }
87}
88
89impl Default for JointAxesMask {
90 fn default() -> Self {
91 Self::empty()
92 }
93}
94
95#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
97#[derive(Copy, Clone, Debug, PartialEq)]
98pub enum JointAxis {
99 LinX = 0,
101 LinY,
103 #[cfg(feature = "dim3")]
105 LinZ,
106 AngX,
108 #[cfg(feature = "dim3")]
110 AngY,
111 #[cfg(feature = "dim3")]
113 AngZ,
114}
115
116impl From<JointAxis> for JointAxesMask {
117 fn from(axis: JointAxis) -> Self {
118 JointAxesMask::from_bits(1 << axis as usize).unwrap()
119 }
120}
121
122#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
131#[derive(Copy, Clone, Debug, PartialEq)]
132pub struct JointLimits<N> {
133 pub min: N,
135 pub max: N,
137 pub impulse: N,
139}
140
141impl<N: SimdRealCopy> Default for JointLimits<N> {
142 fn default() -> Self {
143 Self {
144 min: -N::splat(Real::MAX),
145 max: N::splat(Real::MAX),
146 impulse: N::splat(0.0),
147 }
148 }
149}
150
151impl<N: SimdRealCopy> From<[N; 2]> for JointLimits<N> {
152 fn from(value: [N; 2]) -> Self {
153 Self {
154 min: value[0],
155 max: value[1],
156 impulse: N::splat(0.0),
157 }
158 }
159}
160
161#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
192#[derive(Copy, Clone, Debug, PartialEq)]
193pub struct JointMotor {
194 pub target_vel: Real,
196 pub target_pos: Real,
198 pub stiffness: Real,
200 pub damping: Real,
202 pub max_force: Real,
204 pub impulse: Real,
206 pub model: MotorModel,
208}
209
210impl Default for JointMotor {
211 fn default() -> Self {
212 Self {
213 target_pos: 0.0,
214 target_vel: 0.0,
215 stiffness: 0.0,
216 damping: 0.0,
217 max_force: Real::MAX,
218 impulse: 0.0,
219 model: MotorModel::AccelerationBased,
220 }
221 }
222}
223
224impl JointMotor {
225 pub(crate) fn motor_params(&self, dt: Real) -> MotorParameters<Real> {
226 let (erp_inv_dt, cfm_coeff, cfm_gain) =
227 self.model
228 .combine_coefficients(dt, self.stiffness, self.damping);
229 MotorParameters {
230 erp_inv_dt,
231 cfm_coeff,
232 cfm_gain,
233 target_pos: self.target_pos,
235 target_vel: self.target_vel,
236 max_impulse: self.max_force * dt,
237 }
238 }
239}
240
241#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
242#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
243pub enum JointEnabled {
245 Enabled,
247 DisabledByAttachedBody,
250 Disabled,
252}
253
254#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
255#[derive(Copy, Clone, Debug, PartialEq)]
256pub struct GenericJoint {
258 pub local_frame1: Isometry<Real>,
260 pub local_frame2: Isometry<Real>,
262 pub locked_axes: JointAxesMask,
264 pub limit_axes: JointAxesMask,
266 pub motor_axes: JointAxesMask,
268 pub coupled_axes: JointAxesMask,
275 pub limits: [JointLimits<Real>; SPATIAL_DIM],
281 pub motors: [JointMotor; SPATIAL_DIM],
287 pub softness: SpringCoefficients<Real>,
289 pub contacts_enabled: bool,
291 pub enabled: JointEnabled,
293 pub user_data: u128,
295}
296
297impl Default for GenericJoint {
298 fn default() -> Self {
299 Self {
300 local_frame1: Isometry::identity(),
301 local_frame2: Isometry::identity(),
302 locked_axes: JointAxesMask::empty(),
303 limit_axes: JointAxesMask::empty(),
304 motor_axes: JointAxesMask::empty(),
305 coupled_axes: JointAxesMask::empty(),
306 limits: [JointLimits::default(); SPATIAL_DIM],
307 motors: [JointMotor::default(); SPATIAL_DIM],
308 softness: SpringCoefficients::joint_defaults(),
309 contacts_enabled: true,
310 enabled: JointEnabled::Enabled,
311 user_data: 0,
312 }
313 }
314}
315
316impl GenericJoint {
317 #[must_use]
319 pub fn new(locked_axes: JointAxesMask) -> Self {
320 *Self::default().lock_axes(locked_axes)
321 }
322
323 #[cfg(feature = "simd-is-enabled")]
324 pub(crate) fn supports_simd_constraints(&self) -> bool {
326 self.limit_axes.is_empty() && self.motor_axes.is_empty()
327 }
328
329 #[doc(hidden)]
330 pub fn complete_ang_frame(axis: UnitVector<Real>) -> Rotation<Real> {
331 let basis = axis.orthonormal_basis();
332
333 #[cfg(feature = "dim2")]
334 {
335 use na::{Matrix2, Rotation2, UnitComplex};
336 let mat = Matrix2::from_columns(&[axis.into_inner(), basis[0]]);
337 let rotmat = Rotation2::from_matrix_unchecked(mat);
338 UnitComplex::from_rotation_matrix(&rotmat)
339 }
340
341 #[cfg(feature = "dim3")]
342 {
343 use na::{Matrix3, Rotation3, UnitQuaternion};
344 let mat = Matrix3::from_columns(&[axis.into_inner(), basis[0], basis[1]]);
345 let rotmat = Rotation3::from_matrix_unchecked(mat);
346 UnitQuaternion::from_rotation_matrix(&rotmat)
347 }
348 }
349
350 pub fn is_enabled(&self) -> bool {
352 self.enabled == JointEnabled::Enabled
353 }
354
355 pub fn set_enabled(&mut self, enabled: bool) {
357 match self.enabled {
358 JointEnabled::Enabled | JointEnabled::DisabledByAttachedBody => {
359 if !enabled {
360 self.enabled = JointEnabled::Disabled;
361 }
362 }
363 JointEnabled::Disabled => {
364 if enabled {
365 self.enabled = JointEnabled::Enabled;
366 }
367 }
368 }
369 }
370
371 pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
373 self.locked_axes |= axes;
374 self
375 }
376
377 pub fn set_local_frame1(&mut self, local_frame: Isometry<Real>) -> &mut Self {
379 self.local_frame1 = local_frame;
380 self
381 }
382
383 pub fn set_local_frame2(&mut self, local_frame: Isometry<Real>) -> &mut Self {
385 self.local_frame2 = local_frame;
386 self
387 }
388
389 #[must_use]
391 pub fn local_axis1(&self) -> UnitVector<Real> {
392 self.local_frame1 * Vector::x_axis()
393 }
394
395 pub fn set_local_axis1(&mut self, local_axis: UnitVector<Real>) -> &mut Self {
397 self.local_frame1.rotation = Self::complete_ang_frame(local_axis);
398 self
399 }
400
401 #[must_use]
403 pub fn local_axis2(&self) -> UnitVector<Real> {
404 self.local_frame2 * Vector::x_axis()
405 }
406
407 pub fn set_local_axis2(&mut self, local_axis: UnitVector<Real>) -> &mut Self {
409 self.local_frame2.rotation = Self::complete_ang_frame(local_axis);
410 self
411 }
412
413 #[must_use]
415 pub fn local_anchor1(&self) -> Point<Real> {
416 self.local_frame1.translation.vector.into()
417 }
418
419 pub fn set_local_anchor1(&mut self, anchor1: Point<Real>) -> &mut Self {
421 self.local_frame1.translation.vector = anchor1.coords;
422 self
423 }
424
425 #[must_use]
427 pub fn local_anchor2(&self) -> Point<Real> {
428 self.local_frame2.translation.vector.into()
429 }
430
431 pub fn set_local_anchor2(&mut self, anchor2: Point<Real>) -> &mut Self {
433 self.local_frame2.translation.vector = anchor2.coords;
434 self
435 }
436
437 pub fn contacts_enabled(&self) -> bool {
439 self.contacts_enabled
440 }
441
442 pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self {
444 self.contacts_enabled = enabled;
445 self
446 }
447
448 #[must_use]
450 pub fn set_softness(&mut self, softness: SpringCoefficients<Real>) -> &mut Self {
451 self.softness = softness;
452 self
453 }
454
455 #[must_use]
457 pub fn limits(&self, axis: JointAxis) -> Option<&JointLimits<Real>> {
458 let i = axis as usize;
459 if self.limit_axes.contains(axis.into()) {
460 Some(&self.limits[i])
461 } else {
462 None
463 }
464 }
465
466 pub fn set_limits(&mut self, axis: JointAxis, limits: [Real; 2]) -> &mut Self {
468 let i = axis as usize;
469 self.limit_axes |= axis.into();
470 self.limits[i].min = limits[0];
471 self.limits[i].max = limits[1];
472 self
473 }
474
475 #[must_use]
477 pub fn motor_model(&self, axis: JointAxis) -> Option<MotorModel> {
478 let i = axis as usize;
479 if self.motor_axes.contains(axis.into()) {
480 Some(self.motors[i].model)
481 } else {
482 None
483 }
484 }
485
486 pub fn set_motor_model(&mut self, axis: JointAxis, model: MotorModel) -> &mut Self {
488 self.motors[axis as usize].model = model;
489 self
490 }
491
492 pub fn set_motor_velocity(
494 &mut self,
495 axis: JointAxis,
496 target_vel: Real,
497 factor: Real,
498 ) -> &mut Self {
499 self.set_motor(
500 axis,
501 self.motors[axis as usize].target_pos,
502 target_vel,
503 0.0,
504 factor,
505 )
506 }
507
508 pub fn set_motor_position(
510 &mut self,
511 axis: JointAxis,
512 target_pos: Real,
513 stiffness: Real,
514 damping: Real,
515 ) -> &mut Self {
516 self.set_motor(axis, target_pos, 0.0, stiffness, damping)
517 }
518
519 pub fn set_motor_max_force(&mut self, axis: JointAxis, max_force: Real) -> &mut Self {
521 self.motors[axis as usize].max_force = max_force;
522 self
523 }
524
525 #[must_use]
527 pub fn motor(&self, axis: JointAxis) -> Option<&JointMotor> {
528 let i = axis as usize;
529 if self.motor_axes.contains(axis.into()) {
530 Some(&self.motors[i])
531 } else {
532 None
533 }
534 }
535
536 pub fn set_motor(
538 &mut self,
539 axis: JointAxis,
540 target_pos: Real,
541 target_vel: Real,
542 stiffness: Real,
543 damping: Real,
544 ) -> &mut Self {
545 self.motor_axes |= axis.into();
546 let i = axis as usize;
547 self.motors[i].target_vel = target_vel;
548 self.motors[i].target_pos = target_pos;
549 self.motors[i].stiffness = stiffness;
550 self.motors[i].damping = damping;
551 self
552 }
553
554 pub fn flip(&mut self) {
556 std::mem::swap(&mut self.local_frame1, &mut self.local_frame2);
557
558 let coupled_bits = self.coupled_axes.bits();
559
560 for dim in 0..SPATIAL_DIM {
561 if coupled_bits & (1 << dim) == 0 {
562 let limit = self.limits[dim];
563 self.limits[dim].min = -limit.max;
564 self.limits[dim].max = -limit.min;
565 }
566
567 self.motors[dim].target_vel = -self.motors[dim].target_vel;
568 self.motors[dim].target_pos = -self.motors[dim].target_pos;
569 }
570 }
571
572 pub(crate) fn transform_to_solver_body_space(&mut self, rb1: &RigidBody, rb2: &RigidBody) {
573 if rb1.is_fixed() {
574 self.local_frame1 = rb1.pos.position * self.local_frame1;
575 } else {
576 self.local_frame1.translation.vector -= rb1.mprops.local_mprops.local_com.coords;
577 }
578
579 if rb2.is_fixed() {
580 self.local_frame2 = rb2.pos.position * self.local_frame2;
581 } else {
582 self.local_frame2.translation.vector -= rb2.mprops.local_mprops.local_com.coords;
583 }
584 }
585}
586
587macro_rules! joint_conversion_methods(
588 ($as_joint: ident, $as_joint_mut: ident, $Joint: ty, $axes: expr) => {
589 #[must_use]
591 pub fn $as_joint(&self) -> Option<&$Joint> {
592 if self.locked_axes == $axes {
593 Some(unsafe { std::mem::transmute::<&Self, &$Joint>(self) })
596 } else {
597 None
598 }
599 }
600
601 #[must_use]
603 pub fn $as_joint_mut(&mut self) -> Option<&mut $Joint> {
604 if self.locked_axes == $axes {
605 Some(unsafe { std::mem::transmute::<&mut Self, &mut $Joint>(self) })
608 } else {
609 None
610 }
611 }
612 }
613);
614
615impl GenericJoint {
616 joint_conversion_methods!(
617 as_revolute,
618 as_revolute_mut,
619 RevoluteJoint,
620 JointAxesMask::LOCKED_REVOLUTE_AXES
621 );
622 joint_conversion_methods!(
623 as_fixed,
624 as_fixed_mut,
625 FixedJoint,
626 JointAxesMask::LOCKED_FIXED_AXES
627 );
628 joint_conversion_methods!(
629 as_prismatic,
630 as_prismatic_mut,
631 PrismaticJoint,
632 JointAxesMask::LOCKED_PRISMATIC_AXES
633 );
634 joint_conversion_methods!(
635 as_rope,
636 as_rope_mut,
637 RopeJoint,
638 JointAxesMask::FREE_FIXED_AXES
639 );
640
641 #[cfg(feature = "dim3")]
642 joint_conversion_methods!(
643 as_spherical,
644 as_spherical_mut,
645 SphericalJoint,
646 JointAxesMask::LOCKED_SPHERICAL_AXES
647 );
648}
649
650#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
652#[derive(Copy, Clone, Debug, PartialEq)]
653pub struct GenericJointBuilder(pub GenericJoint);
654
655impl GenericJointBuilder {
656 #[must_use]
658 pub fn new(locked_axes: JointAxesMask) -> Self {
659 Self(GenericJoint::new(locked_axes))
660 }
661
662 #[must_use]
664 pub fn locked_axes(mut self, axes: JointAxesMask) -> Self {
665 self.0.locked_axes = axes;
666 self
667 }
668
669 #[must_use]
671 pub fn contacts_enabled(mut self, enabled: bool) -> Self {
672 self.0.contacts_enabled = enabled;
673 self
674 }
675
676 #[must_use]
678 pub fn local_frame1(mut self, local_frame: Isometry<Real>) -> Self {
679 self.0.set_local_frame1(local_frame);
680 self
681 }
682
683 #[must_use]
685 pub fn local_frame2(mut self, local_frame: Isometry<Real>) -> Self {
686 self.0.set_local_frame2(local_frame);
687 self
688 }
689
690 #[must_use]
692 pub fn local_axis1(mut self, local_axis: UnitVector<Real>) -> Self {
693 self.0.set_local_axis1(local_axis);
694 self
695 }
696
697 #[must_use]
699 pub fn local_axis2(mut self, local_axis: UnitVector<Real>) -> Self {
700 self.0.set_local_axis2(local_axis);
701 self
702 }
703
704 #[must_use]
706 pub fn local_anchor1(mut self, anchor1: Point<Real>) -> Self {
707 self.0.set_local_anchor1(anchor1);
708 self
709 }
710
711 #[must_use]
713 pub fn local_anchor2(mut self, anchor2: Point<Real>) -> Self {
714 self.0.set_local_anchor2(anchor2);
715 self
716 }
717
718 #[must_use]
720 pub fn limits(mut self, axis: JointAxis, limits: [Real; 2]) -> Self {
721 self.0.set_limits(axis, limits);
722 self
723 }
724
725 #[must_use]
727 pub fn coupled_axes(mut self, axes: JointAxesMask) -> Self {
728 self.0.coupled_axes = axes;
729 self
730 }
731
732 #[must_use]
734 pub fn motor_model(mut self, axis: JointAxis, model: MotorModel) -> Self {
735 self.0.set_motor_model(axis, model);
736 self
737 }
738
739 #[must_use]
741 pub fn motor_velocity(mut self, axis: JointAxis, target_vel: Real, factor: Real) -> Self {
742 self.0.set_motor_velocity(axis, target_vel, factor);
743 self
744 }
745
746 #[must_use]
748 pub fn motor_position(
749 mut self,
750 axis: JointAxis,
751 target_pos: Real,
752 stiffness: Real,
753 damping: Real,
754 ) -> Self {
755 self.0
756 .set_motor_position(axis, target_pos, stiffness, damping);
757 self
758 }
759
760 #[must_use]
762 pub fn set_motor(
763 mut self,
764 axis: JointAxis,
765 target_pos: Real,
766 target_vel: Real,
767 stiffness: Real,
768 damping: Real,
769 ) -> Self {
770 self.0
771 .set_motor(axis, target_pos, target_vel, stiffness, damping);
772 self
773 }
774
775 #[must_use]
777 pub fn motor_max_force(mut self, axis: JointAxis, max_force: Real) -> Self {
778 self.0.set_motor_max_force(axis, max_force);
779 self
780 }
781
782 #[must_use]
784 pub fn softness(mut self, softness: SpringCoefficients<Real>) -> Self {
785 self.0.softness = softness;
786 self
787 }
788
789 pub fn user_data(mut self, data: u128) -> Self {
791 self.0.user_data = data;
792 self
793 }
794
795 #[must_use]
797 pub fn build(self) -> GenericJoint {
798 self.0
799 }
800}
801
802impl From<GenericJointBuilder> for GenericJoint {
803 fn from(val: GenericJointBuilder) -> GenericJoint {
804 val.0
805 }
806}