snap: add snap dicts creation for GPU object detection

This commit is contained in:
Bruno Perdigão
2026-08-16 10:56:38 -03:00
committed by Bruno Perdigão
parent 2912df5147
commit d227f45663
2 changed files with 126 additions and 31 deletions
+124 -29
View File
@@ -636,7 +636,7 @@ class Raycast(bonsai.core.tool.Raycast):
return None, None, None return None, None, None
@classmethod @classmethod
def get_gpu_raycast_snaps( def get_gpu_detection_snaps(
cls, cls,
context: bpy.types.Context, context: bpy.types.Context,
event: bpy.types.Event, event: bpy.types.Event,
@@ -811,47 +811,142 @@ class Raycast(bonsai.core.tool.Raycast):
if not hits: if not hits:
return [] return []
return hits
snaps: list[dict] = []
closest_obj = None
closest_dist = float("inf")
ray_origin, _, _ = cls.get_viewport_ray_data(context, event)
objs_to_raycast = []
for obj_index, face_index in hits:
obj = _obj_list[obj_index]
objs_to_raycast.append(obj)
hit_obj, hit, face_index = cls.cast_rays_and_get_best_object(context, event, objs_to_raycast)
snap: dict = {
"point": hit,
"type": "Face",
"group": "Object",
"object": obj,
"face_index": face_index,
"distance": 9, # High value so it has low priority
}
snaps.append(snap)
return snaps, closest_obj
else: else:
centre = (mx - int(read_x), my - int(read_y)) centre = (mx - int(read_x), my - int(read_y))
best = _find_closest_wireframe_pixel(pixel_data, *centre) best = _find_closest_wireframe_pixel(pixel_data, *centre)
if best is None: if best is None:
return [] return []
return best encoded, dx, dy = best
# Decode and build snap dicts
# Build snap dicts snaps: list[dict] = []
snap_threshold = cls.calculate_snap_threshold(rv3d.view_distance)
# snaps: list[dict] = [] # Compute view ray for 3D proximity calculations
# closest_obj = None _, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
# closest_dist = float("inf") try:
# ray_origin, _, _ = cls.get_viewport_ray_data(context, event) loc = tool.Cad.region_2d_to_location_3d_np(region, rv3d, (mx, my), ray_direction)
except Exception:
loc = ray_target
# for obj_index, face_index in hits: for snap_obj, pts_start, n_pts, lines_start, n_lines in obj_slots:
# obj = _obj_list[obj_index] if n_pts > 0 and pts_start <= encoded < pts_start + n_pts:
# if face_index >= len(obj.data.polygons): vi = encoded - pts_start
# continue batches = _wireframe_batch_cache.get(id(snap_obj))
# face = obj.data.polygons[face_index] if batches:
# face_center = obj.matrix_world @ face.center pts_data = batches.get("POINTS")
if pts_data:
_, _, coords = pts_data
if vi < len(coords):
local_pos = Vector(coords[vi])
world_pos = snap_obj.matrix_world @ local_pos
# Compute proper 3D distance from vertex to view ray
proj = tool.Cad.point_on_edge(world_pos, (ray_target, loc))
distance = (world_pos - proj).length
snaps.append({
"object": snap_obj,
"type": "Vertex",
"point": world_pos,
"distance": distance,
"group": "Wireframe",
})
break
# snap: dict = { if n_lines > 0 and lines_start <= encoded < lines_start + n_lines:
# "point": face_center, ei = encoded - lines_start
# "type": "Face", batches = _wireframe_batch_cache.get(id(snap_obj))
# "group": "Object", if batches:
# "object": obj, lines_data = batches.get("LINES")
# "face_index": face_index, if lines_data:
# "distance": 9, # High value so it has low priority _, _, edge_pairs = lines_data
# } if ei < len(edge_pairs):
# dist = (face_center - ray_origin).length c0, c1 = edge_pairs[ei]
# if dist < closest_dist: mw = snap_obj.matrix_world
# closest_dist = dist v0 = mw @ Vector(c0)
# closest_obj = obj v1 = mw @ Vector(c1)
# snap["is_closest_to_camera"] = True
# snaps.append(snap) # Compute closest point on edge to view ray
intersection = tool.Cad.intersect_edges_v2((ray_target, loc), (v0, v1))
if intersection[0] is not None and tool.Cad.is_point_on_edge(intersection[1], (v0, v1)):
edge_point = intersection[1].copy()
distance = (intersection[1] - intersection[0]).length
else:
# Fallback to midpoint if lines are parallel
edge_point = (v0 + v1) / 2
proj = tool.Cad.point_on_edge(edge_point, (ray_target, loc))
distance = (edge_point - proj).length
# return snaps, closest_obj snaps.append({
"object": snap_obj,
"type": "Edge",
"point": edge_point,
"edge_verts": (v0, v1),
"distance": distance,
"group": "Wireframe",
})
# Edge Center snap (midpoint)
mid = (v0 + v1) / 2
mid_proj = tool.Cad.point_on_edge(mid, (ray_target, loc))
mid_dist = (mid - mid_proj).length
snaps.append({
"object": snap_obj,
"type": "Edge Center",
"point": mid,
"distance": mid_dist,
"group": "Wireframe",
})
# Also include vertex snaps for edge endpoints
for vtx in (v0, v1):
proj = tool.Cad.point_on_edge(vtx, (ray_target, loc))
vtx_dist = (vtx - proj).length
if vtx_dist < snap_threshold:
snaps.append({
"object": snap_obj,
"type": "Vertex",
"point": vtx,
"distance": vtx_dist,
"group": "Wireframe",
})
break
return snaps
@classmethod
def get_gpu_solid_snaps(cls, context, event, objs_to_raycast):
return cls.get_gpu_detection_snaps(context, event, objs_to_raycast, tris=True)
@classmethod
def get_gpu_wireframe_snaps(cls, context, event, objs_to_raycast):
return cls.get_gpu_detection_snaps(context, event, objs_to_raycast)
@classmethod @classmethod
+2 -2
View File
@@ -391,8 +391,8 @@ class Snap(bonsai.core.tool.Snap):
# Objects # Objects
objs_to_raycast = tool.Raycast.filter_objects_to_raycast(context, event, objs_2d_bbox) objs_to_raycast = tool.Raycast.filter_objects_to_raycast(context, event, objs_2d_bbox)
obj_face_gpu_raycast = tool.Raycast.get_gpu_raycast_snaps(context, event, objs_to_raycast, tris=True) obj_face_gpu_raycast = tool.Raycast.get_gpu_solid_snaps(context, event, objs_to_raycast)
obj_wireframe_gpu_raycast = tool.Raycast.get_gpu_raycast_snaps(context, event, objs_to_raycast) obj_wireframe_gpu_raycast = tool.Raycast.get_gpu_wireframe_snaps(context, event, objs_to_raycast)
print("FACES", obj_face_gpu_raycast) print("FACES", obj_face_gpu_raycast)
print("WIREFRAME", obj_wireframe_gpu_raycast) print("WIREFRAME", obj_wireframe_gpu_raycast)
closest_snaps = tool.Raycast.ray_cast_and_get_closest_to_camera_snaps(context, event, objs_to_raycast) closest_snaps = tool.Raycast.ray_cast_and_get_closest_to_camera_snaps(context, event, objs_to_raycast)