diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
|---|---|---|
| committer | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
| commit | 754a48b7ff6d8c58b1ee08651e60112900b60455 (patch) | |
| tree | 7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs | |
| download | rapier-0.1.0.tar.gz rapier-0.1.0.tar.bz2 rapier-0.1.0.zip | |
First public release of Rapier.v0.1.0
Diffstat (limited to 'src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs')
| -rw-r--r-- | src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs b/src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs new file mode 100644 index 0000000..c3e4b98 --- /dev/null +++ b/src/dynamics/solver/joint_constraint/prismatic_position_constraint.rs @@ -0,0 +1,170 @@ +use crate::dynamics::{IntegrationParameters, PrismaticJoint, RigidBody}; +use crate::math::{AngularInertia, Isometry, Point, Rotation, Vector}; +use crate::utils::WAngularInertia; +use na::Unit; + +#[derive(Debug)] +pub(crate) struct PrismaticPositionConstraint { + position1: usize, + position2: usize, + + im1: f32, + im2: f32, + + ii1: AngularInertia<f32>, + ii2: AngularInertia<f32>, + + lin_inv_lhs: f32, + ang_inv_lhs: AngularInertia<f32>, + + limits: [f32; 2], + + local_frame1: Isometry<f32>, + local_frame2: Isometry<f32>, + + local_axis1: Unit<Vector<f32>>, + local_axis2: Unit<Vector<f32>>, +} + +impl PrismaticPositionConstraint { + pub fn from_params(rb1: &RigidBody, rb2: &RigidBody, cparams: &PrismaticJoint) -> Self { + let ii1 = rb1.world_inv_inertia_sqrt.squared(); + let ii2 = rb2.world_inv_inertia_sqrt.squared(); + let im1 = rb1.mass_properties.inv_mass; + let im2 = rb2.mass_properties.inv_mass; + let lin_inv_lhs = 1.0 / (im1 + im2); + let ang_inv_lhs = (ii1 + ii2).inverse(); + + Self { + im1, + im2, + ii1, + ii2, + lin_inv_lhs, + ang_inv_lhs, + local_frame1: cparams.local_frame1(), + local_frame2: cparams.local_frame2(), + local_axis1: cparams.local_axis1, + local_axis2: cparams.local_axis2, + position1: rb1.active_set_offset, + position2: rb2.active_set_offset, + limits: cparams.limits, + } + } + + pub fn solve(&self, params: &IntegrationParameters, positions: &mut [Isometry<f32>]) { + let mut position1 = positions[self.position1 as usize]; + let mut position2 = positions[self.position2 as usize]; + + // Angular correction. + let frame1 = position1 * self.local_frame1; + let frame2 = position2 * self.local_frame2; + let ang_err = frame2.rotation * frame1.rotation.inverse(); + #[cfg(feature = "dim2")] + let ang_impulse = self + .ang_inv_lhs + .transform_vector(ang_err.angle() * params.joint_erp); + #[cfg(feature = "dim3")] + let ang_impulse = self + .ang_inv_lhs + .transform_vector(ang_err.scaled_axis() * 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; + + // Linear correction. + let anchor1 = position1 * Point::from(self.local_frame1.translation.vector); + let anchor2 = position2 * Point::from(self.local_frame2.translation.vector); + let axis1 = position1 * self.local_axis1; + let dpos = anchor2 - anchor1; + let limit_err = dpos.dot(&axis1); + let mut err = dpos - *axis1 * limit_err; + + if limit_err < self.limits[0] { + err += *axis1 * (limit_err - self.limits[0]); + } else if limit_err > self.limits[1] { + err += *axis1 * (limit_err - self.limits[1]); + } + + let impulse = err * (self.lin_inv_lhs * params.joint_erp); + position1.translation.vector += self.im1 * impulse; + position2.translation.vector -= self.im2 * impulse; + + positions[self.position1 as usize] = position1; + positions[self.position2 as usize] = position2; + } +} + +#[derive(Debug)] +pub(crate) struct PrismaticPositionGroundConstraint { + position2: usize, + frame1: Isometry<f32>, + local_frame2: Isometry<f32>, + axis1: Unit<Vector<f32>>, + local_axis2: Unit<Vector<f32>>, + limits: [f32; 2], +} + +impl PrismaticPositionGroundConstraint { + pub fn from_params( + rb1: &RigidBody, + rb2: &RigidBody, + cparams: &PrismaticJoint, + flipped: bool, + ) -> Self { + let frame1; + let local_frame2; + let axis1; + let local_axis2; + + if flipped { + frame1 = rb1.predicted_position * cparams.local_frame2(); + local_frame2 = cparams.local_frame1(); + axis1 = rb1.predicted_position * cparams.local_axis2; + local_axis2 = cparams.local_axis1; + } else { + frame1 = rb1.predicted_position * cparams.local_frame1(); + local_frame2 = cparams.local_frame2(); + axis1 = rb1.predicted_position * cparams.local_axis1; + local_axis2 = cparams.local_axis2; + }; + + Self { + frame1, + local_frame2, + axis1, + local_axis2, + position2: rb2.active_set_offset, + limits: cparams.limits, + } + } + + pub fn solve(&self, params: &IntegrationParameters, positions: &mut [Isometry<f32>]) { + let mut position2 = positions[self.position2 as usize]; + + // Angular correction. + let frame2 = position2 * self.local_frame2; + let ang_err = frame2.rotation * self.frame1.rotation.inverse(); + position2.rotation = ang_err.powf(-params.joint_erp) * position2.rotation; + + // Linear correction. + let anchor1 = Point::from(self.frame1.translation.vector); + let anchor2 = position2 * Point::from(self.local_frame2.translation.vector); + let dpos = anchor2 - anchor1; + let limit_err = dpos.dot(&self.axis1); + let mut err = dpos - *self.axis1 * limit_err; + + if limit_err < self.limits[0] { + err += *self.axis1 * (limit_err - self.limits[0]); + } else if limit_err > self.limits[1] { + err += *self.axis1 * (limit_err - self.limits[1]); + } + + // NOTE: no need to divide by im2 just to multiply right after. + let impulse = err * params.joint_erp; + position2.translation.vector -= impulse; + + positions[self.position2 as usize] = position2; + } +} |
