diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 7a6a66cb53..384eb18e73 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -123,11 +123,45 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} def generate_opening_from_filling(self, filling, filling_obj, voided_obj): + filling_type = ifcopenshell.util.element.get_type(filling) + if filling_type: + for filling_occurrence in ifcopenshell.util.element.get_types(filling_type): + if filling_occurrence == filling or not filling_occurence.FillsVoids: + continue + return self.generate_opening_from_existing_filling_occurrence(filling_occurrence, filling_obj) + profile = ifcopenshell.util.representation.get_representation(filling, "Model", "Profile", "ELEVATION_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) + def generate_opening_from_existing_filling_occurrence(self, filling_occurrence, filling_obj): + for rel in getattr(filling_occurrence, "FillsVoids", []) or []: + settings = ifcopenshell.geom.settings() + + shape = ifcopenshell.geom.create_shape(settings, rel.RelatingOpeningElement) + verts = shape.geometry.verts + faces = shape.geometry.faces + grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)] + grouped_faces = [[faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)] + + bm = bmesh.new() + bm.verts.index_update() + bm.faces.index_update() + new_verts = [bm.verts.new(v) for v in grouped_verts] + new_faces = [bm.faces.new((new_verts[f[0]], new_verts[f[1]], new_verts[f[2]])) for f in grouped_faces] + + bm.verts.index_update() + bm.faces.index_update() + + 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_profile(self, filling_obj, voided_obj, profile): settings = ifcopenshell.geom.settings() settings.set(settings.INCLUDE_CURVES, True) diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index 82a9b2fada..07b736ef46 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -126,19 +126,13 @@ class SelectSimilarType(bpy.types.Operator): def execute(self, context): self.file = IfcStore.get_file() related_object = bpy.data.objects.get(self.related_object) if self.related_object else context.active_object - oprops = related_object.BIMObjectProperties - product = self.file.by_id(oprops.ifc_definition_id) - declaration = IfcStore.get_schema().declaration_by_name(product.is_a()) - if ifcopenshell.util.schema.is_a(declaration, "IfcElementType"): - related_objects = ifcopenshell.api.run( - "type.get_related_objects", self.file, **{"relating_type": self.file.by_id(oprops.ifc_definition_id)} - ) - else: - related_objects = ifcopenshell.api.run( - "type.get_related_objects", self.file, **{"related_object": self.file.by_id(oprops.ifc_definition_id)} - ) + relating_type = ifcopenshell.util.element.get_type(tool.Ifc.get_entity(related_object)) + if not relating_type: + return {"FINISHED"} + related_objects = ifcopenshell.util.element.get_types(relating_type) for obj in context.visible_objects: - if obj.BIMObjectProperties.ifc_definition_id in related_objects: + element = tool.Ifc.get_entity(obj) + if element and element in related_objects: obj.select_set(True) return {"FINISHED"} diff --git a/src/blenderbim/test/bim/feature/type.feature b/src/blenderbim/test/bim/feature/type.feature index 3636e75927..3cb1870954 100644 --- a/src/blenderbim/test/bim/feature/type.feature +++ b/src/blenderbim/test/bim/feature/type.feature @@ -148,3 +148,26 @@ Scenario: Select type objects When the object "IfcWallType/Empty" is selected And I press "bim.select_type_objects" Then the object "IfcWall/Cube" is selected + +Scenario: Select similar type + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" + And I press "bim.assign_class" + And I add a cube + And the object "Cube" is selected + And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" + And I press "bim.assign_class" + And I add an empty + And the object "Empty" is selected + And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType" + And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType" + And I press "bim.assign_class" + And the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()" + And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')" + And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube.001')" + When the object "IfcWall/Cube" is selected + And I press "bim.select_similar_type" + Then the object "IfcWall/Cube" is selected + And the object "IfcWall/Cube.001" is selected