From 348e48b49c5b0bf1c4be2ed0ff79f00ab8b0be12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aliste?= Date: Tue, 10 Feb 2026 18:17:52 -0300 Subject: [PATCH 1/5] Add get_angle_snap_value() helper to tool/snap.py This function retrieves the angle snap increment from Blender's tool_settings.snap_angle_increment property, which was added in Blender 4.2. This allows users to configure the angle snap value through Blender's native UI instead of using hardcoded values. Co-Authored-By: Claude Opus 4.5 --- src/bonsai/bonsai/tool/snap.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 5c538dfc43..7ee06cd44e 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -114,6 +114,15 @@ class Snap(bonsai.core.tool.Snap): return increment + @classmethod + def get_angle_snap_value(cls, context: bpy.types.Context) -> float: + """Get the angle snap increment from Blender's tool settings. + + :param context: Blender context + :return: Angle snap increment in degrees + """ + return context.scene.tool_settings.snap_angle_increment + @classmethod def get_snap_points_on_raycasted_face(cls, context, event, obj, face_index): matrix = obj.matrix_world.copy() From cd95f46db5e77d22ad0173137996fb9f99118a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aliste?= Date: Tue, 10 Feb 2026 18:18:31 -0300 Subject: [PATCH 2/5] Use Blender's angle snap setting in tool/polyline.py Replace hardcoded 5-degree angle snapping with Blender's snap_angle_increment setting in calculate_distance_and_angle(). Co-Authored-By: Claude Opus 4.5 --- src/bonsai/bonsai/tool/polyline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/tool/polyline.py b/src/bonsai/bonsai/tool/polyline.py index b288260d7d..5fbc909910 100644 --- a/src/bonsai/bonsai/tool/polyline.py +++ b/src/bonsai/bonsai/tool/polyline.py @@ -191,7 +191,8 @@ class Polyline(bonsai.core.tool.Polyline): orientation_angle = 0 if input_ui: if should_round: - angle = 5 * round(angle / 5) if distance < angle_round_threshold else angle + angle_snap = tool.Snap.get_angle_snap_value(context) + angle = angle_snap * round(angle / angle_snap) if distance < angle_round_threshold else angle factor = tool.Snap.get_increment_snap_value(context) distance = factor * round(distance / factor) input_ui.set_value("X", mouse_vector.x) From 067e04b56443a9bca3eb1e68fefc950d115e8b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aliste?= Date: Tue, 10 Feb 2026 18:19:07 -0300 Subject: [PATCH 3/5] Use Blender's angle snap setting in model/polyline.py Replace hardcoded 5-degree angle snapping with Blender's snap_angle_increment setting in handle_lock_axis() for: - Initial angle rounding when locking axis (A key) - Angle rounding and increments on Shift+Wheel scroll Co-Authored-By: Claude Opus 4.5 --- src/bonsai/bonsai/bim/module/model/polyline.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index de169796f6..92ec36581b 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -211,22 +211,21 @@ class PolylineOperator: context.workspace.status_text_set(draw_instructions) def handle_lock_axis(self, context: bpy.types.Context, event: bpy.types.Event) -> None: + angle_snap = tool.Snap.get_angle_snap_value(context) if event.value == "PRESS" and event.type == "A": self.tool_state.lock_axis = False if self.tool_state.lock_axis else True if self.tool_state.lock_axis: self.tool_state.snap_angle = self.input_ui.get_number_value("WORLD_ANGLE") - # Round to the closest 5 - self.tool_state.snap_angle = round(self.tool_state.snap_angle / 5) * 5 + self.tool_state.snap_angle = round(self.tool_state.snap_angle / angle_snap) * angle_snap if event.shift and event.type in {"WHEELUPMOUSE", "WHEELDOWNMOUSE"}: self.tool_state.lock_axis = True self.tool_state.snap_angle = self.input_ui.get_number_value("WORLD_ANGLE") - # Round to the closest 5 - self.tool_state.snap_angle = round(self.tool_state.snap_angle / 5) * 5 + self.tool_state.snap_angle = round(self.tool_state.snap_angle / angle_snap) * angle_snap if event.type in {"WHEELUPMOUSE"}: - self.tool_state.snap_angle += 5 + self.tool_state.snap_angle += angle_snap else: - self.tool_state.snap_angle -= 5 + self.tool_state.snap_angle -= angle_snap self.handle_mouse_move(context, event) detected_snaps = tool.Snap.detect_snapping_points(context, event, self.objs_2d_bbox, self.tool_state) self.snapping_points = tool.Snap.select_snapping_points(context, event, self.tool_state, detected_snaps) From 740fcf77684909a1d560f93029d21616bc5a34fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aliste?= Date: Tue, 10 Feb 2026 18:20:18 -0300 Subject: [PATCH 4/5] Use Blender's angle snap setting in wall.py and profile.py Replace hardcoded 5-degree angle snapping with Blender's snap_angle_increment setting in create_wall_from_2_points() and create_profile_from_2_points(). Co-Authored-By: Claude Opus 4.5 --- src/bonsai/bonsai/bim/module/model/profile.py | 6 +++--- src/bonsai/bonsai/bim/module/model/wall.py | 4 ++-- src/bonsai/bonsai/tool/snap.py | 6 +++++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index 572898c484..4e16f9b296 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -17,7 +17,7 @@ # along with Bonsai. If not, see . import copy -from math import atan2, degrees, pi +from math import atan2, degrees, pi, radians from typing import Any, Literal, Optional, Union import bmesh @@ -195,8 +195,8 @@ class DumbProfileGenerator: if should_round: # Round to nearest 50mm (yes, metric for now) self.length = 0.05 * round(length / 0.05) - # Round to nearest 5 degrees - nearest_degree = (pi / 180) * 5 + angle_snap = tool.Snap.get_angle_snap_value(bpy.context) + nearest_degree = radians(angle_snap) self.rotation = nearest_degree * round(self.rotation / nearest_degree) self.location = coords[0] data["obj"] = self.create_profile() diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index ba3d93586b..7f4579df31 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -916,8 +916,8 @@ class DumbWallGenerator: if should_round: # Round to nearest 50mm (yes, metric for now) self.length = 0.05 * round(length / 0.05) - # Round to nearest 5 degrees - nearest_degree = (math.pi / 180) * 5 + angle_snap = tool.Snap.get_angle_snap_value(bpy.context) + nearest_degree = math.radians(angle_snap) self.rotation = nearest_degree * round(self.rotation / nearest_degree) self.location = coords[0] data["obj"] = self.create_wall() diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 7ee06cd44e..bc35505826 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -118,10 +118,14 @@ class Snap(bonsai.core.tool.Snap): def get_angle_snap_value(cls, context: bpy.types.Context) -> float: """Get the angle snap increment from Blender's tool settings. + Uses snap_angle_increment_3d (Blender 5.0+) or snap_angle_increment (Blender 4.x). + :param context: Blender context :return: Angle snap increment in degrees """ - return context.scene.tool_settings.snap_angle_increment + if bpy.app.version >= (5, 0, 0): + return math.degrees(context.scene.tool_settings.snap_angle_increment_3d) + return math.degrees(context.scene.tool_settings.snap_angle_increment) @classmethod def get_snap_points_on_raycasted_face(cls, context, event, obj, face_index): From 7b4889d2ec21dbb7c2aebb0a3d9d12e9e286b265 Mon Sep 17 00:00:00 2001 From: ssg3d <64012165+ssg3d@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:26:25 +0800 Subject: [PATCH 5/5] Update IfcParse.cpp IfcOpenshell read file, and write file without changes. This round trip introduces truncation noise. It should not hurt to increase the precision to keep this clean. --- src/ifcparse/IfcParse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index f0f880b7d6..95ab95c0db 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -746,7 +746,7 @@ namespace { static std::string format_double(const double& d) { std::ostringstream oss; oss.imbue(std::locale::classic()); - oss << std::setprecision(std::numeric_limits::digits10) << d; + oss << std::setprecision(std::numeric_limits::max_digits10) << d; const std::string str = oss.str(); oss.str(""); std::string::size_type e = str.find('e');