WIP: started refactoring to develop the measure tool with most of the logic from polyline wall

This commit is contained in:
Bruno Perdigão
2024-08-12 22:02:43 -03:00
committed by Bruno Perdigão
parent 736b50c6fa
commit d1d9db3ed8
7 changed files with 47619 additions and 129 deletions
File diff suppressed because it is too large Load Diff
+30 -15
View File
@@ -303,6 +303,7 @@ class WallPolylineDecorator:
input_type = None
angle_snap_mat = None
angle_snap_loc = None
use_default_container = False
@classmethod
def install(cls, context):
@@ -336,6 +337,10 @@ class WallPolylineDecorator:
cls.axis_start = start
cls.axis_end = end
@classmethod
def set_use_default_container(cls, value=False):
cls.use_default_container = value
@classmethod
def calculate_distance_and_angle(cls, context, is_input_on):
try:
@@ -358,7 +363,10 @@ class WallPolylineDecorator:
(float(cls.input_panel["X"]), float(cls.input_panel["Y"]), default_container_elevation)
)
else:
snap_vector = Vector((snap_prop.x, snap_prop.y, default_container_elevation))
if cls.use_default_container:
snap_vector = Vector((snap_prop.x, snap_prop.y, default_container_elevation))
else:
snap_vector = Vector((snap_prop.x, snap_prop.y, snap_prop.z))
distance = (snap_vector - last_point).length
x_axis_edge = (
@@ -374,6 +382,8 @@ class WallPolylineDecorator:
if cls.input_panel:
cls.input_panel["X"] = str(round(snap_vector.x, 4))
cls.input_panel["Y"] = str(round(snap_vector.y, 4))
if "Z" in list(cls.input_panel.keys()):
cls.input_panel["Z"] = str(round(snap_vector.z, 4))
cls.input_panel["D"] = str(round(distance, 4))
cls.input_panel["A"] = str(round(angle, 4))
@@ -412,7 +422,7 @@ class WallPolylineDecorator:
batch.draw(shader)
def draw_text(self, context):
texts = ["X coord:", "Y coord:", "Distance:", "Angle:"]
texts = {"X": "X coord:", "Y": "Y coord:", "Z": "Z coord:", "D": "Distance:", "A": "Angle:"}
self.addon_prefs = tool.Blender.get_addon_preferences()
self.font_id = 0
blf.size(self.font_id, 12)
@@ -422,14 +432,16 @@ class WallPolylineDecorator:
color_highlight = self.addon_prefs.decorator_color_special
offset = 20
new_line = 20
keys = list(self.input_panel.keys())
for i, text in enumerate(texts):
if keys[i] == self.input_type:
for i, (key, value) in enumerate(self.input_panel.items()):
if key not in list(texts.keys()):
continue
if key == self.input_type:
blf.color(self.font_id, *color_highlight)
else:
blf.color(self.font_id, *color)
blf.position(self.font_id, self.mouse_pos[0] + offset, self.mouse_pos[1] + offset - (new_line * i), 0)
blf.draw(self.font_id, text + self.input_panel[keys[i]])
blf.draw(self.font_id, texts[key] + value)
def __call__(self, context):
@@ -461,15 +473,16 @@ class WallPolylineDecorator:
else:
self.draw_batch("POINTS", mouse_point, (1.0, 0.6, 0.0, 1.0))
# When a point is above the plane it projects the point
# to the plane and creates a line
projection_point = []
if snap_prop.snap_type != "Plane" and snap_prop.z != 0:
self.line_shader.uniform_float("lineWidth", 1.0)
projection_point = [Vector((snap_prop.x, snap_prop.y, default_container_elevation))]
self.draw_batch("POINTS", projection_point, decorator_color_unselected)
edges = [[0, 1]]
self.draw_batch("LINES", mouse_point + projection_point, (1.0, 0.6, 0.0, 1.0), edges)
if self.use_default_container:
# When a point is above the plane it projects the point
# to the plane and creates a line
if snap_prop.snap_type != "Plane" and snap_prop.z != 0:
self.line_shader.uniform_float("lineWidth", 1.0)
projection_point = [Vector((snap_prop.x, snap_prop.y, default_container_elevation))]
self.draw_batch("POINTS", projection_point, decorator_color_unselected)
edges = [[0, 1]]
self.draw_batch("LINES", mouse_point + projection_point, (1.0, 0.6, 0.0, 1.0), edges)
# Polyline with selected points
polyline_data = context.scene.BIMModelProperties.polyline_point
@@ -490,9 +503,11 @@ class WallPolylineDecorator:
# Line between last polyline point and mouse
edges = [[0, 1]]
if polyline_points:
if snap_prop.snap_type != "Plane" and snap_prop.z != 0 and projection_point:
print("PP", polyline_points)
if snap_prop.snap_type != "Plane" and projection_point:
self.draw_batch("LINES", [polyline_points[-1]] + projection_point, decorator_color_unselected, edges)
else:
print("FOI")
self.draw_batch("LINES", [polyline_points[-1]] + mouse_point, decorator_color_unselected, edges)
# Line for angle axis snap
+111 -110
View File
@@ -285,8 +285,6 @@ class DrawPolylineWall(bpy.types.Operator):
bl_label = "Draw Polyline Wall"
bl_options = {"REGISTER", "UNDO"}
objs_bvhs = []
viewport_box = []
@classmethod
def poll(cls, context):
@@ -308,132 +306,132 @@ class DrawPolylineWall(bpy.types.Operator):
self.input_panel = {"X": "", "Y": "", "D": "", "A": ""}
self.snap_angle = None
def snaping_movement(self, context, event):
region = context.region
rv3d = context.region_data
self.mouse_pos = event.mouse_region_x, event.mouse_region_y
# def snaping_movement(self, context, event):
# region = context.region
# rv3d = context.region_data
# self.mouse_pos = event.mouse_region_x, event.mouse_region_y
offset = 5
mouse_offset = (
(-offset, offset),
(0, offset),
(offset, offset),
(-offset, 0),
(0, 0),
(offset, 0),
(-offset, -offset),
(0, -offset),
(offset, -offset),
)
# offset = 5
# mouse_offset = (
# (-offset, offset),
# (0, offset),
# (offset, offset),
# (-offset, 0),
# (0, 0),
# (offset, 0),
# (-offset, -offset),
# (0, -offset),
# (offset, -offset),
# )
# Plane to intersect. Default Container
default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
plane_origin = Vector((0, 0, default_container_elevation))
plane_normal = Vector((0, 0, 1))
# # Plane to intersect. Default Container
# default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
# plane_origin = Vector((0, 0, default_container_elevation))
# plane_normal = Vector((0, 0, 1))
def cast_rays_and_get_best_object():
best_length_squared = 1.0
best_obj = None
best_hit = None
best_face_index = None
# def cast_rays_and_get_best_object():
# best_length_squared = 1.0
# best_obj = None
# best_hit = None
# best_face_index = None
objs_to_raycast = []
# objs_to_raycast = []
for obj, bbox_2d in self.objs_2d_bbox:
if obj.type == "MESH" and bbox_2d:
if tool.Raycast.in_view_2d_bounding_box(self.mouse_pos, bbox_2d):
objs_to_raycast.append(obj)
# for obj, bbox_2d in self.objs_2d_bbox:
# if obj.type == "MESH" and bbox_2d:
# if tool.Raycast.in_view_2d_bounding_box(self.mouse_pos, bbox_2d):
# objs_to_raycast.append(obj)
for obj in objs_to_raycast:
hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
if hit is None:
# Tried original mouse position. Now it will try the offsets.
original_mouse_pos = self.mouse_pos
for value in mouse_offset:
self.mouse_pos = tuple(x + y for x, y in zip(original_mouse_pos, value))
hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
if hit:
break
self.mouse_pos = original_mouse_pos
if hit is not None:
hit_world = obj.original.matrix_world @ hit
length_squared = (hit_world - ray_origin).length_squared
if best_obj is None or length_squared < best_length_squared:
best_length_squared = length_squared
best_obj = obj
best_hit = hit_world
best_face_index = face_index
# for obj in objs_to_raycast:
# hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
# if hit is None:
# # Tried original mouse position. Now it will try the offsets.
# original_mouse_pos = self.mouse_pos
# for value in mouse_offset:
# self.mouse_pos = tuple(x + y for x, y in zip(original_mouse_pos, value))
# hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
# if hit:
# break
# self.mouse_pos = original_mouse_pos
# if hit is not None:
# hit_world = obj.original.matrix_world @ hit
# length_squared = (hit_world - ray_origin).length_squared
# if best_obj is None or length_squared < best_length_squared:
# best_length_squared = length_squared
# best_obj = obj
# best_hit = hit_world
# best_face_index = face_index
if best_obj is not None:
return best_obj, best_hit, best_face_index
# if best_obj is not None:
# return best_obj, best_hit, best_face_index
else:
return None, None, None
# else:
# return None, None, None
snap_threshold = 0.3
ray_origin, ray_target, ray_direction = tool.Raycast.get_viewport_ray_data(context, event)
obj, hit, face_index = cast_rays_and_get_best_object()
intersection = tool.Raycast.ray_cast_to_plane(context, event, plane_origin, plane_normal)
# snap_threshold = 0.3
# ray_origin, ray_target, ray_direction = tool.Raycast.get_viewport_ray_data(context, event)
# obj, hit, face_index = cast_rays_and_get_best_object()
# intersection = tool.Raycast.ray_cast_to_plane(context, event, plane_origin, plane_normal)
# Locks snap into an angle axis
if event.shift:
rot_intersection, _, axis_start, axis_end = tool.Snap.snap_on_axis(intersection, self.snap_angle)
else:
self.snap_angle = None
rot_intersection, self.snap_angle, _, _ = tool.Snap.snap_on_axis(intersection)
# # Locks snap into an angle axis
# if event.shift:
# rot_intersection, _, axis_start, axis_end = tool.Snap.snap_on_axis(intersection, self.snap_angle)
# else:
# self.snap_angle = None
# rot_intersection, self.snap_angle, _, _ = tool.Snap.snap_on_axis(intersection)
if obj is not None:
# if obj is not None:
snap_points = tool.Snap.get_snap_points_on_raycasted_obj(obj, face_index)
snap_point = tool.Snap.select_snap_point(snap_points, hit, snap_threshold)
# snap_points = tool.Snap.get_snap_points_on_raycasted_obj(obj, face_index)
# snap_point = tool.Snap.select_snap_point(snap_points, hit, snap_threshold)
if snap_point:
# Creates a mixed snap point between the locked axis and
# the object snap
# TODO Use ALT key to give the user the option to choose between the two results.
# TODO Create decorator for this
try:
snap_point_vector = Vector((snap_point[0].x, snap_point[0].y, snap_point[0].z))
snap_point_axis_1 = (
Vector((snap_point[0].x + 1000, snap_point[0].y, default_container_elevation)),
Vector((snap_point[0].x - 1000, snap_point[0].y, default_container_elevation)),
)
snap_point_axis_2 = (
Vector((snap_point[0].x, snap_point[0].y + 1000, default_container_elevation)),
Vector((snap_point[0].x, snap_point[0].y - 1000, default_container_elevation)),
)
snap_angle_axis = (axis_start, axis_end)
result_1 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_1)
result_1 = Vector((result_1[0].x, result_1[0].y, default_container_elevation))
distance_1 = (result_1 - snap_point_vector).length
# if snap_point:
# # Creates a mixed snap point between the locked axis and
# # the object snap
# # TODO Use ALT key to give the user the option to choose between the two results.
# # TODO Create decorator for this
# try:
# snap_point_vector = Vector((snap_point[0].x, snap_point[0].y, snap_point[0].z))
# snap_point_axis_1 = (
# Vector((snap_point[0].x + 1000, snap_point[0].y, default_container_elevation)),
# Vector((snap_point[0].x - 1000, snap_point[0].y, default_container_elevation)),
# )
# snap_point_axis_2 = (
# Vector((snap_point[0].x, snap_point[0].y + 1000, default_container_elevation)),
# Vector((snap_point[0].x, snap_point[0].y - 1000, default_container_elevation)),
# )
# snap_angle_axis = (axis_start, axis_end)
# result_1 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_1)
# result_1 = Vector((result_1[0].x, result_1[0].y, default_container_elevation))
# distance_1 = (result_1 - snap_point_vector).length
result_2 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_2)
result_2 = Vector((result_2[0].x, result_2[0].y, default_container_elevation))
distance_2 = (result_2 - snap_point_vector).length
# result_2 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_2)
# result_2 = Vector((result_2[0].x, result_2[0].y, default_container_elevation))
# distance_2 = (result_2 - snap_point_vector).length
if distance_1 < distance_2:
best_result = result_1
else:
best_result = result_2
# if distance_1 < distance_2:
# best_result = result_1
# else:
# best_result = result_2
tool.Snap.update_snaping_point(best_result, "Axis")
# tool.Snap.update_snaping_point(best_result, "Axis")
except Exception as e:
tool.Snap.update_snaping_point(snap_point[0], snap_point[1])
# except Exception as e:
# tool.Snap.update_snaping_point(snap_point[0], snap_point[1])
else:
tool.Snap.update_snaping_point(hit, "Face")
# else:
# tool.Snap.update_snaping_point(hit, "Face")
else:
snap_points = tool.Snap.get_snap_points_on_polyline()
snap_point = tool.Snap.select_snap_point(snap_points, intersection, snap_threshold)
# else:
# snap_points = tool.Snap.get_snap_points_on_polyline()
# snap_point = tool.Snap.select_snap_point(snap_points, intersection, snap_threshold)
if snap_point:
tool.Snap.update_snaping_point(snap_point[0], snap_point[1])
elif rot_intersection:
tool.Snap.update_snaping_point(rot_intersection, "Axis")
else:
tool.Snap.update_snaping_point(intersection, "Plane")
# if snap_point:
# tool.Snap.update_snaping_point(snap_point[0], snap_point[1])
# elif rot_intersection:
# tool.Snap.update_snaping_point(rot_intersection, "Axis")
# else:
# tool.Snap.update_snaping_point(intersection, "Plane")
def validate_input(self, input_number):
grammar = """
@@ -540,7 +538,7 @@ class DrawPolylineWall(bpy.types.Operator):
self.objs_2d_bbox.append(tool.Raycast.get_objects_2d_bounding_boxes(context, obj))
if self.mousemove_count > 3:
self.snaping_movement(context, event)
tool.Snap.snaping_movement(context, event, self.objs_2d_bbox)
WallPolylineDecorator.set_mouse_position(event)
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
tool.Blender.update_viewport()
@@ -660,11 +658,14 @@ class DrawPolylineWall(bpy.types.Operator):
def invoke(self, context, event):
if context.space_data.type == "VIEW_3D":
WallPolylineDecorator.install(context)
tool.Snap.set_use_default_container(True)
WallPolylineDecorator.set_use_default_container(True)
tool.Snap.set_snap_plane_method('XY')
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
self.visible_objs = tool.Raycast.get_visible_objects(context)
for obj in self.visible_objs:
self.objs_2d_bbox.append(tool.Raycast.get_objects_2d_bounding_boxes(context, obj))
self.snaping_movement(context, event)
tool.Snap.snaping_movement(context, event, self.objs_2d_bbox)
WallPolylineDecorator.set_mouse_position(event)
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
tool.Blender.update_viewport()
@@ -43,6 +43,7 @@ classes = (
operator.LoadLinkedProject,
operator.LoadProject,
operator.LoadProjectElements,
operator.MeasureTool,
operator.NewProject,
operator.QueryLinkedElement,
operator.RefreshClippingPlanes,
@@ -52,6 +52,7 @@ from bpy.app.handlers import persistent
from ifcopenshell.geom import ShapeElementType
from bonsai.bim.module.project.data import LinksData
from bonsai.bim.module.project.decorator import ProjectDecorator, ClippingPlaneDecorator
from bonsai.bim.module.model.decorator import WallPolylineDecorator
from typing import Union
@@ -2286,3 +2287,92 @@ if bpy.app.version >= (4, 1, 0):
@classmethod
def poll_drop(cls, context):
return True
class MeasureTool(bpy.types.Operator):
bl_idname = "bim.measure_tool"
bl_options = {"REGISTER", "UNDO"}
bl_label = "Measure Tool"
@classmethod
def poll(cls, context):
return context.space_data.type == "VIEW_3D"
def __init__(self):
self.mousemove_count = 0
self.action_count = 0
self.visible_objs = []
self.objs_2d_bbox = []
self.number_options = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-", "*", "-", "/"}
self.number_input = []
self.number_output = ""
self.number_is_negative = False
self.is_input_on = False
self.input_options = ["X", "Y", "D", "A"]
self.input_type = "OFF"
self.input_value_xy = [None, None]
self.input_panel = {"X": "", "Y": "", "Z": "", "D": "", "A": ""}
self.snap_angle = None
def modal(self, context, event):
if event.type == "MOUSEMOVE":
self.mousemove_count += 1
self.input_type = "OFF"
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
tool.Blender.update_viewport()
else:
self.mousemove_count = 0
if self.mousemove_count == 2:
self.objs_2d_bbox = []
for obj in self.visible_objs:
self.objs_2d_bbox.append(tool.Raycast.get_objects_2d_bounding_boxes(context, obj))
if self.mousemove_count > 3:
tool.Snap.snaping_movement(context, event, self.objs_2d_bbox)
WallPolylineDecorator.set_mouse_position(event)
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, False)
tool.Blender.update_viewport()
return {"RUNNING_MODAL"}
if event.type in {"MIDDLEMOUSE", "WHEELUPMOUSE", "WHEELDOWNMOUSE"}:
return {"PASS_THROUGH"}
if event.value == "RELEASE" and event.type == "LEFTMOUSE":
tool.Snap.insert_polyline_point()
tool.Blender.update_viewport()
if event.value == "RELEASE" and event.type == "BACK_SPACE":
tool.Snap.remove_last_polyline_point()
tool.Blender.update_viewport()
if event.value == "RELEASE" and event.type in {"RIGHTMOUSE", "ESC"}:
WallPolylineDecorator.uninstall()
tool.Snap.clear_polyline()
tool.Blender.update_viewport()
return {"FINISHED"}
return {"RUNNING_MODAL"}
def invoke(self, context, event):
if context.space_data.type == "VIEW_3D":
WallPolylineDecorator.install(context)
tool.Snap.set_use_default_container(False)
WallPolylineDecorator.set_use_default_container(False)
tool.Snap.set_snap_plane_method('No Plane')
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
self.visible_objs = tool.Raycast.get_visible_objects(context)
for obj in self.visible_objs:
self.objs_2d_bbox.append(tool.Raycast.get_objects_2d_bounding_boxes(context, obj))
tool.Snap.snaping_movement(context, event, self.objs_2d_bbox)
WallPolylineDecorator.set_mouse_position(event)
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
tool.Blender.update_viewport()
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
else:
self.report({"WARNING"}, "Active space must be a View3d")
return {"CANCELLED"}
@@ -37,6 +37,7 @@ class ExploreTool(bpy.types.WorkSpaceTool):
("bim.explore_hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_C")]}),
("bim.explore_hotkey", {"type": "F", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_F")]}),
("bim.explore_hotkey", {"type": "C", "value": "PRESS", "alt": True}, {"properties": [("hotkey", "A_C")]}),
("bim.explore_hotkey", {"type": "M", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_M")]}),
)
def draw_settings(context, layout, ws_tool):
@@ -57,6 +58,9 @@ class ExploreTool(bpy.types.WorkSpaceTool):
row = layout.row(align=True)
row.label(text="", icon="EVENT_ALT")
row.label(text="Disable Culling" if LinksData.enable_culling else "Enable Culling", icon="EVENT_C")
row = layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="Measure Tool", icon="EVENT_M")
class ExploreHotkey(bpy.types.Operator):
@@ -88,3 +92,6 @@ class ExploreHotkey(bpy.types.Operator):
bpy.ops.bim.disable_culling()
else:
bpy.ops.bim.enable_culling("INVOKE_DEFAULT")
def hotkey_S_M(self):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT")
+161 -4
View File
@@ -26,6 +26,19 @@ from mathutils import Matrix, Vector
class Snap(bonsai.core.tool.Snap):
mouse_pos = None
snap_angle = None
use_default_container = False
snap_plane_method = "No Plane"
@classmethod
def set_use_default_container(cls, value=True):
cls.use_default_container = value
@classmethod
def set_snap_plane_method(cls, value=True):
cls.snap_plane_method = value
@classmethod
def get_snap_points_on_raycasted_obj(cls, obj, face_index):
snap_points = {}
@@ -91,18 +104,21 @@ class Snap(bonsai.core.tool.Snap):
snap_vertex.snap_type = snap_type
@classmethod
def insert_polyline_point(cls, x=None, y=None):
def insert_polyline_point(cls, x=None, y=None, z=None):
snap_vertex = bpy.context.scene.BIMModelProperties.snap_mouse_point[0]
polyline_point = bpy.context.scene.BIMModelProperties.polyline_point.add()
default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
if cls.use_default_container:
elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
else:
elevation = snap_vertex.z
if x is not None and y is not None:
polyline_point.x = x
polyline_point.y = y
polyline_point.z = default_container_elevation
polyline_point.z = elevation
else:
polyline_point.x = snap_vertex.x
polyline_point.y = snap_vertex.y
polyline_point.z = default_container_elevation
polyline_point.z = elevation
@classmethod
def close_polyline(cls):
@@ -170,3 +186,144 @@ class Snap(bonsai.core.tool.Snap):
return snap_intersection, axis, start, end
return None, None, None, None
@classmethod
def snaping_movement(cls, context, event, objs_2d_bbox):
region = context.region
rv3d = context.region_data
cls.mouse_pos = event.mouse_region_x, event.mouse_region_y
offset = 5
mouse_offset = (
(-offset, offset),
(0, offset),
(offset, offset),
(-offset, 0),
(0, 0),
(offset, 0),
(-offset, -offset),
(0, -offset),
(offset, -offset),
)
# TODO Create option for different planes. RANDOM, XY, YZ, XZ. This should change the code in the bottom
if cls.snap_plane_method == "No Plane":
camera_rotation = rv3d.view_rotation
plane_origin = Vector((0, 0, 0))
plane_normal = Vector((0, 1, 1, 1)) * Vector((camera_rotation))
elif cls.snap_plane_method == "XY":
if cls.use_default_container:
elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z
else:
elevation = 0
plane_origin = Vector((0, 0, elevation))
plane_normal = Vector((0, 0, 1))
def cast_rays_and_get_best_object():
best_length_squared = 1.0
best_obj = None
best_hit = None
best_face_index = None
objs_to_raycast = []
for obj, bbox_2d in objs_2d_bbox:
if obj.type == "MESH" and bbox_2d:
if tool.Raycast.in_view_2d_bounding_box(cls.mouse_pos, bbox_2d):
objs_to_raycast.append(obj)
for obj in objs_to_raycast:
hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
if hit is None:
# Tried original mouse position. Now it will try the offsets.
original_mouse_pos = cls.mouse_pos
for value in mouse_offset:
cls.mouse_pos = tuple(x + y for x, y in zip(original_mouse_pos, value))
hit, normal, face_index = tool.Raycast.obj_ray_cast(context, event, obj)
if hit:
break
cls.mouse_pos = original_mouse_pos
if hit is not None:
hit_world = obj.original.matrix_world @ hit
length_squared = (hit_world - ray_origin).length_squared
if best_obj is None or length_squared < best_length_squared:
best_length_squared = length_squared
best_obj = obj
best_hit = hit_world
best_face_index = face_index
if best_obj is not None:
return best_obj, best_hit, best_face_index
else:
return None, None, None
snap_threshold = 0.3
ray_origin, ray_target, ray_direction = tool.Raycast.get_viewport_ray_data(context, event)
obj, hit, face_index = cast_rays_and_get_best_object()
intersection = tool.Raycast.ray_cast_to_plane(context, event, plane_origin, plane_normal)
if cls.use_default_container:
# Locks snap into an angle axis
if event.shift:
rot_intersection, _, axis_start, axis_end = cls.snap_on_axis(intersection, cls.snap_angle)
else:
cls.snap_angle = None
rot_intersection, cls.snap_angle, _, _ = cls.snap_on_axis(intersection)
else:
rot_intersection = None
if obj is not None:
snap_points = cls.get_snap_points_on_raycasted_obj(obj, face_index)
snap_point = cls.select_snap_point(snap_points, hit, snap_threshold)
if snap_point:
# Creates a mixed snap point between the locked axis and
# the object snap
# TODO Use ALT key to give the user the option to choose between the two results.
# TODO Create decorator for this
# try:
# snap_point_vector = Vector((snap_point[0].x, snap_point[0].y, snap_point[0].z))
# snap_point_axis_1 = (
# Vector((snap_point[0].x + 1000, snap_point[0].y, default_container_elevation)),
# Vector((snap_point[0].x - 1000, snap_point[0].y, default_container_elevation)),
# )
# snap_point_axis_2 = (
# Vector((snap_point[0].x, snap_point[0].y + 1000, default_container_elevation)),
# Vector((snap_point[0].x, snap_point[0].y - 1000, default_container_elevation)),
# )
# snap_angle_axis = (axis_start, axis_end)
# result_1 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_1)
# result_1 = Vector((result_1[0].x, result_1[0].y, default_container_elevation))
# distance_1 = (result_1 - snap_point_vector).length
# result_2 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_2)
# result_2 = Vector((result_2[0].x, result_2[0].y, default_container_elevation))
# distance_2 = (result_2 - snap_point_vector).length
# if distance_1 < distance_2:
# best_result = result_1
# else:
# best_result = result_2
# cls.update_snaping_point(best_result, "Axis")
# except Exception as e:
# cls.update_snaping_point(snap_point[0], snap_point[1])
cls.update_snaping_point(snap_point[0], snap_point[1])
else:
cls.update_snaping_point(hit, "Face")
else:
snap_points = cls.get_snap_points_on_polyline()
snap_point = cls.select_snap_point(snap_points, intersection, snap_threshold)
if snap_point:
cls.update_snaping_point(snap_point[0], snap_point[1])
elif rot_intersection:
cls.update_snaping_point(rot_intersection, "Axis")
else:
cls.update_snaping_point(intersection, "Plane")