Refactor snapping points data structure.

This commit is contained in:
Bruno Perdigão
2025-02-12 15:26:11 -03:00
parent 33d9e050ec
commit 2b7108a1d8
3 changed files with 80 additions and 38 deletions
@@ -657,7 +657,7 @@ class PolylineOperator:
self.info = [ self.info = [
f"Axis: {self.tool_state.axis_method}", f"Axis: {self.tool_state.axis_method}",
f"Plane: {self.tool_state.plane_method}", f"Plane: {self.tool_state.plane_method}",
f"Snap: {self.snapping_points[0][1]}", f"Snap: {self.snapping_points[0]['type']}",
] ]
instructions = self.instructions | custom_instructions if custom_instructions else self.instructions instructions = self.instructions | custom_instructions if custom_instructions else self.instructions
@@ -869,7 +869,7 @@ class PolylineOperator:
detected_snaps = tool.Snap.detect_snapping_points(context, event, self.objs_2d_bbox, self.tool_state) 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) self.snapping_points = tool.Snap.select_snapping_points(context, event, self.tool_state, detected_snaps)
if self.snapping_points[0][1] not in {"Plane", "Axis"}: if self.snapping_points[0]["type"] not in {"Plane", "Axis"}:
should_round = False should_round = False
tool.Polyline.calculate_distance_and_angle( tool.Polyline.calculate_distance_and_angle(
+45 -11
View File
@@ -22,9 +22,8 @@ import copy
from bpy_extras import view3d_utils from bpy_extras import view3d_utils
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import math
import mathutils import mathutils
from mathutils import Matrix, Vector from mathutils import Vector
class Raycast(bonsai.core.tool.Raycast): class Raycast(bonsai.core.tool.Raycast):
@@ -170,10 +169,12 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (v - intersection).length distance = (v - intersection).length
if distance < 0.2: if distance < 0.2:
snap_point = { snap_point = {
"object": obj,
"type": "Vertex", "type": "Vertex",
"point": v, "point": v,
"distance": distance - stick_factor,
} }
points.append([(distance - stick_factor), snap_point]) points.append(snap_point)
for edge in bm.edges: for edge in bm.edges:
v1 = edge.verts[0].co v1 = edge.verts[0].co
@@ -187,10 +188,12 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (division_point - intersection).length distance = (division_point - intersection).length
if distance < 0.2: if distance < 0.2:
snap_point = { snap_point = {
"object": obj,
"type": "Edge Center", "type": "Edge Center",
"point": division_point, "point": division_point,
"distance": distance,
} }
points.append([distance, snap_point]) points.append(snap_point)
intersection = tool.Cad.intersect_edges_v2((ray_target, loc), (v1, v2)) intersection = tool.Cad.intersect_edges_v2((ray_target, loc), (v1, v2))
if intersection[0]: if intersection[0]:
@@ -198,20 +201,22 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (intersection[1] - intersection[0]).length distance = (intersection[1] - intersection[0]).length
if distance < 0.2: if distance < 0.2:
snap_point = { snap_point = {
"object": obj,
"type": "Edge", "type": "Edge",
"point": intersection[1], "point": intersection[1],
"edge_verts": (v1, v2), "edge_verts": (v1, v2),
"distance": distance + 2 * stick_factor,
} }
points.append([(distance + 2 * stick_factor), snap_point]) points.append(snap_point)
bm.free() bm.free()
snapping_points = [] # snapping_points = []
sorted_points = sorted(points, key=lambda x: x[0]) # sorted_points = sorted(points, key=lambda x: x[0])
for p in sorted_points: # for p in sorted_points:
point = copy.deepcopy(p) # point = copy.deepcopy(p)
snapping_points.append(point[1]) # snapping_points.append(point[1])
return snapping_points return points
@classmethod @classmethod
def ray_cast_to_polyline(cls, context, event): def ray_cast_to_polyline(cls, context, event):
@@ -281,3 +286,32 @@ class Raycast(bonsai.core.tool.Raycast):
intersection = Vector((0, 0, default_container_elevation)) intersection = Vector((0, 0, default_container_elevation))
return intersection return intersection
@classmethod
def ray_cast_to_edge_intersection(cls, context, event, edges):
region = context.region
rv3d = context.region_data
mouse_pos = event.mouse_region_x, event.mouse_region_y
ray_origin, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
try:
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, ray_direction)
except:
loc = Vector((0, 0, 0))
for e1, e2 in zip(edges, edges[1:] + [edges[0]]):
if tool.Cad.are_vectors_equal(e1["point"], e2["point"], tolerance=0.1):
edge_intersection = tool.Cad.intersect_edges_v2(e1["edge_verts"], e2["edge_verts"])
if edge_intersection[1]:
mouse_intersection, _ = mathutils.geometry.intersect_point_line(edge_intersection[1], ray_target, loc)
distance = (edge_intersection[1] - mouse_intersection).length
if distance < 0.2:
snap_point = {
"object": None,
"type": "Edge Intersection",
"point": edge_intersection[1],
"distance": distance,
}
return snap_point
+33 -25
View File
@@ -428,7 +428,7 @@ class Snap(bonsai.core.tool.Snap):
) )
if obj.type == "EMPTY": if obj.type == "EMPTY":
snap_point = { snap_point = {
"points": [{"type": "Vertex", "point": obj.location}], "points": [{"type": "Vertex", "point": obj.location, "distance": 10, "object": obj}], # TODO Get the real distance
"group": "Edge-Vertex", "group": "Edge-Vertex",
"object": obj, "object": obj,
} }
@@ -446,6 +446,7 @@ class Snap(bonsai.core.tool.Snap):
"group": "Object", "group": "Object",
"object": snap_obj, "object": snap_obj,
"face_index": face_index, "face_index": face_index,
"distance": 10, # TODO Get the real distance
} }
detected_snaps.append(snap_point) detected_snaps.append(snap_point)
else: else:
@@ -456,6 +457,7 @@ class Snap(bonsai.core.tool.Snap):
"group": "Object", "group": "Object",
"object": snap_obj, "object": snap_obj,
"face_index": face_index, "face_index": face_index,
"distance": 10, # TODO Get the real distance
} }
detected_snaps.append(snap_point) detected_snaps.append(snap_point)
@@ -503,15 +505,21 @@ class Snap(bonsai.core.tool.Snap):
if rot_intersection and polyline_points: if rot_intersection and polyline_points:
snap_point = { snap_point = {
"point": rot_intersection, "point": rot_intersection,
"object": None,
"group": "Axis", "group": "Axis",
"type": "Axis",
"axis_start": axis_start, "axis_start": axis_start,
"axis_end": axis_end, "axis_end": axis_end,
"distance": 10, # TODO Get the real distance
} }
detected_snaps.append(snap_point) detected_snaps.append(snap_point)
snap_point = { snap_point = {
"point": intersection, "point": intersection,
"group": "Plane", "object": None,
"group": "Plane",
"type": "Plane",
"distance": 10, # TODO Get the real distance
} }
detected_snaps.append(snap_point) detected_snaps.append(snap_point)
@@ -526,7 +534,7 @@ class Snap(bonsai.core.tool.Snap):
if getattr(props, prop): if getattr(props, prop):
options.append(props.rna_type.properties[prop].name) options.append(props.rna_type.properties[prop].name)
filtered_points = [point for point in snapping_points if point[1] in options] filtered_points = [point for point in snapping_points if point["type"] in options]
return filtered_points return filtered_points
def filter_snapping_groups_based_on_settings(detected_snaps): def filter_snapping_groups_based_on_settings(detected_snaps):
@@ -542,18 +550,17 @@ class Snap(bonsai.core.tool.Snap):
snapping_points = [] snapping_points = []
edges = [] # Get edges to create edge-intersection snap edges = [] # Get edges to create edge-intersection snap
for snap_group in filtered_snaps: for snap_group in filtered_snaps:
snap_obj = None
if snap_group["group"] == "Polyline": if snap_group["group"] == "Polyline":
for p in snap_group["points"]: for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], None)) snapping_points.append(p)
if snap_group["group"] == "Measure": if snap_group["group"] == "Measure":
for p in snap_group["points"]: for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], None)) snapping_points.append(p)
if p["type"] == "Edge": if p["type"] == "Edge":
edges.append(p) edges.append(p)
if snap_group["group"] == "Edge-Vertex": if snap_group["group"] == "Edge-Vertex":
for p in snap_group["points"]: for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], snap_group["object"])) snapping_points.append(p)
if p["type"] == "Edge": if p["type"] == "Edge":
edges.append(p) edges.append(p)
if snap_group["group"] == "Object": if snap_group["group"] == "Object":
@@ -565,10 +572,11 @@ class Snap(bonsai.core.tool.Snap):
verts.append(matrix @ obj.data.vertices[i].co) verts.append(matrix @ obj.data.vertices[i].co)
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, obj, face) snap_points = tool.Raycast.ray_cast_by_proximity(context, event, obj, face)
if not snap_points: if not snap_points:
snapping_points.append((snap_group["point"], "Face", obj)) snap_group["type"] = "Face"
snapping_points.append(snap_group)
else: else:
for p in snap_points: for p in snap_points:
snapping_points.append((p["point"], p["type"], obj)) snapping_points.append(p)
if p["type"] == "Edge": if p["type"] == "Edge":
edges.append(p) edges.append(p)
@@ -576,36 +584,36 @@ class Snap(bonsai.core.tool.Snap):
if snap_group["group"] == "Axis": if snap_group["group"] == "Axis":
axis_start = snap_group["axis_start"] axis_start = snap_group["axis_start"]
axis_end = snap_group["axis_end"] axis_end = snap_group["axis_end"]
snapping_points.append((snap_group["point"], "Axis", snap_obj)) snapping_points.append(snap_group)
if snap_group["group"] == "Plane": if snap_group["group"] == "Plane":
snapping_points.append((snap_group["point"], "Plane", snap_obj)) snapping_points.append(snap_group)
# Edges intersection snap # Edges intersection snap
if edges: if edges:
for e1, e2 in zip(edges, edges[1:] + [edges[0]]): snap_point = tool.Raycast.ray_cast_to_edge_intersection(context, event, edges)
if tool.Cad.are_vectors_equal(e1["point"], e2["point"], tolerance=0.1): if snap_point:
intersection = tool.Cad.intersect_edges_v2(e1["edge_verts"], e2["edge_verts"]) snapping_points.insert(0, snap_point)
if intersection[1]:
snapping_points.insert(0, (intersection[1], "Edge Intersection", None))
filtered_snapping_points = filter_snapping_points_based_on_settings(snapping_points) filtered_snapping_points = filter_snapping_points_based_on_settings(snapping_points)
filtered_snapping_points = sorted(filtered_snapping_points, key=lambda x: x["distance"])
# Make Axis first priority # Make Axis first priority
if tool_state.lock_axis or tool_state.axis_method in {"X", "Y", "Z"}: if tool_state.lock_axis or tool_state.axis_method in {"X", "Y", "Z"}:
cls.update_snapping_ref(filtered_snapping_points[0][0], filtered_snapping_points[0][1]) cls.update_snapping_ref(filtered_snapping_points[0]["point"], filtered_snapping_points[0]["type"])
for point in filtered_snapping_points: for point in filtered_snapping_points:
if point[1] == "Axis": if point["point"] == "Axis":
if filtered_snapping_points[0][1] not in {"Axis", "Plane"}: if filtered_snapping_points[0]["type"] not in {"Axis", "Plane"}:
# TODO Fix this based on the dictionary
mixed_snap = cls.mix_snap_and_axis(filtered_snapping_points[0], axis_start, axis_end) mixed_snap = cls.mix_snap_and_axis(filtered_snapping_points[0], axis_start, axis_end)
for mixed_point in mixed_snap: for mixed_point in mixed_snap:
filtered_snapping_points.insert(0, mixed_point) filtered_snapping_points.insert(0, mixed_point)
cls.update_snapping_point(mixed_snap[0][0], mixed_snap[0][1]) cls.update_snapping_point(mixed_snap[0]["point"], mixed_snap[0]["type"])
return filtered_snapping_points return filtered_snapping_points
cls.update_snapping_point(point[0], point[1]) cls.update_snapping_point(point["point"], point["type"])
return filtered_snapping_points return filtered_snapping_points
cls.update_snapping_point( cls.update_snapping_point(
filtered_snapping_points[0][0], filtered_snapping_points[0][1], filtered_snapping_points[0][2] filtered_snapping_points[0]["point"], filtered_snapping_points[0]["type"], filtered_snapping_points[0]["object"]
) )
return filtered_snapping_points return filtered_snapping_points
@@ -613,10 +621,10 @@ class Snap(bonsai.core.tool.Snap):
def modify_snapping_point_selection(cls, snapping_points, lock_axis=False): def modify_snapping_point_selection(cls, snapping_points, lock_axis=False):
shifted_list = snapping_points[1:] + snapping_points[:1] shifted_list = snapping_points[1:] + snapping_points[:1]
if lock_axis: # Will only cycle through mix or axis if lock_axis: # Will only cycle through mix or axis
non_axis_snap = [point for point in snapping_points if point[1] not in {"Axis", "Mix"}] non_axis_snap = [point for point in snapping_points if point["type"] not in {"Axis", "Mix"}]
axis_snap = [point for point in snapping_points if point[1] in {"Axis", "Mix"}] axis_snap = [point for point in snapping_points if point["type"] in {"Axis", "Mix"}]
shifted_list = axis_snap[1:] + axis_snap[:1] shifted_list = axis_snap[1:] + axis_snap[:1]
shifted_list.extend(non_axis_snap) shifted_list.extend(non_axis_snap)
cls.update_snapping_point(shifted_list[0][0], shifted_list[0][1]) cls.update_snapping_point(shifted_list[0]["point"], shifted_list[0]["type"])
return shifted_list return shifted_list