diff options
| author | Sébastien Crozet <developer@crozet.re> | 2021-08-07 18:20:19 +0200 |
|---|---|---|
| committer | Sébastien Crozet <sebastien@crozet.re> | 2021-08-08 18:38:12 +0200 |
| commit | f7643272f40fa5776ce21a5ccdb43101d987030e (patch) | |
| tree | 0a5a374aa879f830b710d91d1ef1d2ea4d21793b /src/dynamics/solver/joint_constraint/ball_position_constraint.rs | |
| parent | ac77c95c9c161948433ce3a05bab1f2e9fe32f61 (diff) | |
| download | rapier-f7643272f40fa5776ce21a5ccdb43101d987030e.tar.gz rapier-f7643272f40fa5776ce21a5ccdb43101d987030e.tar.bz2 rapier-f7643272f40fa5776ce21a5ccdb43101d987030e.zip | |
Implement limits for ball joints.
Diffstat (limited to 'src/dynamics/solver/joint_constraint/ball_position_constraint.rs')
| -rw-r--r-- | src/dynamics/solver/joint_constraint/ball_position_constraint.rs | 78 |
1 files changed, 75 insertions, 3 deletions
diff --git a/src/dynamics/solver/joint_constraint/ball_position_constraint.rs b/src/dynamics/solver/joint_constraint/ball_position_constraint.rs index 0227960..0169f30 100644 --- a/src/dynamics/solver/joint_constraint/ball_position_constraint.rs +++ b/src/dynamics/solver/joint_constraint/ball_position_constraint.rs @@ -3,7 +3,7 @@ use crate::dynamics::{ }; #[cfg(feature = "dim2")] use crate::math::SdpMatrix; -use crate::math::{AngularInertia, Isometry, Point, Real, Rotation}; +use crate::math::{AngularInertia, Isometry, Point, Real, Rotation, UnitVector}; use crate::utils::{WAngularInertia, WCross, WCrossMatrix}; #[derive(Debug)] @@ -19,9 +19,15 @@ pub(crate) struct BallPositionConstraint { ii1: AngularInertia<Real>, ii2: AngularInertia<Real>, + inv_ii1_ii2: AngularInertia<Real>, local_anchor1: Point<Real>, local_anchor2: Point<Real>, + + limits_enabled: bool, + limits_angle: Real, + limits_local_axis1: UnitVector<Real>, + limits_local_axis2: UnitVector<Real>, } impl BallPositionConstraint { @@ -33,17 +39,26 @@ impl BallPositionConstraint { let (mprops1, ids1) = rb1; let (mprops2, ids2) = rb2; + let ii1 = mprops1.effective_world_inv_inertia_sqrt.squared(); + let ii2 = mprops2.effective_world_inv_inertia_sqrt.squared(); + let inv_ii1_ii2 = (ii1 + ii2).inverse(); + Self { local_com1: mprops1.local_mprops.local_com, local_com2: mprops2.local_mprops.local_com, im1: mprops1.effective_inv_mass, im2: mprops2.effective_inv_mass, - ii1: mprops1.effective_world_inv_inertia_sqrt.squared(), - ii2: mprops2.effective_world_inv_inertia_sqrt.squared(), + ii1, + ii2, + inv_ii1_ii2, local_anchor1: cparams.local_anchor1, local_anchor2: cparams.local_anchor2, position1: ids1.active_set_offset, position2: ids2.active_set_offset, + limits_enabled: cparams.limits_enabled, + limits_angle: cparams.limits_angle, + limits_local_axis1: cparams.limits_local_axis1, + limits_local_axis2: cparams.limits_local_axis2, } } @@ -96,6 +111,31 @@ impl BallPositionConstraint { position1.rotation = Rotation::new(angle1) * position1.rotation; position2.rotation = Rotation::new(angle2) * position2.rotation; + /* + * Limits part. + */ + if self.limits_enabled { + let axis1 = position1 * self.limits_local_axis1; + let axis2 = position2 * self.limits_local_axis2; + + // TODO: handle the case where dot(axis1, axis2) = -1.0 + if let Some((axis, angle)) = + Rotation::rotation_between_axis(&axis2, &axis1).and_then(|r| r.axis_angle()) + { + if angle >= self.limits_angle { + let ang_error = angle - self.limits_angle; + let ang_impulse = self + .inv_ii1_ii2 + .transform_vector(*axis * ang_error * params.joint_erp); + + position1.rotation = + Rotation::new(self.ii1.transform_vector(-ang_impulse)) * position1.rotation; + position2.rotation = + Rotation::new(self.ii2.transform_vector(ang_impulse)) * position2.rotation; + } + } + } + positions[self.position1 as usize] = position1; positions[self.position2 as usize] = position2; } @@ -109,6 +149,11 @@ pub(crate) struct BallPositionGroundConstraint { ii2: AngularInertia<Real>, local_anchor2: Point<Real>, local_com2: Point<Real>, + + limits_enabled: bool, + limits_angle: Real, + limits_axis1: UnitVector<Real>, + limits_local_axis2: UnitVector<Real>, } impl BallPositionGroundConstraint { @@ -132,6 +177,10 @@ impl BallPositionGroundConstraint { local_anchor2: cparams.local_anchor1, position2: ids2.active_set_offset, local_com2: mprops2.local_mprops.local_com, + limits_enabled: cparams.limits_enabled, + limits_angle: cparams.limits_angle, + limits_axis1: poss1.next_position * cparams.limits_local_axis2, + limits_local_axis2: cparams.limits_local_axis1, } } else { Self { @@ -141,6 +190,10 @@ impl BallPositionGroundConstraint { local_anchor2: cparams.local_anchor2, position2: ids2.active_set_offset, local_com2: mprops2.local_mprops.local_com, + limits_enabled: cparams.limits_enabled, + limits_angle: cparams.limits_angle, + limits_axis1: poss1.next_position * cparams.limits_local_axis1, + limits_local_axis2: cparams.limits_local_axis2, } } } @@ -172,6 +225,25 @@ impl BallPositionGroundConstraint { let angle2 = self.ii2.transform_vector(centered_anchor2.gcross(-impulse)); position2.rotation = Rotation::new(angle2) * position2.rotation; + + /* + * Limits part. + */ + if self.limits_enabled { + let axis2 = position2 * self.limits_local_axis2; + + // TODO: handle the case where dot(axis1, axis2) = -1.0 + if let Some((axis, angle)) = Rotation::rotation_between_axis(&axis2, &self.limits_axis1) + .and_then(|r| r.axis_angle()) + { + if angle >= self.limits_angle { + let ang_error = angle - self.limits_angle; + let ang_correction = *axis * ang_error * params.joint_erp; + position2.rotation = Rotation::new(ang_correction) * position2.rotation; + } + } + } + positions[self.position2 as usize] = position2; } } |
