pub enum BoolFailureReason {
Show 16 variants
OperandTooLarge {
polys_a: usize,
polys_b: usize,
},
EmptyOperand,
DegenerateOperand,
NoBoundsOverlap,
KernelOutputInvalid,
SolidSolidDifferenceSkipped,
PolygonalBoundedHalfSpaceFallback,
CutterUnionUnavailable,
UnknownBooleanOperator(String),
OperandBudgetExhausted,
ManifoldOutputDegenerate {
host_tris: usize,
result_tris: usize,
},
KernelError(String),
DifferenceEmptiedHost,
UnsupportedOperand(String),
OpenTopologyRejected,
NonManifoldRejected {
over_used: usize,
same_direction: usize,
},
}Expand description
Why a boolean operation failed or was skipped.
Variants§
OperandTooLarge
HISTORICAL: at least one operand exceeded the deleted legacy BSP CSG polygon cap. The pure-Rust exact kernel has no operand cap, so this is no longer emitted by the boolean ops; the variant (and its JSON label) is kept for the frozen diagnostics surface and void-router plumbing.
EmptyOperand
One or both operand meshes were empty before polygon extraction.
DegenerateOperand
Polygon extraction yielded an empty list (degenerate / non-finite vertices).
NoBoundsOverlap
Operand bounding boxes don’t overlap. Informational — host returned unchanged.
KernelOutputInvalid
The CSG kernel returned malformed polygons (NaN / non-finite).
SolidSolidDifferenceSkipped
HISTORICAL: solid-vs-solid IfcBooleanResult.DIFFERENCE was not
attempted because the deleted legacy BSP could stack-overflow on
arbitrary solid combinations. No longer emitted — the exact kernel
always attempts the cut. Variant kept for the frozen label surface.
PolygonalBoundedHalfSpaceFallback
IfcPolygonalBoundedHalfSpace prism-subtraction failed; the kernel
fell back to an unbounded plane clip, silently dropping the polygonal
boundary. The clip is applied but is a strict superset of the
requested cut.
The chained-clip cutter prisms couldn’t be unioned into one watertight solid, so the single batched subtract (issue #960) was skipped and the chain fell back to sequential per-cutter subtraction. The cuts are applied, but abutting cutters may leave zero-thickness seam fins that the batched path would have eliminated.
UnknownBooleanOperator(String)
IfcBooleanResult operator string didn’t match any known op.
OperandBudgetExhausted
The operand walk under one representation item entered more
boolean/CSG nodes than processors::boolean::MAX_OPERAND_VISITS
allows and was stopped. The item is dropped (the walk returns Err),
so this is the only trace of why. A shared SecondOperand re-meshed
down m^levels paths is the shape that gets here; a real item does
not.
ManifoldOutputDegenerate
HISTORICAL: the deleted Manifold C++ kernel’s difference returned
output implausibly small relative to the host (a Linux-x86_64-only
pathology). No longer emitted — the deterministic exact kernel
replaced Manifold. Variant kept for the frozen label surface.
KernelError(String)
Catch-all for kernel-specific errors (free-form string).
DifferenceEmptiedHost
IfcBooleanResult.DIFFERENCE produced an empty mesh from a non-empty
host. Almost always a buggy export — a clip plane authored AT the
wall’s top with AgreementFlag = .T. (issue #821, Revit IFC2x3
TallBuilding.ifc) makes the half-space material region exactly cover
the wall body, so the strict-spec subtract yields nothing. The caller
falls back to the un-cut host (matching what BIMVision and similar
viewers do in practice) and records this so the loss surfaces in
diagnostics rather than as a silently missing element.
UnsupportedOperand(String)
A boolean operand’s IfcRepresentationItem type has no meshing branch
in BooleanClippingProcessor::process_operand_checked, so the operand
resolved to an EMPTY mesh. Carries the operand’s IFC type name.
As a FIRST operand this is a real element-geometry loss: the base solid
is empty, the whole boolean result is empty, and the element renders
nothing from that item. As a SECOND operand it means “unsupported
cutter” — the host renders un-cut, and the pre-existing EmptyOperand
record for the same step is also emitted (one record for the cause, one
for the consequence).
OpenTopologyRejected
#3440 step 2: the kernel result passed validate_mesh (finite,
in-bounds) but failed the directed-edge closure audit
(topology_gate_reject — same predicate KernelError’s step-1
informational record already checks) and was REJECTED rather than
merely flagged. Only ever constructed when this crate is built with
the csg_topology_gate feature, which is off by default and enabled
by nothing downstream — so this variant exists in every build (a
stable thing for consumers to match on, per the crate’s convention for
its other rarely-emitted variants above) but is only ever actually
recorded in a --features csg_topology_gate build.
NonManifoldRejected
#3440 step 3: the kernel result passed validate_mesh AND the signed
closure audit, but carries an edge-multiplicity defect that audit
cannot express — an undirected edge used by more than two triangles, or
used twice the same way round (edge_multiplicity_defects). Rejected,
and the caller falls back exactly as it does for
KernelOutputInvalid.
Like Self::OpenTopologyRejected, only ever constructed under a
feature — its own csg_manifold_gate, kept separate from
csg_topology_gate so a census can attribute a flip to one defect
class rather than to whichever gate fired first. The variant exists in
every build, per this enum’s convention for its other rarely-emitted
reasons.
The gate reads a defect class benign tessellation cannot produce, so it
was tried as a default; the fallback a rejection reaches turned out to
be worse than the tear it replaces. The numbers behind that live in one
place — csg_manifold_gate in Cargo.toml — with the corpus sweep in
tests/issue_3440_manifold_gate_census.rs.
Carries the two counts (as OperandTooLarge carries its operand sizes)
so the census can break the flip set down by defect class without a
second sweep: the two say different things about the kernel, and a bare
variant would force anyone measuring to re-derive them.
Implementations§
Trait Implementations§
Source§impl Clone for BoolFailureReason
impl Clone for BoolFailureReason
Source§fn clone(&self) -> BoolFailureReason
fn clone(&self) -> BoolFailureReason
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for BoolFailureReason
impl Debug for BoolFailureReason
Source§impl Display for BoolFailureReason
impl Display for BoolFailureReason
Source§impl PartialEq for BoolFailureReason
impl PartialEq for BoolFailureReason
impl Eq for BoolFailureReason
impl StructuralPartialEq for BoolFailureReason
Auto Trait Implementations§
impl Freeze for BoolFailureReason
impl RefUnwindSafe for BoolFailureReason
impl Send for BoolFailureReason
impl Sync for BoolFailureReason
impl Unpin for BoolFailureReason
impl UnwindSafe for BoolFailureReason
Blanket Implementations§
§impl<U> As for U
impl<U> As for U
§fn as_<T>(self) -> Twhere
T: CastFrom<U>,
fn as_<T>(self) -> Twhere
T: CastFrom<U>,
self to type T. The semantics of numeric casting with the as operator are followed, so <T as As>::as_::<U> can be used in the same way as T as U for numeric conversions. Read moreSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> Pointable for T
impl<T> Pointable for T
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.