pub struct GeometryRouter { /* private fields */ }Expand description
Geometry router - routes entities to processors
Implementations§
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn new_brep_signature_cache() -> SharedBrepSignatureCache
pub fn new_brep_signature_cache() -> SharedBrepSignatureCache
Create a fresh signature cache for ONE immutable loaded model.
Reuse completed BREP signatures across routers of the SAME source model. Attach a fresh cache when replacing the source, just like the item cache.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn drain_processor_failures(&self)
pub fn drain_processor_failures(&self)
Sweep every registered processor’s own boolean-failure log into this
router’s map. Called by Self::take_csg_failures, so a consumer that
already drains the router — the native pipeline via
produce_element_meshes, the wasm batch path via
drain_and_log_csg_diagnostics — picks these up with no second opt-in.
Before #3821 BooleanClippingProcessor::take_failures was called from
tests ONLY. Everything the boolean processor recorded (an unsupported
operand, an EmptyOperand cutter, an unknown operator) accumulated in a
RefCell no production caller ever read, so a model whose booleans all
degraded still reported a clean load: absence was indistinguishable from
success.
Bucketed under UNATTRIBUTED_PRODUCT_ID — the same “no attribution
available” bucket take_csg_failures already uses for
PENDING_MAPPED_BOOL_FAILURES. A processor is registered once per
router and reused across every item it meshes, so at drain time its log
is not attributable to one product from in here.
What that bucket does and does NOT preserve, precisely: the native and
wasm pipelines both drain PER ELEMENT (produce_element_meshes takes
the router’s failures after each job), so a record can never be
mis-attributed to a DIFFERENT element — it is attributed to none. The
element it came from is lost, so these records do not appear in the
per-product worst_hosts detail and are excluded from
products_with_failures (see super::count_attributed_products);
they do count towards the failure totals and the reason breakdown.
Real per-product attribution would mean threading the owning product id
down to every processor.process call site; that is a follow-up, not a
reason to keep dropping the records.
register stores ONE Rc per custom processor under each supported IFC type
(IfcBooleanResult and IfcBooleanClippingResult share an instance),
so iterating custom registrations can visit the same processor twice; the second visit
drains an already-emptied log and contributes nothing. No double count.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn take_unsupported_items(&self) -> FxHashMap<String, u64>
pub fn take_unsupported_items(&self) -> FxHashMap<String, u64>
Drain the dropped-item counts gathered since the last call.
Does NOT forget the sources already counted: the drain moves counts to
the caller, it does not un-see them. That happens with the mapped-item
cache this mirrors (set_tessellation_quality), since a re-tessellation
re-walks every source.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn take_csg_failures(&self) -> FxHashMap<u32, Vec<BoolFailure>>
pub fn take_csg_failures(&self) -> FxHashMap<u32, Vec<BoolFailure>>
Drain every boolean / CSG failure this router knows about since it was
created (or the last take_csg_failures call). The single drain point:
the native pipeline and the wasm batch path both call this and nothing
else.
Two kinds of record come out, distinguished by their key:
- Keyed by IFC product express id — the void-subtraction path
(multi-layer wall sub-meshes, single-mesh
process_element_with_voids_parts), which knows the host element whose opening / clip tripped a fallback. - Keyed by
UNATTRIBUTED_PRODUCT_ID— the registered processors’ own logs (swept bySelf::drain_processor_failures, #3821, including what the transient boolean under anIfcCsgSolidhands back toCsgSolidProcessor) and the producer-less hatch. StandaloneIfcBooleanResultchains DO flow here now; what they still lack is the owning product id. Seedrain_processor_failuresfor the cost.
Sourcepub fn take_layer_slice_diag(&self) -> Vec<(u32, &'static str)>
pub fn take_layer_slice_diag(&self) -> Vec<(u32, &'static str)>
Drain the per-element layered-slice diagnostics gathered since the last call (wasm logs them to the browser console after each batch).
Sourcepub fn csg_failure_product_count(&self) -> usize
pub fn csg_failure_product_count(&self) -> usize
Products with at least one recorded CSG failure, under the same
count_attributed_products rule the pipelines’ scalar uses (a bare
.len() would make this the one surface counting the synthetic
bucket). PEEKS: no processor sweep, unlike take_csg_failures.
Sourcepub fn csg_failure_total(&self) -> usize
pub fn csg_failure_total(&self) -> usize
Total CSG failures, INCLUDING the unattributed bucket (real failures,
unknown owner). Peeks, like Self::csg_failure_product_count.
Sourcepub fn host_consumed_by_void(&self, product_id: u32) -> bool
pub fn host_consumed_by_void(&self, product_id: u32) -> bool
Whether a host product was fully consumed by a containing void (its opening’s real solid engulfs the host). An empty void-cut result for such a host is CORRECT — the element should render nothing — and must not trigger the un-cut fallback.
Sourcepub fn take_classification_stats(&self) -> ClassificationStats
pub fn take_classification_stats(&self) -> ClassificationStats
Drain and return the cumulative opening-classification counters
since the router was created (or the last take_classification_stats
call). The internal counters are reset to zero.
Sourcepub fn take_host_opening_diagnostics(
&self,
) -> FxHashMap<u32, HostOpeningDiagnostic>
pub fn take_host_opening_diagnostics( &self, ) -> FxHashMap<u32, HostOpeningDiagnostic>
Drain and return the per-host opening diagnostic map.
Sourcepub fn take_rect_fast_stats(&self) -> RectFastStats
pub fn take_rect_fast_stats(&self) -> RectFastStats
Drain and return this router’s rect_fast counters (resets them to zero).
Sourcepub fn host_opening_diagnostic_count(&self) -> usize
pub fn host_opening_diagnostic_count(&self) -> usize
Total number of hosts with diagnostic records (mostly for tests).
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn process_element_with_material_layers(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
buildup: &LayerBuildup,
void_index: &FxHashMap<u32, Vec<u32>>,
) -> Result<Option<SubMeshCollection>>
pub fn process_element_with_material_layers( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, buildup: &LayerBuildup, void_index: &FxHashMap<u32, Vec<u32>>, ) -> Result<Option<SubMeshCollection>>
Process an element into per-layer sub-meshes, subtracting any openings first.
Returns Ok(None) when the buildup isn’t sliceable (single material,
constituent set, profile set, degenerate) so the caller can fall back
to the existing sub-mesh-voids path without duplicating work.
Each emitted SubMesh carries the layer’s IfcMaterial entity ID
as its geometry_id — callers key colour lookup on that.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn process_element(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Mesh>
pub fn process_element( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Mesh>
Process building element (IfcWall, IfcBeam, etc.) into mesh Follows the representation chain: Element → Representation → ShapeRepresentation → Items
Errors when the items cannot share one f64 frame (#6349); use
Self::process_element_parts to keep such products at full precision.
Sourcepub fn process_element_parts(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Vec<Mesh>>
pub fn process_element_parts( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Vec<Mesh>>
Self::process_element as frame parts: one mesh, unless body items lie
in frames at least 1 km apart, which stay separate meshes (#6349).
Sourcepub fn process_element_with_submeshes(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<SubMeshCollection>
pub fn process_element_with_submeshes( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<SubMeshCollection>
Process element and return sub-meshes with their geometry item IDs. This preserves per-item identity for color/style lookup.
For elements with multiple styled geometry items (like windows with frames + glass), this returns separate sub-meshes that can receive different colors.
Sourcepub fn process_representation_item(
&self,
item: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Mesh>
pub fn process_representation_item( &self, item: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Mesh>
Process a single representation item (IfcExtrudedAreaSolid, etc.), with
content-dedup: a 128-bit structural hash of the item subtree skips the
meshing + CSG for geometry byte-identical to an item meshed earlier (e.g.
the thousands of Tekla connection plates/bolts an exporter failed to share
via IfcMappedItem). The cached mesh is colour-free and pre-placement; the
caller keeps this item’s own geometry_id (so colour/palette/texture stay
per-instance) and applies voids + placement afterwards, so a cache hit is
indistinguishable from a fresh build.
Sourcepub fn take_content_hash_oversized_ref_drops(&self) -> usize
pub fn take_content_hash_oversized_ref_drops(&self) -> usize
Drain refs the content-hash walk refused above u32::MAX (#3421/#3752).
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn detect_rtc_anchor_for_file(
&self,
content: &[u8],
decoder: &mut EntityDecoder<'_>,
) -> Option<(f64, f64, f64)>
pub fn detect_rtc_anchor_for_file( &self, content: &[u8], decoder: &mut EntityDecoder<'_>, ) -> Option<(f64, f64, f64)>
Self::detect_rtc_offset_for_file’s window with no placement-bounds
fallback. None when no usable translation sample was found, so a caller
can tell “no shift needed” from “detection had no data” — the distinction
the streaming ladder in ifc_lite_processing::stream_meta climbs.
Sourcepub fn detect_rtc_offset_for_file(
&self,
content: &[u8],
decoder: &mut EntityDecoder<'_>,
) -> Option<RtcVerdict>
pub fn detect_rtc_offset_for_file( &self, content: &[u8], decoder: &mut EntityDecoder<'_>, ) -> Option<RtcVerdict>
The RTC verdict for content: the median over the canonical sample
window, or the full-file placement-bounds scan when that window yielded
no usable translation.
Single shared entry point for the server processing path, the wasm
prepasses and the overlays, so every one of them makes the identical
needs-shift decision: a model whose sampled placements fail to decode
while raw geometry carries coordinates past
crate::LARGE_COORD_THRESHOLD_METERS (1 km, was 10 km before
#4934) must be re-based
identically everywhere (previously the wasm prepasses silently fell
back to (0,0,0) and the browser rendered f32 vertex jitter that the
server never saw).
The spans are [file_geometry_spans] — every geometry-bearing entity of
content, in file order, sampled lazily to the sampler’s usable-sample
cap. They are deliberately NOT a job list the caller passes in: a job
list is a SCHEDULE, and every pipeline schedules differently, so a
caller-supplied window made the median anchor a function of the
scheduler rather than of the model and one file resolved to several
anchors (#4611, pinned by
wasm-bindings/src/api/gpu_meshes/prepass_tests.rs).
None means neither ladder found a coordinate to judge; MeshFrame::select
in ifc_lite_processing decides what that means.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn process_element_with_submeshes_textured(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
texture_index: &FxHashMap<u32, ResolvedTextureMap>,
) -> Result<SubMeshCollection>
pub fn process_element_with_submeshes_textured( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, texture_index: &FxHashMap<u32, ResolvedTextureMap>, ) -> Result<SubMeshCollection>
Texture-aware Self::process_element_with_submeshes (#1781): a face
set listed in texture_index becomes its own textured sub-mesh carrying
per-vertex UVs + the texture attachment. The void path never passes an
index — a CSG cut rebuilds vertices, which would orphan the UVs, so a
voided textured element renders with its style colour instead.
Sourcepub fn process_representation_map(
&self,
rep_map: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Mesh>
pub fn process_representation_map( &self, rep_map: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Mesh>
Tessellate an IfcRepresentationMap’s MappedRepresentation and bake
its MappingOrigin placement (issue #957).
Used to render geometry that hangs off an IfcTypeProduct (e.g.
IfcBoilerType) through its RepresentationMaps when no occurrence
instantiates it — the buildingSMART annex-E “tessellated shape with
style” samples ship exactly this shape (geometry on the type, declared
via IfcRelDeclares, with no product instance).
Unlike Self::process_mapped_item_cached, this applies MappingOrigin
(IfcRepresentationMap attr 0) rather than a MappingTarget: there is
no occurrence placement and no IfcMappedItem to carry one, so the
MappingOrigin axis placement is the only transform. It is the caller’s
responsibility to only invoke this for orphan representation maps so
normally-instanced typed products aren’t double-rendered.
Errors when the map’s items cannot share one f64 frame (#6446); use
Self::process_representation_map_with_texture to keep such a map
at full precision.
Sourcepub fn process_representation_map_with_texture(
&self,
rep_map: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
texture_index: &FxHashMap<u32, ResolvedTextureMap>,
) -> Result<Vec<(Mesh, Vec<f32>, Option<TextureAttachment>)>>
pub fn process_representation_map_with_texture( &self, rep_map: &DecodedEntity, decoder: &mut EntityDecoder<'_>, texture_index: &FxHashMap<u32, ResolvedTextureMap>, ) -> Result<Vec<(Mesh, Vec<f32>, Option<TextureAttachment>)>>
Texture-aware variant of Self::process_representation_map (issue
#961). Returns one render part per output mesh: each textured
IfcTriangulatedFaceSet item becomes its OWN part carrying its UVs +
decoded image (so a representation with several differently-textured
items renders each with the correct image), and all untextured items are
merged into a single part with empty UVs / no texture, except that
untextured items in frames at least 1 km apart stay separate untextured
parts (#6446). The MappingOrigin placement is baked into every part.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn resolve_linear_placement_local_strict(
&self,
placement: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<[f64; 16]>
pub fn resolve_linear_placement_local_strict( &self, placement: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<[f64; 16]>
Strict column-major local frame of an IfcLinearPlacement relative to
its PlacementRelTo, exactly as rendering composes it, in file units.
Unlike rendering there is no identity fallback: a writer baking this
frame must refuse a placement it cannot resolve (#7335).
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn resolve_scaled_mapped_item_transform(
&self,
item: &DecodedEntity,
source: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Option<[f64; 16]>>
pub fn resolve_scaled_mapped_item_transform( &self, item: &DecodedEntity, source: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Option<[f64; 16]>>
Resolve an IfcMappedItem placement in metre coordinates. The returned
column-major matrix retains the authored linear part; only translation
receives the IFC length-unit scale.
Sourcepub fn resolve_scaled_mapped_item_transform_with_origin_loader<F>(
&self,
item: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
origin: F,
) -> Result<Option<[f64; 16]>>
pub fn resolve_scaled_mapped_item_transform_with_origin_loader<F>( &self, item: &DecodedEntity, decoder: &mut EntityDecoder<'_>, origin: F, ) -> Result<Option<[f64; 16]>>
Resolve a mapped target with a caller-supplied source-origin loader. The loader runs after target parsing, preserving the standard error precedence, and may reuse a parsed origin for repeated source maps.
Sourcepub fn mapping_origin_transform(
&self,
source: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Option<Matrix4<f64>>>
pub fn mapping_origin_transform( &self, source: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Option<Matrix4<f64>>>
IfcRepresentationMap.MappingOrigin (attr 0) as a 4x4, or None when it
is absent or null (nothing to compose), or the identity.
A PRESENT origin that cannot be turned into a placement — a dangling
reference, or an entity that is not an IfcAxis2Placement — is an ERROR,
not a silent identity. Every other consumer of a broken mapped-item
transform now behaves that way: the MappingTarget operator parse has
always propagated (a non-IfcDirection axis errors), the void fast-path
probes defer the opening to the exact kernel, and the 2D drawing extractor
abandons the profile. Substituting the identity here would render the item
at a position nothing else agrees with. #1985
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn resolve_scaled_placement_strict(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<[f64; 16]>
pub fn resolve_scaled_placement_strict( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<[f64; 16]>
Exact counterpart to resolve_scaled_placement: refuses a world
placement when the shared reference-walk guard truncated its chain.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn parametric_rect_probe_all(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Option<Vec<RectParam>>
pub fn parametric_rect_probe_all( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Option<Vec<RectParam>>
EXACT boxes for a body that is a UNION OF RECTANGULAR PRISMS (the common Tekla
multi-solid opening): one box per representation item, or None if any item is not a
rectangular extrusion. The cellular rect_fast cut subtracts the N boxes natively.
Sourcepub fn parametric_rect_probe(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Option<RectParam>
pub fn parametric_rect_probe( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Option<RectParam>
PHASE-0 CENSUS (read-only): the EXACT oriented rectangular box of an extruded
element, read from the IFC parametrics (IfcRectangleProfileDef XDim/YDim/Depth +
composed placement axes), NOT inferred from the f32 mesh. Returns None unless the
element’s body is a single clean IfcRectangleProfileDef extrusion (after unwrapping
IfcBooleanClippingResult / IfcMappedItem). This is the parametric frame + extents the
failed oriented attempt should have used instead of infer_opening_frame + mesh-AABB.
Sourcepub fn get_opening_item_meshes_world(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Vec<Mesh>>
pub fn get_opening_item_meshes_world( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Vec<Mesh>>
Get per-item meshes for an opening element, transformed to world coordinates.
Uses the same transform_mesh path as process_element to ensure identical
coordinate handling (ObjectPlacement, unit scaling, conditional RTC offset).
Sourcepub fn get_opening_item_bounds_with_direction(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<Vec<(Point3<f64>, Point3<f64>, Option<Vector3<f64>>)>>
pub fn get_opening_item_bounds_with_direction( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<Vec<(Point3<f64>, Point3<f64>, Option<Vector3<f64>>)>>
Extrusion direction is in world coordinates, normalized Returns None for extrusion direction if it cannot be extracted (fallback to bounds-only)
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn opening_requires_subtraction(
&self,
id: u32,
decoder: &mut EntityDecoder<'_>,
) -> bool
pub fn opening_requires_subtraction( &self, id: u32, decoder: &mut EntityDecoder<'_>, ) -> bool
Whether an opening must retain the canonical cutter path. Only a proven Reference-only opening (optionally with BoundingBox) returns false. Unknown, malformed, empty and over-budget representation data returns true so ordinary cutter/error handling remains authoritative (#4440).
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn process_element_with_voids(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
void_index: &FxHashMap<u32, Vec<u32>>,
) -> Result<Mesh>
pub fn process_element_with_voids( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, void_index: &FxHashMap<u32, Vec<u32>>, ) -> Result<Mesh>
Process element with void subtraction (openings) Process element with voids using optimized plane clipping
This approach is more efficient than full 3D CSG for rectangular openings:
- Get chamfered wall mesh (preserves chamfered corners)
- For each opening, use optimized box cutting with internal face generation
- Apply any clipping operations (roof clips) from original representation
Process an element with void subtraction (openings).
This function handles three distinct cases for cutting openings:
-
Floor/Slab openings (vertical Z-extrusion): Uses CSG with actual mesh geometry because the XY footprint may be rotated relative to the slab orientation.
-
Wall openings (horizontal X/Y-extrusion, axis-aligned): Uses AABB clipping for fast, accurate cutting of rectangular openings.
-
Diagonal wall openings: Uses AABB clipping without internal face generation to avoid rotation artifacts.
Reveal faces (inner surfaces of the opening holes) are generated as a post-clipping step for rectangular and diagonal openings. For diagonal walls the geometry is computed in a rotated axis-aligned frame and rotated back, giving correct results for any wall orientation.
Errors when the element’s body items cannot share one f64 frame
(#6349); Self::process_element_with_voids_parts keeps them.
Sourcepub fn process_element_with_voids_parts(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
void_index: &FxHashMap<u32, Vec<u32>>,
) -> Result<Vec<Mesh>>
pub fn process_element_with_voids_parts( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, void_index: &FxHashMap<u32, Vec<u32>>, ) -> Result<Vec<Mesh>>
Self::process_element_with_voids over the element’s frame parts
(Self::process_element_parts): each part is cut by the same openings,
classified once. An ordinary element has exactly one part (#6349).
Sourcepub fn process_element_with_submeshes_and_voids(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
void_index: &FxHashMap<u32, Vec<u32>>,
) -> Result<SubMeshCollection>
pub fn process_element_with_submeshes_and_voids( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, void_index: &FxHashMap<u32, Vec<u32>>, ) -> Result<SubMeshCollection>
Process an element into per-item sub-meshes with opening subtraction.
Mirrors [process_element_with_voids] but preserves each
IfcShapeRepresentation item as its own sub-mesh so that callers can
look up a direct IfcStyledItem color per geometry item (e.g. the
three extrusion layers of a multi-layer wall). The opening(s) are
subtracted from each sub-mesh independently so that windows and doors
cut through every material layer they intersect.
Returns an empty collection when there are no openings (callers should
fall back to [process_element_with_submeshes]) or when every
sub-mesh is destroyed by void subtraction.
Source§impl GeometryRouter
impl GeometryRouter
Sourcepub fn with_units<T>(content: &T, decoder: &mut EntityDecoder<'_>) -> Self
pub fn with_units<T>(content: &T, decoder: &mut EntityDecoder<'_>) -> Self
Create router and extract unit scale from IFC file Automatically finds IFCPROJECT and extracts length unit conversion
Sourcepub fn with_units_and_rtc<T>(
content: &T,
decoder: &mut EntityDecoder<'_>,
rtc_offset: (f64, f64, f64),
) -> Self
pub fn with_units_and_rtc<T>( content: &T, decoder: &mut EntityDecoder<'_>, rtc_offset: (f64, f64, f64), ) -> Self
Create router with unit scale extracted from IFC file AND RTC offset for large coordinates This is the recommended method for georeferenced models (Swiss UTM, etc.)
§Arguments
content- IFC file contentdecoder- Entity decoderrtc_offset- RTC offset to subtract from world coordinates (typically model centroid)
Sourcepub fn with_scale(unit_scale: f64) -> Self
pub fn with_scale(unit_scale: f64) -> Self
Create router with pre-calculated unit scale
Sourcepub fn with_scale_and_local_frame(unit_scale: f64, enabled: bool) -> Self
pub fn with_scale_and_local_frame(unit_scale: f64, enabled: bool) -> Self
Create a router with an explicit per-mesh local-frame policy.
This is intentionally a constructor rather than a mutable switch: mesh caches are frame-dependent, so the policy must be fixed before any geometry is produced.
Sourcepub fn new_dedup_cache() -> ItemDedupCache
pub fn new_dedup_cache() -> ItemDedupCache
A fresh empty shared item-dedup cache, to be cloned into every per-element / per-batch router of ONE loaded model so they all dedup against it. Keep one per model: the key is a per-model entity-structure hash, and the cached meshes bake in this model’s unit scale / tessellation quality.
Sourcepub fn build_dedup_extra_enabled() -> bool
pub fn build_dedup_extra_enabled() -> bool
Whether content-dedup covers EXTRA item types beyond the proven default
set (faceset / surface-model families). item_signature’s generic byte
walk is already complete for them, so this is pure additive build savings
on models that repeat tessellated geometry — but it pays a hash on every
such item, so it stays OFF by default until corpus-validated (low-reuse
models would pay the hash for no payback, the #1177 trap). Opt in with
IFC_LITE_DEDUP_EXTRA=1 or Self::set_build_dedup_extra_override.
Default OFF keeps native==wasm identical.
Sourcepub fn set_build_dedup_extra_override(v: Option<bool>)
pub fn set_build_dedup_extra_override(v: Option<bool>)
Test-only: force Self::build_dedup_extra_enabled on/off (None = env).
Inject a shared item-dedup cache (see Self::new_dedup_cache) into this
router. All routers given the SAME Arc dedup against one cache, so
byte-identical geometry is meshed once across the whole model regardless of
how elements are partitioned across threads or batches.
Sourcepub fn new_mapped_item_cache() -> SharedMappedItemCache
pub fn new_mapped_item_cache() -> SharedMappedItemCache
A fresh empty shared IfcMappedItem source cache, to be cloned into every
per-element / per-batch router of ONE loaded model so a mapped source shared
across owning elements is meshed once model-wide (#1623). Mirrors
Self::new_dedup_cache. Keep one per model/pass: the cached meshes bake in
this pass’s unit scale / tessellation quality.
Inject a shared IfcMappedItem source cache (see
Self::new_mapped_item_cache) into this router. All routers given the
SAME Arc mesh each unique IfcRepresentationMap source once across the
whole model, instead of once per owning element (a fresh router is built per
element). Takes precedence over the per-router RefCell mapped_item_cache;
leaving it unset keeps the per-router fallback for single-shot callers.
Sourcepub fn enable_output_instancing(&mut self, plan: MappedInstancePlan)
pub fn enable_output_instancing(&mut self, plan: MappedInstancePlan)
Arm the #1623 Phase 2 don’t-bake instancing plan (see MappedInstancePlan)
on this router. Requires a shared mapped-item cache to be enabled too — the
don’t-bake instance placeholders rely on the source being meshed once into it
(the orphan-recovery template at finalize reads it). Leaving it unset keeps
every occurrence materializing (byte-identical flat output).
Sourcepub fn enable_indexed_colour_split_guard(&mut self, ids: Arc<FxHashSet<u32>>)
pub fn enable_indexed_colour_split_guard(&mut self, ids: Arc<FxHashSet<u32>>)
Arm the #858 don’t-bake exclusion set: geometry-item ids of mapped sources
whose single solid carries an IfcIndexedColourMap. Such a source is routed
to the flat materialize (per-palette split) instead of don’t-bake, so its
occurrences keep the per-triangle palette (an instance placeholder would
collapse it to one colour). Armed alongside Self::enable_output_instancing
when the model has any indexed-colour maps; unset ⇒ no exclusion.
Sourcepub fn set_preserve_triangle_order(&self, on: bool) -> bool
pub fn set_preserve_triangle_order(&self, on: bool) -> bool
Keep source hygiene index-only for the elements meshed until this is
called again with false, because a caller will map their triangles back
to source faces by index (#858’s per-triangle colour split). Returns the
previous setting so a caller can restore it.
Sourcepub fn set_instancing_batch_local(&mut self, on: bool)
pub fn set_instancing_batch_local(&mut self, on: bool)
Select the #1623 Phase 3 batch-local template mode (see
Self::instancing_batch_local). The WASM per-batch path sets this so each
batch materializes its OWN first-seen template per source and stays a
self-contained shard; the native path leaves it off (global min-id template).
Sourcepub fn disable_content_dedup(&mut self)
pub fn disable_content_dedup(&mut self)
Disable content-dedup (drops the cache reference so item_dedup_key
returns None and meshing is never skipped). Test/bench helper for an A/B
against the deduped path.
Sourcepub fn dedup_unique_count(&self) -> usize
pub fn dedup_unique_count(&self) -> usize
Number of unique item meshes cached by content-dedup so far — the reuse the pipeline recovered (vs. the meshed-item count). Diagnostics.
Number of unique IfcRepresentationMap sources meshed into the SHARED
mapped-item cache so far (0 when no shared cache is injected — the RefCell
fallback isn’t counted). Diagnostics, mirroring Self::dedup_unique_count;
used by the #1623 A/B test to confirm the shared cache actually captured
sources (so a cross-router hit is genuinely exercised, not a no-op).
Sourcepub fn geometry_routing_key(
&self,
element: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Option<u128>
pub fn geometry_routing_key( &self, element: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Option<u128>
Content-routing key for an element: a 128-bit structural hash of its WHOLE
representation subtree (the Representation attribute, e.g. an
IfcProductDefinitionShape), or None if it has no geometry. Two elements
with byte-identical geometry — even renumbered — share a key, so a host can
route them to the same worker; combined with the per-worker dedup cache the
geometry is then meshed once per worker. Meshing-free (decode + fold) and
reuses the per-router signature memo so shared sub-entities are hashed once.
(A per-instance shape-representation wrapper can make this finer than the per-ITEM dedup unit, but a true 4-router simulation showed that costs essentially no extra meshing — 1.01× — because the shared items still land on one worker, so the simpler whole-representation hash is used.)
Sourcepub fn with_rtc(rtc_offset: (f64, f64, f64)) -> Self
pub fn with_rtc(rtc_offset: (f64, f64, f64)) -> Self
Create router with RTC offset for large coordinate handling Use this for georeferenced models (e.g., Swiss UTM coordinates)
Sourcepub fn with_scale_and_rtc(unit_scale: f64, rtc_offset: (f64, f64, f64)) -> Self
pub fn with_scale_and_rtc(unit_scale: f64, rtc_offset: (f64, f64, f64)) -> Self
Create router with both unit scale and RTC offset
Sourcepub fn with_quality(quality: TessellationQuality) -> Self
pub fn with_quality(quality: TessellationQuality) -> Self
Create router with a specific tessellation quality level
Sourcepub fn with_scale_and_quality(
unit_scale: f64,
quality: TessellationQuality,
) -> Self
pub fn with_scale_and_quality( unit_scale: f64, quality: TessellationQuality, ) -> Self
Create router with both unit scale and tessellation quality
Sourcepub fn set_tessellation_quality(&mut self, quality: TessellationQuality)
pub fn set_tessellation_quality(&mut self, quality: TessellationQuality)
Set the tessellation quality level.
A quality change invalidates mapped_item_cache (keyed by RepresentationMap
id, not by quality) and the record of which sources’ drops are already
counted, since every source is re-walked; both are cleared here. The
content-hash-keyed caches stay correct.
Sourcepub fn tessellation_quality(&self) -> TessellationQuality
pub fn tessellation_quality(&self) -> TessellationQuality
Get the current tessellation quality level
Sourcepub fn set_skip_small_cuts(&mut self, on: bool)
pub fn set_skip_small_cuts(&mut self, on: bool)
Set the per-build small-cut skip (#1286) and re-register the boolean /
CSG / mapped processors so they carry it. Tier-independent: the viewer
turns this on to skip tiny steel copes/notches for fast first paint while
the tessellation tier stays at Medium (curves keep full density).
Scoped to this router instance, so a concurrent native build with the
skip off is unaffected (this replaced a process-wide static that bled
across builds). false (default) keeps every cut, byte-identical to
before the optimization.
Sourcepub fn skip_small_cuts(&self) -> bool
pub fn skip_small_cuts(&self) -> bool
Get the current per-build small-cut skip flag.
Sourcepub fn set_rtc_offset(&mut self, offset: (f64, f64, f64))
pub fn set_rtc_offset(&mut self, offset: (f64, f64, f64))
Set the RTC offset for large coordinate handling
Sourcepub fn rtc_offset(&self) -> (f64, f64, f64)
pub fn rtc_offset(&self) -> (f64, f64, f64)
Get the current RTC offset
Sourcepub fn has_rtc_offset(&self) -> bool
pub fn has_rtc_offset(&self) -> bool
Check if RTC offset is active (non-zero)
Sourcepub fn unit_scale(&self) -> f64
pub fn unit_scale(&self) -> f64
Get the current unit scale factor
Sourcepub fn set_material_layer_index(&mut self, index: Arc<MaterialLayerIndex>)
pub fn set_material_layer_index(&mut self, index: Arc<MaterialLayerIndex>)
Attach a material-layer buildup index. After this, sub-mesh processing
automatically slices single-solid elements whose buildup is sliceable
(walls with IfcMaterialLayerSetUsage, etc.) into per-layer slabs.
Sourcepub fn is_material_layer_sliceable(&self, element_id: u32) -> bool
pub fn is_material_layer_sliceable(&self, element_id: u32) -> bool
True when element_id carries a sliceable IfcMaterialLayerSetUsage, i.e.
process_element_with_submeshes would split it into per-layer sub-meshes.
Lets the mesh producer render the wall as ONE solid in 3D while still
emitting the per-layer slices (tagged section-only) for the 2D cut.
Sourcepub fn register(&mut self, processor: Box<dyn GeometryProcessor>)
pub fn register(&mut self, processor: Box<dyn GeometryProcessor>)
Register a geometry processor
Sourcepub fn resolve_scaled_placement(
&self,
entity: &DecodedEntity,
decoder: &mut EntityDecoder<'_>,
) -> Result<[f64; 16]>
pub fn resolve_scaled_placement( &self, entity: &DecodedEntity, decoder: &mut EntityDecoder<'_>, ) -> Result<[f64; 16]>
Resolve an element’s ObjectPlacement to a scaled world-space transform matrix. Returns the 4x4 matrix as a flat column-major array of 16 f64 values. The translation component is scaled from file units to meters.
Contributed by Mathias Søndergaard (Sonderwoods/Linkajou).
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for GeometryRouter
impl !RefUnwindSafe for GeometryRouter
impl !Send for GeometryRouter
impl !Sync for GeometryRouter
impl Unpin for GeometryRouter
impl !UnwindSafe for GeometryRouter
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
§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.