From 0b6f3113a7ae74927604b3b66ef5ad814c5720e8 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 30 May 2021 21:02:03 +1000 Subject: [PATCH] Changing types of a dumb wall now auto updates their wall thicknesses --- src/blenderbim/blenderbim/bim/ifc.py | 13 ++++++++ .../bim/module/geometry/operator.py | 11 +++---- .../blenderbim/bim/module/model/operator.py | 1 - .../bim/module/parametric/operator.py | 30 ++++++++++++++----- .../blenderbim/bim/module/spatial/operator.py | 2 +- .../blenderbim/bim/module/type/operator.py | 3 ++ 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index aa401a46de..457c70bada 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -47,6 +47,19 @@ class IfcStore: IfcStore.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(IfcStore.file.schema) return IfcStore.schema + @staticmethod + def get_element(id_or_guid): + if isinstance(id_or_guid, int): + map_object = IfcStore.id_map + else: + map_object = IfcStore.guid_map + try: + obj = map_object[id_or_guid] + obj.type # In case the object has been deleted, this triggers an exception + except: + return + return obj + @staticmethod def link_element(element, obj): IfcStore.id_map[element.id()] = obj diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 961b1b538a..b5ba6c15b1 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -200,11 +200,12 @@ class SwitchRepresentation(bpy.types.Operator): if self.oprops.ifc_definition_id not in VoidData.products: VoidData.load(IfcStore.get_file(), self.oprops.ifc_definition_id) for opening_id in VoidData.products[self.oprops.ifc_definition_id]: - if opening_id in IfcStore.id_map: - opening = IfcStore.id_map[opening_id] - modifier = self.element_obj.modifiers.new("IfcOpeningElement", "BOOLEAN") - modifier.operation = "DIFFERENCE" - modifier.object = opening + opening = IfcStore.get_element(opening_id) + if not opening: + continue + modifier = self.element_obj.modifiers.new("IfcOpeningElement", "BOOLEAN") + modifier.operation = "DIFFERENCE" + modifier.object = opening else: for modifier in self.element_obj.modifiers: if modifier.type == "BOOLEAN" and "IfcOpeningElement" in modifier.name: diff --git a/src/blenderbim/blenderbim/bim/module/model/operator.py b/src/blenderbim/blenderbim/bim/module/model/operator.py index a11176da0b..d72ee36514 100644 --- a/src/blenderbim/blenderbim/bim/module/model/operator.py +++ b/src/blenderbim/blenderbim/bim/module/model/operator.py @@ -735,7 +735,6 @@ class DumbWallGenerator: element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbWall"}) - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") MaterialData.load(self.file) obj.select_set(True) return obj diff --git a/src/blenderbim/blenderbim/bim/module/parametric/operator.py b/src/blenderbim/blenderbim/bim/module/parametric/operator.py index 5035bc455d..2a3ded62a6 100644 --- a/src/blenderbim/blenderbim/bim/module/parametric/operator.py +++ b/src/blenderbim/blenderbim/bim/module/parametric/operator.py @@ -106,7 +106,7 @@ def calculate_dumb_quantities(usecase_path, ifc_file, **settings): class DumbWallPlaner: - def regenerate_dumb_wall_thicknesses(self, usecase_path, ifc_file, **settings): + def regenerate_wall_thicknesses_from_layer(self, usecase_path, ifc_file, **settings): self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) layer = settings["layer"] thickness = settings["attributes"].get("LayerThickness") @@ -114,7 +114,7 @@ class DumbWallPlaner: return delta_thickness = thickness - layer.LayerThickness for layer_set in layer.ToMaterialLayerSet: - total_thickness = sum([l.LayerThickness for l in layer_set.MaterialLayers]) * self.unit_scale + total_thickness = sum([l.LayerThickness for l in layer_set.MaterialLayers]) if not total_thickness: continue for inverse in ifc_file.get_inverse(layer_set): @@ -131,14 +131,27 @@ class DumbWallPlaner: for element in rel.RelatedObjects: self.regenerate_wall_thickness(element, delta_thickness) + def regenerate_wall_thicknesses_from_type(self, usecase_path, ifc_file, **settings): + self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) + new_material = ifcopenshell.util.element.get_material(settings["relating_type"]) + if not new_material.is_a("IfcMaterialLayerSet"): + return + obj = IfcStore.get_element(settings["related_object"].id()) + if not obj: + return + current_thickness = obj.dimensions.y / self.unit_scale + new_thickness = sum([l.LayerThickness for l in new_material.MaterialLayers]) + if current_thickness == new_thickness: + return + self.regenerate_wall_thickness(settings["related_object"], new_thickness - current_thickness) + def regenerate_wall_thickness(self, element, delta_thickness): parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric") if not parametric or parametric["Engine"] != "BlenderBIM.DumbWall": return - try: - obj = IfcStore.id_map[element.id()] - obj.name # In case the object has been deleted - except: + + obj = IfcStore.get_element(element.id()) + if not obj: return bm = bmesh.new() @@ -206,6 +219,9 @@ class ActivateParametricEngine(bpy.types.Operator): "geometry.add_representation", IfcStore.get_file(), calculate_dumb_quantities ) ifcopenshell.api.add_pre_listener( - "material.edit_layer", IfcStore.get_file(), DumbWallPlaner().regenerate_dumb_wall_thicknesses + "material.edit_layer", IfcStore.get_file(), DumbWallPlaner().regenerate_wall_thicknesses_from_layer + ) + ifcopenshell.api.add_pre_listener( + "type.assign_type", IfcStore.get_file(), DumbWallPlaner().regenerate_wall_thicknesses_from_type ) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/spatial/operator.py b/src/blenderbim/blenderbim/bim/module/spatial/operator.py index b83d7ff223..ae512da728 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/operator.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/operator.py @@ -38,7 +38,7 @@ class AssignContainer(bpy.types.Operator): aggregate_collection = bpy.data.collections.get(related_element.name) - relating_structure_obj = IfcStore.id_map.get(relating_structure) + relating_structure_obj = IfcStore.get_element(relating_structure) relating_collection = None if relating_structure_obj: relating_collection = bpy.data.collections.get(relating_structure_obj.name) diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index 9d50aa6804..08ed63d9b7 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -5,6 +5,7 @@ import ifcopenshell.api from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.type.data import Data from ifcopenshell.api.geometry.data import Data as GeometryData +from ifcopenshell.api.material.data import Data as MaterialData class AssignType(bpy.types.Operator): @@ -31,6 +32,7 @@ class AssignType(bpy.types.Operator): ) Data.load(IfcStore.get_file(), oprops.ifc_definition_id) GeometryData.load(IfcStore.get_file(), oprops.ifc_definition_id) + MaterialData.load(IfcStore.get_file(), oprops.ifc_definition_id) representation_ids = GeometryData.products[oprops.ifc_definition_id] if not representation_ids: pass # TODO: clear geometry? Make void? Make none type? @@ -44,6 +46,7 @@ class AssignType(bpy.types.Operator): bpy.ops.bim.switch_representation(obj=related_object.name, ifc_definition_id=representation_id) bpy.ops.bim.disable_editing_type(obj=related_object.name) + MaterialData.load(self.file) return {"FINISHED"}