use crate::csg::{BooleanMesh, Manifold};
use axiolid_contracts::GeomError;
use axiolid_core::{Point3, Vec3};
use axiolid_mesh::TriMesh;
use axiolid_mesh_contracts::SolidRequirements;
pub(crate) fn six_signed_volume(positions: &[Point3], indices: &[u32]) -> f64 {
let n = positions.len() as f64;
if n == 0.0 {
return 0.0;
}
let mut c = [0.0f64; 3];
for p in positions {
c[0] += p.x;
c[1] += p.y;
c[2] += p.z;
}
let c = [c[0] / n, c[1] / n, c[2] / n];
let shifted = |i: u32| {
let p = positions[i as usize];
Vec3::new(p.x - c[0], p.y - c[1], p.z - c[2])
};
let mut total = 0.0;
for corner in indices.chunks_exact(3) {
let a = shifted(corner[0]);
let b = shifted(corner[1]);
let c = shifted(corner[2]);
total += a.dot(b.cross(c));
}
total
}
pub(crate) fn to_manifold(mesh: &TriMesh, role: &str) -> Result<Manifold, GeomError> {
SolidRequirements::Oriented.validate(mesh, role)?;
let positions: Vec<f64> = mesh
.positions
.iter()
.flat_map(|p| [p.x, p.y, p.z])
.collect();
let indices: Vec<usize> = mesh.indices.iter().map(|&i| i as usize).collect();
Manifold::new(&positions, &indices)
.map_err(|reason| GeomError::NotManifold(format!("{role}: {reason}")))
}
pub(crate) fn from_boolean_mesh(mesh: &BooleanMesh) -> TriMesh {
let positions = mesh.ps.iter().map(|p| Point3::new(p.x, p.y, p.z)).collect();
let indices = mesh
.tris
.iter()
.flat_map(|t| [t.x as u32, t.y as u32, t.z as u32])
.collect();
TriMesh::new(positions, indices)
}