diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 773b23399b..171e138af5 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -340,7 +340,7 @@ class PolylineDecorator: @classmethod def set_axis_rectangle(cls, corners): - cls.axis_rectangle = corners + cls.axis_rectangle = [*corners] @classmethod def set_use_default_container(cls, value=False): @@ -394,7 +394,6 @@ class PolylineDecorator: distance = (snap_vector - last_point).length if distance > 0: angle = tool.Cad.angle_3_vectors(snap_vector, last_point, second_to_last_point, degrees=True) - angle = 180 - angle if cls.input_panel: cls.input_panel["X"] = str(round(snap_vector.x, 4)) cls.input_panel["Y"] = str(round(snap_vector.y, 4)) @@ -460,7 +459,7 @@ class PolylineDecorator: last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z)) second_to_last_point = None - if len(polyline_data) > 2: + if len(polyline_data) > 1: second_to_last_point_data = polyline_data[len(polyline_data) - 2] second_to_last_point = Vector( (second_to_last_point_data.x, second_to_last_point_data.y, second_to_last_point_data.z) @@ -472,11 +471,9 @@ class PolylineDecorator: if distance < 0 or distance > 0: angle_degrees = float(cls.input_panel["A"]) - reference_vector = second_to_last_point - last_point - reference_angle = degrees(atan2(reference_vector[1], reference_vector[0])) - angle_radians = radians( - 360 - (angle_degrees - reference_angle) - ) # Substracting from 360 to make it clockwise + vector_to_axis = last_point + Vector((1, 0, 0)) # TODO Make it work for other axis + reference_angle = tool.Cad.angle_3_vectors(second_to_last_point, last_point, vector_to_axis, degrees=True) + angle_radians = radians(reference_angle + angle_degrees) # Substracting from 360 to make it clockwise x = last_point[0] + distance * cos(angle_radians) y = last_point[1] + distance * sin(angle_radians) if cls.input_panel: diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 303d63bb38..53b8327d47 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -294,7 +294,7 @@ class DrawPolylineWall(bpy.types.Operator): 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_options = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-", "*", "/"} self.number_input = [] self.number_output = "" self.number_is_negative = False @@ -305,180 +305,6 @@ 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 - - # 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)) - - # 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 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 - - # 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) - - # # 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: - - # 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 - - # 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 - - # tool.Snap.update_snaping_point(best_result, "Axis") - - # except Exception as e: - # tool.Snap.update_snaping_point(snap_point[0], snap_point[1]) - - # 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) - - # 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 = """ - start: dim expr? - dim: NUMBER - expr: (ADD | SUB | MUL | DIV) NUMBER - - NUMBER: /-?\\d+(?:\\.\\d+)?/ - ADD: "+" - SUB: "-" - MUL: "*" - DIV: "/" - - %ignore " " - """ - - class InputTransform(Transformer): - def dim(self, args): - return float(args[0]) - - def expr(self, args): - op = args[0] - value = float(args[1]) - if op == "+": - return lambda x: x + value - elif op == "-": - return lambda x: x - value - elif op == "*": - return lambda x: x * value - elif op == "/": - return lambda x: x / value - - def start(self, args): - dimension = args[0] - if len(args) > 1: - expression = args[1] - return expression(dimension) - else: - return dimension - - try: - parser = Lark(grammar, parser="lalr", transformer=InputTransform()) - result = parser.parse(input_number) - return True, str(result) - except: - self.report({"WARNING"}, "The number typed is not valid.") - return False, "0" - def recalculate_inputs(self, context): if self.number_input: is_valid, self.number_output = tool.Snap.validate_input(self.number_output) @@ -592,9 +418,7 @@ class DrawPolylineWall(bpy.types.Operator): tool.Blender.update_viewport() if self.input_type in self.input_options: - if (event.ascii in self.number_options) or ( - event.value == "RELEASE" and event.type in {"BACK_SPACE", "MINUS", "NUMPAD_MINUS"} - ): + if (event.ascii in self.number_options) or (event.value == "RELEASE" and event.type == "BACK_SPACE"): if event.type == "BACK_SPACE": if len(self.number_input) <= 1: self.number_input = [] @@ -610,32 +434,25 @@ class DrawPolylineWall(bpy.types.Operator): if self.number_input: self.input_panel[self.input_type] = self.number_output - WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type) + PolylineDecorator.set_input_panel(self.input_panel, self.input_type) tool.Blender.update_viewport() if not self.is_input_on and event.value == "RELEASE" and event.type in {"RET", "NUMPAD_ENTER"}: self.create_walls_from_polyline(context) - WallPolylineDecorator.uninstall() + PolylineDecorator.uninstall() tool.Snap.clear_polyline() tool.Blender.update_viewport() return {"FINISHED"} if self.is_input_on and event.value == "RELEASE" and event.type in {"RET", "NUMPAD_ENTER"}: - if self.input_type in self.input_options: - self.recalculate_inputs(context) - self.is_input_on = True - self.input_type = "OFF" - self.number_input = [] - WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type) - tool.Blender.update_viewport() - else: - tool.Snap.insert_polyline_point(float(self.input_panel["X"]), float(self.input_panel["Y"])) - self.is_input_on = False - self.input_type = "OFF" - self.number_input = [] - self.number_output = "" - WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type) - tool.Blender.update_viewport() + self.recalculate_inputs(context) + tool.Snap.insert_polyline_point(float(self.input_panel["X"]), float(self.input_panel["Y"])) + self.is_input_on = False + self.input_type = "OFF" + self.number_input = [] + self.number_output = "" + PolylineDecorator.set_input_panel(self.input_panel, self.input_type) + tool.Blender.update_viewport() if event.type in {"MIDDLEMOUSE", "WHEELUPMOUSE", "WHEELDOWNMOUSE"}: return {"PASS_THROUGH"} diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 143703175c..4031b9640e 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -125,12 +125,11 @@ class Snap(bonsai.core.tool.Snap): snap_vertex = bpy.context.scene.BIMModelProperties.snap_mouse_point[0] if cls.use_default_container: z = tool.Ifc.get_object(tool.Root.get_default_container()).location.z - else: - z = snap_vertex.z if x is None and y is None: x = snap_vertex.x y = snap_vertex.y + z = snap_vertex.z # Avoids creating two points at the same location polyline_data = bpy.context.scene.BIMModelProperties.polyline_point @@ -301,6 +300,9 @@ class Snap(bonsai.core.tool.Snap): ) def select_plane_method(): + if not last_polyline_point: + plane_origin = Vector((0, 0, 0)) + if cls.snap_plane_method == "No Plane": camera_rotation = rv3d.view_rotation plane_origin = Vector((0, 0, 0))