Releases: LTplus-AG/ifc-lite
@ifc-lite/wasm@2.9.1
Patch Changes
- #1131
b7353abThanks @louistrue! - Content-affinity worker routing for boolean-heavy models. The streaming geometry
pre-pass now tags each job with an affinity key — the exact 128-bit hash of the
element's representation geometry — and the parallel dispatcher routes all jobs
sharing a key to the same worker. Combined with the per-worker geometry-dedup
cache, each unique geometry is meshed once per model instead of once per
worker, so the workers partition the unique meshing instead of replicating it.
Restores fast loads on models exported withoutIfcMappedItem(e.g.
structural-steel detailers that emit thousands of byte-identical parts): a 19.5 MB
steel model drops from ~32 s to ≈ the dedup floor split across the worker pool.
Falls back to the previous interleaved split when no affinity data is present.
@ifc-lite/viewer@1.30.2
Patch Changes
-
#1159
39e0f82Thanks @louistrue! - Add a?geomWorkers=Noverride for the geometry worker pool, and document the
per-tier worker caps as a memory-bandwidth ceiling.The parallel geometry pool picks a worker count from a cores/memory heuristic.
A?geomWorkers=NA/B sweep on a large (722 MB) georef model showed that, with
the pure-Rust exact CSG kernel, geometry wall-time is bound by memory
bandwidth, not CPU cores: 3→4→5 workers gave no geometry speedup (flat
wall-time, higher peak memory) and progressively starved the co-running parser.
So the existing caps are correct for this class of file and are left unchanged —
only their rationale is updated in comments.The override (
?geomWorkers=N, persisted to localStorage so it survives the
reload a re-measure needs;?geomWorkers=0/autoclears it) lets a user measure
their own host's optimum, since the bandwidth ceiling is hardware-specific. It is
threaded tocomputeWorkerCount, which honours it but still clamps to the memory
budget, so the knob can never OOM the tab. Geometry output is byte-identical
across worker counts (verified in the wild: identical mesh count at 3 and 4
workers) — the count only repartitions which worker meshes which disjoint,
deterministic element slice. -
Updated dependencies [
39e0f82,2556677]:- @ifc-lite/geometry@2.7.5
@ifc-lite/viewer@1.30.1
Patch Changes
- #1136
98457b8Thanks @louistrue! - Show IfcElementAssembly / IfcStair parts in the spatial tree and make assemblies
selectable (#1133). A decomposing assembly carries no geometry of its own — its
stair flights, railings, landing slabs and virtual clearance volumes hang off it
viaIfcRelAggregatesand hold the meshes — so the spatial panel previously
listed the assembly as a childless leaf, the parts were unreachable, and
clicking the assembly highlighted nothing. The hierarchy now nests an
assembly's aggregated parts beneath it (recursively, cycle-guarded), clicking
the assembly highlights and frames the whole thing, soloing a storey keeps the
parts (they inherit the storey through the assembly), andIfcVirtualElement
clearance volumes are hidden by default with a new "Virtual Elements"
visibility toggle. - Updated dependencies [
61bad47,bfd9004,69e5425,81a6cdf,ca8a856,bd585c7,248f2c0,200681b,ef8343b,ddae2b0]:- @ifc-lite/mutations@1.15.5
- @ifc-lite/data@2.1.0
- @ifc-lite/parser@3.3.0
- @ifc-lite/geometry@2.7.3
- @ifc-lite/renderer@1.28.2
- @ifc-lite/sdk@1.19.0
- @ifc-lite/sandbox@1.16.0
- @ifc-lite/export@1.20.0
- @ifc-lite/lens@1.15.3
- @ifc-lite/lists@1.15.4
- @ifc-lite/cache@2.0.4
- @ifc-lite/ids@1.15.12
@ifc-lite/sdk@1.19.0
Minor Changes
- #1152
ca8a856Thanks @louistrue! - Addbim.query.matchingActiveFilter()— returns the entities matching the host's active advanced filter (ornullwhen no filter is set). Backed by a newQueryBackendMethods.entitiesMatchingActiveFilter(). Lets scripted exports (e.g. the CSV quantity take-off) honour the current filtered view instead of always exporting the whole model (issue #1107).
Patch Changes
@ifc-lite/sandbox@1.16.0
Minor Changes
- #1152
ca8a856Thanks @louistrue! - Addbim.query.matchingActiveFilter()— returns the entities matching the host's active advanced filter (ornullwhen no filter is set). Backed by a newQueryBackendMethods.entitiesMatchingActiveFilter(). Lets scripted exports (e.g. the CSV quantity take-off) honour the current filtered view instead of always exporting the whole model (issue #1107).
Patch Changes
- Updated dependencies [
ca8a856]:- @ifc-lite/sdk@1.19.0
@ifc-lite/renderer@1.28.3
Patch Changes
-
#1160
631511eThanks @louistrue! - Restore per-layer slicing of single-solid walls/slabs with anIfcMaterialLayerSetUsage. Slicing turns one solid into one coloured sub-mesh per material layer (geometry_id = the layer'sIfcMaterial) so the build-up is visible in 3D. The "Merge Multilayer Walls" toggle now does what its label promises for these walls too — "render walls as one solid": with the toggle on, the layer index is not attached, so each wall stays a single swept solid instead of slicing into layers (off, the default, shows the layered build-up).The slicing kernel stayed intact, but #874 (mesh-production unification) dropped the
set_material_layer_indexwiring from every pipeline, so the router's index was alwaysNoneandtry_layered_sub_meshesnever fired — layered walls silently rendered as a plain single solid in the browser, native, and server paths. Re-wire it: build theMaterialLayerIndexonce per load (cached on the IfcAPI for the streaming path, with a cheap substring bail-out so files with no layer set pay nothing) and attach it to every batch router. This also restores the "Merge Multilayer Walls" toggle for models whose sliceable walls carry their geometry asIfcBuildingElementParts — the merged parent now actually draws its sliced solid instead of leaving a gap.2D section now shows the layers too. The section cutter carries each sub-mesh's colour onto its cut segments (CPU and GPU paths), and the polygon builder splits one entity's cut into a polygon per material colour — single-material elements still produce one colourless polygon, so their existing per-
ifcType/ per-entity fill is unchanged. When the viewer shows IFC materials, each sliced layer fills with its ownIfcMaterialcolour instead of one colour for the whole wall, and the layer divisions are drawn as outlines — matching the 3D build-up.Two follow-on robustness fixes:
-
3D layer glitch (z-fighting). Adjacent layer slabs share the parent wall's
expressId, so the renderer's per-entity depth nudge (keyed onentityId) gave their coincident interior interface caps the SAME depth — undercullMode: 'none'+ MSAA that z-fought into a flickering comb that read as "see inside / not solid". The shader now folds the per-drawbaseColorinto the depth-nudge hash; batches are keyed by colour, so abutting layers (distinct colours) land on distinct depths. Constant per draw, so flat faces stay flat and curved surfaces are unaffected. -
Cap watertightness on irregular profiles. A layer slab's innermost cut is built by two successive plane clips; on a non-convex
IfcArbitraryClosedProfileDefthe two passes deposit geometrically-coincident section vertices that differ by ~1 ULP.cap_half_space_clipwelded by exact f32 bits, so those twins stayed separate, the boundary chain dead-ended and a cap sub-loop was silently dropped — leaving open edges (a hole you could see through and a section with no fill there). The cap now welds on a spatial grid tied to its on-plane tolerance, collapsing the twins so the loop closes. Single-plane callers (opening cuts) have no such twins and are unaffected. -
3D section cut read hollow. The live 3D section cap (
Section2DOverlayRenderer) filled each cut polygon with a naive convex fan over the outer ring only, ignoring holes — a long-standing KNOWN LIMITATION. On the concave cross-sections that arbitrary IFC profiles (and material-layer slabs) cut into, the fan inverts and leaves the cut face uncovered, so a sectioned wall read as a hollow shell. The fill now uses the renderer's existing hole-aware ear-clipping (the same one the annotation-fill path uses), so the cut face is solid. The cap also now honours a per-polygon colour: a material-layer wall fills each layer of its 3D section cut with that layer'sIfcMaterialcolour (matching the 3D solids and the 2D section), while single-material cuts keep the uniform cap style + hatch unchanged via a sentinel. -
Solid layered 3D walls via backface culling. Rendering a material-layer wall as N thin coincident-faced layer solids made it shimmer / read as a hollow shell — adjacent layers' interface caps z-fight under the viewer's double-sided rendering (culling is globally off because general IFC winding is unreliable), and same-material adjacent layers can't be depth-separated. The layer slices DO have reliable outward winding, though, so they're now tagged
geometryClass3 and the renderer draws that class with a dedicated backface-culling pipeline: the build-up stays visible on the wall's faces and edges, but the interior coincident caps never rasterise, so the wall reads as a clean solid (and a section cut through it shows the interior material surface rather than a hollow shell). The 2D/section cut consumes the same class — it never culls — for its per-layer fills. CacheFORMAT_VERSION→ 9 so stale caches re-mesh with the class-3 slices.
-
-
Updated dependencies [
631511e]:- @ifc-lite/geometry@2.7.6
@ifc-lite/renderer@1.28.2
Patch Changes
-
#1148
81a6cdfThanks @louistrue! - AddCamera.getSceneBounds()— an O(1) accessor for the cached scene bounds (the value last passed tosetSceneBounds). The viewer uses it to anchor the orbit pivot to the scene centre on a raycast miss / large model, instead of the drifting camera target which made repeated rotation feel untethered (issue #1107). -
#1161
ef8343bThanks @louistrue! - Keep internal edges/facets visible on selected objects.The selection highlight painted every fragment a single flat blue (
color = vec3(0.3, 0.6, 1.0)), discarding all lighting. Because the viewer's "internal lines" are really the per-face shading step of flat-shaded facets, that flat fill collapsed a selected object into one featureless silhouette — creases and bends disappeared the moment it was highlighted (the faint screen-space edge line alone could not stand in for the lost face-shading cue).The highlight now re-lights a selection-blue albedo with the scene's own lighting term instead of overwriting it. The base material colour never enters the result (no green-site / red-roof bleed-through, the reason the flat override existed), but the per-face brightness variation is preserved, so internal edges read on the highlight exactly as they do unselected. A multiplicative gain on the lighting luminance keeps sunlit faces at full selection-blue, with a floor/ceiling clamp so shadowed faces only dim and bright scenes never wash out.
-
Updated dependencies [
69e5425,bd585c7,200681b]:- @ifc-lite/geometry@2.7.3
@ifc-lite/parser@3.3.0
Minor Changes
-
#1143
248f2c0Thanks @louistrue! - Preserve source IFC HEADER fields on round-trip export. Re-exporting an
imported file previously regenerated a fresh ifc-lite header, silently dropping
the sourceFILE_DESCRIPTIONitems (anyViewDefinition [...]label and vendor
identifier / coordinate-reference strings) and flattening the exact
FILE_SCHEMAtoken (e.g.IFC4X3_ADD2→IFC4X3, which some toolchains
reject).The parser now captures the verbatim HEADER onto a new
IfcDataStore.sourceHeader(IfcSourceHeader, exported from@ifc-lite/data;
parser also exportsparseSourceHeader), threaded through the worker transport.
StepExporterreproduces the sourceFILE_DESCRIPTIONitems and the exact
FILE_SCHEMAtoken when not converting schemas, falling back to parsing the
source bytes for cache-restored stores. Provenance stays honest:
preprocessor_versionis set toifc-litewhile the source authoring tool is
kept asoriginating_system, and when mutations exist exactly one
Re-exported by ifc-lite, N modification(s)item is appended without removing
the source items.generateHeadernow accepts description/author/organization
arrays plus a free-form schema token and STEP-escapes all fields; it also emits
a properly parenthesisedFILE_DESCRIPTIONlist (the prior single-string form
was malformed STEP). Created-from-scratch (IfcCreator) and federated/merged
exports are unaffected — they keep their own provenance headers by design.
Patch Changes
-
#1151
bfd9004Thanks @louistrue! - De-duplicate the STEP serializer into a single source of truth. The
schema-agnostic STEP serialization logic (serializeValue,generateHeader,
parseStepValue,ref/enumVal/isEntityRef/isEnumValue, and the
registry-injectedtoStepLineWithRegistry/generateStepFileWithRegistry)
previously existed as four hand-synced copies — the codegen template plus three
generatedserializers.tsfiles — which had already silently drifted (the
runtime copy carried a?? []hardening the template lacked). It now lives once
in@ifc-lite/data; the per-schema bundles (parser runtime + codegen outputs)
are thin re-exports that only bind their ownSCHEMA_REGISTRYto the
registry-coupled helpers, so the copies can never diverge again. A codegen test
asserts the generated bundle stays a thin re-export rather than re-inlining
logic.Also fixes the broken
generate:ifc4script (it pointed at a non-existent
schemas/IFC4.exp; the real file isschemas/IFC4_ADD2_TC1.exp). No public
behaviour change:@ifc-lite/parserre-exports the same serializer symbols as
before;@ifc-lite/datagains the shared primitives;@ifc-lite/codegennow
declares@ifc-lite/dataas a dependency since the generated bundle imports it. -
#1145
ddae2b0Thanks @louistrue! - Resolve names for IfcGroup-family entities and make zones/systems listable (#1075 follow-up).IfcZone,IfcGroup,IfcSystemandIfcDistributionSystemare notIfcProductsubtypes, so the columnar parser categorised them asCAT_SKIPand never added them to theEntityTable. As a resultgetName()returned''(the UI showed "Group #"),getByType()could not find them (so they were absent from lists), and the "By Zone" lens fell back to an arbitrary first group becausegetTypeName()returnedUnknown.IfcSpatialZonewas in the table but itsNamewas never extracted.This routes the group family into the
EntityTablewithName(falling back toLongNamefor systems/zones that leaveNameempty) plusDescriptionandObjectType(the system designation), and extracts names for the previously-unnamed "other relevant" products (includingIfcSpatialZone). NewIfcSystem/IfcDistributionSystemIfcTypeEnumentries make systems addressable bygetByType. Zones, spatial zones and systems are now selectable in the list builder and ship a "Zones & Systems" preset, the relationship card and "By Zone" lens legend show real names (with anObjectTypefallback for unnamed systems), and selecting a group surfaces its attributes.The cache
FORMAT_VERSIONis bumped (6 → 7) so models cached before the fix re-parse and pick up the resolved names. -
Updated dependencies [
bfd9004,248f2c0,ddae2b0]:- @ifc-lite/data@2.1.0
@ifc-lite/mutations@1.15.5
Patch Changes
-
#1149
61bad47Thanks @louistrue! - Treat a null/unset property value as present, not absent. A property may legitimately exist with no value (e.g. an IFC boolean added from bSDD, which now starts unset rather than defaulting tofalse), soMutablePropertyViewno longer readsvalue === nullas "property does not exist":deletePropertykeys absence off existence (in-session pset membership), so an unset property is still deletable instead of the trash button being a silent no-op.setPropertyclassifies a write asUPDATE_PROPERTYvsCREATE_PROPERTYby whether the property already existed (not by null value), so undoing an edit to an unset property restores its prior unset state instead of deleting the whole property.
-
Updated dependencies [
bfd9004,248f2c0,ddae2b0]:- @ifc-lite/data@2.1.0
@ifc-lite/lists@1.15.4
Patch Changes
-
#1145
ddae2b0Thanks @louistrue! - Resolve names for IfcGroup-family entities and make zones/systems listable (#1075 follow-up).IfcZone,IfcGroup,IfcSystemandIfcDistributionSystemare notIfcProductsubtypes, so the columnar parser categorised them asCAT_SKIPand never added them to theEntityTable. As a resultgetName()returned''(the UI showed "Group #"),getByType()could not find them (so they were absent from lists), and the "By Zone" lens fell back to an arbitrary first group becausegetTypeName()returnedUnknown.IfcSpatialZonewas in the table but itsNamewas never extracted.This routes the group family into the
EntityTablewithName(falling back toLongNamefor systems/zones that leaveNameempty) plusDescriptionandObjectType(the system designation), and extracts names for the previously-unnamed "other relevant" products (includingIfcSpatialZone). NewIfcSystem/IfcDistributionSystemIfcTypeEnumentries make systems addressable bygetByType. Zones, spatial zones and systems are now selectable in the list builder and ship a "Zones & Systems" preset, the relationship card and "By Zone" lens legend show real names (with anObjectTypefallback for unnamed systems), and selecting a group surfaces its attributes.The cache
FORMAT_VERSIONis bumped (6 → 7) so models cached before the fix re-parse and pick up the resolved names. -
Updated dependencies [
bfd9004,248f2c0,ddae2b0]:- @ifc-lite/data@2.1.0