pub struct BoolmeshBoolean;Expand description
Mesh boolean built on the algorithm absorbed from boolmesh (pure Rust,
glam-only, MPL-2.0).
Adopted in docs/adr/0014 and absorbed into this crate’s private csg
module by docs/adr/0047. This type owns conversion and contract
enforcement; no csg type is part of the public API, so the kernel can
be replaced without a consumer noticing.
Implementations§
Source§impl BoolmeshBoolean
impl BoolmeshBoolean
Sourcepub fn subtract_boxes_analytic(
&self,
subject: &TriMesh,
tools: &[TriMesh],
options: &ExecutionOptions,
max_cells: usize,
) -> GeomResult<Option<BooleanOutcome>>
pub fn subtract_boxes_analytic( &self, subject: &TriMesh, tools: &[TriMesh], options: &ExecutionOptions, max_cells: usize, ) -> GeomResult<Option<BooleanOutcome>>
Subtract axis-aligned box cutters from an axis-aligned box subject using an exact closed-form construction, bypassing the general solver.
Returns Ok(None) when the operands are outside this path’s competence,
so the caller falls back to MeshBoolean::subtract_many rather than
receiving an approximate answer. Declining cases:
- subject or any tool is not an axis-aligned box (recognised structurally – triangle count, corner lattice, and face planes – not by bounding box, since every mesh has one of those)
- no tools, or no tool overlapping the subject
- the induced grid would exceed
max_cells
§Why opt-in rather than automatic
Dispatching on shape automatically would make output topology depend on
input in a way the caller cannot predict: the same wall would produce
different triangle counts depending on whether its openings happened to
be axis-aligned. Callers that want the speed ask for it and handle the
None; callers that want one predictable code path never see this.
§Guarantees
The result is watertight by construction (adjacent cells address shared grid vertices by integer index) and deterministic across processes (vertex identity is an ordered map, not a randomly-seeded hash map).
The returned evidence has BooleanEvidence::analytic_path set, so a
caller can tell this result apart from a general-solver result.
Source§impl BoolmeshBoolean
impl BoolmeshBoolean
Sourcepub fn boolean_fast(
&self,
subject: &TriMesh,
tool: &TriMesh,
operation: BooleanOperator,
options: &ExecutionOptions,
) -> GeomResult<BooleanOutcome>
pub fn boolean_fast( &self, subject: &TriMesh, tool: &TriMesh, operation: BooleanOperator, options: &ExecutionOptions, ) -> GeomResult<BooleanOutcome>
Alternative to MeshBoolean::boolean using a cheaper winding-number
classification for the same result.
See csg::boolean03::kernel03::winding03_fast’s doc comment for the
guarantee: not an approximation, but a bug in edge-break detection
would mislabel a whole connected component instead of one vertex.
Opt-in rather than the default until this has run against a wider
correctness corpus than the differential tests already covering it.
SymmetricDifference is refused rather than silently composed from
three slow-path calls: a caller asking for the fast path should get
it or a clear refusal, not a surprise fallback.
Trait Implementations§
Source§impl Backend for BoolmeshBoolean
impl Backend for BoolmeshBoolean
Source§fn descriptor(&self) -> BackendDescriptor
fn descriptor(&self) -> BackendDescriptor
Source§impl Clone for BoolmeshBoolean
impl Clone for BoolmeshBoolean
Source§fn clone(&self) -> BoolmeshBoolean
fn clone(&self) -> BoolmeshBoolean
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for BoolmeshBoolean
impl Debug for BoolmeshBoolean
Source§impl Default for BoolmeshBoolean
impl Default for BoolmeshBoolean
Source§fn default() -> BoolmeshBoolean
fn default() -> BoolmeshBoolean
Source§impl MeshBoolean for BoolmeshBoolean
impl MeshBoolean for BoolmeshBoolean
Source§fn determinism(&self) -> Determinism
fn determinism(&self) -> Determinism
Honest about the general path, which is not byte-reproducible.
Upstream boolmesh dedups vertices through a randomly-seeded
HashMap, so its output ordering varies between processes even
single-threaded. That is the same root cause documented in
Self::subtract_boxes_analytic, which avoids it with a BTreeMap. The general
path therefore cannot claim Determinism::Bitwise at any thread
count, and enabling parallel does not make it weaker than it
already is.
Determinism::Topological is the honest ceiling: the result’s
connectivity is stable, its vertex ordering is not. Callers needing
byte reproducibility use Self::subtract_boxes_analytic,
whose ordered vertex identity makes it reproducible across processes.
Source§fn scratch_requirement(&self) -> ScratchRequirement
fn scratch_requirement(&self) -> ScratchRequirement
Measured, not guessed.
boolmesh builds a Morton collider and intersection tables sized by the
combined input. It exposes no bound, so this was measured directly with
a counting global allocator (src/bin/scratch_probe/) across all four
operations at 24 to 1,536 input triangles, after one discarded warmup
call so the first operation measured is not charged for process
startup (#110):
triangles peak bytes bytes/triangle worst operation
24 52424 2184 SymmetricDifference
96 98920 1030 SymmetricDifference
384 343768 895 SymmetricDifference
1536 1349668 878 SymmetricDifferenceConsumption is linear in input size, converging to under 1 KiB per
triangle; the higher ratio at small inputs is fixed setup cost being
divided by few triangles. SymmetricDifference is worst because it is
composed from three passes and holds intermediates alive.
The declared bound is 4 KiB per triangle: about 1.9x the worst
observed ratio, as headroom for allocator variance and future operand
shapes. tests/scratch_bound.rs measures the same workloads and fails
if any peak exceeds it. A declared bound that is occasionally too low
is worse than Unbounded, because it makes a budget look enforced
when it is not.
Source§fn cancellation_granularity(&self) -> CancellationGranularity
fn cancellation_granularity(&self) -> CancellationGranularity
boolmesh takes no cancellation handle, so nothing can interrupt a
single boolean once it starts. Declared honestly: the batch override
polls between groups, which is the only real poll point available.
Source§fn subtract_many(
&self,
subject: &TriMesh,
tools: &[TriMesh],
options: &ExecutionOptions,
) -> GeomResult<BooleanOutcome>
fn subtract_many( &self, subject: &TriMesh, tools: &[TriMesh], options: &ExecutionOptions, ) -> GeomResult<BooleanOutcome>
Group mutually disjoint cutters and remove each group with one boolean, instead of one boolean per cutter.
Rests on (S \ A) \ B == S \ (A union B) and on a concatenation of
disjoint solids being their union. Bounding-box grouping over-separates
but never wrongly fuses, so the result is identical to the sequential
default – gated by volume equality in tests/batch.rs.
Source§fn union_many(
&self,
solids: &[TriMesh],
options: &ExecutionOptions,
) -> GeomResult<BooleanOutcome>
fn union_many( &self, solids: &[TriMesh], options: &ExecutionOptions, ) -> GeomResult<BooleanOutcome>
Source§fn boolean(
&self,
subject: &TriMesh,
tool: &TriMesh,
operation: BooleanOperator,
options: &ExecutionOptions,
) -> GeomResult<BooleanOutcome>
fn boolean( &self, subject: &TriMesh, tool: &TriMesh, operation: BooleanOperator, options: &ExecutionOptions, ) -> GeomResult<BooleanOutcome>
Source§fn solid_requirements(&self) -> SolidRequirements
fn solid_requirements(&self) -> SolidRequirements
impl Copy for BoolmeshBoolean
Auto Trait Implementations§
impl Freeze for BoolmeshBoolean
impl RefUnwindSafe for BoolmeshBoolean
impl Send for BoolmeshBoolean
impl Sync for BoolmeshBoolean
impl Unpin for BoolmeshBoolean
impl UnwindSafe for BoolmeshBoolean
Blanket Implementations§
Source§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,
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