From 4f77df99a595e47a72d16e33b5a5f902ffd7fdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 23 Jan 2025 11:35:01 -0300 Subject: [PATCH] Add slab preview decorator --- .../bonsai/bim/module/model/polyline.py | 88 +++++++++++++++---- src/bonsai/bonsai/bim/module/model/slab.py | 2 + 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 1eb4bc2baa..fb4940918e 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -43,24 +43,23 @@ from bonsai.bim.module.geometry.decorator import ItemDecorator from typing import Optional, Union, Literal from lark import Lark, Transformer +def create_bmesh_from_vertices(vertices, is_closed=False): + bm = bmesh.new() + + new_verts = [bm.verts.new(v) for v in 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 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"]: @@ -105,7 +104,7 @@ def get_wall_preview_data(context, relating_type): 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) + bm_base = create_bmesh_from_vertices(polyline_vertices, is_closed) 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) @@ -185,6 +184,55 @@ def get_wall_preview_data(context, relating_type): return data +def get_slab_preview_data(context, relating_type): + props = context.scene.BIMModelProperties + x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle + layers = tool.Model.get_material_layer_parameters(relating_type) + if not layers["thickness"]: + return + thickness = layers["thickness"] + 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) < 3: + data = [] + return + for point in polyline_points: + polyline_vertices.append(Vector((point.x, point.y, point.z))) + if x_angle: + # Get vertices relative to the first polyline point as origin + local_vertices = [v - Vector(polyline_vertices[0]) for v in polyline_vertices] + # Make the transformation relative to the x_angle + transformed_vertices = [Vector((v.x, v.y * (1 / cos(x_angle)), v.z)) for v in local_vertices] + # Convert back to world origin + polyline_vertices = [v + Vector(polyline_vertices[0]) for v in transformed_vertices] + is_closed = True + 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 + ): + polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. + bm = create_bmesh_from_vertices(polyline_vertices, is_closed) + bm.verts.ensure_lookup_table() + if x_angle: + bmesh.ops.rotate(bm, cent=Vector(bm.verts[0].co), verts=bm.verts, matrix=Matrix.Rotation(x_angle, 3, 'X')) + new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) + new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.edges[:] + bm.faces[:]) + 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, thickness)) + bm.verts.index_update() + bm.edges.index_update() + verts = [tuple(v.co) for v in bm.verts] + edges = [[v.index for v in e.verts] for e in bm.edges] + tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] + data["verts"] = verts + data["edges"] = edges + data["tris"] = tris + return data def get_vertical_profile_preview_data(context, relating_type): material = ifcopenshell.util.element.get_material(relating_type) @@ -428,7 +476,7 @@ def get_horizontal_profile_preview_data(context, relating_type): return data -def get_product_preview_data(context, relating_type): +def get_generic_product_preview_data(context, relating_type): model_props = context.scene.BIMModelProperties if relating_type.is_a("IfcDoorType"): rl = float(model_props.rl1) @@ -820,8 +868,10 @@ class PolylineOperator: 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) + elif tool.Model.get_usage_type(relating_type) == "LAYER3": + data = get_slab_preview_data(context, relating_type) else: - data = get_product_preview_data(context, relating_type) + data = get_generic_product_preview_data(context, relating_type) # Update properties so it can be used by the decorator if not data: diff --git a/src/bonsai/bonsai/bim/module/model/slab.py b/src/bonsai/bonsai/bim/module/model/slab.py index 2d02155ab1..43db73b3c6 100644 --- a/src/bonsai/bonsai/bim/module/model/slab.py +++ b/src/bonsai/bonsai/bim/module/model/slab.py @@ -926,6 +926,8 @@ class DrawPolylineSlab(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()