use crate::collision::{Capsule, Circle, MassData, Polygon};
use crate::hull::MAX_POLYGON_VERTICES;
use crate::math_functions::{
add, cross, dot, length, mul_add, normalize, sub, Vec2, PI, VEC2_ZERO,
};
pub fn compute_circle_mass(shape: &Circle, density: f32) -> MassData {
let rr = shape.radius * shape.radius;
let mass = density * PI * rr;
MassData {
mass,
center: shape.center,
rotational_inertia: mass * 0.5 * rr,
}
}
pub fn compute_capsule_mass(shape: &Capsule, density: f32) -> MassData {
let radius = shape.radius;
let rr = radius * radius;
let p1 = shape.center1;
let p2 = shape.center2;
let length = length(sub(p2, p1));
let ll = length * length;
let circle_mass = density * (PI * radius * radius);
let box_mass = density * (2.0 * radius * length);
let mut mass_data = MassData {
mass: circle_mass + box_mass,
center: Vec2 {
x: 0.5 * (p1.x + p2.x),
y: 0.5 * (p1.y + p2.y),
},
rotational_inertia: 0.0,
};
let lc = 4.0 * radius / (3.0 * PI);
let h = 0.5 * length;
let circle_inertia = circle_mass * (0.5 * rr + h * h + 2.0 * h * lc);
let box_inertia = box_mass * (4.0 * rr + ll) / 12.0;
mass_data.rotational_inertia = circle_inertia + box_inertia;
mass_data
}
pub fn compute_polygon_mass(shape: &Polygon, density: f32) -> MassData {
debug_assert!(shape.count > 0);
if shape.count == 1 {
let circle = Circle {
center: shape.vertices[0],
radius: shape.radius,
};
return compute_circle_mass(&circle, density);
}
if shape.count == 2 {
let capsule = Capsule {
center1: shape.vertices[0],
center2: shape.vertices[1],
radius: shape.radius,
};
return compute_capsule_mass(&capsule, density);
}
let mut vertices = [VEC2_ZERO; MAX_POLYGON_VERTICES];
let count = shape.count as usize;
let radius = shape.radius;
if radius > 0.0 {
let sqrt2 = 1.412f32;
for (i, vertex) in vertices.iter_mut().enumerate().take(count) {
let j = if i == 0 { count - 1 } else { i - 1 };
let n1 = shape.normals[j];
let n2 = shape.normals[i];
let mid = normalize(add(n1, n2));
*vertex = mul_add(shape.vertices[i], sqrt2 * radius, mid);
}
} else {
vertices[..count].copy_from_slice(&shape.vertices[..count]);
}
let mut center = VEC2_ZERO;
let mut area = 0.0f32;
let mut rotational_inertia = 0.0f32;
let r = vertices[0];
let inv3 = 1.0 / 3.0;
for i in 1..count - 1 {
let e1 = sub(vertices[i], r);
let e2 = sub(vertices[i + 1], r);
let d = cross(e1, e2);
let triangle_area = 0.5 * d;
area += triangle_area;
center = mul_add(center, triangle_area * inv3, add(e1, e2));
let (ex1, ey1) = (e1.x, e1.y);
let (ex2, ey2) = (e2.x, e2.y);
let intx2 = ex1 * ex1 + ex2 * ex1 + ex2 * ex2;
let inty2 = ey1 * ey1 + ey2 * ey1 + ey2 * ey2;
rotational_inertia += (0.25 * inv3 * d) * (intx2 + inty2);
}
let mut mass_data = MassData {
mass: density * area,
..Default::default()
};
debug_assert!(area > f32::EPSILON);
let inv_area = 1.0 / area;
center.x *= inv_area;
center.y *= inv_area;
mass_data.center = add(r, center);
mass_data.rotational_inertia = density * rotational_inertia;
mass_data.rotational_inertia -= mass_data.mass * dot(center, center);
debug_assert!(mass_data.rotational_inertia >= 0.0);
mass_data
}