Commit Graph

20897 Commits

Author SHA1 Message Date
Ryan Schultz 6441c39c4e Fix #6392: when duplicating a window/door/etc, the associated IfcOpenElement duplicates as well.
Also when `bim.append_library_element` it copies the IfcOpenElement, as well.
2026-06-22 12:56:23 -05:00
Ryan Schultz 8cd797eeec Fix extruded void mirror in LAYER2 walls
IfcExtrudedAreaSolid opening geometry must be transformed by the
wall-local Householder H applied numerically to opening-local coords
(T_geom = H), not the opening-local Householder R^T H R.  The
correct Position-local transform is placement_mat.T @ H @ placement_mat,
reusing H already computed for the placement conjugation.

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:23 -05:00
Ryan Schultz 60a0411e96 Add LAYER2 wall mirror support
Three changes:

1. Mirror LAYER2 (wall) geometry correctly: exclude LAYER2 from the
   assign_inverted_type path (which only flips the type geometry and
   leaves the instance body unchanged) and route it through
   invert_representation like LAYER3 slabs.  For Y-axis flips also
   invert DirectionSense and negate OffsetFromReferenceLine on the
   IfcMaterialLayerSetUsage so regenerated walls stay correct.

2. Surface bim.mirror_geometry in the right-click context menu and
   Object menu so it is reachable without activating the BIM Tool.

3. Guard bpy.ops.bim.extend_to_underside.__doc__ with try/except so a
   missing operator (branch without that feature) does not crash the
   entire tool-header draw and hide all other buttons.

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:23 -05:00
Ryan Schultz b6476b764e Fix void mirroring on assign_type path
Two bugs fixed in TrueMirrorElements for tessellated elements with
IfcExtrudedAreaSolid voids on the assign_inverted_type path:

1. Sync element IFC placement before computing opening positions so the
   geometry engine uses the correct element-local frame when applying
   boolean voids (fixes void appearing at wrong element-local offset).

2. Replace builder.mirror for IfcExtrudedAreaSolid with direct coordinate
   negation to avoid IFC entity aliasing that corrupted profile vertices
   in the translate→mirror→translate sequence.

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:23 -05:00
Ryan Schultz 1a15cfef70 Fix BRep and opening element mirroring
Three fixes in TrueMirrorElements / _apply_opening_mirror:

1. IfcFacetedBrep support: implement mirroring in mirror_item by
   negating vertex coordinates along the flipped axes and reversing
   face winding for an odd number of flipped axes (restores outward
   normals).

2. Routing: add type_has_reps guard to is_assign_type_path so
   elements whose IfcTypeProduct carries no RepresentationMaps fall
   through to direct geometry mirroring instead of a no-op type swap.

3. Opening placement: use H@R@H conjugation (not direct Householder
   on columns) for the rotation part of _apply_opening_mirror.
   Direct Householder yields det=-1; IFC's Y=Z×X normalization then
   introduces a spurious 180°Z rotation. Conjugation keeps det=+1
   and produces the correct mirrored rotation. Also call
   builder.mirror() on each opening representation item so local
   vertex data is mirrored alongside the placement frame.

Generated with the assistance of an AI coding tool.
AI effort: 8/10
2026-06-22 12:56:23 -05:00
Ryan Schultz 3782bbe790 Fix IfcOpeningElement mirror on LAYER3 slabs
Three-part fix in _apply_opening_mirror:

1. Rotation: replace direct Householder on rotation columns with
   conjugation H@R@H. Direct Householder gives det=-1; IFC's
   Y=Z×X normalization then introduces a spurious 180°Z rotation
   (R_z(π−θ) instead of the correct R_z(−θ)). Conjugation keeps
   det=+1 and produces the correct mirrored rotation for all θ.

2. Geometry: call builder.mirror() on each representation item of
   the opening so that local vertices/profiles are also mirrored.
   edit_object_placement only moves the placement frame; without
   this step the void shape is the original, not its mirror image.

3. Ordering (existing): opening update runs before
   invert_representation so the internal reload_representation
   sees correct positions.

Generated with the assistance of an AI coding tool.
AI effort: 8/10
2026-06-22 12:56:23 -05:00
Ryan Schultz 95e11a56bf Add LAYER3 (slab) mirror geometry support
- Bypass type-based mirroring for LAYER3 elements: slab geometry lives
  on the instance (IfcExtrudedAreaSolid), not the type's RepresentationMaps,
  so the old path was a no-op that silently reassigned an empty mirrored type
- Handle IfcBooleanResult in invert_general_object by recursing into
  FirstOperand/SecondOperand before calling ShapeBuilder.mirror, which
  only handles leaf geometry types
- Mirror IfcOpeningElement placements in slab-local coordinate space:
  working in world space caused a double-offset because edit_object_placement
  stores a relative matrix, so when the depsgraph later synced the slab's
  Blender move to IFC the opening shifted again by the full slab displacement;
  mirroring the relative offset directly avoids this regardless of sync timing
2026-06-22 12:56:22 -05:00
Ryan Schultz d45fc0601d copy_representation: preserve MappedRepresentation structure for IfcTypeProduct
Incorporates the per-map copy logic from build-0.8.5 that preserves nested
MappedRepresentation structure instead of blindly using copy_deep, while
retaining HasShapeAspects and StyledByItem handling from this branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 12:56:22 -05:00
Ryan Schultz 2f7ed0ea52 Add Z-axis mirror support
Extend mirror_axes from a 2-tuple to a 3-tuple so the Z component
is no longer silently dropped. Truncate to 2D only at the
ShapeBuilder.mirror call site (which is 2D-only). Add 180° Y-axis
rotation compensation for the Z-flip case, analogous to the existing
Z-axis rotation compensation for Y-flip.

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:22 -05:00
Ryan Schultz 76ff5c67e0 Fix mirror axis mismatch when ref object is rotated
The geometry inversion was hardcoded to the object's local X axis
regardless of the mirror reference orientation. When the reference
was rotated (e.g. a wall at 90°), the inversion axis and the
position reflection were perpendicular, producing a rotation artefact.

Fix by computing the mirror plane normal in the object's local space
and passing it as the inversion axis for untyped elements. For typed
elements, the cached inverted type is always X-flipped; a 180° Z
rotation is applied to the object when a Y-flip is needed instead
(flip_Y = Rotate_Z_180 ∘ flip_X).

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:22 -05:00
Ryan Schultz ef779e2259 - Shift+click or Shift+Ctrl+F duplicates and mirrors, keeping original
- Show Mirror Geometry button for any active IFC element, not just
  flippable types

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:22 -05:00
Ryan Schultz 53a275501e - Use active object as mirror plane when other objects are selected,
falling back to in-place X-axis flip when only one object is selected
- Show Mirror Geometry button for any active IFC element, not just
  flippable types

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:22 -05:00
Ryan Schultz 888cbf7a63 Fix NoneType error and missing argument in mirror_geometry operator
- Guard against `RepresentationMaps` being `None` for type products without geometry
- Fix `assign_type()` call missing `tool.Model` argument

Generated with the assistance of an AI coding tool.
2026-06-22 12:56:22 -05:00
Robin Quint 84902d9130 Mirroring should now support IfcBoundingBox 2026-06-22 12:56:22 -05:00
Robin Quint dcb22acd3c Fixed double mirroring when two IfcPolygonalFaceSets reuse the same coordinate list entity 2026-06-22 12:56:22 -05:00
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