Cache all API responses at module level with sleeps between calls to
avoid hitting the bSDD rate limit. Fix test_get_class_relations to
call get_class_relations() instead of get_class_properties(uri, True).
Fix "X" and "Y" in [...] assertions which only checked "Y".
Generated with the assistance of an AI coding tool.
ItemIsASum and Quantities are exporter columns that were missing from
MAIN_CSV_HEADER_COLUMNS, causing them to be misidentified as numeric cost
value categories on re-import. Also initialise rate_cost_schedule to None
before the search loop to avoid UnboundLocalError when no match is found.
Generated with the assistance of an AI coding tool.
Contexts were deleted with remove_deep2 into a single set, but
file.add() inflates inverse counts causing phantom references. Split
into coord_ops (0 real inverses, remove_deep2 recurses to clean
IfcProjectedCRS) and contexts (sorted parent-first so phantoms don't
become dangling references). Remove stale MakeVolume stub from
ifcopenshell_wrapper.pyi.
Generated with the assistance of an AI coding tool.
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.
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.
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.
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
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
- 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
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>
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.
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.
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.
- 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.
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.
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.
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.