Commit Graph

20882 Commits

Author SHA1 Message Date
Robin Quint f1754ca523 Fixed missing length unit conversion in FilledOpeningGenerator 2026-06-22 12:56:22 -05:00
Robin Quint f576c58c05 Applied formatting 2026-06-22 12:56:22 -05:00
Robin Quint 01a5e457a2 copy_representation now properly copies explicitly assigned IfcStyledItems 2026-06-22 12:56:22 -05:00
Robin Quint 0b7f798c03 Mirrored objects now stay in place correctly. Editing doors no longer results in switching representations. 2026-06-22 12:56:22 -05:00
Robin Quint be62fd494e Simplified shape aspect duplication in copy_representation() 2026-06-22 12:56:22 -05:00
Robin Quint 8b155fc989 Root.copy_representation() now also copies shape aspects of product types 2026-06-22 12:56:22 -05:00
Robin Quint faf489e9dc extended Root.copy_representation to also copy shape aspects 2026-06-22 12:56:22 -05:00
Robin Quint d48f02a40b Implemented material syncing for mirrored types 2026-06-22 12:56:22 -05:00
Robin Quint adac547222 ShapeBuilder: added support for IndexedPolygonalFaceWithVoids, fixed winding order when mirroring on an even number of axes 2026-06-22 12:56:22 -05:00
Robin Quint 21d1d014e3 Added tool.Blender.Modifier.has_mirrored_type and set_mirrored_type. 2026-06-22 12:56:21 -05:00
Robin Quint e96420335b Geometry for arbitrary objects is now synced for mirrored objects 2026-06-22 12:54:07 -05:00
Robin Quint 3094ed7225 Door materials are now synced to mirrored types. Fixed door editing applying materials to product when modifying product type geometry. 2026-06-22 12:54:07 -05:00
Robin Quint 011a6d127f Inverted type name is now xxx.Mirror 2026-06-22 12:54:07 -05:00
Robin Quint 2a1d9461f2 fixed directly flipping a product type throwing an exception 2026-06-22 12:54:07 -05:00
Robin Quint 55a8ac82a7 changed hotkey to ctrl + f, added icon 2026-06-22 12:54:07 -05:00
Robin Quint 521fc63c48 Added bim.mirror_geometry() operator for truly mirroring products / types 2026-06-22 12:54:07 -05:00
Robin Quint 9674cedf47 Added ShapeBuilder support for mirroring 3d curves, IfcPolygonalFaceSet and IfcGeometricSet 2026-06-22 12:54:07 -05:00
Robin Quint 2f11f06fef Added ChangeSwingDirection operator for parametric doors 2026-06-22 12:54:07 -05:00
Robin Quint babc73d057 Made door / window preview both simpler and more intuitive 2026-06-22 12:54:06 -05:00
Robin Quint db8bbb9a6e Fixed preview for rotated walls 2026-06-22 12:54:06 -05:00
Robin Quint 51016de211 Fixed door / window preview and made preview of other objects not rotate with wall 2026-06-22 12:54:06 -05:00
Robin Quint 59dd25e1c2 Flip tool now moves windows / doors to the other side of a wall 2026-06-22 12:54:06 -05:00
Robin Quint 130b569f6f Doors are now placed on the side of the wall that was snapped to 2026-06-22 12:54:06 -05:00
Gorgious56 3c9ee4a71f Clip box: include linked IFC geometry
Add include_linked_ifc toggle on BIMSceneClipBoxProperties so the cap
pipeline can also bisect meshes inside Project > Links collection-instance
empties. Off by default - linked IFCs may carry the entire site or
structural backbone, and capping them adds per-mesh bisect cost on every
clip-box edit.

The new iterator composes instance.matrix_world @ inner.matrix_world as
the effective world placement so caps land in the active scene rather
than at the linked library's local origin. Linked-mesh cache entries are
namespaced with a 'link:' prefix to avoid collisions with top-level
scene objects.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606221158
2026-06-22 13:58:45 +02:00
Gorgious56 27b0b920a9 Apply black formatting and ruff isort fixes
Pre-commit checklist: black + ruff check.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606220909
2026-06-22 11:09:18 +02:00
Gorgious56 6367de6102 Add tool.Blender.draw_quads utility
Promotes the private _fill_quads_alpha helper from
bim/module/model/decorator.py to tool.Blender.draw_quads so any feature
decorator can reuse the same TRIS-batch path.

