#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CollisionBoundsType {
Box,
Sphere,
ConvexHull,
Capsule,
}
#[derive(Debug, Clone)]
pub struct CollisionBounds {
pub bounds_type: CollisionBoundsType,
pub extents: [f32; 3],
pub margin: f32,
pub label: String,
}
pub fn new_box_bounds(half_extents: [f32; 3], label: &str) -> CollisionBounds {
CollisionBounds {
bounds_type: CollisionBoundsType::Box,
extents: half_extents,
margin: 0.04,
label: label.to_owned(),
}
}
pub fn new_sphere_bounds(radius: f32, label: &str) -> CollisionBounds {
CollisionBounds {
bounds_type: CollisionBoundsType::Sphere,
extents: [radius.max(0.0), 0.0, 0.0],
margin: 0.04,
label: label.to_owned(),
}
}
pub fn new_hull_bounds(aabb_half: [f32; 3], label: &str) -> CollisionBounds {
CollisionBounds {
bounds_type: CollisionBoundsType::ConvexHull,
extents: aabb_half,
margin: 0.04,
label: label.to_owned(),
}
}
pub fn bounds_volume(b: &CollisionBounds) -> f32 {
match b.bounds_type {
CollisionBoundsType::Box => 8.0 * b.extents[0] * b.extents[1] * b.extents[2],
CollisionBoundsType::Sphere => (4.0 / 3.0) * std::f32::consts::PI * b.extents[0].powi(3),
CollisionBoundsType::ConvexHull => {
8.0 * b.extents[0] * b.extents[1] * b.extents[2]
}
CollisionBoundsType::Capsule => {
let r = b.extents[0];
let h = b.extents[1];
std::f32::consts::PI * r * r * h + (4.0 / 3.0) * std::f32::consts::PI * r.powi(3)
}
}
}
pub fn bounds_type_name(b: &CollisionBounds) -> &'static str {
match b.bounds_type {
CollisionBoundsType::Box => "box",
CollisionBoundsType::Sphere => "sphere",
CollisionBoundsType::ConvexHull => "convex_hull",
CollisionBoundsType::Capsule => "capsule",
}
}
pub fn collision_bounds_to_json(b: &CollisionBounds) -> String {
format!(
r#"{{"label":"{}", "type":"{}", "extents":[{:.4},{:.4},{:.4}], "margin":{:.4}}}"#,
b.label,
bounds_type_name(b),
b.extents[0],
b.extents[1],
b.extents[2],
b.margin
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn box_volume_correct() {
let b = new_box_bounds([1.0, 1.0, 1.0], "box");
assert!((bounds_volume(&b) - 8.0).abs() < 1e-4);
}
#[test]
fn sphere_volume_correct() {
let b = new_sphere_bounds(1.0, "sph");
let expected = (4.0 / 3.0) * std::f32::consts::PI;
assert!((bounds_volume(&b) - expected).abs() < 1e-4);
}
#[test]
fn bounds_type_name_box() {
let b = new_box_bounds([1.0; 3], "b");
assert_eq!(bounds_type_name(&b), "box");
}
#[test]
fn bounds_type_name_sphere() {
let b = new_sphere_bounds(1.0, "s");
assert_eq!(bounds_type_name(&b), "sphere");
}
#[test]
fn bounds_type_name_hull() {
let b = new_hull_bounds([1.0; 3], "h");
assert_eq!(bounds_type_name(&b), "convex_hull");
}
#[test]
fn json_contains_label() {
let b = new_box_bounds([1.0; 3], "myBounds");
assert!(collision_bounds_to_json(&b).contains("myBounds"));
}
#[test]
fn default_margin_is_nonzero() {
let b = new_box_bounds([1.0; 3], "b");
assert!((b.margin - 0.04).abs() < 1e-5);
}
#[test]
fn sphere_radius_stored_in_extents_x() {
let b = new_sphere_bounds(2.5, "s");
assert!((b.extents[0] - 2.5).abs() < 1e-5);
}
#[test]
fn hull_is_convex_hull_type() {
let b = new_hull_bounds([1.0; 3], "h");
assert_eq!(b.bounds_type, CollisionBoundsType::ConvexHull);
}
}