From 37e080c6deb95ac9f184d904a46a970b345f6ce6 Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Wed, 10 Jun 2026 13:17:07 +0200 Subject: [PATCH] Read wall extent from bbox in cursor gizmo layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GizmoWallEdition.position_gizmos used props.anchor_x / props.length for the in-range check (split icon visibility) and perpendicular gizmo placement. Those props mirror IFC and are re-primed by _maybe_resync_wall_props_from_ifc — any operator path that skips the re-sync leaves the perpendicular gizmo clamped to the previous wall extent, so the icon parks at the old wall end instead of the cursor's orthogonal projection. Visible after a wall mutation as the perpendicular icon landing way off the cursor in top-down view. Switch to the mesh bbox along local X. recreate_wall rebuilds the mesh to match the current IFC body on every wall mutation, so bound_box is authoritative without an explicit props sync. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/bim/module/model/wall.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index a314e9c598..dd9d21697c 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -2225,10 +2225,22 @@ class GizmoWallEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): ) cursor_world = context.scene.cursor.location cursor_local = mw.inverted() @ cursor_world - in_range = props.anchor_x < cursor_local.x < props.anchor_x + props.length + # ``props.anchor_x`` / ``props.length`` mirror IFC and are only refreshed + # when an operator calls ``_maybe_resync_wall_props_from_ifc``. Reading + # the live extent from the mesh bbox makes the gizmo position robust + # against any operator path that skips that re-sync — the mesh is + # always rebuilt by ``recreate_wall`` to match the current IFC body. + bbox_x = [v[0] for v in context.active_object.bound_box] if context.active_object else None + if bbox_x: + wall_anchor_x = min(bbox_x) + wall_length = max(bbox_x) - wall_anchor_x + else: + wall_anchor_x = props.anchor_x + wall_length = props.length + in_range = wall_anchor_x < cursor_local.x < wall_anchor_x + wall_length billboard_rot = self._frame_billboard_rot top_down = tool.Blender.is_view_top_down(context) - perp_params = _perpendicular_wall_params(cursor_local.x, cursor_local.y, props.anchor_x, props.length) + perp_params = _perpendicular_wall_params(cursor_local.x, cursor_local.y, wall_anchor_x, wall_length) # Candidates ordered by priority (lowest first). Each is (gizmo, local_z). candidates: list[tuple[bpy.types.Gizmo, float]] = [(self.extend_x_gizmo, 0.0)]