use super::ClippingProcessor;
use crate::diagnostics::{BoolFailureReason, BoolOp};
use crate::mesh::Mesh;
#[cfg(feature = "csg_manifold_gate")]
use crate::router::voids::prism_cut::closure_checks::edge_multiplicity_defects;
use crate::router::voids::prism_cut::closure_checks::{closed_or_hairline, directed_closed};
pub(crate) const OPEN_TOPOLOGY_MESSAGE: &str =
"open topology: accepted result passed validate_mesh but failed the directed-edge closure audit (#3440 step 1 — informational, non-gating)";
impl ClippingProcessor {
pub(crate) fn record_topology_tear(&self, op: BoolOp, mesh: &Mesh) {
if !mesh.is_empty() && !directed_closed(mesh) && !closed_or_hairline(mesh) {
self.record_failure(
op,
BoolFailureReason::KernelError(OPEN_TOPOLOGY_MESSAGE.to_string()),
);
}
}
#[cfg(feature = "csg_topology_gate")]
pub(crate) fn topology_gate_reject(&self, op: BoolOp, mesh: &Mesh) -> bool {
if mesh.is_empty() || directed_closed(mesh) || closed_or_hairline(mesh) {
return false;
}
self.record_failure(op, BoolFailureReason::OpenTopologyRejected);
true
}
#[cfg(not(feature = "csg_topology_gate"))]
#[inline(always)]
pub(crate) fn topology_gate_reject(&self, _op: BoolOp, _mesh: &Mesh) -> bool {
false
}
#[cfg(feature = "csg_manifold_gate")]
pub(crate) fn manifold_gate_reject(&self, op: BoolOp, mesh: &Mesh) -> bool {
if mesh.is_empty() {
return false;
}
let defects = edge_multiplicity_defects(mesh);
if defects.is_clean() {
return false;
}
self.record_failure(
op,
BoolFailureReason::NonManifoldRejected {
over_used: defects.over_used,
same_direction: defects.same_direction,
},
);
true
}
#[cfg(not(feature = "csg_manifold_gate"))]
#[inline(always)]
pub(crate) fn manifold_gate_reject(&self, _op: BoolOp, _mesh: &Mesh) -> bool {
false
}
pub(crate) fn accept_gates_reject(&self, op: BoolOp, mesh: &Mesh) -> bool {
let manifold_rejected = self.manifold_gate_reject(op, mesh);
let topology_rejected = self.topology_gate_reject(op, mesh);
manifold_rejected | topology_rejected
}
}