use crate::{Mesh, Point3, TessellationQuality, Vector3};
pub(super) fn quality_skips_small_cuts(quality: TessellationQuality) -> bool {
matches!(quality, TessellationQuality::Lowest | TessellationQuality::Low)
}
pub(super) fn fast_cut_skip_ratio() -> f64 {
use std::sync::OnceLock;
static R: OnceLock<f64> = OnceLock::new();
*R.get_or_init(|| {
std::env::var("IFC_LITE_FAST_CUT_RATIO")
.ok()
.and_then(|v| v.parse::<f64>().ok())
.filter(|v| v.is_finite() && *v > 0.0)
.unwrap_or(0.10)
})
}
pub(super) fn cutter_below_skip_ratio(host: &Mesh, cutter: &Mesh) -> bool {
let max_dim = |m: &Mesh| -> f64 {
let (mn, mx) = m.bounds();
(((mx.x - mn.x) as f64).max((mx.y - mn.y) as f64)).max((mx.z - mn.z) as f64)
};
let h = max_dim(host);
if h <= 0.0 {
return false;
}
max_dim(cutter) / h < fast_cut_skip_ratio()
}
pub(super) fn plane_is_coincident_with_host_face(
host: &Mesh,
plane_point: Point3<f64>,
plane_normal: Vector3<f64>,
) -> bool {
let (mn, mx) = host.bounds();
let host_min = Point3::new(mn.x as f64, mn.y as f64, mn.z as f64);
let host_max = Point3::new(mx.x as f64, mx.y as f64, mx.z as f64);
let dx = host_max.x - host_min.x;
let dy = host_max.y - host_min.y;
let dz = host_max.z - host_min.z;
let diag = (dx * dx + dy * dy + dz * dz).sqrt();
if diag <= 0.0 {
return false;
}
let tol = (diag * 0.001).max(0.001);
let corners = [
Point3::new(host_min.x, host_min.y, host_min.z),
Point3::new(host_max.x, host_min.y, host_min.z),
Point3::new(host_min.x, host_max.y, host_min.z),
Point3::new(host_max.x, host_max.y, host_min.z),
Point3::new(host_min.x, host_min.y, host_max.z),
Point3::new(host_max.x, host_min.y, host_max.z),
Point3::new(host_min.x, host_max.y, host_max.z),
Point3::new(host_max.x, host_max.y, host_max.z),
];
for c in &corners {
let signed = (c - plane_point).dot(&plane_normal);
if signed.abs() <= tol {
return true;
}
}
false
}