The new utility accepts an optional outline_color so callers can draw
fill, outline, or both in a single call. Migrates the only existing
caller (WallGizmoPreviewDecorator in model/wall.py) to the public API
and removes the local helper.

Generated with the assistance of an AI coding tool.
2026-06-22 11:09:18 +02:00
Gorgious56 3c20c27794 Extend clip box with face handles and presets
Add source-based clip box presets — a dropdown menu next to the Add
Clip Box button lets the user pre-size a clip box to the bounding box
of a chosen IFC source: a spatial element, IFC class, type, material,
profile, drawing camera frustum, status, system, group, or zone. The
picker dialog uses prop_with_search so files with hundreds of materials
or types remain browsable.

Add interactive face resize handles — six near-invisible click-target
quads render on the active clip box when its empty is the active
object. Dragging a face grows or shrinks the box one-sided on that
axis; the opposite face stays fixed. Ctrl+Click on a face aligns the
viewport to look at that face, following Blender's numpad-view
convention applied to the box's local axes so rotated boxes align
orthogonally to the screen. The gizmos honour negative-scale empties
so the visible cube and the clickable handles stay aligned.

Add settings and info menus — a gear-icon menu next to the Enable
Clipping / Show Caps toggles exposes per-file preferences (cap only
IFC products, show face handles); an info-icon menu adjacent documents
the gizmo gestures. A quick-access toggle row also appears in the
viewport Overlay popover, greyed out when no clip box exists, and
orphaned clip-box list entries now expose an X button so users can
recover from external host-empty deletions.

Plumbing: cap rebuild fires synchronously on gizmo release and
clip-box selection change, so the cross-section overlay re-forms
without waiting for the depsgraph debounce; cap eligibility honours
the "Only IFC Products" toggle. Includes 121 tests covering source
resolution, drag math, face visibility, gizmo registration, and the
view-alignment up-axis convention.

Generated with the assistance of an AI coding tool.
2026-06-22 11:09:18 +02:00
Thomas Krijnen 312be203c9 SYN004 test case 2026-06-20 21:30:31 +02:00
Thomas Krijnen 7c9df9f980 Don't erronously terminate on [SYN004] Non-entity type messages 2026-06-20 21:18:23 +02:00
Thomas Krijnen 669e04664d Consistent policy on normalization in halfspace eq map() 2026-06-20 13:30:17 +02:00
Thomas Krijnen c0f2fb1860 Store actual subentities in CgalShape instead of the strange degeneracies convention 2026-06-19 20:50:40 +02:00
Thomas Krijnen 9396340b13 parse examples: Include -definitions.h header as well so that preprocessor switches works 2026-06-19 20:38:37 +02:00
Gorgious56 e2a4e5692f Add network path overlay for walls and MEP
Adds a viewport overlay that traces the connected element path from
the selected wall or MEP element. Walls follow IfcRelConnectsPathElements
and draw each connected wall's reference axis with endpoint dots; MEP
elements follow IfcRelConnectsPorts and draw each segment's axis plus
a port-to-port spider for each fitting.

