From 47e6352350835a72b9394e18a77fffa9ad1c00c1 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Feb 2023 18:45:53 +1100 Subject: [PATCH] Don't create temporary objs when updating filling openings. --- .../blenderbim/bim/module/model/opening.py | 170 +++++------------- 1 file changed, 43 insertions(+), 127 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 0749708a24..07a0d124b8 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -21,12 +21,14 @@ import gpu import bgl import bmesh import logging -import blenderbim.bim.handler +import numpy as np import ifcopenshell +import ifcopenshell.util.shape_builder import ifcopenshell.util.representation import blenderbim.tool as tool import blenderbim.core.geometry import blenderbim.bim.import_ifc as import_ifc +import blenderbim.bim.handler from blenderbim.bim.ifc import IfcStore from math import pi from mathutils import Vector, Matrix @@ -112,30 +114,21 @@ class FilledOpeningGenerator: "geometry.assign_representation", tool.Ifc.get(), product=opening, representation=mapped_representation ) else: - has_visible_openings = self.has_visible_openings(element) - opening_obj = self.generate_opening_from_filling(filling, filling_obj, voided_obj) - opening = blenderbim.core.root.assign_class( - tool.Ifc, - tool.Collector, - tool.Root, - obj=opening_obj, - ifc_class="IfcOpeningElement", - should_add_representation=True, - context=ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body"), + representation = self.generate_opening_from_filling(filling, filling_obj, voided_obj) + opening = ifcopenshell.api.run( + "root.create_entity", tool.Ifc.get(), ifc_class="IfcOpeningElement", predefined_type="OPENING" + ) + + matrix = np.array(filling_obj.matrix_world) + ifcopenshell.api.run( + "geometry.edit_object_placement", tool.Ifc.get(), product=opening, matrix=matrix, is_si=True ) - representation = ifcopenshell.util.representation.get_representation(opening, "Model", "Body", "MODEL_VIEW") mapped_representation = ifcopenshell.api.run( "geometry.map_representation", tool.Ifc.get(), representation=representation ) - ifcopenshell.api.run( - "geometry.unassign_representation", tool.Ifc.get(), product=opening, representation=representation - ) ifcopenshell.api.run( "geometry.assign_representation", tool.Ifc.get(), product=opening, representation=mapped_representation ) - if not has_visible_openings: - tool.Ifc.unlink(obj=opening_obj) - bpy.data.objects.remove(opening_obj) ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=opening, element=element) ifcopenshell.api.run("void.add_filling", tool.Ifc.get(), opening=opening, element=filling) @@ -165,6 +158,7 @@ class FilledOpeningGenerator: ifcopenshell.api.run( "geometry.unassign_representation", tool.Ifc.get(), product=opening, representation=opening_rep ) + ifcopenshell.api.run("geometry.remove_representation", tool.Ifc.get(), representation=opening_rep) existing_opening_occurrence = self.get_existing_opening_occurrence_if_any(filling) @@ -186,32 +180,13 @@ class FilledOpeningGenerator: bpy.data.objects.remove(opening_obj) filling_obj = tool.Ifc.get_object(filling) - opening_obj = self.generate_opening_from_filling(filling, filling_obj, voided_obj) - tool.Ifc.link(opening, opening_obj) - - representation = ifcopenshell.api.run( - "geometry.add_representation", - tool.Ifc.get(), - context=ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body"), - blender_object=opening_obj, - geometry=opening_obj.data, - coordinate_offset=tool.Geometry.get_cartesian_point_coordinate_offset(opening_obj), - total_items=tool.Geometry.get_total_representation_items(opening_obj), - should_force_faceted_brep=tool.Geometry.should_force_faceted_brep(), - should_force_triangulation=tool.Geometry.should_force_triangulation(), - should_generate_uvs=tool.Geometry.should_generate_uvs(opening_obj), - ifc_representation_class=None, - profile_set_usage=None, - ) - + representation = self.generate_opening_from_filling(filling, filling_obj, voided_obj) mapped_representation = ifcopenshell.api.run( "geometry.map_representation", tool.Ifc.get(), representation=representation ) ifcopenshell.api.run( "geometry.assign_representation", tool.Ifc.get(), product=opening, representation=mapped_representation ) - tool.Ifc.unlink(obj=opening_obj) - bpy.data.objects.remove(opening_obj) representation = tool.Ifc.get().by_id(voided_obj.data.BIMMeshProperties.ifc_definition_id) blenderbim.core.geometry.switch_representation( @@ -225,10 +200,37 @@ class FilledOpeningGenerator: ) def generate_opening_from_filling(self, filling, filling_obj, voided_obj): - profile = ifcopenshell.util.representation.get_representation(filling, "Model", "Profile", "ELEVATION_VIEW") + thickness = voided_obj.dimensions[1] + 0.1 + 0.1 + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + shape_builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) + + profile = None + filling_type = ifcopenshell.util.element.get_type(filling) + if filling_type: + profile = ifcopenshell.util.representation.get_representation( + filling_type, "Model", "Profile", "ELEVATION_VIEW" + ) + filling_obj = tool.Ifc.get_object(filling_type) + context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") + if profile: - return self.generate_opening_from_filling_profile(filling_obj, voided_obj, profile) - return self.generate_opening_from_filling_box(filling_obj, voided_obj) + extrusion = shape_builder.extrude( + ifcopenshell.util.representation.resolve_representation(profile).Items[0], + magnitude=thickness / unit_scale, + position=Vector([0.0, -0.1 / unit_scale, 0.0]), + extrusion_vector=Vector([0.0, 1.0, 0.0]), + ) + return shape_builder.get_representation(context, [extrusion]) + + x, y, z = filling_obj.dimensions + extrusion = shape_builder.extrude( + shape_builder.rectangle(size=Vector([x, 0.0, z])), + magnitude=thickness / unit_scale, + position=Vector([0.0, -0.1 / unit_scale, 0.0]), + extrusion_vector=Vector([0.0, 1.0, 0.0]), + ) + + return shape_builder.get_representation(context, [extrusion]) def has_visible_openings(self, element): for opening in [r.RelatedOpeningElement for r in element.HasOpenings]: @@ -244,92 +246,6 @@ class FilledOpeningGenerator: if filling_occurrence != filling and filling_occurrence.FillsVoids: return filling_occurrence.FillsVoids[0].RelatingOpeningElement - def generate_opening_from_filling_profile(self, filling_obj, voided_obj, profile): - settings = ifcopenshell.geom.settings() - settings.set(settings.INCLUDE_CURVES, True) - shape = ifcopenshell.geom.create_shape(settings, profile) - verts = shape.verts - edges = shape.edges - grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)] - grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)] - - bm = bmesh.new() - bm.verts.index_update() - bm.edges.index_update() - new_verts = [bm.verts.new(v) for v in grouped_verts] - new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in grouped_edges] - - bm.verts.index_update() - bm.edges.index_update() - - bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-5) - bmesh.ops.triangle_fill(bm, edges=bm.edges) - bmesh.ops.dissolve_limit(bm, angle_limit=pi, verts=bm.verts, edges=bm.edges) - - bmesh.ops.translate(bm, vec=[0.0, -0.1, 0.0], verts=bm.verts) - extrusion = bmesh.ops.extrude_face_region(bm, geom=bm.faces) - extruded_verts = [g for g in extrusion["geom"] if isinstance(g, bmesh.types.BMVert)] - bmesh.ops.translate(bm, vec=[0.0, voided_obj.dimensions[1] + 0.1 + 0.1, 0.0], verts=extruded_verts) - - mesh = bpy.data.meshes.new(name="Opening") - bm.to_mesh(mesh) - bm.free() - - obj = bpy.data.objects.new("Opening", mesh) - obj.matrix_world = filling_obj.matrix_world - return obj - - def generate_opening_from_filling_box(self, filling_obj, voided_obj): - x, y, z = filling_obj.dimensions - dimension = min(voided_obj.dimensions) - if dimension == voided_obj.dimensions[0]: - verts = [ - Vector((-0.1, 0, 0)), - Vector((-0.1, 0, z)), - Vector((-0.1, y, 0)), - Vector((-0.1, y, z)), - Vector((dimension + 0.1, 0, 0)), - Vector((dimension + 0.1, 0, z)), - Vector((dimension + 0.1, y, 0)), - Vector((dimension + 0.1, y, z)), - ] - elif dimension == voided_obj.dimensions[1]: - verts = [ - Vector((0, -0.1, 0)), - Vector((0, -0.1, z)), - Vector((0, dimension + 0.1, 0)), - Vector((0, dimension + 0.1, z)), - Vector((x, -0.1, 0)), - Vector((x, -0.1, z)), - Vector((x, dimension + 0.1, 0)), - Vector((x, dimension + 0.1, z)), - ] - elif dimension == voided_obj.dimensions[2]: - verts = [ - Vector((0, 0, -0.1)), - Vector((0, 0, dimension + 0.1)), - Vector((0, y, -0.1)), - Vector((0, y, dimension + 0.1)), - Vector((x, 0, -0.1)), - Vector((x, 0, dimension + 0.1)), - Vector((x, y, -0.1)), - Vector((x, y, dimension + 0.1)), - ] - edges = [] - faces = [ - [0, 1, 3, 2], - [2, 3, 7, 6], - [6, 7, 5, 4], - [4, 5, 1, 0], - [2, 6, 4, 0], - [7, 3, 1, 5], - ] - mesh = bpy.data.meshes.new(name="Opening") - mesh.from_pydata(verts, edges, faces) - obj = bpy.data.objects.new("Opening", mesh) - obj.matrix_world = filling_obj.matrix_world - return obj - class RecalculateFill(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.recalculate_fill"