Commit Graph

21813 Commits

Author SHA1 Message Date
Dion Moult bc31e91e35 ifcviewer-web: handle device loss so GPU pressure can't freeze the tab
Reported: open a model in the web viewer, then launch the desktop
BonsaiViewer and open another model — the browser tab freezes, and a
fresh web tab then fails with "RequestDevice failed: Not enough memory
left". Root cause is GPU-memory contention: two heavy GPU clients on one
GPU, and the desktop app's allocations starve the browser's WebGPU
process, which reclaims our device.

We can't conjure GPU memory, but we were amplifying the symptom: with no
device-lost handler, render() kept driving a dead device —
wgpuSurfaceGetCurrentTexture returns Lost every frame and the
reconfigure + requestFrame retry becomes a tight per-RAF loop that hangs
the tab. Now the web device descriptor wires a device-lost callback that
latches device_lost_ (ignoring the intentional Destroyed reason from our
own shutdown); render() bails while set, so the loop goes idle instead of
spinning, and the console logs guidance to reload. The fresh-tab
RequestDevice OOM is genuine GPU exhaustion — surfaced as before, now with
a clearer message.

Verified the lost callback doesn't disturb Dawn-web's RequestDevice (all
5 web smoke tests still init + pass); desktop unaffected (device_lost_
stays false). The real contention path can't be reproduced in the headless
harness, so the loss handler itself is covered by review, not a test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 11:24:56 +10:00
Dion Moult a6cfb2651a ifcviewer-web: render through an sRGB surface view (fix dark colors)
The fragment shader pre-decodes sRGB→linear to cancel the surface's
automatic linear→sRGB write encoding, so the final bytes match the GL
backend. That only holds when the render target is an sRGB format. On
desktop the surface's preferred format already is (e.g. BGRA8UnormSrgb),
but the browser canvas only offers plain BGRA8Unorm — so nothing
re-encoded and the whole image (background + models) rendered ~3× too
dark (authored bg 0.125,0.137,0.161 → ~32,35,41 collapsed to ~3,4,6).

Fix: when the surface format isn't sRGB, render through an sRGB *view* of
it — the standard WebGPU canvas pattern. surface_view_format_ is the sRGB
sibling of surface_format_ (unchanged when already sRGB, so desktop is a
no-op); configureSurface advertises it via viewFormats, the colour
pipelines (main, MSAA target, edge) target it, and render() creates the
surface view with it. The screenshot path still reads the base texture, so
its BGRA byte-order check stays on surface_format_.

Regression test: sample a 1x1 background pixel and assert it isn't crushed
dark (R,B > 20). Verified visually too — bg is now the correct dark
blue-gray and the cube is properly lit. 5/5 web smoke + 107/107 unit pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 11:08:30 +10:00
Dion Moult 3cc759d72b ifcviewer: fix blank-until-interaction stall on web (streaming settle burst)
On first web load the sample stayed blank until a click/drag, then popped
in. Root cause: the main draw + cull run before driveStreamingLoads in
render(), so a chunk that becomes resident there is only painted a frame
later. On desktop the streaming thread keeps inFlightApprox() > 0 during a
load, so the render loop keeps ticking and the next frame paints it. On web
the sync MEMFS / Blob load finishes instantly (inFlightApprox stays 0), so
the single post-load requestFrame fired once and the on-demand loop went
idle before the geometry was ever drawn — until some input re-armed it.

Fix: arm a bounded settle burst (kStreamingSettleFrames) whenever there's
streaming activity — a load this frame, work still queued, or a visible
chunk not yet resident — and bleed it down over the next few frames, each
requesting one more. Covers the cull→display latency under an on-demand
loop and still quiesces at idle (no busy-rendering). General, not web-only.

