diff --git a/src.ts/dynamics/impulse_joint.ts b/src.ts/dynamics/impulse_joint.ts index a69c38e..12e2cb6 100644 --- a/src.ts/dynamics/impulse_joint.ts +++ b/src.ts/dynamics/impulse_joint.ts @@ -369,6 +369,10 @@ export class JointData { anchor1: Vector; anchor2: Vector; axis: Vector; + // #if DIM3 + axis1: Vector; + axis2: Vector; + // #endif frame1: Rotation; frame2: Rotation; jointType: JointType; @@ -588,6 +592,36 @@ export class JointData { res.jointType = JointType.Revolute; return res; } + + /** + * Create a new joint descriptor that builds Revolute joints with independent + * local axes for each attached rigid-body. + * + * This is useful when the same world-space hinge axis is represented by + * different local axes on the two bodies. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis1 - Axis of the joint, expressed in the local-space of the first rigid-body. + * @param axis2 - Axis of the joint, expressed in the local-space of the second rigid-body. + */ + public static revoluteWithAxes( + anchor1: Vector, + anchor2: Vector, + axis1: Vector, + axis2: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis1; + res.axis1 = axis1; + res.axis2 = axis2; + res.jointType = JointType.Revolute; + return res; + } // #endif public intoRaw(): RawGenericJoint { @@ -674,9 +708,22 @@ export class JointData { result = RawGenericJoint.spherical(rawA1, rawA2); break; case JointType.Revolute: - rawAx = VectorOps.intoRaw(this.axis); - result = RawGenericJoint.revolute(rawA1, rawA2, rawAx); - rawAx.free(); + if (!!this.axis1 && !!this.axis2) { + let rawAx1 = VectorOps.intoRaw(this.axis1); + let rawAx2 = VectorOps.intoRaw(this.axis2); + result = RawGenericJoint.revoluteWithAxes( + rawA1, + rawA2, + rawAx1, + rawAx2, + ); + rawAx1.free(); + rawAx2.free(); + } else { + rawAx = VectorOps.intoRaw(this.axis); + result = RawGenericJoint.revolute(rawA1, rawA2, rawAx); + rawAx.free(); + } break; // #endif } diff --git a/src/dynamics/joint.rs b/src/dynamics/joint.rs index 74ab2b3..e66bb7b 100644 --- a/src/dynamics/joint.rs +++ b/src/dynamics/joint.rs @@ -311,4 +311,28 @@ impl RawGenericJoint { .into(), )) } + + /// Create a new joint descriptor that builds Revolute joints with + /// independent local axes for each attached rigid-body. + /// + /// This is equivalent to a revolute generic joint with all linear axes + /// locked and only angular X free, but it preserves the local hinge axis + /// on each body instead of assuming they are identical. + #[cfg(feature = "dim3")] + pub fn revoluteWithAxes( + anchor1: &RawVector, + anchor2: &RawVector, + axis1: &RawVector, + axis2: &RawVector, + ) -> Option { + let axis1 = Unit::try_new(axis1.0, 0.0)?; + let axis2 = Unit::try_new(axis2.0, 0.0)?; + let joint: GenericJoint = GenericJointBuilder::new(JointAxesMask::LOCKED_REVOLUTE_AXES) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .local_axis1(axis1) + .local_axis2(axis2) + .into(); + Some(Self(joint)) + } }