aboutsummaryrefslogtreecommitdiff
path: root/src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2020-08-25 22:10:25 +0200
committerSébastien Crozet <developer@crozet.re>2020-08-25 22:10:25 +0200
commit754a48b7ff6d8c58b1ee08651e60112900b60455 (patch)
tree7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs
downloadrapier-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/ball_position_constraint_wide.rs')
-rw-r--r--src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs b/src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs
new file mode 100644
index 0000000..c552d57
--- /dev/null
+++ b/src/dynamics/solver/joint_constraint/ball_position_constraint_wide.rs
@@ -0,0 +1,199 @@
+use crate::dynamics::{BallJoint, IntegrationParameters, RigidBody};
+#[cfg(feature = "dim2")]
+use crate::math::SdpMatrix;
+use crate::math::{AngularInertia, Isometry, Point, Rotation, SimdFloat, SIMD_WIDTH};
+use crate::utils::{WAngularInertia, WCross, WCrossMatrix};
+use simba::simd::SimdValue;
+
+#[derive(Debug)]
+pub(crate) struct WBallPositionConstraint {
+ position1: [usize; SIMD_WIDTH],
+ position2: [usize; SIMD_WIDTH],
+
+ local_com1: Point<SimdFloat>,
+ local_com2: Point<SimdFloat>,
+
+ im1: SimdFloat,
+ im2: SimdFloat,
+
+ ii1: AngularInertia<SimdFloat>,
+ ii2: AngularInertia<SimdFloat>,
+
+ local_anchor1: Point<SimdFloat>,
+ local_anchor2: Point<SimdFloat>,
+}
+
+impl WBallPositionConstraint {
+ pub fn from_params(
+ rbs1: [&RigidBody; SIMD_WIDTH],
+ rbs2: [&RigidBody; SIMD_WIDTH],
+ cparams: [&BallJoint; SIMD_WIDTH],
+ ) -> Self {
+ let local_com1 = Point::from(array![|ii| rbs1[ii].mass_properties.local_com; SIMD_WIDTH]);
+ let local_com2 = Point::from(array![|ii| rbs2[ii].mass_properties.local_com; SIMD_WIDTH]);
+ let im1 = SimdFloat::from(array![|ii| rbs1[ii].mass_properties.inv_mass; SIMD_WIDTH]);
+ let im2 = SimdFloat::from(array![|ii| rbs2[ii].mass_properties.inv_mass; SIMD_WIDTH]);
+ let ii1 = AngularInertia::<SimdFloat>::from(
+ array![|ii| rbs1[ii].world_inv_inertia_sqrt; SIMD_WIDTH],
+ )
+ .squared();
+ let ii2 = AngularInertia::<SimdFloat>::from(
+ array![|ii| rbs2[ii].world_inv_inertia_sqrt; SIMD_WIDTH],
+ )
+ .squared();
+ let local_anchor1 = Point::from(array![|ii| cparams[ii].local_anchor1; SIMD_WIDTH]);
+ let local_anchor2 = Point::from(array![|ii| cparams[ii].local_anchor2; SIMD_WIDTH]);
+ let position1 = array![|ii| rbs1[ii].active_set_offset; SIMD_WIDTH];
+ let position2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
+
+ Self {
+ local_com1,
+ local_com2,
+ im1,
+ im2,
+ ii1,
+ ii2,
+ local_anchor1,
+ local_anchor2,
+ position1,
+ position2,
+ }
+ }
+
+ pub fn solve(&self, params: &IntegrationParameters, positions: &mut [Isometry<f32>]) {
+ let mut position1 = Isometry::from(array![|ii| positions[self.position1[ii]]; SIMD_WIDTH]);
+ let mut position2 = Isometry::from(array![|ii| positions[self.position2[ii]]; SIMD_WIDTH]);
+
+ let anchor1 = position1 * self.local_anchor1;
+ let anchor2 = position2 * self.local_anchor2;
+
+ let com1 = position1 * self.local_com1;
+ let com2 = position2 * self.local_com2;
+
+ let err = anchor1 - anchor2;
+
+ let centered_anchor1 = anchor1 - com1;
+ let centered_anchor2 = anchor2 - com2;
+
+ let cmat1 = centered_anchor1.gcross_matrix();
+ let cmat2 = centered_anchor2.gcross_matrix();
+
+ // NOTE: the -cmat1 is just a simpler way of doing cmat1.transpose()
+ // because it is anti-symmetric.
+ #[cfg(feature = "dim3")]
+ let lhs = self.ii1.quadform(&cmat1).add_diagonal(self.im1)
+ + self.ii2.quadform(&cmat2).add_diagonal(self.im2);
+
+ // In 2D we just unroll the computation because
+ // it's just easier that way.
+ #[cfg(feature = "dim2")]
+ let lhs = {
+ let m11 =
+ self.im1 + self.im2 + cmat1.x * cmat1.x * self.ii1 + cmat2.x * cmat2.x * self.ii2;
+ let m12 = cmat1.x * cmat1.y * self.ii1 + cmat2.x * cmat2.y * self.ii2;
+ let m22 =
+ self.im1 + self.im2 + cmat1.y * cmat1.y * self.ii1 + cmat2.y * cmat2.y * self.ii2;
+ SdpMatrix::new(m11, m12, m22)
+ };
+
+ let inv_lhs = lhs.inverse_unchecked();
+ let impulse = inv_lhs * -(err * SimdFloat::splat(params.joint_erp));
+
+ position1.translation.vector += impulse * self.im1;
+ position2.translation.vector -= impulse * self.im2;
+
+ let angle1 = self.ii1.transform_vector(centered_anchor1.gcross(impulse));
+ let angle2 = self.ii2.transform_vector(centered_anchor2.gcross(-impulse));
+
+ position1.rotation = Rotation::new(angle1) * position1.rotation;
+ position2.rotation = Rotation::new(angle2) * position2.rotation;
+
+ for ii in 0..SIMD_WIDTH {
+ positions[self.position1[ii]] = position1.extract(ii);
+ }
+ for ii in 0..SIMD_WIDTH {
+ positions[self.position2[ii]] = position2.extract(ii);
+ }
+ }
+}
+
+#[derive(Debug)]
+pub(crate) struct WBallPositionGroundConstraint {
+ position2: [usize; SIMD_WIDTH],
+ anchor1: Point<SimdFloat>,
+ im2: SimdFloat,
+ ii2: AngularInertia<SimdFloat>,
+ local_anchor2: Point<SimdFloat>,
+ local_com2: Point<SimdFloat>,
+}
+
+impl WBallPositionGroundConstraint {
+ pub fn from_params(
+ rbs1: [&RigidBody; SIMD_WIDTH],
+ rbs2: [&RigidBody; SIMD_WIDTH],
+ cparams: [&BallJoint; SIMD_WIDTH],
+ flipped: [bool; SIMD_WIDTH],
+ ) -> Self {
+ let position1 = Isometry::from(array![|ii| rbs1[ii].predicted_position; SIMD_WIDTH]);
+ let anchor1 = position1
+ * Point::from(array![|ii| if flipped[ii] {
+ cparams[ii].local_anchor2
+ } else {
+ cparams[ii].local_anchor1
+ }; SIMD_WIDTH]);
+ let im2 = SimdFloat::from(array![|ii| rbs2[ii].mass_properties.inv_mass; SIMD_WIDTH]);
+ let ii2 = AngularInertia::<SimdFloat>::from(
+ array![|ii| rbs2[ii].world_inv_inertia_sqrt; SIMD_WIDTH],
+ )
+ .squared();
+ let local_anchor2 = Point::from(array![|ii| if flipped[ii] {
+ cparams[ii].local_anchor1
+ } else {
+ cparams[ii].local_anchor2
+ }; SIMD_WIDTH]);
+ let position2 = array![|ii| rbs2[ii].active_set_offset; SIMD_WIDTH];
+ let local_com2 = Point::from(array![|ii| rbs2[ii].mass_properties.local_com; SIMD_WIDTH]);
+
+ Self {
+ anchor1,
+ im2,
+ ii2,
+ local_anchor2,
+ position2,
+ local_com2,
+ }
+ }
+
+ pub fn solve(&self, params: &IntegrationParameters, positions: &mut [Isometry<f32>]) {
+ let mut position2 = Isometry::from(array![|ii| positions[self.position2[ii]]; SIMD_WIDTH]);
+
+ let anchor2 = position2 * self.local_anchor2;
+ let com2 = position2 * self.local_com2;
+
+ let err = self.anchor1 - anchor2;
+ let centered_anchor2 = anchor2 - com2;
+ let cmat2 = centered_anchor2.gcross_matrix();
+
+ #[cfg(feature = "dim3")]
+ let lhs = self.ii2.quadform(&cmat2).add_diagonal(self.im2);
+
+ #[cfg(feature = "dim2")]
+ let lhs = {
+ let m11 = self.im2 + cmat2.x * cmat2.x * self.ii2;
+ let m12 = cmat2.x * cmat2.y * self.ii2;
+ let m22 = self.im2 + cmat2.y * cmat2.y * self.ii2;
+ SdpMatrix::new(m11, m12, m22)
+ };
+
+ let inv_lhs = lhs.inverse_unchecked();
+ let impulse = inv_lhs * -(err * SimdFloat::splat(params.joint_erp));
+ position2.translation.vector -= impulse * self.im2;
+
+ let angle2 = self.ii2.transform_vector(centered_anchor2.gcross(-impulse));
+ position2.rotation = Rotation::new(angle2) * position2.rotation;
+
+ for ii in 0..SIMD_WIDTH {
+ positions[self.position2[ii]] = position2.extract(ii);
+ }
+ }
+}