From 20261be78cf7f4ca9dcbd3123355ae36234b6304 Mon Sep 17 00:00:00 2001 From: st170001 Date: Sat, 14 Dec 2024 21:02:27 +0100 Subject: [PATCH] Additional groove joint 2D implementation with 1 translation + 1 rotation --- src/dynamics/joint/generic_joint.rs | 2 + src/dynamics/joint/groove_joint.rs | 272 ++++++++++++++++++++++++++++ src/dynamics/joint/mod.rs | 2 + 3 files changed, 276 insertions(+) create mode 100644 src/dynamics/joint/groove_joint.rs diff --git a/src/dynamics/joint/generic_joint.rs b/src/dynamics/joint/generic_joint.rs index 8d4066d35..23f5f2727 100644 --- a/src/dynamics/joint/generic_joint.rs +++ b/src/dynamics/joint/generic_joint.rs @@ -65,6 +65,8 @@ bitflags::bitflags! { const LOCKED_REVOLUTE_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits(); /// The set of degrees of freedom locked by a prismatic joint. const LOCKED_PRISMATIC_AXES = Self::LIN_Y.bits() | Self::ANG_X.bits(); + /// The set of degrees of freedom locked by a groove joint. + const LOCKED_GROOVE_AXES = Self::LIN_Y.bits(); /// The set of degrees of freedom locked by a fixed joint. const LOCKED_FIXED_AXES = Self::LIN_X.bits() | Self::LIN_Y.bits() | Self::ANG_X.bits(); /// The set of degrees of freedom left free by a revolute joint. diff --git a/src/dynamics/joint/groove_joint.rs b/src/dynamics/joint/groove_joint.rs new file mode 100644 index 000000000..fa84b0815 --- /dev/null +++ b/src/dynamics/joint/groove_joint.rs @@ -0,0 +1,272 @@ +use crate::dynamics::joint::{GenericJoint, GenericJointBuilder, JointAxesMask}; +use crate::dynamics::{JointAxis, MotorModel}; +use crate::math::{Point, Real, UnitVector}; + +use super::{JointLimits, JointMotor}; + +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(transparent)] +/// A groove joint, locks all relative motion between two bodies except for translation along the joint’s principal axis and relative rotations. +pub struct GrooveJoint { + /// The underlying joint data. + pub data: GenericJoint, +} + +impl GrooveJoint { + /// Creates a new groove joint allowing only relative translations along the specified axis and relative rotations. + /// + /// This axis is expressed in the local-space of both rigid-bodies. + #[cfg(feature = "dim2")] + pub fn new(axis: UnitVector) -> Self { + let data = GenericJointBuilder::new(JointAxesMask::LOCKED_GROOVE_AXES) + .local_axis1(axis) + .local_axis2(axis) + .build(); + Self { data } + } + + /// The underlying generic joint. + pub fn data(&self) -> &GenericJoint { + &self.data + } + + /// Are contacts between the attached rigid-bodies enabled? + pub fn contacts_enabled(&self) -> bool { + self.data.contacts_enabled + } + + /// Sets whether contacts between the attached rigid-bodies are enabled. + pub fn set_contacts_enabled(&mut self, enabled: bool) -> &mut Self { + self.data.set_contacts_enabled(enabled); + self + } + + /// The joint’s anchor, expressed in the local-space of the first rigid-body. + #[must_use] + pub fn local_anchor1(&self) -> Point { + self.data.local_anchor1() + } + + /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body. + pub fn set_local_anchor1(&mut self, anchor1: Point) -> &mut Self { + self.data.set_local_anchor1(anchor1); + self + } + + /// The joint’s anchor, expressed in the local-space of the second rigid-body. + #[must_use] + pub fn local_anchor2(&self) -> Point { + self.data.local_anchor2() + } + + /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body. + pub fn set_local_anchor2(&mut self, anchor2: Point) -> &mut Self { + self.data.set_local_anchor2(anchor2); + self + } + + /// The principal axis of the joint, expressed in the local-space of the first rigid-body. + #[must_use] + pub fn local_axis1(&self) -> UnitVector { + self.data.local_axis1() + } + + /// Sets the principal axis of the joint, expressed in the local-space of the first rigid-body. + pub fn set_local_axis1(&mut self, axis1: UnitVector) -> &mut Self { + self.data.set_local_axis1(axis1); + self + } + + /// The principal axis of the joint, expressed in the local-space of the second rigid-body. + #[must_use] + pub fn local_axis2(&self) -> UnitVector { + self.data.local_axis2() + } + + /// Sets the principal axis of the joint, expressed in the local-space of the second rigid-body. + pub fn set_local_axis2(&mut self, axis2: UnitVector) -> &mut Self { + self.data.set_local_axis2(axis2); + self + } + + /// The motor affecting the joint’s translational degree of freedom. + #[must_use] + pub fn motor(&self) -> Option<&JointMotor> { + self.data.motor(JointAxis::LinX) + } + + /// Set the spring-like model used by the motor to reach the desired target velocity and position. + pub fn set_motor_model(&mut self, model: MotorModel) -> &mut Self { + self.data.set_motor_model(JointAxis::LinX, model); + self + } + + /// Sets the target velocity this motor needs to reach. + pub fn set_motor_velocity(&mut self, target_vel: Real, factor: Real) -> &mut Self { + self.data + .set_motor_velocity(JointAxis::LinX, target_vel, factor); + self + } + + /// Sets the target angle this motor needs to reach. + pub fn set_motor_position( + &mut self, + target_pos: Real, + stiffness: Real, + damping: Real, + ) -> &mut Self { + self.data + .set_motor_position(JointAxis::LinX, target_pos, stiffness, damping); + self + } + + /// Configure both the target angle and target velocity of the motor. + pub fn set_motor( + &mut self, + target_pos: Real, + target_vel: Real, + stiffness: Real, + damping: Real, + ) -> &mut Self { + self.data + .set_motor(JointAxis::LinX, target_pos, target_vel, stiffness, damping); + self + } + + /// Sets the maximum force the motor can deliver. + pub fn set_motor_max_force(&mut self, max_force: Real) -> &mut Self { + self.data.set_motor_max_force(JointAxis::LinX, max_force); + self + } + + /// The limit distance attached bodies can translate along the joint’s principal axis. + #[must_use] + pub fn limits(&self) -> Option<&JointLimits> { + self.data.limits(JointAxis::LinX) + } + + /// Sets the `[min,max]` limit distances attached bodies can translate along the joint’s principal axis. + pub fn set_limits(&mut self, limits: [Real; 2]) -> &mut Self { + self.data.set_limits(JointAxis::LinX, limits); + self + } +} + +impl From for GenericJoint { + fn from(val: GrooveJoint) -> GenericJoint { + val.data + } +} + +/// Create groove joints using the builder pattern. +/// +/// A groove joint locks all relative motion except for translations along the joint’s principal axis and relative rotations. +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct GrooveJointBuilder(pub GrooveJoint); + +impl GrooveJointBuilder { + /// Creates a new builder for groove joints. + /// + /// This axis is expressed in the local-space of both rigid-bodies. + #[cfg(feature = "dim2")] + pub fn new(axis: UnitVector) -> Self { + Self(GrooveJoint::new(axis)) + } + + /// Sets whether contacts between the attached rigid-bodies are enabled. + #[must_use] + pub fn contacts_enabled(mut self, enabled: bool) -> Self { + self.0.set_contacts_enabled(enabled); + self + } + + /// Sets the joint’s anchor, expressed in the local-space of the first rigid-body. + #[must_use] + pub fn local_anchor1(mut self, anchor1: Point) -> Self { + self.0.set_local_anchor1(anchor1); + self + } + + /// Sets the joint’s anchor, expressed in the local-space of the second rigid-body. + #[must_use] + pub fn local_anchor2(mut self, anchor2: Point) -> Self { + self.0.set_local_anchor2(anchor2); + self + } + + /// Sets the principal axis of the joint, expressed in the local-space of the first rigid-body. + #[must_use] + pub fn local_axis1(mut self, axis1: UnitVector) -> Self { + self.0.set_local_axis1(axis1); + self + } + + /// Sets the principal axis of the joint, expressed in the local-space of the second rigid-body. + #[must_use] + pub fn local_axis2(mut self, axis2: UnitVector) -> Self { + self.0.set_local_axis2(axis2); + self + } + + /// Set the spring-like model used by the motor to reach the desired target velocity and position. + #[must_use] + pub fn motor_model(mut self, model: MotorModel) -> Self { + self.0.set_motor_model(model); + self + } + + /// Sets the target velocity this motor needs to reach. + #[must_use] + pub fn motor_velocity(mut self, target_vel: Real, factor: Real) -> Self { + self.0.set_motor_velocity(target_vel, factor); + self + } + + /// Sets the target angle this motor needs to reach. + #[must_use] + pub fn motor_position(mut self, target_pos: Real, stiffness: Real, damping: Real) -> Self { + self.0.set_motor_position(target_pos, stiffness, damping); + self + } + + /// Configure both the target angle and target velocity of the motor. + #[must_use] + pub fn set_motor( + mut self, + target_pos: Real, + target_vel: Real, + stiffness: Real, + damping: Real, + ) -> Self { + self.0.set_motor(target_pos, target_vel, stiffness, damping); + self + } + + /// Sets the maximum force the motor can deliver. + #[must_use] + pub fn motor_max_force(mut self, max_force: Real) -> Self { + self.0.set_motor_max_force(max_force); + self + } + + /// Sets the `[min,max]` limit distances attached bodies can translate along the joint’s principal axis. + #[must_use] + pub fn limits(mut self, limits: [Real; 2]) -> Self { + self.0.set_limits(limits); + self + } + + /// Builds the groove joint. + #[must_use] + pub fn build(self) -> GrooveJoint { + self.0 + } +} + +impl From for GenericJoint { + fn from(val: GrooveJointBuilder) -> GenericJoint { + val.0.into() + } +} diff --git a/src/dynamics/joint/mod.rs b/src/dynamics/joint/mod.rs index 423d4c285..af398120a 100644 --- a/src/dynamics/joint/mod.rs +++ b/src/dynamics/joint/mod.rs @@ -1,5 +1,6 @@ pub use self::fixed_joint::*; pub use self::generic_joint::*; +pub use self::groove_joint::*; pub use self::impulse_joint::*; pub use self::motor_model::MotorModel; pub use self::multibody_joint::*; @@ -13,6 +14,7 @@ pub use self::spherical_joint::*; mod fixed_joint; mod generic_joint; +mod groove_joint; mod impulse_joint; mod motor_model; mod multibody_joint;