Regression test: the sample must render with NO pointer input — a centred
patch (the framed cube) differs from a corner patch (background); a blank
stall leaves both as background. Verified empirically with a no-interaction
probe (canvas went from a static blank hash to a stable rendered one).
107/107 unit tests pass; 4/4 web smoke tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:11:58 +10:00
Dion Moult 2b58d7be74 ifcviewer-web: smoke-test click-to-select highlight
Third Playwright case: click dead-centre on the framed sample, assert the
canvas changes (selection highlight rendered) with zero WebGPU errors. A
broken async pick would hang init or leave the canvas unchanged. All three
cases pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:06:28 +10:00
Dion Moult 094575fc19 ifcviewer-web: async object pick → click-to-select on web
Desktop pick reads the pick staging buffer back with a blocking
`while(!done) waitTickInstance()` spin. On web that spin is a no-op
(Asyncify is off) and hangs the JS event loop, so click-to-select was
dead on web. This adds an async sibling that uses the spontaneous
map-callback pattern (AllowSpontaneous + the browser microtask loop)
already proven by the HiZ readback — no blocking.

  - encodePickReadbackToStaging(x,y,want_normal): the pick-pass render +
    copy-texel-to-staging, extracted from pickObjectAt verbatim and shared
    by both readbacks (desktop sync path unchanged).
  - pickObjectAtAsync(x,y,cb) [web]: encode, then map the staging buffer
    with a spontaneous callback that delivers object_id to cb. One pick in
    flight at a time (a pick issued mid-map is dropped → cb(0)).
  - applyPickToSelection(id, add, remove): routes a pick result through the
    selection state machine (replace / Shift-add / Ctrl-remove / empty-click
    clear), mirroring the desktop ViewportWindow click semantics. selection_
    marks dirty so the next render's uploadSelectionFlagsIfDirty flushes the
    highlight.

main_web wires it: a left release under a 4px drag threshold (no orbit) is
a pick at down-position * devicePixelRatio, with Shift/Ctrl modifiers;
the result callback applies selection and requests a frame. Web + desktop
build clean; 107/107 unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:06:28 +10:00
Ryan Schultz db0bbf6b84 adding vscode workspaces to .gitignore 2026-06-29 14:29:17 -05:00
Gorgious56 a757641b84 Bonsai: derive prefs PropertyGroups from EDIT_TYPES
Collapse two parallel hand-maintained lists in the addon-preferences
PropertyGroups into derivations from `tool.Parametric.EDIT_TYPES`:

- GizmoPreferences: the 10 `<name>: BoolProperty` annotations now
  generated from the full EDIT_TYPES list.

- DefaultParameters: add `has_default_parameters` flag to
  ParametricObject (set True on door/window/stair/railing/roof);
  derive the 5 `<name>: PointerProperty(type=BIM<X>Properties)`
  annotations and collapse the 5 hand-written `draw_expandable_panel`
  blocks in `draw_default_parameters` into loops driven by the flag.

Existing `test_gizmo_preferences_field_per_registry_entry` pinned the
GizmoPreferences contract; new
`test_default_parameters_field_per_registry_entry_with_defaults`
pins the DefaultParameters contract (one-directional: flag=True
implies field present, flag=False allows absence).

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606291429
2026-06-29 16:29:44 +02:00
Thomas Krijnen 8bd22178f7 OCC_VER Compatibility 2026-06-29 11:30:37 +02:00
Thomas Krijnen b4d7780e14 Use opencascade::handle for compatibility with earlier versions 2026-06-29 11:30:37 +02:00
Frozen Forest Reality Technologies 7c092db9e6 OCCT 8 Update Part 4
Fix For : ``C:\Program Files\OCCT\inc\NCollection_Sequence.hxx(45,18): error C2280: 'CSLib_Class2d::CSLib_Class2d(const CSLib_Class2d &)': attempting to reference a deleted function``.
2026-06-29 11:30:36 +02:00
Frozen Forest Reality Technologies 38e3bb0590 Boost 1.88 Update 2026-06-29 11:30:36 +02:00
Frozen Forest Reality Technologies 7f49c945b9 OCCT 8.0 Update Part 3 2026-06-29 11:30:36 +02:00
Frozen Forest Reality Technologies 81f71e6418 OCCT 8.0 Update Part 2 2026-06-29 11:30:36 +02:00
Frozen Forest Reality Technologies 6318610bdb OCCT Update to 8.0 Part 1 2026-06-29 11:30:36 +02:00
Gorgious56 82dd1d94de Bonsai: batch host recuts in array/opening paths
Refs gh#8088. Array regen + multi-opening drops fan out N+1 wall recuts
per operator (one per child filling deletion + the final mirror recut),
making CSG opening-subtraction O(N^2) for a linear UX action.

