From 2ea4fc649170f410d678d44afcb82dfef1c3659c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Sat, 5 Oct 2024 11:12:03 -0300 Subject: [PATCH] Polyline tool - properties refactor. Better separation of insertion polyline and measurement polyline --- .../bonsai/bim/module/model/__init__.py | 2 +- .../bonsai/bim/module/model/decorator.py | 54 ++++++++++--------- src/bonsai/bonsai/bim/module/model/product.py | 2 +- src/bonsai/bonsai/bim/module/model/prop.py | 6 +-- src/bonsai/bonsai/bim/module/model/wall.py | 15 +++--- .../bonsai/bim/module/project/operator.py | 11 ++-- src/bonsai/bonsai/tool/polyline.py | 33 +++++++----- src/bonsai/bonsai/tool/raycast.py | 21 ++++---- src/bonsai/bonsai/tool/snap.py | 54 +++++++++++-------- 9 files changed, 113 insertions(+), 85 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index 33f94fd613..10c0f06d48 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -119,7 +119,7 @@ classes = ( mep.RegenerateDistributionElement, prop.SnapMousePoint, prop.PolylinePoint, - prop.MeasurePolyline, + prop.Polyline, prop.BIMModelProperties, prop.BIMArrayProperties, prop.BIMStairProperties, diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index f7e80b4802..758c784161 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -355,16 +355,17 @@ class PolylineDecorator: cls.tool_state = tool_state def calculate_measurement_x_y_and_z(self, context): - measurement_prop = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] - if len(measurement_prop) == 0 or len(measurement_prop) > 2: + if len(polyline_points) == 0 or len(polyline_points) > 2: return None, None - start = measurement_prop[0] - if len(measurement_prop) == 1: + start = polyline_points[0] + if len(polyline_points) == 1: end = context.scene.BIMPolylineProperties.snap_mouse_point[0] else: - end = measurement_prop[1] + end = polyline_points[1] x_axis = (Vector((start.x, start.y, start.z)), Vector((end.x, start.y, start.z))) y_axis = (Vector((end.x, start.y, start.z)), Vector((end.x, end.y, start.z))) @@ -413,7 +414,8 @@ class PolylineDecorator: self.shader = gpu.shader.from_builtin("UNIFORM_COLOR") self.line_shader.uniform_float("lineWidth", 2.0) decorator_color = self.addon_prefs.decorator_color_special - polyline = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] prop = context.scene.BIMPolylineProperties.product_preview points = [] @@ -527,7 +529,8 @@ class PolylineDecorator: region = context.region rv3d = region.data measure_type = context.scene.MeasureToolSettings.measure_type - measurement_prop = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] self.addon_prefs = tool.Blender.get_addon_preferences() self.font_id = 1 @@ -539,13 +542,13 @@ class PolylineDecorator: color = self.addon_prefs.decorations_colour blf.color(self.font_id, *color) - for i in range(len(measurement_prop)): + for i in range(len(polyline_points)): if i == 0: continue - dim_text_pos = (Vector(measurement_prop[i].position) + Vector(measurement_prop[i - 1].position)) / 2 + dim_text_pos = (Vector(polyline_points[i].position) + Vector(polyline_points[i - 1].position)) / 2 dim_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, dim_text_pos) - formatted_value = measurement_prop[i].dim + formatted_value = polyline_points[i].dim blf.position(self.font_id, dim_text_coords[0], dim_text_coords[1], 0) text = "d: " + formatted_value @@ -555,10 +558,10 @@ class PolylineDecorator: if i == 1: continue - angle_text_pos = measurement_prop[i - 1].position + angle_text_pos = polyline_points[i - 1].position angle_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, angle_text_pos) blf.position(self.font_id, angle_text_coords[0], angle_text_coords[1], 0) - text = "a: " + measurement_prop[i].angle + text = "a: " + polyline_points[i].angle text_length = blf.dimensions(self.font_id, text) self.draw_text_background(context, angle_text_coords, text_length) blf.draw(self.font_id, text) @@ -673,14 +676,15 @@ class PolylineDecorator: self.draw_batch("LINES", mouse_point + projection_point, decorator_color_unselected, edges) # Create polyline with selected points - polyline_data = context.scene.BIMPolylineProperties.polyline_points - polyline_points = [] + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] + polyline_verts = [] polyline_edges = [] - for point_prop in polyline_data: + for point_prop in polyline_points: point = Vector((point_prop.x, point_prop.y, point_prop.z)) - polyline_points.append(point) + polyline_verts.append(point) - for i in range(len(polyline_points) - 1): + for i in range(len(polyline_verts) - 1): polyline_edges.append([i, i + 1]) # Line for angle axis snap @@ -718,8 +722,8 @@ class PolylineDecorator: has_area = False if has_area: if self.input_ui.get_number_value("AREA") > 0: - tris = self.calculate_polygon(polyline_points) - self.draw_batch("TRIS", polyline_points, transparent_color(decorator_color_special), tris) + tris = self.calculate_polygon(polyline_verts) + self.draw_batch("TRIS", polyline_verts, transparent_color(decorator_color_special), tris) # Mouse points if snap_prop.snap_type in ["Plane", "Axis", "Mix"]: @@ -728,14 +732,14 @@ class PolylineDecorator: # Line between last polyline point and mouse self.line_shader.uniform_float("lineWidth", 2.0) edges = [[0, 1]] - if polyline_points: + if polyline_verts: if snap_prop.snap_type != "Plane" and projection_point: - self.draw_batch("LINES", [polyline_points[-1]] + projection_point, decorator_color_selected, edges) + self.draw_batch("LINES", [polyline_verts[-1]] + projection_point, decorator_color_selected, edges) else: - self.draw_batch("LINES", [polyline_points[-1]] + mouse_point, decorator_color_selected, edges) + self.draw_batch("LINES", [polyline_verts[-1]] + mouse_point, decorator_color_selected, edges) # Draw polyline with selected points self.line_shader.uniform_float("lineWidth", 2.0) - self.draw_batch("POINTS", polyline_points, decorator_color_unselected) - if len(polyline_points) > 1: - self.draw_batch("LINES", polyline_points, decorator_color_unselected, polyline_edges) + self.draw_batch("POINTS", polyline_verts, decorator_color_unselected) + if len(polyline_verts) > 1: + self.draw_batch("LINES", polyline_verts, decorator_color_unselected, polyline_edges) diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index f771433d2e..93d758c14d 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -137,7 +137,7 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): except: pass - point = context.scene.BIMPolylineProperties.polyline_points[0] + point = context.scene.BIMPolylineProperties.insertion_polyline[0].polyline_points[0] context.scene.cursor.location = Vector((point.x, point.y, point.z)) tool.Snap.clear_polyline() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index ef1480bbdf..0d6b6220df 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -750,7 +750,7 @@ class PolylinePoint(PropertyGroup): position: bpy.props.FloatVectorProperty(name="Decorator Position", size=3) -class MeasurePolyline(PropertyGroup): +class Polyline(PropertyGroup): polyline_points: bpy.props.CollectionProperty(type=PolylinePoint) measurement_type: bpy.props.StringProperty(name="Measurement Type") area: bpy.props.StringProperty(name="Measured Area") @@ -760,6 +760,6 @@ class MeasurePolyline(PropertyGroup): class BIMPolylineProperties(PropertyGroup): snap_mouse_point: bpy.props.CollectionProperty(type=SnapMousePoint) snap_mouse_ref: bpy.props.CollectionProperty(type=SnapMousePoint) - polyline_points: bpy.props.CollectionProperty(type=PolylinePoint) + insertion_polyline: bpy.props.CollectionProperty(type=Polyline) product_preview: bpy.props.CollectionProperty(type=PolylinePoint) - measurement_polyline: bpy.props.CollectionProperty(type=MeasurePolyline) + measurement_polyline: bpy.props.CollectionProperty(type=Polyline) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 7cebf7fda9..a0b2a0f7f6 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -520,18 +520,19 @@ class DumbWallGenerator: ) def derive_from_polyline(self): - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data.polyline_points is_polyline_closed = False - if len(polyline_data) > 3: - first_vec = Vector((polyline_data[0].x, polyline_data[0].y, polyline_data[0].z)) - last_vec = Vector((polyline_data[-1].x, polyline_data[-1].y, polyline_data[-1].z)) + if len(polyline_points) > 3: + first_vec = Vector((polyline_points[0].x, polyline_points[0].y, polyline_points[0].z)) + last_vec = Vector((polyline_points[-1].x, polyline_points[-1].y, polyline_points[-1].z)) if first_vec == last_vec: is_polyline_closed = True walls = [] - for i in range(len(polyline_data) - 1): - vec1 = Vector((polyline_data[i].x, polyline_data[i].y, polyline_data[i].z)) - vec2 = Vector((polyline_data[i + 1].x, polyline_data[i + 1].y, polyline_data[i + 1].z)) + for i in range(len(polyline_points) - 1): + vec1 = Vector((polyline_points[i].x, polyline_points[i].y, polyline_points[i].z)) + vec2 = Vector((polyline_points[i + 1].x, polyline_points[i + 1].y, polyline_points[i + 1].z)) coords = (vec1, vec2) walls.append(self.create_wall_from_2_points(coords)) return walls, is_polyline_closed diff --git a/src/bonsai/bonsai/bim/module/project/operator.py b/src/bonsai/bonsai/bim/module/project/operator.py index 9838033d03..0665a5d52e 100644 --- a/src/bonsai/bonsai/bim/module/project/operator.py +++ b/src/bonsai/bonsai/bim/module/project/operator.py @@ -2380,7 +2380,7 @@ class MeasureTool(bpy.types.Operator, PolylineOperator): def __init__(self): super().__init__() - if self.measure_type == 'AREA': + if self.measure_type == "AREA": self.input_ui = tool.Polyline.create_input_ui(init_z=True, init_area=True) else: self.input_ui = tool.Polyline.create_input_ui(init_z=True) @@ -2411,9 +2411,14 @@ class MeasureTool(bpy.types.Operator, PolylineOperator): self.handle_snap_selection(context, event) single_mode = False - if self.measure_type == "SINGLE" and len(context.scene.BIMPolylineProperties.polyline_points) >= 2: + + if ( + self.measure_type == "SINGLE" + and context.scene.BIMPolylineProperties.insertion_polyline + and len(context.scene.BIMPolylineProperties.insertion_polyline[0].polyline_points) >= 2 + ): single_mode = True - + if ( not self.tool_state.is_input_on and event.value == "RELEASE" diff --git a/src/bonsai/bonsai/tool/polyline.py b/src/bonsai/bonsai/tool/polyline.py index adcae9675d..bf92bddf71 100644 --- a/src/bonsai/bonsai/tool/polyline.py +++ b/src/bonsai/bonsai/tool/polyline.py @@ -106,10 +106,12 @@ class Polyline(bonsai.core.tool.Polyline): def calculate_distance_and_angle(cls, context, input_ui, tool_state): try: - polyline_data = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z - last_point_data = polyline_data[len(polyline_data) - 1] + last_point_data = polyline_points[len(polyline_points) - 1] except: + polyline_points = [] default_container_elevation = 0 last_point_data = None @@ -136,8 +138,8 @@ class Polyline(bonsai.core.tool.Polyline): snap_vector = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) second_to_last_point = None - if len(polyline_data) > 1: - second_to_last_point_data = polyline_data[len(polyline_data) - 2] + if len(polyline_points) > 1: + second_to_last_point_data = polyline_points[len(polyline_points) - 2] second_to_last_point = Vector( (second_to_last_point_data.x, second_to_last_point_data.y, second_to_last_point_data.z) ) @@ -174,15 +176,16 @@ class Polyline(bonsai.core.tool.Polyline): @classmethod def calculate_area(cls, context, input_ui): try: - polyline_data = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points except: return input_ui - if len(polyline_data) < 3: + if len(polyline_points) < 3: return input_ui points = [] - for data in polyline_data: + for data in polyline_points: points.append(Vector((data.x, data.y, data.z))) if points[0] == points[-1]: @@ -217,9 +220,10 @@ class Polyline(bonsai.core.tool.Polyline): @classmethod def calculate_x_y_and_z(cls, context, input_ui, tool_state): try: - polyline_data = context.scene.BIMPolylineProperties.polyline_points + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z - last_point_data = polyline_data[len(polyline_data) - 1] + last_point_data = polyline_points[len(polyline_points) - 1] last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z)) except: default_container_elevation = 0 @@ -233,8 +237,8 @@ class Polyline(bonsai.core.tool.Polyline): else: snap_vector = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) - if len(polyline_data) > 1: - second_to_last_point_data = polyline_data[len(polyline_data) - 2] + if len(polyline_points) > 1: + second_to_last_point_data = polyline_points[len(polyline_points) - 2] second_to_last_point = Vector( (second_to_last_point_data.x, second_to_last_point_data.y, second_to_last_point_data.z) ) @@ -301,11 +305,12 @@ class Polyline(bonsai.core.tool.Polyline): base_vertices = [] top_vertices = [] - polyline_data = context.scene.BIMPolylineProperties.polyline_points - if len(polyline_data) < 2: + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points + if len(polyline_points) < 2: context.scene.BIMPolylineProperties.product_preview.clear() return - for point in polyline_data: + for point in polyline_points: base_vertices.append(Vector((point.x, point.y, point.z))) is_closed = False diff --git a/src/bonsai/bonsai/tool/raycast.py b/src/bonsai/bonsai/tool/raycast.py index 7cca27482e..fa859c403e 100644 --- a/src/bonsai/bonsai/tool/raycast.py +++ b/src/bonsai/bonsai/tool/raycast.py @@ -209,20 +209,21 @@ class Raycast(bonsai.core.tool.Raycast): except: loc = Vector((0, 0, 0)) - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - polyline_data = polyline_data[ - : len(polyline_data) - 1 + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points + polyline_points = polyline_points[ + : len(polyline_points) - 1 ] # It doesn't make sense to snap to the last point created - polyline_points = [] - for point_data in polyline_data: - point = Vector((point_data.x, point_data.y, point_data.z)) + polyline_verts = [] + for point_data in polyline_points: + vertex = Vector((point_data.x, point_data.y, point_data.z)) - intersection, _ = mathutils.geometry.intersect_point_line(point, ray_target, loc) - distance = (point - intersection).length + intersection, _ = mathutils.geometry.intersect_point_line(vertex, ray_target, loc) + distance = (vertex - intersection).length if distance < 0.2: - polyline_points.append((point, "Vertex")) + polyline_verts.append((vertex, "Vertex")) - return polyline_points + return polyline_verts @classmethod def ray_cast_to_measure(cls, context, event, points): diff --git a/src/bonsai/bonsai/tool/snap.py b/src/bonsai/bonsai/tool/snap.py index 455e741c09..6faee5aa9a 100644 --- a/src/bonsai/bonsai/tool/snap.py +++ b/src/bonsai/bonsai/tool/snap.py @@ -112,21 +112,27 @@ class Snap(bonsai.core.tool.Snap): y = snap_vertex.y z = snap_vertex.z - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - if polyline_data: + + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + if not polyline_data: + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline.add() + else: + polyline_data = polyline_data[0] + polyline_points = polyline_data.polyline_points + if polyline_points: # Avoids creating two points at the same location - for point in polyline_data[1:]: # The first can be repeated to form a wall loop + for point in polyline_points[1:]: # The first can be repeated to form a wall loop if (x, y, z) == (point.x, point.y, point.z): return "Cannot create two points at the same location" # TODO move this limitation to be Wall tool specific. Right now it also affects Measure tool # Avoids creating segments smaller then 0.1. This is a limitation from create_wall_from_2_points length = ( - Vector((x, y, z)) - Vector((polyline_data[-1].x, polyline_data[-1].y, polyline_data[-1].z)) + Vector((x, y, z)) - Vector((polyline_points[-1].x, polyline_points[-1].y, polyline_points[-1].z)) ).length if round(length, 4) < 0.1: return "Cannot create a segment smaller then 10cm" - polyline_point = bpy.context.scene.BIMPolylineProperties.polyline_points.add() + polyline_point = polyline_points.add() polyline_point.x = x polyline_point.y = y polyline_point.z = z @@ -137,32 +143,35 @@ class Snap(bonsai.core.tool.Snap): @classmethod def close_polyline(cls): - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - if len(polyline_data) > 2: - first_point = polyline_data[0] - last_point = polyline_data[-1] + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] + if len(polyline_points) > 2: + first_point = polyline_points[0] + last_point = polyline_points[-1] if not (first_point.x == last_point.x and first_point.y == last_point.y and first_point.z == last_point.z): - polyline_point = bpy.context.scene.BIMPolylineProperties.polyline_points.add() + polyline_point = polyline_points.add() polyline_point.x = first_point.x polyline_point.y = first_point.y polyline_point.z = first_point.z @classmethod def clear_polyline(cls): - bpy.context.scene.BIMPolylineProperties.polyline_points.clear() + bpy.context.scene.BIMPolylineProperties.insertion_polyline.clear() @classmethod def remove_last_polyline_point(cls): - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - polyline_data.remove(len(polyline_data) - 1) + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] + polyline_points.remove(len(polyline_points) - 1) @classmethod def move_polyline_to_measure(cls, context, input_ui): - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] measurement_data = bpy.context.scene.BIMPolylineProperties.measurement_polyline.add() measurement_type = bpy.context.scene.MeasureToolSettings.measure_type measurement_data.measurement_type = measurement_type - for point in polyline_data: + for point in polyline_points: measurement_point = measurement_data.polyline_points.add() measurement_point.x = point.x measurement_point.y = point.y @@ -221,9 +230,10 @@ class Snap(bonsai.core.tool.Snap): return (v1, v2, v3, v4) default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - if polyline_data: - last_point_data = polyline_data[-1] + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if len(polyline_data) > 0 else [] + if polyline_points: + last_point_data = polyline_points[-1] last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z)) else: last_point = Vector((0, 0, default_container_elevation)) @@ -400,11 +410,13 @@ class Snap(bonsai.core.tool.Snap): detected_snaps.append({"Edge-Vertex": (obj, snap_point)}) # Polyline try: - polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points - last_polyline_point = polyline_data[len(polyline_data) - 1] + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline[0] + polyline_points = polyline_data.polyline_points + last_polyline_point = polyline_points[len(polyline_points) - 1] except: + polyline_points = [] last_polyline_point = None - if polyline_data: + if polyline_points: snap_points = tool.Raycast.ray_cast_to_polyline(context, event) if snap_points: detected_snaps.append({"Polyline": snap_points})