use crate::prelude::*;
use bevy::prelude::*;
#[cfg(feature = "3d")]
use crate::utils::get_rotated_inertia_tensor;
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct Mass(pub Scalar);
impl Mass {
pub const ZERO: Self = Self(0.0);
}
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct InverseMass(pub Scalar);
impl InverseMass {
pub const ZERO: Self = Self(0.0);
}
#[cfg(feature = "2d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct Inertia(pub Scalar);
#[cfg(feature = "3d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct Inertia(pub Matrix3);
#[cfg(feature = "3d")]
impl Default for Inertia {
fn default() -> Self {
Self(Matrix3::ZERO)
}
}
impl Inertia {
#[cfg(feature = "2d")]
pub const ZERO: Self = Self(0.0);
#[cfg(feature = "3d")]
pub const ZERO: Self = Self(Matrix3::ZERO);
#[cfg(feature = "2d")]
#[allow(dead_code)]
pub(crate) fn rotated(&self, _rot: &Rotation) -> Self {
*self
}
#[cfg(feature = "3d")]
pub fn rotated(&self, rot: &Rotation) -> Self {
Self(get_rotated_inertia_tensor(self.0, rot.0))
}
#[cfg(feature = "2d")]
pub fn inverse(&self) -> InverseInertia {
InverseInertia(1.0 / self.0)
}
#[cfg(feature = "3d")]
pub fn inverse(&self) -> InverseInertia {
InverseInertia(self.0.inverse())
}
#[cfg(feature = "2d")]
pub fn shifted(&self, mass: Scalar, offset: Vector) -> Scalar {
if mass > 0.0 && mass.is_finite() {
self.0 + offset.length_squared() * mass
} else {
self.0
}
}
#[cfg(feature = "3d")]
pub fn shifted(&self, mass: Scalar, offset: Vector) -> Matrix3 {
type NaMatrix3 = parry::na::Matrix3<math::Scalar>;
use parry::na::*;
if mass > 0.0 && mass.is_finite() {
let matrix = NaMatrix3::from(self.0);
let offset = Vector::from(offset);
let diagonal_el = offset.norm_squared();
let diagonal_mat = NaMatrix3::from_diagonal_element(diagonal_el);
math::Matrix3::from(matrix + (diagonal_mat + offset * offset.transpose()) * mass)
} else {
self.0
}
}
}
#[cfg(feature = "2d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct InverseInertia(pub Scalar);
#[cfg(feature = "3d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct InverseInertia(pub Matrix3);
#[cfg(feature = "3d")]
impl Default for InverseInertia {
fn default() -> Self {
InverseInertia(Matrix3::ZERO)
}
}
impl InverseInertia {
#[cfg(feature = "2d")]
pub const ZERO: Self = Self(0.0);
#[cfg(feature = "3d")]
pub const ZERO: Self = Self(Matrix3::ZERO);
#[cfg(feature = "2d")]
pub fn rotated(&self, _rot: &Rotation) -> Self {
*self
}
#[cfg(feature = "3d")]
pub fn rotated(&self, rot: &Rotation) -> Self {
Self(get_rotated_inertia_tensor(self.0, rot.0))
}
#[cfg(feature = "2d")]
pub fn inverse(&self) -> Inertia {
Inertia(1.0 / self.0)
}
#[cfg(feature = "3d")]
pub fn inverse(&self) -> Inertia {
Inertia(self.0.inverse())
}
}
impl From<Inertia> for InverseInertia {
fn from(inertia: Inertia) -> Self {
inertia.inverse()
}
}
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[reflect(Component)]
pub struct CenterOfMass(pub Vector);
impl CenterOfMass {
pub const ZERO: Self = Self(Vector::ZERO);
}
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[allow(missing_docs)]
#[derive(Bundle, Debug, Default, Clone, PartialEq)]
pub struct MassPropertiesBundle {
pub mass: Mass,
pub inverse_mass: InverseMass,
pub inertia: Inertia,
pub inverse_inertia: InverseInertia,
pub center_of_mass: CenterOfMass,
}
impl MassPropertiesBundle {
pub fn new_computed(collider: &Collider, density: Scalar) -> Self {
let ColliderMassProperties {
mass,
inverse_mass,
inertia,
inverse_inertia,
center_of_mass,
..
} = collider.mass_properties(density);
Self {
mass,
inverse_mass,
inertia,
inverse_inertia,
center_of_mass,
}
}
}
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[derive(Reflect, Clone, Copy, Component, Debug, Deref, DerefMut, PartialEq, PartialOrd)]
#[reflect(Component)]
pub struct ColliderDensity(pub Scalar);
impl ColliderDensity {
pub const ZERO: Self = Self(0.0);
}
impl Default for ColliderDensity {
fn default() -> Self {
Self(1.0)
}
}
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq)]
#[reflect(Component)]
pub struct ColliderMassProperties {
pub(crate) mass: Mass,
pub(crate) inverse_mass: InverseMass,
pub(crate) inertia: Inertia,
pub(crate) inverse_inertia: InverseInertia,
pub(crate) center_of_mass: CenterOfMass,
}
impl ColliderMassProperties {
pub const ZERO: Self = Self {
mass: Mass::ZERO,
inverse_mass: InverseMass(Scalar::INFINITY),
inertia: Inertia::ZERO,
inverse_inertia: InverseInertia::ZERO,
center_of_mass: CenterOfMass::ZERO,
};
pub fn new(collider: &Collider, density: Scalar) -> Self {
let props = collider.shape_scaled().mass_properties(density);
Self {
mass: Mass(props.mass()),
inverse_mass: InverseMass(props.inv_mass),
#[cfg(feature = "2d")]
inertia: Inertia(props.principal_inertia()),
#[cfg(feature = "3d")]
inertia: Inertia(props.reconstruct_inertia_matrix().into()),
#[cfg(feature = "2d")]
inverse_inertia: InverseInertia(1.0 / props.principal_inertia()),
#[cfg(feature = "3d")]
inverse_inertia: InverseInertia(props.reconstruct_inverse_inertia_matrix().into()),
center_of_mass: CenterOfMass(props.local_com.into()),
}
}
pub fn mass(&self) -> Scalar {
self.mass.0
}
pub fn inverse_mass(&self) -> Scalar {
self.inverse_mass.0
}
#[cfg(feature = "2d")]
pub fn inertia(&self) -> Scalar {
self.inertia.0
}
#[cfg(feature = "3d")]
pub fn inertia(&self) -> Matrix3 {
self.inertia.0
}
#[cfg(feature = "2d")]
pub fn inverse_inertia(&self) -> Scalar {
self.inverse_inertia.0
}
#[cfg(feature = "3d")]
pub fn inverse_inertia(&self) -> Matrix3 {
self.inverse_inertia.0
}
pub fn center_of_mass(&self) -> Vector {
self.center_of_mass.0
}
}
impl Default for ColliderMassProperties {
fn default() -> Self {
Self::ZERO
}
}