use crate::dynamics::solver::joint_constraint::joint_velocity_constraint::{
JointVelocityConstraint, JointVelocityGroundConstraint, WritebackId,
};
use crate::dynamics::solver::joint_constraint::SolverBody;
use crate::dynamics::solver::MotorParameters;
use crate::dynamics::{IntegrationParameters, JointIndex, JointLimits};
use crate::math::{AngVector, Isometry, Matrix, Point, Real, Rotation, Vector, ANG_DIM, DIM};
use crate::utils::{IndexMut2, WCrossMatrix, WDot, WQuat, WReal};
use na::SMatrix;
#[derive(Debug, Copy, Clone)]
pub struct JointVelocityConstraintBuilder<N: WReal> {
pub basis: Matrix<N>,
pub cmat1_basis: SMatrix<N, ANG_DIM, DIM>,
pub cmat2_basis: SMatrix<N, ANG_DIM, DIM>,
pub ang_basis: SMatrix<N, ANG_DIM, ANG_DIM>,
pub lin_err: Vector<N>,
pub ang_err: Rotation<N>,
}
impl<N: WReal> JointVelocityConstraintBuilder<N> {
pub fn new(
frame1: &Isometry<N>,
frame2: &Isometry<N>,
world_com1: &Point<N>,
world_com2: &Point<N>,
locked_lin_axes: u8,
) -> Self {
let mut frame1 = *frame1;
let basis = frame1.rotation.to_rotation_matrix().into_inner();
let lin_err = frame2.translation.vector - frame1.translation.vector;
// Adjust the point of application of the force for the first body,
// by snapping free axes to the second frame’s center (to account for
// the allowed relative movement).
{
let mut new_center1 = frame2.translation.vector; // First, assume all dofs are free.
// Then snap the locked ones.
for i in 0..DIM {
if locked_lin_axes & (1 << i) != 0 {
let axis = basis.column(i);
new_center1 -= axis * lin_err.dot(&axis);
}
}
frame1.translation.vector = new_center1;
}
let r1 = frame1.translation.vector - world_com1.coords;
let r2 = frame2.translation.vector - world_com2.coords;
let cmat1 = r1.gcross_matrix();
let cmat2 = r2.gcross_matrix();
#[allow(unused_mut)] // The mut is needed for 3D
let mut ang_basis = frame1.rotation.diff_conj1_2(&frame2.rotation).transpose();
#[allow(unused_mut)] // The mut is needed for 3D
let mut ang_err = frame1.rotation.inverse() * frame2.rotation;
#[cfg(feature = "dim3")]
{
let sgn = N::one().simd_copysign(frame1.rotation.dot(&frame2.rotation));
ang_basis *= sgn;
*ang_err.as_mut_unchecked() *= sgn;
}
Self {
basis,
cmat1_basis: cmat1 * basis,
cmat2_basis: cmat2 * basis,
ang_basis,
lin_err,
ang_err,
}
}
pub fn limit_linear<const LANES: usize>(
&self,
params: &IntegrationParameters,
joint_id: [JointIndex; LANES],
body1: &SolverBody<N, LANES>,
body2: &SolverBody<N, LANES>,
limited_axis: usize,
limits: [N; 2],
writeback_id: WritebackId,
) -> JointVelocityConstraint<N, LANES> {
let zero = N::zero();
let mut constraint =
self.lock_linear(params, joint_id, body1, body2, limited_axis, writeback_id);
let dist = self.lin_err.dot(&constraint.lin_jac);
let min_enabled = dist.simd_lt(limits[0]);
let max_enabled = limits[1].simd_lt(dist);
let erp_inv_dt = N::sp