use axiolid_core::Point3;
use axiolid_mesh::TriMesh;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AlignedBox {
pub min: [f64; 3],
pub max: [f64; 3],
}
impl AlignedBox {
fn extent(&self) -> [f64; 3] {
[
self.max[0] - self.min[0],
self.max[1] - self.min[1],
self.max[2] - self.min[2],
]
}
fn is_proper(&self, eps: f64) -> bool {
self.extent().iter().all(|e| *e > eps)
}
}
pub fn recognise(mesh: &TriMesh, eps: f64) -> Option<AlignedBox> {
if mesh.indices.len() != 36 {
return None;
}
let p = &mesh.positions;
if p.is_empty() {
return None;
}
let mut min = [f64::INFINITY; 3];
let mut max = [f64::NEG_INFINITY; 3];
for v in p {
let c = [v.x, v.y, v.z];
for a in 0..3 {
if !c[a].is_finite() {
return None;
}
min[a] = min[a].min(c[a]);
max[a] = max[a].max(c[a]);
}
}
let bbox = AlignedBox { min, max };
if !bbox.is_proper(eps) {
return None;
}
for v in p {
let c = [v.x, v.y, v.z];
for a in 0..3 {
let on_min = (c[a] - min[a]).abs() <= eps;
let on_max = (c[a] - max[a]).abs() <= eps;
if !on_min && !on_max {
return None;
}
}
}
let mut plane_counts = [0usize; 6];
for tri in mesh.indices.chunks_exact(3) {
let vs: [[f64; 3]; 3] = [
corner_of(p, tri[0])?,
corner_of(p, tri[1])?,
corner_of(p, tri[2])?,
];
let mut matched = None;
for a in 0..3 {
if vs.iter().all(|v| (v[a] - min[a]).abs() <= eps) {
matched = Some(a * 2);
break;
}
if vs.iter().all(|v| (v[a] - max[a]).abs() <= eps) {
matched = Some(a * 2 + 1);
break;
}
}
plane_counts[matched?] += 1;
}
if plane_counts.iter().any(|c| *c != 2) {
return None;
}
Some(bbox)
}
fn corner_of(positions: &[Point3], index: u32) -> Option<[f64; 3]> {
let v = positions.get(index as usize)?;
Some([v.x, v.y, v.z])
}