From aea0395fd6eafbe9cb6a0afcacf7fff8b832f413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Fri, 26 Sep 2025 21:57:44 -0300 Subject: [PATCH] See #7046. Remove snapping points that are not visible with clipping planes. --- src/bonsai/bonsai/tool/project.py | 20 +++++++++++++++++ src/bonsai/bonsai/tool/raycast.py | 36 ++++++++++++++++++++++++++++++- src/bonsai/bonsai/tool/snap.py | 2 +- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/bonsai/bonsai/tool/project.py b/src/bonsai/bonsai/tool/project.py index 2f01db7f90..11f3dfd9ff 100644 --- a/src/bonsai/bonsai/tool/project.py +++ b/src/bonsai/bonsai/tool/project.py @@ -483,3 +483,23 @@ class Project(bonsai.core.tool.Project): organisation_email=organization_email, authorisation=authorization, ) + + @classmethod + def get_clipping_planes_normals(cls): + normals =[] + for clipping_plane in tool.Project.get_project_props().clipping_planes: + plane = clipping_plane.obj + if not plane or not plane.data: + continue + + if plane.mode == "EDIT": + continue # A profile decorator or something else is used here. + + v1 = plane.matrix_world @ plane.data.vertices[0].co + v2 = plane.matrix_world @ plane.data.vertices[1].co + v3 = plane.matrix_world @ plane.data.vertices[2].co + d1 = v1 - v2 + d2 = v3 - v2 + normals.append((v1, d1.cross(d2).normalized())) + return normals + diff --git a/src/bonsai/bonsai/tool/raycast.py b/src/bonsai/bonsai/tool/raycast.py index bae6fe3e07..7f3b1b877a 100644 --- a/src/bonsai/bonsai/tool/raycast.py +++ b/src/bonsai/bonsai/tool/raycast.py @@ -134,6 +134,38 @@ class Raycast(bonsai.core.tool.Raycast): else: return False + @classmethod + def object_is_visible_in_clipping_plane(cls, obj): + is_visible = True + if obj.type == "EMPTY": + vertex = obj.location + is_visible = cls.point_is_visible_in_clipping_plane(vertex) + + if obj.type == "CURVE": + obj = bpy.data.objects.new("new_object", obj.to_mesh().copy()) + + if obj.type == "MESH": + for v in obj.data.vertices: + vertex = obj.matrix_world @ v.co + is_visible = cls.point_is_visible_in_clipping_plane(vertex) + if is_visible: + break + return is_visible + + @classmethod + def point_is_visible_in_clipping_plane(cls, vertex): + normals = tool.Project.get_clipping_planes_normals() + print("NORMALS", normals) + if not normals: + return True + for normal in normals: + t = (vertex - normal[0]).normalized() + result = normal[1].dot(t) + if result < 0: + return False + return True + + @classmethod def get_viewport_ray_data( cls, context: bpy.types.Context, event: bpy.types.Event, mouse_pos: tuple[int, int] = None @@ -421,7 +453,9 @@ class Raycast(bonsai.core.tool.Raycast): for obj, bbox_2d in objs_2d_bbox: if bbox_2d: if tool.Raycast.intersect_mouse_2d_bounding_box(mouse_pos, bbox_2d): - objs_to_raycast.append(obj) + if tool.Raycast.object_is_visible_in_clipping_plane(obj): + objs_to_raycast.append(obj) + return objs_to_raycast @classmethod diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 176930f1a2..557979e5ae 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -491,7 +491,7 @@ class Snap(bonsai.core.tool.Snap): "distance": 10, # High value so it has low priority } detected_snaps.append(snap_point) - + detected_snaps = [snap for snap in detected_snaps if (tool.Raycast.point_is_visible_in_clipping_plane(snap["point"]) or snap["group"] == "Plane")] return detected_snaps @classmethod