From cf054e11a18dbe6ebf32bce93855c25c41308c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 15:52:33 -0300 Subject: [PATCH] Refactor: improve preview decorators for other products, following 420a4cfdc --- .../bonsai/bim/module/model/decorator.py | 213 +---------- .../bonsai/bim/module/model/polyline.py | 350 ++++++++++++++++-- src/bonsai/bonsai/bim/module/model/product.py | 2 + src/bonsai/bonsai/bim/module/model/prop.py | 4 +- src/bonsai/bonsai/bim/module/model/wall.py | 2 + 5 files changed, 342 insertions(+), 229 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 5e3fc70e06..a11bd6efff 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -25,15 +25,14 @@ import bmesh import ifcopenshell import bonsai.tool as tool import math -from math import sin, cos, tan, radians, atan2 +from math import sin, cos, radians from bpy.types import SpaceView3D from bpy_extras import view3d_utils -from mathutils import Vector, Matrix, Quaternion +from mathutils import Vector, Matrix from gpu_extras.batch import batch_for_shader from gpu_extras.presets import draw_circle_2d from typing import Union from bonsai.bim.module.drawing.helper import format_distance -from bonsai.bim.module.geometry.decorator import ItemDecorator def transparent_color(color, alpha=0.1): @@ -803,191 +802,12 @@ class ProductDecorator: shader.uniform_float("color", color) batch.draw(shader) - def get_wall_preview_data(cls, context, relating_type): - def create_bmesh_from_vertices(vertices): - bm = bmesh.new() - - new_verts = [bm.verts.new(v) for v in polyline_vertices] - if is_closed: - new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] - new_edges.append( - bm.edges.new((new_verts[-1], new_verts[0])) - ) # Add an edge between the last an first point to make it closed. - else: - new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] - - bm.verts.index_update() - bm.edges.index_update() - return bm - - # Get properties from object type - layers = tool.Model.get_material_layer_parameters(relating_type) - if not layers["thickness"]: - return - thickness = layers["thickness"] - model_props = context.scene.BIMModelProperties - direction_sense = model_props.direction_sense - direction = 1 - if direction_sense == "NEGATIVE": - direction = -1 - offset_type = model_props.offset_type - offset = 0 - if offset_type == "CENTER": - offset = -thickness / 2 - elif offset_type == "INTERIOR": - offset = -thickness - - unit_system = tool.Drawing.get_unit_system() - factor = 1 - if unit_system == "IMPERIAL": - factor = 3.048 - if unit_system == "METRIC": - unit_length = context.scene.unit_settings.length_unit - if unit_length == "MILLIMETERS": - factor = 1000 - - # For the model properties, the offset value should just be converted - # However, for the wall preview logic that follows, offset and thickness must change direction - model_props.offset = offset * factor - thickness *= direction - offset *= direction - - height = float(model_props.extrusion_depth) - rl = float(model_props.rl1) - x_angle = float(model_props.x_angle) - angle_distortion = height * tan(x_angle) - - wall_preview_data = {} - wall_preview_data["verts"] = [] - - # Verts - polyline_vertices = [] - polyline_data = context.scene.BIMPolylineProperties.insertion_polyline - polyline_points = polyline_data[0].polyline_points if polyline_data else [] - if len(polyline_points) < 2: - wall_preview_data = [] - return - for point in polyline_points: - polyline_vertices.append(Vector((point.x, point.y, point.z))) - - is_closed = False - if ( - polyline_vertices[0].x == polyline_vertices[-1].x - and polyline_vertices[0].y == polyline_vertices[-1].y - and polyline_vertices[0].z == polyline_vertices[-1].z - ): - is_closed = True - polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. - - bm_base = create_bmesh_from_vertices(polyline_vertices) - base_vertices = tool.Cad.offset_edges(bm_base, offset) - offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset) - top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset) - offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset) - if is_closed: - base_vertices.append(base_vertices[0]) - offset_base_verts.append(offset_base_verts[0]) - top_vertices.append(top_vertices[0]) - offset_top_verts.append(offset_top_verts[0]) - - if offset_base_verts is not None: - for v in base_vertices: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) - - for v in offset_base_verts[::-1]: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) - - for v in top_vertices: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) - - for v in offset_top_verts[::-1]: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) - - bm_base.free() - - # Edges and Tris - points = [] - side_edges_1 = [] - side_edges_2 = [] - base_edges = [] - - for i in range(len(wall_preview_data["verts"])): - points.append(Vector(wall_preview_data["verts"][i])) - - n = len(points) // 2 - bottom_side_1 = [[i, (i + 1) % (n)] for i in range((n - 1) // 2)] - bottom_side_2 = [[i, (i + 1) % (n)] for i in range(n // 2, n - 1)] - bottom_connections = [[i, n - i - 1] for i in range(n // 2)] - bottom_loop = bottom_connections + bottom_side_1 + bottom_side_2 - side_edges_1.extend(bottom_side_1) - side_edges_2.extend(bottom_side_2) - base_edges.extend(bottom_loop) - - upper_side_1 = [[i + n for i in edges] for edges in bottom_side_1] - upper_side_2 = [[i + n for i in edges] for edges in bottom_side_2] - upper_loop = [[i + n for i in edges] for edges in bottom_loop] - side_edges_1.extend(upper_side_1) - side_edges_2.extend(upper_side_2) - base_edges.extend(upper_loop) - - loops = [side_edges_1, side_edges_2, base_edges] - - wall_preview_data["edges"] = [] - wall_preview_data["tris"] = [] - for i, group in enumerate(loops): - bm = bmesh.new() - - new_verts = [bm.verts.new(v) for v in points] - new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in group] - - bm.verts.index_update() - bm.edges.index_update() - - if i == 2: - new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) - new_faces = bmesh.ops.bridge_loops(bm, edges=bm.edges, use_pairs=True, use_cyclic=True) - - bm.verts.index_update() - bm.edges.index_update() - edges = [[v.index for v in e.verts] for e in bm.edges] - tris = [[l.vert.index for l in loop] for loop in bm.calc_loop_triangles()] - wall_preview_data["edges"].extend(edges) - wall_preview_data["tris"].extend(tris) - - wall_preview_data["edges"] = list(set(tuple(e) for e in wall_preview_data["edges"])) - wall_preview_data["tris"] = list(set(tuple(t) for t in wall_preview_data["tris"])) - - return wall_preview_data - - def get_product_preview_data(cls, context, relating_type): - model_props = context.scene.BIMModelProperties - if relating_type.is_a("IfcDoorType"): - rl = float(model_props.rl1) - elif relating_type.is_a("IfcWindowType"): - rl = float(model_props.rl2) - else: - rl = 0 - snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] - mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) - snap_obj = bpy.data.objects.get(snap_prop.snap_object) - snap_element = tool.Ifc.get_entity(snap_obj) - rot_mat = Quaternion() - if snap_element and snap_element.is_a("IfcWall"): - rot_mat = snap_obj.matrix_world.to_quaternion() - - obj_type = tool.Ifc.get_object(relating_type) - if obj_type.data: - data = ItemDecorator.get_obj_data(obj_type) - data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]] - data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point) for v in data["verts"]] - return data - - def get_profile_preview_data(self, context): + def get_product_preview_data(self, context): props = context.scene.BIMProductPreviewProperties data = {} - data["verts"] = [(*v.value,) for v in props.verts] - data["edges"] = [(int(e.tvalue[0]),int(e.tvalue[1])) for e in props.edges] - data["tris"] = [(int(t.value[0]), int(t.value[1]), int(t.value[2])) for t in props.tris] + data["verts"] = [(*v.value_3d,) for v in props.verts] + data["edges"] = [(int(e.value_2d[0]),int(e.value_2d[1])) for e in props.edges] + data["tris"] = [(int(t.value_3d[0]), int(t.value_3d[1]), int(t.value_3d[2])) for t in props.tris] return data def draw_product_preview(self, context): @@ -1014,26 +834,7 @@ class ProductDecorator: else: return - # Wall - if self.relating_type.is_a("IfcWallType"): - wall_preview_data = self.get_wall_preview_data(context, self.relating_type) - if wall_preview_data: - self.draw_batch("LINES", wall_preview_data["verts"], decorator_color, wall_preview_data["edges"]) - self.draw_batch( - "TRIS", wall_preview_data["verts"], transparent_color(decorator_color), wall_preview_data["tris"] - ) - - # Mesh type products - product_preview_data = self.get_product_preview_data(context, self.relating_type) - if product_preview_data: - self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) - self.draw_batch( - "TRIS", product_preview_data["verts"], transparent_color(decorator_color), product_preview_data["tris"] - ) - - # Profile type products - self.line_shader.uniform_float("lineWidth", 0.5) - product_preview_data = self.get_profile_preview_data(context) + product_preview_data = self.get_product_preview_data(context) if product_preview_data: self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) self.draw_batch( diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 168f0af08f..fbaa088003 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -35,15 +35,282 @@ import bonsai.core.geometry import bonsai.core.model as core import bonsai.tool as tool from bonsai.bim.ifc import IfcStore -from math import pi, sin, cos, degrees -from mathutils import Vector, Matrix +from math import pi, sin, cos, degrees, tan +from mathutils import Vector, Matrix, Quaternion from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.decorator import PolylineDecorator +from bonsai.bim.module.geometry.decorator import ItemDecorator from typing import Optional, Union, Literal from lark import Lark, Transformer -def get_profile_preview_data(context, relating_type): +def get_wall_preview_data(context, relating_type): + def create_bmesh_from_vertices(vertices): + bm = bmesh.new() + + new_verts = [bm.verts.new(v) for v in polyline_vertices] + if is_closed: + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] + new_edges.append( + bm.edges.new((new_verts[-1], new_verts[0])) + ) # Add an edge between the last an first point to make it closed. + else: + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] + + bm.verts.index_update() + bm.edges.index_update() + return bm + + # Get properties from object type + layers = tool.Model.get_material_layer_parameters(relating_type) + if not layers["thickness"]: + return + thickness = layers["thickness"] + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + direction = 1 + if direction_sense == "NEGATIVE": + direction = -1 + offset_type = model_props.offset_type + offset = 0 + if offset_type == "CENTER": + offset = -thickness / 2 + elif offset_type == "INTERIOR": + offset = -thickness + + unit_system = tool.Drawing.get_unit_system() + factor = 1 + if unit_system == "IMPERIAL": + factor = 3.048 + if unit_system == "METRIC": + unit_length = context.scene.unit_settings.length_unit + if unit_length == "MILLIMETERS": + factor = 1000 + + # For the model properties, the offset value should just be converted + # However, for the wall preview logic that follows, offset and thickness must change direction + model_props.offset = offset * factor + thickness *= direction + offset *= direction + + height = float(model_props.extrusion_depth) + rl = float(model_props.rl1) + x_angle = float(model_props.x_angle) + angle_distortion = height * tan(x_angle) + + data = {} + data["verts"] = [] + + # Verts + polyline_vertices = [] + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if polyline_data else [] + if len(polyline_points) < 2: + data = [] + return + for point in polyline_points: + polyline_vertices.append(Vector((point.x, point.y, point.z))) + + is_closed = False + if ( + polyline_vertices[0].x == polyline_vertices[-1].x + and polyline_vertices[0].y == polyline_vertices[-1].y + and polyline_vertices[0].z == polyline_vertices[-1].z + ): + is_closed = True + polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. + + bm_base = create_bmesh_from_vertices(polyline_vertices) + base_vertices = tool.Cad.offset_edges(bm_base, offset) + offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset) + top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset) + offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset) + if is_closed: + base_vertices.append(base_vertices[0]) + offset_base_verts.append(offset_base_verts[0]) + top_vertices.append(top_vertices[0]) + offset_top_verts.append(offset_top_verts[0]) + + if offset_base_verts is not None: + for v in base_vertices: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) + + for v in offset_base_verts[::-1]: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) + + for v in top_vertices: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) + + for v in offset_top_verts[::-1]: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) + + bm_base.free() + + # Edges and Tris + points = [] + side_edges_1 = [] + side_edges_2 = [] + base_edges = [] + + for i in range(len(data["verts"])): + points.append(Vector(data["verts"][i])) + + n = len(points) // 2 + bottom_side_1 = [[i, (i + 1) % (n)] for i in range((n - 1) // 2)] + bottom_side_2 = [[i, (i + 1) % (n)] for i in range(n // 2, n - 1)] + bottom_connections = [[i, n - i - 1] for i in range(n // 2)] + bottom_loop = bottom_connections + bottom_side_1 + bottom_side_2 + side_edges_1.extend(bottom_side_1) + side_edges_2.extend(bottom_side_2) + base_edges.extend(bottom_loop) + + upper_side_1 = [[i + n for i in edges] for edges in bottom_side_1] + upper_side_2 = [[i + n for i in edges] for edges in bottom_side_2] + upper_loop = [[i + n for i in edges] for edges in bottom_loop] + side_edges_1.extend(upper_side_1) + side_edges_2.extend(upper_side_2) + base_edges.extend(upper_loop) + + loops = [side_edges_1, side_edges_2, base_edges] + + data["edges"] = [] + data["tris"] = [] + for i, group in enumerate(loops): + bm = bmesh.new() + + new_verts = [bm.verts.new(v) for v in points] + new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in group] + + bm.verts.index_update() + bm.edges.index_update() + + if i == 2: + new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) + new_faces = bmesh.ops.bridge_loops(bm, edges=bm.edges, use_pairs=True, use_cyclic=True) + + bm.verts.index_update() + bm.edges.index_update() + edges = [[v.index for v in e.verts] for e in bm.edges] + tris = [[l.vert.index for l in loop] for loop in bm.calc_loop_triangles()] + data["edges"].extend(edges) + data["tris"].extend(tris) + + data["edges"] = list(set(tuple(e) for e in data["edges"])) + data["tris"] = list(set(tuple(t) for t in data["tris"])) + + return data + +def get_vertical_profile_preview_data(context, relating_type): + material = ifcopenshell.util.element.get_material(relating_type) + try: + profile = material.MaterialProfiles[0].Profile + except: + return {} + + model_props = context.scene.BIMModelProperties + extrusion_depth = model_props.extrusion_depth + cardinal_point = model_props.cardinal_point + rot_mat = Quaternion() + if relating_type.is_a("IfcBeamType"): + y_rot = Quaternion((0.0, 1.0, 0.0), radians(90)) + z_rot = Quaternion((0.0, 0.0, 1.0), radians(90)) + rot_mat = y_rot @ z_rot + # Get profile data + settings = ifcopenshell.geom.settings() + settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) + shape = ifcopenshell.geom.create_shape(settings, profile) + + verts = shape.verts + if not verts: + raise RuntimeError("Profile shape has no vertices, it probably is invalid.") + + edges = shape.edges + + grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)] + grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)] + + # Create offsets based on cardinal point + min_x = min(v[0] for v in grouped_verts) + max_x = max(v[0] for v in grouped_verts) + min_y = min(v[1] for v in grouped_verts) + max_y = max(v[1] for v in grouped_verts) + + x_offset = (max_x - min_x) / 2 + y_offset = (max_y - min_y) / 2 + + match cardinal_point: + case "1": + grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "2": + grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts] + case "3": + grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "4": + grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts] + case "5": + grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts] + case "6": + grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts] + case "7": + grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + case "8": + grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts] + case "9": + grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + + # Create extrusion bmesh + bm = bmesh.new() + + grouped_verts.append(grouped_verts[0]) # Close profile + new_verts = [bm.verts.new(v) for v in grouped_verts] + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(grouped_verts) - 1)] + + bm.verts.index_update() + bm.edges.index_update() + + bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) + + new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) + + new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.faces, use_dissolve_ortho_edges=True) + new_verts = [e for e in new_faces["geom"] if isinstance(e, bmesh.types.BMVert)] + new_faces = bmesh.ops.translate(bm, verts=new_verts, vec=(0.0, 0.0, extrusion_depth)) + + bm.verts.index_update() + bm.edges.index_update() + tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] + + # Calculate rotation, mouse position, angle and cardinal point + snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] + mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) + data = {} + + verts = [tuple(v.co) for v in bm.verts] + verts = [tuple(rot_mat @ Vector(v)) for v in verts] + verts = [tuple(Vector(v) + mouse_point) for v in verts] + min_z = min(v.co.z for v in bm.verts) + max_z = max(v.co.z for v in bm.verts) + # Add axis verts + verts.append(tuple(mouse_point)) + verts.append(tuple(mouse_point + Vector((0, 0, max_z)))) + # Add only profile edges + edges = [] + for edge in bm.edges: + if (edge.verts[0].co.z == min_z and edge.verts[1].co.z == min_z) or (edge.verts[0].co.z == max_z and edge.verts[1].co.z == max_z): + edges.append(edge) + # Add axis edge + edges = [(edge.verts[0].index, edge.verts[1].index) for edge in edges] + edges.append((len(verts)-1, len(verts)-2)) + data["verts"] = verts + data["edges"] = edges + data["tris"] = tris + + bm.free() + + return data + + +def get_horizontal_profile_preview_data(context, relating_type): material = ifcopenshell.util.element.get_material(relating_type) try: profile_curve = material.MaterialProfiles[0].Profile @@ -169,24 +436,37 @@ def get_profile_preview_data(context, relating_type): data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] data["tris"] = tris - # Update properties so it can be used by the decorator - props = context.scene.BIMProductPreviewProperties - props.verts.clear() - props.edges.clear() - props.tris.clear() - - for vert in data["verts"]: - v = props.verts.add() - v.value = vert - for edge in data["edges"]: - e = props.edges.add() - e.tvalue = edge - for tri in data["tris"]: - t = props.tris.add() - t.value = tri - bm.free() + return data + + +def get_product_preview_data(context, relating_type): + model_props = context.scene.BIMModelProperties + if relating_type.is_a("IfcDoorType"): + rl = float(model_props.rl1) + elif relating_type.is_a("IfcWindowType"): + rl = float(model_props.rl2) + else: + rl = 0 + snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] + default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z + mouse_point = Vector((snap_prop.x, snap_prop.y, default_container_elevation)) + snap_obj = bpy.data.objects.get(snap_prop.snap_object) + snap_element = tool.Ifc.get_entity(snap_obj) + rot_mat = Quaternion() + if snap_element and snap_element.is_a("IfcWall"): + rot_mat = snap_obj.matrix_world.to_quaternion() + + obj_type = tool.Ifc.get_object(relating_type) + if obj_type.data: + data = ItemDecorator.get_obj_data(obj_type) + data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]] + data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point) for v in data["verts"]] + + return data + + class PolylineOperator: # TODO Fill doc strings """ """ @@ -532,8 +812,36 @@ class PolylineOperator: tool.Blender.update_viewport() def get_product_preview_data(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_isntance): - if relating_type.is_a() in ["IfcBeamType", "IfcCoveringType", "IfcMemberType"]: - return get_profile_preview_data(context, relating_type) + if ( + tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() not in {"IfcColumnType"} + ): + data = get_horizontal_profile_preview_data(context, relating_type) + elif ( + tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() in {"IfcColumnType"} + ): + data = get_vertical_profile_preview_data(context, relating_type) + elif tool.Model.get_usage_type(relating_type) == "LAYER2": + data = get_wall_preview_data(context, relating_type) + else: + data = get_product_preview_data(context, relating_type) + + # Update properties so it can be used by the decorator + if not data: + return + props = context.scene.BIMProductPreviewProperties + props.verts.clear() + props.edges.clear() + props.tris.clear() + + for vert in data["verts"]: + v = props.verts.add() + v.value_3d = vert + for edge in data["edges"]: + e = props.edges.add() + e.value_2d = edge + for tri in data["tris"]: + t = props.tris.add() + t.value_3d = tri def modal(self, context: bpy.types.Context, event: bpy.types.Event) -> Union[set[str], None]: PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0]) diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index efa39f3cbe..b4bec77d48 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -191,6 +191,8 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): if event.value == "RELEASE" and event.type == "LEFTMOUSE": self.create_occurrence(context, event) + self.get_product_preview_data(context, self.relating_type) + cancel = self.handle_cancelation(context, event) if cancel is not None: ProductDecorator.uninstall() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 7809d5b2d1..bda91f79f3 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -822,8 +822,8 @@ class BIMPolylineProperties(PropertyGroup): measurement_polyline: bpy.props.CollectionProperty(type=Polyline) class ProductPreviewItem(PropertyGroup): - value: bpy.props.FloatVectorProperty() - tvalue: bpy.props.FloatVectorProperty(size=2) + value_3d: bpy.props.FloatVectorProperty() + value_2d: bpy.props.FloatVectorProperty(size=2) class BIMProductPreviewProperties(PropertyGroup): verts: bpy.props.CollectionProperty(type=ProductPreviewItem) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 88db7f3a26..1988ab7864 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -421,6 +421,8 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): self.handle_inserting_polyline(context, event) + self.get_product_preview_data(context, self.relating_type) + cancel = self.handle_cancelation(context, event) if cancel is not None: ProductDecorator.uninstall()