use crate::{
dynamics::solver::{
solver_body::{SolverBody, SolverBodyInertia},
xpbd::*,
},
prelude::*,
};
use bevy::prelude::*;
#[derive(Clone, Copy, Debug, Default, PartialEq, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, PartialEq)]
pub struct FixedAngleConstraintShared {
#[cfg(feature = "2d")]
pub rotation_difference: Scalar,
#[cfg(feature = "3d")]
pub rotation_difference: Quaternion,
pub total_lagrange: AngularVector,
}
impl XpbdConstraintSolverData for FixedAngleConstraintShared {
fn clear_lagrange_multipliers(&mut self) {
self.total_lagrange = AngularVector::ZERO;
}
fn total_rotation_lagrange(&self) -> AngularVector {
self.total_lagrange
}
}
impl FixedAngleConstraintShared {
pub fn prepare(
&mut self,
rotation1: &Rotation,
rotation2: &Rotation,
local_basis1: Rot,
local_basis2: Rot,
) {
#[cfg(feature = "2d")]
{
self.rotation_difference =
(*rotation1 * local_basis1).angle_between(*rotation2 * local_basis2);
}
#[cfg(feature = "3d")]
{
self.rotation_difference =
(rotation1.0 * local_basis1) * (rotation2.0 * local_basis2).inverse();
}
}
pub fn solve(
&mut self,
bodies: [&mut SolverBody; 2],
inertias: [&SolverBodyInertia; 2],
compliance: Scalar,
dt: Scalar,
) {
let [body1, body2] = bodies;
let [inertia1, inertia2] = inertias;
let inv_inertia1 = inertia1.effective_inv_angular_inertia();
let inv_inertia2 = inertia2.effective_inv_angular_inertia();
#[cfg(feature = "2d")]
let difference =
self.rotation_difference + body1.delta_rotation.angle_between(body2.delta_rotation);
#[cfg(feature = "3d")]
let difference = -2.0
* (self.rotation_difference
* body1.delta_rotation.0
* body2.delta_rotation.0.inverse())
.xyz();
self.total_lagrange += self.align_orientation(
body1,
body2,
inv_inertia1,
inv_inertia2,
difference,
0.0,
compliance,
dt,
);
}
}
impl AngularConstraint for FixedAngleConstraintShared {}