mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 15:08:51 +00:00
Early-terminate solid raycasts in non-xray mode
This commit is contained in:
@@ -800,6 +800,30 @@ class Raycast(bonsai.core.tool.Raycast):
|
|||||||
else:
|
else:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def process_wireframe_snap_obj(
|
||||||
|
cls,
|
||||||
|
context: bpy.types.Context,
|
||||||
|
event: bpy.types.Event,
|
||||||
|
snap_obj,
|
||||||
|
ray_origin: Vector,
|
||||||
|
closest_snaps: list,
|
||||||
|
):
|
||||||
|
snap_points = tool.Raycast.ray_cast_by_proximity_2d(context, event, snap_obj)
|
||||||
|
hit_obj = None
|
||||||
|
hit = None
|
||||||
|
if snap_points:
|
||||||
|
closest_length_squared = float("inf")
|
||||||
|
for point in snap_points:
|
||||||
|
point["group"] = "Wireframe"
|
||||||
|
closest_snaps.append(point)
|
||||||
|
length = (point["point"] - ray_origin).length_squared
|
||||||
|
if length < closest_length_squared:
|
||||||
|
closest_length_squared = length
|
||||||
|
hit = point["point"]
|
||||||
|
hit_obj = point["object"]
|
||||||
|
return hit_obj, hit
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ray_cast_and_get_closest_to_camera_snaps(
|
def ray_cast_and_get_closest_to_camera_snaps(
|
||||||
cls,
|
cls,
|
||||||
@@ -814,35 +838,45 @@ class Raycast(bonsai.core.tool.Raycast):
|
|||||||
|
|
||||||
ray_origin, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
|
ray_origin, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
|
||||||
|
|
||||||
|
space = context.space_data
|
||||||
|
xray_mode = (space.shading.type == "SOLID" and space.shading.show_xray) or (
|
||||||
|
space.shading.type == "WIREFRAME" and space.shading.show_xray_wireframe
|
||||||
|
)
|
||||||
|
|
||||||
closest_snaps = []
|
closest_snaps = []
|
||||||
hit = None
|
|
||||||
|
|
||||||
for snap_obj in objs_to_raycast:
|
if not xray_mode and objs_to_raycast:
|
||||||
if snap_obj.obj.type in {"EMPTY", "CURVE"} or (
|
# Non-xray - only the closest solid object's Face snap is kept by
|
||||||
hasattr(snap_obj.obj.data, "polygons") and len(snap_obj.obj.data.polygons) == 0
|
# the caller (detect_snapping_points). Process solids in distance
|
||||||
):
|
# order and stop at the first hit to minimise raycasts.
|
||||||
# For wireframe objects we have to test all the snaps to see which is closer
|
wireframe_objs = []
|
||||||
snap_points = tool.Raycast.ray_cast_by_proximity_2d(context, event, snap_obj)
|
solid_objs = []
|
||||||
closest_wf_hit = None
|
for snap_obj in objs_to_raycast:
|
||||||
closest_wf_length_squared = 1.0
|
if snap_obj.obj.type in {"EMPTY", "CURVE"} or (
|
||||||
closest_wf_point = None
|
hasattr(snap_obj.obj.data, "polygons") and len(snap_obj.obj.data.polygons) == 0
|
||||||
if snap_points:
|
):
|
||||||
for point in snap_points:
|
wireframe_objs.append(snap_obj)
|
||||||
point["group"] = "Wireframe"
|
else:
|
||||||
closest_snaps.append(point)
|
solid_objs.append(snap_obj)
|
||||||
length = (point["point"] - ray_origin).length_squared
|
|
||||||
if closest_wf_hit is None or length < closest_wf_length_squared:
|
|
||||||
closest_wf_length_squared = length
|
|
||||||
closest_wf_hit = point["point"]
|
|
||||||
closest_wf_point = point
|
|
||||||
|
|
||||||
if closest_wf_point:
|
# Rough distance - object origin to ray origin
|
||||||
hit_obj = closest_wf_point["object"]
|
solid_objs.sort(key=lambda so: (so.obj.matrix_world.translation - ray_origin).length_squared)
|
||||||
hit = closest_wf_point["point"]
|
|
||||||
face_index = None
|
|
||||||
|
|
||||||
else:
|
# Process wireframe objects first (all of them, always collected)
|
||||||
# Solid objects
|
for snap_obj in wireframe_objs:
|
||||||
|
hit_obj, hit = cls.process_wireframe_snap_obj(
|
||||||
|
context, event, snap_obj, ray_origin, closest_snaps
|
||||||
|
)
|
||||||
|
if hit is not None:
|
||||||
|
length_squared = (hit - ray_origin).length_squared
|
||||||
|
if closest_obj is None or length_squared < closest_length_squared:
|
||||||
|
closest_length_squared = length_squared
|
||||||
|
closest_obj = hit_obj
|
||||||
|
closest_hit = hit
|
||||||
|
closest_face_index = None
|
||||||
|
|
||||||
|
# Process solid objects in distance order, stop at first hit
|
||||||
|
for snap_obj in solid_objs:
|
||||||
hit_obj, hit, face_index = cls.cast_rays_to_single_object(context, event, snap_obj.obj)
|
hit_obj, hit, face_index = cls.cast_rays_to_single_object(context, event, snap_obj.obj)
|
||||||
|
|
||||||
if hit:
|
if hit:
|
||||||
@@ -856,14 +890,47 @@ class Raycast(bonsai.core.tool.Raycast):
|
|||||||
}
|
}
|
||||||
closest_snaps.append(snap_point)
|
closest_snaps.append(snap_point)
|
||||||
|
|
||||||
# Here we test which is closer, including wireframe and solid objects
|
length_squared = (hit - ray_origin).length_squared
|
||||||
if hit is not None:
|
if closest_obj is None or length_squared < closest_length_squared:
|
||||||
length_squared = (hit - ray_origin).length_squared
|
closest_length_squared = length_squared
|
||||||
if closest_obj is None or length_squared < closest_length_squared:
|
closest_obj = hit_obj
|
||||||
closest_length_squared = length_squared
|
closest_hit = hit
|
||||||
closest_obj = hit_obj
|
closest_face_index = face_index
|
||||||
closest_hit = hit
|
|
||||||
closest_face_index = face_index
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Xray mode - process all objects (all snaps are kept by the caller)
|
||||||
|
for snap_obj in objs_to_raycast:
|
||||||
|
if snap_obj.obj.type in {"EMPTY", "CURVE"} or (
|
||||||
|
hasattr(snap_obj.obj.data, "polygons") and len(snap_obj.obj.data.polygons) == 0
|
||||||
|
):
|
||||||
|
hit_obj, hit = cls.process_wireframe_snap_obj(
|
||||||
|
context, event, snap_obj, ray_origin, closest_snaps
|
||||||
|
)
|
||||||
|
face_index = None
|
||||||
|
else:
|
||||||
|
# Solid objects
|
||||||
|
hit_obj, hit, face_index = cls.cast_rays_to_single_object(context, event, snap_obj.obj)
|
||||||
|
|
||||||
|
if hit:
|
||||||
|
snap_point = {
|
||||||
|
"point": hit,
|
||||||
|
"type": "Face",
|
||||||
|
"group": "Object",
|
||||||
|
"object": hit_obj,
|
||||||
|
"face_index": face_index,
|
||||||
|
"distance": 9, # High value so it has low priority
|
||||||
|
}
|
||||||
|
closest_snaps.append(snap_point)
|
||||||
|
|
||||||
|
if hit is not None:
|
||||||
|
length_squared = (hit - ray_origin).length_squared
|
||||||
|
if closest_obj is None or length_squared < closest_length_squared:
|
||||||
|
closest_length_squared = length_squared
|
||||||
|
closest_obj = hit_obj
|
||||||
|
closest_hit = hit
|
||||||
|
closest_face_index = face_index
|
||||||
|
|
||||||
# Label snaps from the closest object
|
# Label snaps from the closest object
|
||||||
if closest_obj is not None:
|
if closest_obj is not None:
|
||||||
|
|||||||
Reference in New Issue
Block a user