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 = [
f"Axis: {self.tool_state.axis_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
@@ -869,7 +869,7 @@ class PolylineOperator:
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)
if self.snapping_points[0][1] not in {"Plane", "Axis"}:
if self.snapping_points[0]["type"] not in {"Plane", "Axis"}:
should_round = False
tool.Polyline.calculate_distance_and_angle(
+45 -11
View File
@@ -22,9 +22,8 @@ import copy
from bpy_extras import view3d_utils
import bonsai.core.tool
import bonsai.tool as tool
import math
import mathutils
from mathutils import Matrix, Vector
from mathutils import Vector
class Raycast(bonsai.core.tool.Raycast):
@@ -170,10 +169,12 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (v - intersection).length
if distance < 0.2:
snap_point = {
"object": obj,
"type": "Vertex",
"point": v,
"distance": distance - stick_factor,
}
points.append([(distance - stick_factor), snap_point])
points.append(snap_point)
for edge in bm.edges:
v1 = edge.verts[0].co
@@ -187,10 +188,12 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (division_point - intersection).length
if distance < 0.2:
snap_point = {
"object": obj,
"type": "Edge Center",
"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))
if intersection[0]:
@@ -198,20 +201,22 @@ class Raycast(bonsai.core.tool.Raycast):
distance = (intersection[1] - intersection[0]).length
if distance < 0.2:
snap_point = {
"object": obj,
"type": "Edge",
"point": intersection[1],
"edge_verts": (v1, v2),
"distance": distance + 2 * stick_factor,
}
points.append([(distance + 2 * stick_factor), snap_point])
points.append(snap_point)
bm.free()
snapping_points = []
sorted_points = sorted(points, key=lambda x: x[0])
for p in sorted_points:
point = copy.deepcopy(p)
snapping_points.append(point[1])
# snapping_points = []
# sorted_points = sorted(points, key=lambda x: x[0])
# for p in sorted_points:
# point = copy.deepcopy(p)
# snapping_points.append(point[1])
return snapping_points
return points
@classmethod
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))
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":
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",
"object": obj,
}
@@ -446,6 +446,7 @@ class Snap(bonsai.core.tool.Snap):
"group": "Object",
"object": snap_obj,
"face_index": face_index,
"distance": 10, # TODO Get the real distance
}
detected_snaps.append(snap_point)
else:
@@ -456,6 +457,7 @@ class Snap(bonsai.core.tool.Snap):
"group": "Object",
"object": snap_obj,
"face_index": face_index,
"distance": 10, # TODO Get the real distance
}
detected_snaps.append(snap_point)
@@ -503,15 +505,21 @@ class Snap(bonsai.core.tool.Snap):
if rot_intersection and polyline_points:
snap_point = {
"point": rot_intersection,
"object": None,
"group": "Axis",
"type": "Axis",
"axis_start": axis_start,
"axis_end": axis_end,
"distance": 10, # TODO Get the real distance
}
detected_snaps.append(snap_point)
snap_point = {
"point": intersection,
"group": "Plane",
"object": None,
"group": "Plane",
"type": "Plane",
"distance": 10, # TODO Get the real distance
}
detected_snaps.append(snap_point)
@@ -526,7 +534,7 @@ class Snap(bonsai.core.tool.Snap):
if getattr(props, prop):
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
def filter_snapping_groups_based_on_settings(detected_snaps):
@@ -542,18 +550,17 @@ class Snap(bonsai.core.tool.Snap):
snapping_points = []
edges = [] # Get edges to create edge-intersection snap
for snap_group in filtered_snaps:
snap_obj = None
if snap_group["group"] == "Polyline":
for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], None))
snapping_points.append(p)
if snap_group["group"] == "Measure":
for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], None))
snapping_points.append(p)
if p["type"] == "Edge":
edges.append(p)
if snap_group["group"] == "Edge-Vertex":
for p in snap_group["points"]:
snapping_points.append((p["point"], p["type"], snap_group["object"]))
snapping_points.append(p)
if p["type"] == "Edge":
edges.append(p)
if snap_group["group"] == "Object":
@@ -565,10 +572,11 @@ class Snap(bonsai.core.tool.Snap):
verts.append(matrix @ obj.data.vertices[i].co)
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, obj, face)
if not snap_points:
snapping_points.append((snap_group["point"], "Face", obj))
snap_group["type"] = "Face"
snapping_points.append(snap_group)
else:
for p in snap_points:
snapping_points.append((p["point"], p["type"], obj))
snapping_points.append(p)
if p["type"] == "Edge":
edges.append(p)
@@ -576,36 +584,36 @@ class Snap(bonsai.core.tool.Snap):
if snap_group["group"] == "Axis":
axis_start = snap_group["axis_start"]
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":
snapping_points.append((snap_group["point"], "Plane", snap_obj))
snapping_points.append(snap_group)
# Edges intersection snap
if edges:
for e1, e2 in zip(edges, edges[1:] + [edges[0]]):
if tool.Cad.are_vectors_equal(e1["point"], e2["point"], tolerance=0.1):
intersection = tool.Cad.intersect_edges_v2(e1["edge_verts"], e2["edge_verts"])
if intersection[1]:
snapping_points.insert(0, (intersection[1], "Edge Intersection", None))
snap_point = tool.Raycast.ray_cast_to_edge_intersection(context, event, edges)
if snap_point:
snapping_points.insert(0, snap_point)
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
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:
if point[1] == "Axis":
if filtered_snapping_points[0][1] not in {"Axis", "Plane"}:
if point["point"] == "Axis":
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)
for mixed_point in mixed_snap:
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
cls.update_snapping_point(point[0], point[1])
cls.update_snapping_point(point["point"], point["type"])
return filtered_snapping_points
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
@@ -613,10 +621,10 @@ class Snap(bonsai.core.tool.Snap):
def modify_snapping_point_selection(cls, snapping_points, lock_axis=False):
shifted_list = snapping_points[1:] + snapping_points[:1]
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"}]
axis_snap = [point for point in snapping_points if point[1] 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["type"] in {"Axis", "Mix"}]
shifted_list = axis_snap[1:] + axis_snap[:1]
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