The new BIMModelProperties.show_paths toggle (Element Paths in the
Bonsai Decorators group of Blender's viewport overlay popover) drives
install / uninstall of both decorators on flip and on file load,
mirroring the show_slab_direction wiring. The popover row also
surfaces the pre-existing BIMSystemProperties.should_draw_decorations
toggle (System Decorations) so both connectivity overlays sit
together.

Dot colors split free endpoints (decorator_color_special, blue by
default) from junction nodes (decorator_color_selected, green by
default) so dangling chain tips read apart from interior joins. Walls
classify endpoints by IFC topology: rels expose RelatingConnectionType /
RelatedConnectionType and ATPATH dots use tool.Wall.path_connection_location_world
for the canonical T-meets join. MEP keeps the geometric classifier
because port positions coincide exactly across fitting + segment.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606190707
2026-06-19 09:07:11 +02:00
Gorgious56 104eeaf0cd Fix clip-box edit-mode picker + rotation margin
Edit-mode click-select rejected verts inside the clip volume
because clip_bb stayed at the first-arm view; the depsgraph and
PRE_VIEW handlers updated clip_planes but skipped the
view3d.clip_border call that refreshes clip_bb. Schedule a full
re-arm at transform-commit, IFC reload, and view drift.

The empty's wireframe was clipped by its own planes when rotated
at non-trivial scale because the 1e-6 absolute margin can't
absorb float-precision drift that scales with the box's world
half-extent. Add a 1e-5 relative expand.

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606181539 bonsai-0.8.6-alpha2606181541
2026-06-18 17:39:25 +02:00
Gorgious56 260a387069 Fix loading project library without IfcProject
Per IFC4+, IfcContext is the abstract supertype of IfcProject and
IfcProjectLibrary; library-only files legitimately contain only
IfcProjectLibrary as their root context. Bonsai assumed an IfcProject
was always present at three crash sites: the parent-library enum
(reported in #8183), RefreshLibrary's tree view, and AddProjectLibrary.

Introduce tool.Project.get_root_context() that prefers IfcProject and
falls back to IfcProjectLibrary, and route the three sites through it.
get_parent_library() now returns None for a root IfcProjectLibrary;
get_project_hierarchy() and the EditProjectLibrary parent-swap branch
handle that. AddProjectLibrary creates the nested sub-library via
IfcRelNests when the root is an IfcProjectLibrary, matching the
existing convention for library-under-library nesting.

For the separate "Open IFC Project" path, abort with a friendly error
pointing users to Project Setup -> Project Library -> Select Library
File instead of letting set_units() crash deep in the importer.

Closes #8183.

Partly generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606181517
2026-06-18 17:17:32 +02:00
Bruno Perdigão 937270fc49 Fix thickness and offset calculation for rotated slabs.
Get existing `x_angle` instead of using object `rotation_euler.x`

Co-Authored-By: Ryan Schultz <ryan@openingdesign.com>
bonsai-0.8.6-alpha2606180121
2026-06-17 22:20:52 -03:00
Bruno Perdigão 156c6183eb fix custom offset unit scale when loading from pset. 2026-06-17 22:20:51 -03:00
Bruno Perdigão 95fcf9e35c fix custom_offset scale material layers 2026-06-17 22:20:51 -03:00
Thomas Krijnen 855de34d22 Catch and log errors during initialize_settings() 2026-06-17 18:23:19 +02:00
dependabot[bot] 1e91eebf51 Bump tar from 7.5.11 to 7.5.16 in /src/ifctester/webapp
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.11 to 7.5.16.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.11...v7.5.16)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.16
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-17 14:37:12 +02:00
Thomas Krijnen d5bed316cd Option for ifcwrap cmake to run standalone #8165 2026-06-17 14:28:36 +02:00
carlopav 4d3bff4e3a feat(ifc5d): include quantity Formula in serialised Quantities
IfcQuantity* carries an optional Formula (IfcLabel) documenting how a
quantity was derived. Export it alongside each quantity so it survives
in the Quantities column.

The per-quantity entry shape grows from [name, value] to
[name, value, formula], which stays backward compatible for positional
consumers reading index 0/1. Formula is read with a schema-safe getattr
(it does not exist on IfcPhysicalComplexQuantity, nor in IFC2X3) and is
coalesced to "" when absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bonsai-0.8.6-alpha2606161131 bonsai-0.8.6-alpha2606161135
2026-06-16 13:34:46 +02:00
Gorgious56 0b0e34f18d Merge pull request #8178 from Gorgious56/bonsai/clip-box
Adds a viewport clip box feature to Bonsai: a user-controllable oriented bounding box that hides everything outside its 6 faces and draws filled cross-section caps where IFC product geometry intersects the planes.

Quality and coordination > Sandbox > Clip Box
2026-06-16 13:31:04 +02:00
Gorgious56 6147a58d7a Add viewport clip-box feature
A clip box hides everything outside a user-controllable oriented
bounding box, with cross-section caps drawn where IFC product
geometry intersects the planes. The box is hosted on a Blender
empty (CUBE display); its matrix_world is the single source of
truth — G/R/S edits the empty and the viewport clip planes track.

State persists through IFC save/load via a project-level pset
(IfcProject.BBIM_ClipBoxes) so the boxes survive without binding
to any IfcRoot entity (avoids the IFC scale-lock / strip).

UI: BIM_PT_clip_box under the Sandbox tab. Prominent Enable
Clipping + Show Caps toggles at top, then Add, then a UIList with
per-row duplicate / remove icons. Scene-level enabled / show_caps
so the "hide everything outside" intent applies file-wide;
enabled is intentionally not persisted to the pset so reopening
an IFC never silently hides geometry. Adding a clip box arms
clipping so the user immediately sees the cut.

Default spawn at the 3D cursor with scale 10 (a 20 m cube) so the
volume covers a typical building storey or two rather than the
meaningless 2 m unit cube.

Modal-aware: depsgraph + draw-handler paths gate per-frame side
effects on tool.Blender.is_transform_modal_active so dragging
G/R/S on the box only writes the pset once on commit, not per
frame. Shift+D / Alt+D / Ctrl+Shift+D on a clip box gets adopted
as a first-class entry via the collection-to-list sync.

Cap eligibility is gated on IfcElement (walls, slabs, doors, …)
so spatial structure (IfcSpace, IfcBuildingStorey, IfcSite) and
annotations / grids never sprout solid fills at clip boundaries.

Cap rebuild is debounced behind a 1 s quiet window so external
gizmo drags (and any other burst of non-Bonsai depsgraph updates)
collapse to one rebuild on release. Bonsai's own G/R/S keeps the
snappy on-release feel via a modal-end fast-path. The relevance
filter compares a per-Object matrix hash against a baseline so a
plain selection click — which Blender quirkily flags as a
transform update — doesn't churn the cache or flash the caps off.
Edit mode short-circuits both the rebuild scheduler and the draw
handler entirely.

Caps use the evaluated mesh (modifier stack applied) and a
session/matrix/clip-box-hash cache so a typical scene only
re-bisects meshes whose geometry actually changed.

Performance: every per-frame poller (refresh, depsgraph handlers,
draw handlers) short-circuits on the cheapest available check
first — cap_cache emptiness for the post-view draw handler,
scene_props.enabled for the rest — so a session with clipping
disabled pays only one boolean read per tick.

Known v1 limitations documented in tests / docstrings: hollow
profiles cap as solid discs (single-ring tessellation only),
non-watertight inputs may produce degenerate caps, quad-view
untested, Cycles / EEVEE render not supported (GPU-overlay only).

Generated with the assistance of an AI coding tool.
2026-06-16 13:26:44 +02:00
Gorgious56 51eb8aece7 Add bisect_and_cap helper to tool.Geometry
Bisects a BMesh against a set of planes (clear_outer per plane),
then fills the cut edges as cap faces tagged via a BMesh int layer
so the tag survives subsequent bisects. Cut edges are grouped into
connected components before filling so a hollow profile's outer +
inner loops produce two separate cap faces instead of a single
welded outer face that hides the hole. Pre-welds T-junctions
introduced by IFC Boolean meshes so the cut closes into a fillable
loop.

Callers are responsible for input mesh quality. Non-watertight
inputs (terrain, single-shell surfaces) may produce degenerate
cap faces — that's an accepted user-supplied data limitation
which can be revisited if real-world feedback shows it matters.

Used by the clip-box feature to compute cross-section caps per IFC
product mesh.

Generated with the assistance of an AI coding tool.
2026-06-16 13:26:08 +02:00
Gorgious56 5cc9daa2f9 Add OBB clip-plane and planar tessellation to tool.Cad
Adds geometry primitives the viewport clip-box feature needs:

- obb_world_clip_planes / obb_clip_planes_from_matrix: derive the 6
  inward clip planes of an oriented bounding box (or unit cube under
  a matrix_world) in RegionView3D.clip_planes form. expand / expand_rel
  margins let callers visualising the box with overlapping geometry
  (an empty CUBE display sharing edges with the planes) keep the box's
  own wireframe inside the clip volume.
- point_is_inside_clip_planes / corners_might_cross_clip_planes: cheap
  reject tests for the per-mesh capping pass to skip the expensive
  bisect when an object's AABB is fully outside the box.
- newell_normal / plane_basis: robust planar-ring normal for thin
  near-degenerate cap rings where a two-edge cross product is unstable.
- tessellate_ring_planar: triangulate [outer, *inners] 3D rings in the
  outer ring's best-fit plane, with a shapely constrained-Delaunay
  fallback for the known failure mode of mathutils.tessellate_polygon
  on complex concave polygons-with-holes.

Tests cover unit-box, translated, rotated, and scaled cases for the
OBB-from-matrix builder + the rejection helpers.

Generated with the assistance of an AI coding tool.
2026-06-16 13:24:42 +02:00
Gorgious56 a56b5660d0 Extract transform-modal gate + viewport helpers to tool.Blender
The transform-modal active check (Bonsai keymap macros + Blender's
TRANSFORM_OT_* family) was a module-local helper in drawing/gizmos.py
used by per-gizmo poll callbacks. It needs to be shared with other
features that gate per-frame side effects on whether a drag is in
progress (clip box plane re-arming, future modal-aware decorators).

Move BONSAI_TRANSFORM_MACROS and the gate into tool.Blender as
is_transform_modal_active classmethod; widen its window scan to all
WM windows for callers without a window-bound context (depsgraph
callbacks). Leave a thin module-local alias in drawing/gizmos.py so
AST scans and existing call sites stay decoupled from the helper's
home module.

Also add generic Blender helpers needed by the clip-box feature
(reusable by any future feature):

- iter_view3d_regions: yield (area, region, region_3d) for every
  WINDOW region in every 3D viewport — for clip-plane / draw-handler
  fanout.
- get_or_create_collection: idempotent named-collection lookup +
  link to a scene.
- is_in_edit_mode: True iff the active object is in any EDIT_*
  mode — for features that need to suspend per-tick work during
  vert/edge/face manipulation.
- serialize_matrix / deserialize_matrix / hash_matrix: round-trip a
  4x4 matrix as a 16-float CSV string for IFC pset persistence + a
  matching hash for cache keys.

Generated with the assistance of an AI coding tool.
2026-06-16 13:23:46 +02:00
Gorgious56 5f1efeffaf Tolerate stale array child/parent GUIDs (#8177)
* Tolerate stale array child/parent GUIDs

A real-world IFC project (an arrayed door whose host got deleted
externally) crashed Bonsai's project load with "Instance with
GlobalId not found" inside setup_arrays.

tool.Blender.get_object_from_guid declared Optional return but let
RuntimeError propagate; callers iterating BBIM_Array child lists then
crashed instead of skipping. Honour the documented contract by
returning None on miss, matching the convention used by every other
by_guid lookup helper in tool/array.py, tool/ifc.py, tool/geometry.py.

Sweep the four user-action sites that resolve array child/parent
GUIDs without a guard - they shared the same bug class but were
reachable from different operators (regenerate_array, RegenerateArray
clear, duplicate_ifc_objects, process_arrays). An already-missing
entity is the desired terminal state for each, so the fix is
try/except RuntimeError: continue/skip.

setup_arrays now also collects each parent with at least one stale
child GUID into IfcImporter.broken_arrays, surfaced via a new Project
panel banner mirroring the existing pending_opening_recut UX. The
banner reports the count and offers "Select Elements" to navigate to
the affected array parents and a Dismiss button.

constrain_children_to_parent was being called once per layer inside
setup_arrays' for loop even though it always iterates all layers
internally - lifted out of the loop (pre-existing N x perf bug
that the stale-GUID print exposed).

Regression tests:
- test_returns_none_when_guid_not_in_file pins the get_object_from_guid
  Optional contract.
- test_remove_array_tolerates_stale_child_guid injects a fake child
  GUID into BBIM_Array.Data and asserts bim.remove_array completes
  cleanly.

Generated with the assistance of an AI coding tool.

* Black: wrap long bl_description in dismiss_pending_array_repair

Generated with the assistance of an AI coding tool.
bonsai-0.8.6-alpha2606160834
2026-06-16 10:33:56 +02:00
carlopav 074021de70 fix(ifc5d): escape quantity names when serialising Quantities to JSON
serialise_cost_quantities built the "Quantities" JSON string by manual
concatenation, inserting quantity.Name and the related element's Name
without any escaping. A name containing a double quote, backslash or
newline produced invalid JSON, breaking any downstream parser (e.g. a
Typst json.decode consumer reporting "failed to parse JSON"). It also
crashed with a TypeError when a name was None (str += None).

Build a Python list and serialise it with json.dumps instead, keeping
the exact same [[name, value], ...] output shape, the element-name
prefix and the unsupported-type behaviour. None names are coalesced to
"" and quantity values are defensively coerced to float.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bonsai-0.8.6-alpha2606160435
2026-06-16 06:35:06 +02:00
Gorgious56 ed7239526c Merge pull request #8173 from Gorgious56/bonsai/wall-slab-gizmos
Bonsai/wall slab gizmos
bonsai-0.8.6-alpha2606151401
2026-06-15 16:00:56 +02:00