Introduces tool.Geometry.batch_host_recut() — a context manager that
coalesces switch_representation and bpy.ops.bim.update_representation
calls per voided element within one operator transaction. The drain
re-reads the active representation so the recut reflects current IFC.

Wraps 7 entry points (regenerate_array, RegenerateArray, RemoveArray,
AddOpening, RecalculateFill, CloneOpening, regenerate_from_type) and
rewires 7 leaf call sites in opening.py, void/operator.py, and
mirror_parent_void_fillings_to_children.

An AST forward-compat guard pins the rewire contract: no direct
switch_representation or bpy.ops.bim.update_representation in the
three target files outside the helper definitions.

A 16-child array regen now recuts the wall once instead of 17 times.
The CSG cost per recut is unchanged; only the count is reduced.

21 new tests across three lanes (helper unit, entry-point coalescing,
AST guard) — all green.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606290835
2026-06-29 10:35:01 +02:00
Gorgious56 4004344c20 Bonsai: TAB enters wall parametric edit
Mirror the icon-click entry into wall parametric edit on the TAB key.
The dispatch in Modifier.try_applying_edit_mode had no branch for fresh
LAYER2 walls, so TAB landed in item mode instead of the parametric
draft + gizmos. Add the missing entry leg of the toggle, placed after
the generic is_object_editing branch so the finish leg still fires
when a wall is already in edit mode.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606290748
2026-06-29 09:48:20 +02:00
Dion Moult e70c58fe99 ifcviewer-web: smoke-test the Blob.slice byte-range load path
Adds a second Playwright case that picks the sample sidecar through the
file input, waits for the C side to confirm the blob load (console),
then asserts an orbit drag changes the canvas with zero WebGPU errors.
This exercises the #88 path distinctly from the embedded MEMFS sample —
a broken metadata-head/tail or chunk range read renders blank and fails
the orbit-changed-canvas check. Both cases pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:44:02 +10:00
Dion Moult 584504dcdc ifcviewer-web: stream user sidecars via Blob.slice byte ranges (#88)
Picked files are no longer copied whole into the wasm heap. The browser
File object stays in JS (Module.__ifcvFile) and is read lazily through
Blob.slice byte ranges, so a 200-500 MB sidecar never enters wasm linear
memory — only chunk-sized slices do.

Mechanism (web-only, #if __EMSCRIPTEN__):

  - JS glue (EM_JS): ifcvFileSize + ifcvReadRangeInto — slice [off,off+n)
    of the File and copy it into a caller-provided heap pointer, then call
    back _ifcv_on_range_done. No malloc across the boundary; C pre-sizes
    the destination from the read plan.
  - webReadRangesAsync: reuses planSidecarReadRanges to coalesce a range
    set into Blob.slice reads (1 MB gap — each slice is an async hop),
    scatters them into a destination laid out in input order, and fires a
    continuation when the whole set lands. An in-flight map keyed by id
    survives unordered_map rehash (scratch buffers are heap-owned).
  - loadSidecarFromBlobWeb: async metadata load — head (16 B) -> index
    count -> tail-to-EOF -> parseSidecarHead/Tail -> applyCachedModel, then
    tags the model streaming_from_blob and frames it.
  - driveStreamingLoads: blob-sourced models route to beginWebChunkLoad
    (async vertex+index range reads -> applyStreamedChunk in the callback),
    holding is_loading until the bytes arrive. The embedded MEMFS sample
    keeps the synchronous fopen path.

shell.html stashes the File and calls _load_sidecar_from_blob_c instead of
FS.writeFile'ing the whole thing; EXPORTED_RUNTIME_METHODS=['FS'] dropped.
Desktop is untouched (the new members + driveStreamingLoads branch are all
emscripten-guarded). Web links clean; desktop rebuilds; 107/107 unit tests
pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:43:53 +10:00
Dion Moult a0ba3c0b98 ifcviewer: extract pure buffer-based sidecar parse + read-plan helpers
Splits the v13 metadata wire-format knowledge out of the FILE*-bound
streaming reader into pure, buffer-based functions so the web byte-range
path (#88) can reuse it without loading the whole sidecar into the wasm
heap:

  - parseSidecarHead  — validates the 16-byte head, yields num_vertex_bytes
  - parseSidecarTail  — parses meshes/instances/georef/elements/strings
                        from an in-memory tail buffer, bounds-checked
  - planSidecarReadRanges + SidecarReadPlan — the range-coalescing /
    scatter planner, promoted out of the anonymous namespace

readSidecarMetadataOnly and the range readers now call these; desktop
behaviour is unchanged (head + tail are small, the bulk is still skipped
via seek). The metadata tail is split from the head around the bulk
sections, so a blob-backed loader just slices those two regions and
hands the bytes to the same parsers.

Closes a coverage gap: StreamingLoader had no unit tests. Adds
test_streaming_loader.cpp (7 cases: metadata round-trip, corrupt/truncated
rejection, vertex+index range scatter, head validation, tail truncation,
read-plan coalescing). 107/107 unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 15:26:29 +10:00
Dion Moult fcf3a645db ifcviewer-web: add a headless-browser smoke test
Drives the built web page in a real Chrome (channel:'chrome', so no
`playwright install`): waits for wgpu init, then asserts an orbit drag
changes the composited canvas — one check that simultaneously proves the
scene rendered, mouse input is wired, and the log overlay isn't eating
events — and that zero uncaptured WebGPU errors were logged. Every web
bring-up bug so far (blank render, error-buffer cascade, overlay
swallowing input) is this shape; this would have caught them.

serve.mjs statically serves build-web; the config launches headed
against the real GPU (--use-angle=vulkan + --ignore-gpu-blocklist are
load-bearing for a non-null adapter on Linux Chrome). node_modules and
results are gitignored. See README.md to run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 12:14:27 +10:00
Dion Moult 89beee6514 ifcviewer: detect web pool-grow OOM via provisional sub-buffers
On web we skip the desktop error-scope spin-wait (it blocks the JS event
loop and hangs the page). The old web addSubBuffer then judged success by
`buf != nullptr` — but Dawn-web returns a NON-NULL error buffer on OOM,
so the pool committed an invalid sub-buffer, alloc handed out slices in
it, and every chunk_bind_group built against it failed ("BindGroup is
invalid" spam + a wgpuQueueSubmit panic). Loading a model larger than the
browser's WebGPU budget triggered exactly this.

Add the grown sub-buffer as *provisional* (alloc and the capacity/free
tallies skip it) and validate it through a non-blocking AllowSpontaneous
PopErrorScope. resolveProvisionalGrowth() clears the flag when it's good,
or drops the sub-buffer and latches growth_disabled_ on a real OOM — at
which point the streaming evictor bounds the working set to what fits
instead of cascading. Only one provisional grow is in flight at a time
(growth_pending_). Desktop keeps its synchronous halve-retry path
unchanged. All 100 unit tests still pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 12:13:34 +10:00
Dion Moult 2237b4acdd ifcviewer-web: stop the log overlay from covering + blocking the canvas
The status overlay was position:fixed top/left/right with max-height
80vh and pointer-events:auto — a near-fullscreen div that both hid the
model and swallowed mouse events, so orbit drags over most of the canvas
did nothing. Move it to a small bottom-left box, set pointer-events:none
so it never intercepts navigation, and collapse it to a few dimmed lines
once the app goes live (errors re-expand it). It still auto-scrolls to
the newest line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:33:14 +10:00
Dion Moult e3722cf243 ifcviewer-web: load user sidecars via a file-browse button (#46)
Adds an "Open .ifcview…" button that opens the browser's native file
chooser. The picked file's bytes are written into MEMFS and a new
exported entry point, load_uploaded_model_c, reads them back via the
existing loadSidecarFromPath: it resetScene()s the current model
(replace, not append), loads the sidecar, and viewAll()s it. Geometry
becomes resident over subsequent frames through render()'s inline
driveStreamingLoads, same as the embedded sample.

Deliberately a file picker, not drag-drop: browser file drag-drop needs
an X11 drag source (a file manager) to drag *from*, which a minimal WM
(ratpoison) doesn't provide. The native chooser is WM-independent.

Exports _load_uploaded_model_c and the FS runtime method; URL/byte-range
fetch of remote models stays for #88.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:19:49 +10:00
Dion Moult d36d241da2 ifcviewer: size streaming pool to demand instead of probing for the max
The desktop pool walked down from 4 GB looking for the largest single
buffer the runtime would grant, then used that as the pool's first
sub-buffer and growth increment. On a stack that advertises an
effectively unbounded maxBufferSize (1 TB observed on wgpu-native here)
the walk lands on 2 GB, so loading even a 1.2 MB model allocated a 2 GB
sub-buffer. That plus the depth/MSAA/HiZ/pick attachments exhausted
VRAM, and the next tiny allocation — the ~4 KB selection_flags buffer —
failed with "Not enough memory left", invalidating its bind group and
panicking wgpuQueueSubmit.

Drop the probe and size the pool to demand, mirroring the web path:
configure a modest initial sub-buffer and let BufferPool::addSubBuffer
grow it lazily (halve-retrying to its 64 MB floor on constrained
devices). A single chunk is capped at 16 MB, so the initial sub-buffer
only has to clear that. Web keeps its 64 MB initial (Chrome contends on
large first allocations); desktop uses 256 MB to keep sub-buffer count
low for big models. The two platforms now share one createPool() (was
probeAndCreatePool — it no longer probes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:09:12 +10:00
Dion Moult c0c0c987c4 ifcviewer-web: wire mouse + wheel navigation (#85)
Register emscripten HTML5 pointer/wheel handlers that translate raw
events into ViewportCore::orbitBy / panBy / dollyBy: left-drag orbits,
middle/right-drag pans, wheel zooms. mousedown binds to the canvas;
mousemove/up bind to the window so a drag keeps tracking off-canvas. A
contextmenu suppressor lets right-drag pan without the browser menu.

Pure callbacks — no Asyncify, no sync spin — so none of the web init
gotchas apply. Pick stays deferred until the async buffer-readback
rewrite. The embedded sample is now navigable on Chrome + Firefox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:50:11 +10:00
Dion Moult d92f6e6226 ifcviewer: route desktop orbit/pan/zoom through ViewportCore (#85)
Replace the inline orbit/pan/wheel math in ViewportWindow's mouse
handlers with calls to ViewportCore::orbitBy / panBy / dollyBy. The core
methods request the frame (via the host), so the now-redundant
requestUpdate() calls drop out; the pivot-indicator afterglow and 3px
drag-promotion stay in the Qt layer where they belong. Behaviour is
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:50:11 +10:00
Dion Moult 1d13b05acf ifcviewer: add incremental orbit/pan/zoom to ViewportCore (#85)
The orbit navigation math lived in the Qt ViewportWindow, operating on
ViewportCore's camera fields through references. That left the web host
with no way to drive the camera — orbit/pan/zoom were Qt-only.

Lift the three pixel-delta moves into ViewportCore as orbitBy / panBy /
dollyBy so every host (Qt desktop + web) shares one implementation and
the math can't drift between platforms. panBy takes the viewport height
as a parameter (the one Qt coupling: pan's world-units-per-pixel needs
it) so the core stays toolkit-free.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:49:54 +10:00
Petru Conduraru fce7cd3eb4 test(ifcpatch): add MergeProjects regression test for merging 3+ files (#7973)
Merging more than two IFC models with the MergeProjects recipe leaves
duplicated IfcGeometricRepresentationContext entities behind. All elements
are kept, but the accumulated contexts cause later disciplines to appear
"not merged" in viewers.

This test merges three projects and asserts the elements are kept, a single
IfcProject remains, and the geometric contexts are reused rather than
accumulated. It currently fails on the context assertion, reproducing #7973.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 13:43:07 +02:00
Thomas Krijnen f3dcf0b539 Attempt at less double counting of inverses #7973 2026-06-28 13:42:36 +02:00
Thomas Krijnen f5ebbd1917 Add test case for https://github.com/buildingSMART/validate/issues/305 2026-06-28 11:12:14 +02:00
Thomas Krijnen 77aa080334 Recompile rules bonsai-0.8.6-alpha2606280847 2026-06-28 10:37:33 +02:00
Thomas Krijnen 5afad2b179 Partial revert of 84abf5e91 2026-06-26 16:29:27 +02:00
Thomas Krijnen 98aa2c635e Rerun express-related codegen 2026-06-26 16:09:44 +02:00
Thomas Krijnen 7db1ceb07f Convert to lower() immediately after originalTextFor to retain more similar behaviour 2026-06-26 16:01:46 +02:00
Thomas Krijnen 84abf5e918 Adapt codegen for new parsing bonsai-0.8.6-alpha2606251229 2026-06-25 14:29:14 +02:00
Thomas Krijnen 741e8233ca originalTextFor() for on parsing express string literals 2026-06-25 14:29:14 +02:00
Thomas Krijnen 262b55630c Allow to compare simple type instance to underlying type 2026-06-25 14:29:14 +02:00
Gorgious56 f60a3423d0 Fix: commit pending parametric draft before extrusion-edit
EnableEditingExtrusionAxis and EnableEditingExtrusionProfile both
import a mesh from the IFC representation into obj.data as their
first real action. That mesh-import overwrites any in-memory
parametric (gizmo) draft on the object, silently discarding the
user's pending dimension edits.

Concrete reproduction: drag a wall's length gizmo (draft pending),
then click "Edit Axis" before validating the draft. The axis-edit
imports the wall axis mesh; the in-flight draft vanishes; on
cancel the wall snaps back to its pre-drag length.

Both call sites now commit the active draft via
tool.Parametric.commit_object_draft before the mesh import, gated
on tool.Parametric.is_object_editing so the guard is a no-op when
no draft is in flight.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606241508
2026-06-24 17:08:50 +02:00
Gorgious56 4f2c4d1633 Bonsai: promote load-warning banners to top-level UI
Multi-instance cache-lock, "Opening Cuts Skipped", and "Arrays With
Missing Children" banners now draw in BIM_PT_tabs alongside the
existing global error / outdated-model banners, so they remain
visible regardless of the active Bonsai tab. The corresponding
blocks are removed from BIM_PT_project. Dead imports
(is_cache_locked_by_other_process, draw_multiline_text) dropped
from project/ui.py.

Generated with the assistance of an AI coding tool.
2026-06-24 17:08:50 +02:00
Gorgious56 3b584ef242 Bonsai: short-circuit recreate_wall when no layer set
regenerate_wall_representation returns None for walls without an
IfcMaterialLayerSet (the only mode it knows how to rebuild). Feeding
None to switch_representation crashes deep in resolve_representation
on .Items. Document the None return on the API side and bail in
tool.Model.recreate_wall when it hits.

Generated with the assistance of an AI coding tool.
2026-06-24 17:08:50 +02:00
Gorgious56 10ee5aef4f Bonsai: refuse class-mismatched type assignment
Schema-illegal IfcDoor->IfcWallType pairings parse cleanly but propagate
into operators that fan out by type and eventually crash the wrapper.
Block the pairing at its source: API guard in ifcopenshell.api.type.
assign_type, per-object partition in BIM_OT_assign_type + DuplicateType,
new tool.Type.is_relating_type_compatible helper, AST forward-compat
guard. Files in the wild are still loaded unchanged.

Generated with the assistance of an AI coding tool.
2026-06-24 17:08:50 +02:00
Thomas Krijnen 59383f5010 constexpr more cases to prevent gcc calling non-existing template overloads 2026-06-24 11:34:04 +02:00
Thomas Krijnen a9d6776875 header.assign() helper 2026-06-24 11:12:21 +02:00
Thomas Krijnen 1057f794f6 Small conv result number tweaks 2026-06-24 11:12:11 +02:00
Thomas Krijnen b3218ced3f Mistake in parse examples include macro 2026-06-24 08:46:21 +02:00
Thomas Krijnen 49d9c416b1 Fix compilation 2026-06-23 21:51:27 +02:00
Thomas Krijnen 55e778f82e does_self_intersect() requires tri mesh 2026-06-23 20:26:28 +02:00
Thomas Krijnen 13681cdf9b Build all volumes when converting between nef and poly 2026-06-23 20:26:16 +02:00
Thomas Krijnen c592018b3f Minor changes to conversion result numbers 2026-06-23 20:25:57 +02:00
Thomas Krijnen dad4cc8a3c Merge branch 'v0.8.0' of https://github.com/IfcOpenShell/IfcOpenShell into v0.8.0 2026-06-23 20:23:13 +02:00