mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Make snapping system zoom-dependent. See #6162
Refactor the snapping system to better organize the weighting and ordering of snap distances. This change enhances the "stickiness" of snapping points, allowing for prioritized control over different types of snapping points.
This commit is contained in:
@@ -140,10 +140,12 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
ray_origin, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
|
||||
points = []
|
||||
|
||||
# Makes the snapping point more or less sticky then others
|
||||
# Makes the snapping point more or less sticky than others
|
||||
# It changes the distance and affects how the snapping point are sorted
|
||||
reference = 0.2
|
||||
stick_factor = 0.02
|
||||
# We multiply by the increment snap which is based on the viewport zoom
|
||||
snap_threshold = 10 * tool.Snap.get_increment_snap_value(bpy.context)
|
||||
if face:
|
||||
snap_threshold = tool.Snap.get_increment_snap_value(bpy.context)
|
||||
|
||||
try:
|
||||
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, ray_direction)
|
||||
@@ -167,12 +169,12 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
v = obj.matrix_world.copy() @ v
|
||||
intersection = tool.Cad.point_on_edge(v, (ray_target, loc))
|
||||
distance = (v - intersection).length
|
||||
if distance < 0.2:
|
||||
if distance < snap_threshold:
|
||||
snap_point = {
|
||||
"object": obj,
|
||||
"type": "Vertex",
|
||||
"point": v.copy(),
|
||||
"distance": distance - stick_factor,
|
||||
"distance": distance,
|
||||
}
|
||||
points.append(snap_point)
|
||||
|
||||
@@ -186,7 +188,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
|
||||
intersection = tool.Cad.point_on_edge(division_point, (ray_target, loc))
|
||||
distance = (division_point - intersection).length
|
||||
if distance < 0.2:
|
||||
if distance < snap_threshold:
|
||||
snap_point = {
|
||||
"object": obj,
|
||||
"type": "Edge Center",
|
||||
@@ -199,13 +201,13 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
if intersection[0]:
|
||||
if tool.Cad.is_point_on_edge(intersection[1], (v1, v2)):
|
||||
distance = (intersection[1] - intersection[0]).length
|
||||
if distance < 0.2:
|
||||
if distance < snap_threshold:
|
||||
snap_point = {
|
||||
"object": obj,
|
||||
"type": "Edge",
|
||||
"point": intersection[1].copy(),
|
||||
"edge_verts": (v1, v2),
|
||||
"distance": distance + 2 * stick_factor,
|
||||
"distance": distance,
|
||||
}
|
||||
points.append(snap_point)
|
||||
bm.free()
|
||||
@@ -218,6 +220,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
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)
|
||||
snap_threshold = tool.Snap.get_increment_snap_value(bpy.context)
|
||||
|
||||
try:
|
||||
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, ray_direction)
|
||||
@@ -235,7 +238,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
|
||||
intersection, _ = mathutils.geometry.intersect_point_line(vertex, ray_target, loc)
|
||||
distance = (vertex - intersection).length
|
||||
if distance < 0.2:
|
||||
if distance < snap_threshold:
|
||||
snap_point = {
|
||||
"type": "Vertex",
|
||||
"point": vertex,
|
||||
@@ -289,6 +292,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
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)
|
||||
snap_threshold = tool.Snap.get_increment_snap_value(bpy.context)
|
||||
|
||||
try:
|
||||
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, ray_direction)
|
||||
@@ -303,7 +307,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
edge_intersection[1], ray_target, loc
|
||||
)
|
||||
distance = (edge_intersection[1] - mouse_intersection).length
|
||||
if distance < 0.2:
|
||||
if distance < snap_threshold:
|
||||
snap_point = {
|
||||
"object": None,
|
||||
"type": "Edge Intersection",
|
||||
|
||||
@@ -155,7 +155,8 @@ class Snap(bonsai.core.tool.Snap):
|
||||
|
||||
# Makes the snapping point more or less sticky than others
|
||||
# It changes the distance and affects how the snapping point is sorted
|
||||
stick_factor = 0.15
|
||||
# We multiply by the increment snap which is based on the viewport zoom
|
||||
snap_threshold = 1 * cls.get_increment_snap_value(bpy.context)
|
||||
|
||||
default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
|
||||
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
|
||||
@@ -195,7 +196,7 @@ class Snap(bonsai.core.tool.Snap):
|
||||
if tool_state.plane_method == "XZ":
|
||||
proximity = rot_intersection.x
|
||||
|
||||
is_on_rot_axis = abs(proximity) <= stick_factor
|
||||
is_on_rot_axis = abs(proximity) <= snap_threshold
|
||||
if is_on_rot_axis:
|
||||
elegible_axis.append((abs(proximity), axis))
|
||||
|
||||
@@ -543,6 +544,19 @@ class Snap(bonsai.core.tool.Snap):
|
||||
filtered_groups = [group for group in detected_snaps if group["group"] in options]
|
||||
return filtered_groups
|
||||
|
||||
def sort_points_by_weighted_distance(snapping_points):
|
||||
for snap in snapping_points:
|
||||
weight_factor = 100 * cls.get_increment_snap_value(context)
|
||||
if snap["type"] == "Vertex":
|
||||
snap["distance"] *= weight_factor / 12
|
||||
if snap["type"] == "Edge":
|
||||
snap["distance"] *= weight_factor
|
||||
if snap["type"] == "Edge Center":
|
||||
snap["distance"] *= weight_factor / 5
|
||||
if snap["type"] == "Edge Intersection":
|
||||
snap["distance"] *= weight_factor / 10
|
||||
return sorted(snapping_points, key=lambda x: x["distance"])
|
||||
|
||||
snaps_by_group = filter_snapping_points_by_group(detected_snaps)
|
||||
edges = [] # Get edges to create edge-intersection snap
|
||||
for snapping_point in snaps_by_group:
|
||||
@@ -560,30 +574,33 @@ class Snap(bonsai.core.tool.Snap):
|
||||
snaps_by_group.insert(0, snap_point)
|
||||
|
||||
snaps_by_type = filter_snapping_points_by_type(snaps_by_group)
|
||||
snaps_by_type = sorted(snaps_by_type, key=lambda x: x["distance"])
|
||||
ordered_snaps = sort_points_by_weighted_distance(snaps_by_type)
|
||||
|
||||
for snap in ordered_snaps:
|
||||
print("\n", snap["type"], snap["distance"])
|
||||
|
||||
# Make Axis first priority
|
||||
if tool_state.lock_axis or tool_state.axis_method in {"X", "Y", "Z"}:
|
||||
cls.update_snapping_ref(snaps_by_type[0]["point"], snaps_by_type[0]["type"])
|
||||
for point in snaps_by_type:
|
||||
cls.update_snapping_ref(ordered_snaps[0]["point"], ordered_snaps[0]["type"])
|
||||
for point in ordered_snaps:
|
||||
if point["type"] == "Axis":
|
||||
if snaps_by_type[0]["type"] not in {"Axis", "Plane"}:
|
||||
obj = snaps_by_type[0]["object"]
|
||||
mixed_snap = cls.mix_snap_and_axis(snaps_by_type[0]["point"], axis_start, axis_end)
|
||||
if ordered_snaps[0]["type"] not in {"Axis", "Plane"}:
|
||||
obj = ordered_snaps[0]["object"]
|
||||
mixed_snap = cls.mix_snap_and_axis(ordered_snaps[0]["point"], axis_start, axis_end)
|
||||
for mixed_point in mixed_snap:
|
||||
snap_point = {
|
||||
"point": mixed_point,
|
||||
"type": "Mix",
|
||||
"object": obj,
|
||||
}
|
||||
snaps_by_type.insert(0, snap_point)
|
||||
ordered_snaps.insert(0, snap_point)
|
||||
cls.update_snapping_point(snap_point["point"], snap_point["type"])
|
||||
return snaps_by_type
|
||||
return ordered_snaps
|
||||
cls.update_snapping_point(point["point"], point["type"])
|
||||
return snaps_by_type
|
||||
return ordered_snaps
|
||||
|
||||
cls.update_snapping_point(snaps_by_type[0]["point"], snaps_by_type[0]["type"], snaps_by_type[0]["object"])
|
||||
return snaps_by_type
|
||||
cls.update_snapping_point(ordered_snaps[0]["point"], ordered_snaps[0]["type"], ordered_snaps[0]["object"])
|
||||
return ordered_snaps
|
||||
|
||||
@classmethod
|
||||
def modify_snapping_point_selection(cls, snapping_points, lock_axis=False):
|
||||
|
||||
Reference in New Issue
Block a user