#![allow(missing_docs)]
use super::PyPhysicsWorld;
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct ContactPair {
pub body_a: u32,
pub body_b: u32,
pub contact_point: [f64; 3],
pub normal: [f64; 3],
pub depth: f64,
pub impulse: f64,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct InertiaTensor {
pub elements: [f64; 9],
}
impl InertiaTensor {
pub fn from_diagonal(ix: f64, iy: f64, iz: f64) -> Self {
#[allow(clippy::zero_prefixed_literal)]
let elements = [ix, 0.0, 0.0, 0.0, iy, 0.0, 0.0, 0.0, iz];
Self { elements }
}
pub fn diagonal(&self) -> [f64; 3] {
[self.elements[0], self.elements[4], self.elements[8]]
}
pub fn trace(&self) -> f64 {
self.elements[0] + self.elements[4] + self.elements[8]
}
}
#[allow(dead_code)]
pub struct PyRigidBody {
pub mass: f64,
pub half_extents: [f64; 3],
}
impl PyRigidBody {
pub fn new(mass: f64, half_extents: [f64; 3]) -> Self {
Self { mass, half_extents }
}
pub fn compute_moment_of_inertia_box(&self) -> InertiaTensor {
let m = self.mass;
let hx = self.half_extents[0];
let hy = self.half_extents[1];
let hz = self.half_extents[2];
let ixx = (m / 3.0) * (hy * hy + hz * hz);
let iyy = (m / 3.0) * (hx * hx + hz * hz);
let izz = (m / 3.0) * (hx * hx + hy * hy);
InertiaTensor::from_diagonal(ixx, iyy, izz)
}
pub fn compute_moment_of_inertia_sphere(&self, radius: f64) -> InertiaTensor {
let i = 0.4 * self.mass * radius * radius;
InertiaTensor::from_diagonal(i, i, i)
}
}
impl PyPhysicsWorld {
pub fn compute_total_energy(&self) -> (f64, f64, f64) {
let g = self.config.gravity;
let g_mag = (g[0] * g[0] + g[1] * g[1] + g[2] * g[2]).sqrt();
let g_dir = if g_mag > 1e-10 {
[g[0] / g_mag, g[1] / g_mag, g[2] / g_mag]
} else {
[0.0, -1.0, 0.0]
};
let mut ke = 0.0_f64;
let mut pe = 0.0_f64;
for slot in &self.slots {
let body = match slot.body.as_ref() {
Some(b) if !b.is_static && !b.is_kinematic => b,
_ => continue,
};
let v = body.velocity;
let v2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
ke += 0.5 * body.mass * v2;
let h = -(body.position[0] * g_dir[0]
+ body.position[1] * g_dir[1]
+ body.position[2] * g_dir[2]);
pe += body.mass * g_mag * h;
}
(ke, pe, ke + pe)
}
pub fn apply_gravity_field<F>(&mut self, field: F)
where
F: Fn([f64; 3]) -> [f64; 3],
{
for slot in &mut self.slots {
let body = match slot.body.as_mut() {
Some(b) if !b.is_static && !b.is_kinematic => b,
_ => continue,
};
let g_local = field(body.position);
body.accumulated_force[0] += body.mass * g_local[0];
body.accumulated_force[1] += body.mass * g_local[1];
body.accumulated_force[2] += body.mass * g_local[2];
}
}
pub fn get_contact_list(&self) -> Vec<ContactPair> {
self.contacts
.iter()
.map(|c| ContactPair {
body_a: c.body_a,
body_b: c.body_b,
contact_point: c.contact_point,
normal: c.normal,
depth: c.depth,
impulse: c.impulse,
})
.collect()
}
}