use crate::Scalar;
use crate::storage::MeshStorage;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AABB {
pub min: [Scalar; 3],
pub max: [Scalar; 3],
}
impl AABB {
pub fn new() -> Self {
Self {
min: [f64::MAX; 3],
max: [f64::MIN; 3],
}
}
pub fn from_points(points: &[[f64; 3]]) -> Self {
let mut aabb = Self::new();
for p in points {
aabb.extend(p);
}
aabb
}
pub fn extend(&mut self, point: &[f64; 3]) {
for ((&p, min_i), max_i) in point
.iter()
.zip(self.min.iter_mut())
.zip(self.max.iter_mut())
{
if p < *min_i {
*min_i = p;
}
if p > *max_i {
*max_i = p;
}
}
}
pub fn union(&self, other: &AABB) -> AABB {
let mut result = *self;
for i in 0..3 {
if other.min[i] < result.min[i] {
result.min[i] = other.min[i];
}
if other.max[i] > result.max[i] {
result.max[i] = other.max[i];
}
}
result
}
pub fn center(&self) -> [f64; 3] {
[
(self.min[0] + self.max[0]) / 2.0,
(self.min[1] + self.max[1]) / 2.0,
(self.min[2] + self.max[2]) / 2.0,
]
}
pub fn diagonal(&self) -> f64 {
let d = [
self.max[0] - self.min[0],
self.max[1] - self.min[1],
self.max[2] - self.min[2],
];
(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt()
}
pub fn is_empty(&self) -> bool {
self.min[0] > self.max[0]
}
}
impl Default for AABB {
fn default() -> Self {
Self::new()
}
}
pub fn mesh_aabb(mesh: &MeshStorage) -> Option<AABB> {
let positions = mesh.positions_dense();
if positions.is_empty() {
return None;
}
let mut aabb = AABB::new();
for p in positions {
aabb.extend(p);
}
Some(aabb)
}
pub fn mesh_centroid(mesh: &MeshStorage) -> Option<[f64; 3]> {
let positions = mesh.positions_dense();
if positions.is_empty() {
return None;
}
let mut sum = [0.0; 3];
for p in positions {
sum[0] += p[0];
sum[1] += p[1];
sum[2] += p[2];
}
let n = positions.len() as f64;
Some([sum[0] / n, sum[1] / n, sum[2] / n])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ids::VertexId;
use crate::storage::{Face, HalfEdge, Vertex};
#[test]
fn aabb_unit_triangle() {
let (mesh, _v, _f) = build_unit_triangle();
let aabb = mesh_aabb(&mesh).unwrap();
assert!(!aabb.is_empty());
assert!((aabb.min[0] - 0.0).abs() < 1e-12);
assert!((aabb.max[0] - 1.0).abs() < 1e-12);
assert!((aabb.max[1] - 1.0).abs() < 1e-12);
}
#[test]
fn aabb_empty_mesh() {
let mesh = MeshStorage::new();
assert!(mesh_aabb(&mesh).is_none());
}
#[test]
fn aabb_center_and_diagonal() {
let aabb = AABB {
min: [0.0, 0.0, 0.0],
max: [2.0, 2.0, 2.0],
};
assert_eq!(aabb.center(), [1.0, 1.0, 1.0]);
let diag = aabb.diagonal();
assert!((diag - (12.0_f64).sqrt()).abs() < 1e-12);
}
#[test]
fn centroid_basic() {
let (mesh, _v, _f) = build_unit_triangle();
let c = mesh_centroid(&mesh).unwrap();
assert!((c[0] - 1.0 / 3.0).abs() < 1e-12);
assert!((c[1] - 1.0 / 3.0).abs() < 1e-12);
}
#[test]
fn aabb_on_icosphere() {
let mesh = crate::test_util::build_icosphere(1);
let aabb = mesh_aabb(&mesh).unwrap();
assert!(aabb.min[0] >= -1.0 && aabb.min[0] <= -0.9);
assert!(aabb.max[0] <= 1.0 && aabb.max[0] >= 0.9);
}
fn build_unit_triangle() -> (MeshStorage, [VertexId; 3], crate::ids::FaceId) {
let mut mesh = MeshStorage::new();
let a = mesh.add_vertex(Vertex::new([0.0, 0.0, 0.0]));
let b = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0]));
let c = mesh.add_vertex(Vertex::new([0.0, 1.0, 0.0]));
let h_ab = mesh.add_halfedge(HalfEdge::new(b)); let h_bc = mesh.add_halfedge(HalfEdge::new(c)); let h_ca = mesh.add_halfedge(HalfEdge::new(a)); let t_ab = mesh.add_halfedge(HalfEdge::new(a)); let t_bc = mesh.add_halfedge(HalfEdge::new(b)); let t_ca = mesh.add_halfedge(HalfEdge::new(c));
let f = mesh.add_face(Face::new());
for (he, twin, next, prev) in [
(h_ab, t_ab, h_bc, h_ca),
(h_bc, t_bc, h_ca, h_ab),
(h_ca, t_ca, h_ab, h_bc),
] {
let h = mesh.get_halfedge_mut(he).unwrap();
h.twin = Some(twin);
h.next = Some(next);
h.prev = Some(prev);
h.face = Some(f);
}
for (t, he) in [(t_ab, h_ab), (t_bc, h_bc), (t_ca, h_ca)] {
mesh.get_halfedge_mut(t).unwrap().twin = Some(he);
}
mesh.get_vertex_mut(a).unwrap().halfedge = Some(h_ab);
mesh.get_vertex_mut(b).unwrap().halfedge = Some(h_bc);
mesh.get_vertex_mut(c).unwrap().halfedge = Some(h_ca);
mesh.get_face_mut(f).unwrap().halfedge = Some(h_ab);
(mesh, [a, b, c], f)
}
}