use phys_geom::volume::ComputeVolume;
use glam_det::{Point3, Vec3};
use super::traits::{ComplexShapeTrait, ShapePlugin};
use crate::bvh::bvh::Bvh4;
use crate::traits::Expansion;
use crate::{
Aabb3, ComputeAabb3, ContainsPoint, Ray, Raycast, RaycastHitResult, SignedDistanceToPoint,
};
#[derive(Default, Clone, Debug)]
pub struct Mesh {
tree: Bvh4<u32>,
vertices: Vec<Point3>,
triangles: Vec<u32>,
scale: Vec3,
inverse_scale: Vec3,
}
impl Mesh {
pub const PLUGIN_ID: u64 = 0x5fd1243d;
}
impl ComputeAabb3 for Mesh {
fn compute_aabb(&self) -> Aabb3 {
phys_geom::volume::compute_mesh_bound(self.vertices.iter().map(Point3::to_array))
}
}
impl Raycast for Mesh {
fn raycast(
&self,
_local_ray: Ray,
_max_distance: f32,
_discard_inside_hit: bool,
) -> Option<RaycastHitResult> {
todo!("issue #1201");
}
}
impl Expansion for Mesh {
#[inline]
fn max_radius_and_max_angular_expansion(&self) -> (f32, f32) {
todo!()
}
}
impl ComputeVolume for Mesh {
#[inline]
fn compute_volume(&self) -> phys_geom::math::Real {
todo!()
}
}
impl SignedDistanceToPoint for Mesh {
fn signed_distance_to_point(&self, _local_point: Point3) -> f32 {
todo!()
}
}
impl ContainsPoint for Mesh {
fn contains_point_with_threshold(
&self,
_local_point: Point3,
_threshold: f32,
) -> crate::ContainsResult {
todo!()
}
}
impl ShapePlugin for Mesh {
const PLUGIN_ID: u64 = Mesh::PLUGIN_ID;
}
impl ComplexShapeTrait for Mesh {}
#[cfg(test)]
mod tests {
use approx_det::assert_relative_eq;
use chull_adapt::ConvexHullConstructState;
use phys_geom::math::Point3;
use phys_geom::volume::ComputeVolume;
use glam_det::Vec3;
use wasm_bindgen_test::*;
use crate::bvh::bvh::Bvh4;
use crate::shapes::CuboidExt;
use crate::traits::Expansion;
use crate::{ComputeAabb3, ContainsPoint, ConvexMesh, Cuboid, Mesh, SignedDistanceToPoint};
wasm_bindgen_test_configure!(run_in_browser);
#[test]
#[wasm_bindgen_test]
fn mesh_compute_bound() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid = Cuboid::UNIT;
let points = vec![
cuboid.get_vertex(0),
cuboid.get_vertex(1),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
];
let mesh = Mesh {
tree: Bvh4::default(),
vertices: points,
triangles: vec![],
scale: Vec3::default(),
inverse_scale: Vec3::default(),
};
let bound0 = mesh.compute_aabb();
let bound1 = cuboid.compute_aabb();
assert_eq!(bound0.min(), bound1.min());
assert_eq!(bound0.max(), bound1.max());
}
#[test]
#[wasm_bindgen_test]
#[should_panic]
fn test_compute_expand() {
let _ = env_logger::builder().is_test(true).try_init();
let shape = Mesh {
tree: Bvh4::default(),
vertices: vec![],
triangles: vec![],
scale: Vec3::default(),
inverse_scale: Vec3::default(),
};
let (max_radius, max_angular_expansion) = shape.max_radius_and_max_angular_expansion();
assert_relative_eq!(max_radius, 0f32);
assert_relative_eq!(max_angular_expansion, 0f32);
}
#[test]
#[wasm_bindgen_test]
fn test_convex_mesh() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid = Cuboid::UNIT;
let points = vec![
cuboid.get_vertex(0),
cuboid.get_vertex(1),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
glam_det::Point3::new(0.0, 0.0, 0.0),
];
let (mesh, state) = ConvexMesh::new(&points).unwrap();
if state == ConvexHullConstructState::Success {
let num_triangles = mesh.num_triangles();
assert_eq!(12, num_triangles);
let num_vertices = mesh.num_vertices();
assert_eq!(8, num_vertices);
let vertices = mesh.vertices();
assert_eq!(8, vertices.len());
let triangles = mesh.triangles();
assert_eq!(36, triangles.len());
} else {
panic!("Build convex mesh from cuboid failed!")
}
}
#[test]
#[wasm_bindgen_test]
#[should_panic]
fn test_mesh_volume() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid = Cuboid::UNIT;
let points = vec![
cuboid.get_vertex(0),
cuboid.get_vertex(1),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
];
let mesh = Mesh {
tree: Bvh4::default(),
vertices: points,
triangles: vec![],
scale: Vec3::default(),
inverse_scale: Vec3::default(),
};
mesh.compute_volume();
}
#[test]
#[wasm_bindgen_test]
#[should_panic]
fn test_mesh_signed_distance() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid = Cuboid::UNIT;
let points = vec![
cuboid.get_vertex(0),
cuboid.get_vertex(1),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
];
let mesh = Mesh {
tree: Bvh4::default(),
vertices: points,
triangles: vec![],
scale: Vec3::default(),
inverse_scale: Vec3::default(),
};
mesh.signed_distance_to_point(Point3::new(0.0, 0.0, 0.0));
}
#[test]
#[wasm_bindgen_test]
#[should_panic]
fn test_mesh_contains_point() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid = Cuboid::UNIT;
let points = vec![
cuboid.get_vertex(0),
cuboid.get_vertex(1),
cuboid.get_vertex(2),
cuboid.get_vertex(3),
cuboid.get_vertex(4),
cuboid.get_vertex(5),
cuboid.get_vertex(6),
cuboid.get_vertex(7),
];
let mesh = Mesh {
tree: Bvh4::default(),
vertices: points,
triangles: vec![],
scale: Vec3::default(),
inverse_scale: Vec3::default(),
};
mesh.contains_point_with_threshold(Point3::new(0.0, 0.0, 0.0), 0.01f32);
}
}