diff --git a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py index 285a451b06..ab2ea7b3c5 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py @@ -4,8 +4,6 @@ from . import ui, prop, operator classes = ( operator.EditObjectPlacement, operator.AddRepresentation, - operator.MapRepresentations, - operator.MapRepresentation, operator.SwitchRepresentation, operator.RemoveRepresentation, operator.UpdateMeshRepresentation, diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 37051e839b..cd85dca02d 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -156,23 +156,35 @@ class AddRepresentation(bpy.types.Operator): class SwitchRepresentation(bpy.types.Operator): bl_idname = "bim.switch_representation" bl_label = "Switch Representation" + obj: bpy.props.StringProperty() ifc_definition_id: bpy.props.IntProperty() + should_reload: bpy.props.BoolProperty() disable_opening_subtractions: bpy.props.BoolProperty() def execute(self, context): - self.obj = bpy.context.active_object - self.oprops = self.obj.BIMObjectProperties + self.element_obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object + self.oprops = self.element_obj.BIMObjectProperties self.file = IfcStore.get_file() self.context_of_items = self.file.by_id(self.ifc_definition_id).ContextOfItems - self.mesh_name = "{}/{}".format(self.context_of_items.id(), self.ifc_definition_id) + self.mesh_name = self.get_mesh_name() mesh = bpy.data.meshes.get(self.mesh_name) if mesh: - self.obj.data.user_remap(mesh) - self.pull_mesh_from_ifc() + self.element_obj.data.user_remap(mesh) + if not mesh or self.should_reload: + self.pull_mesh_from_ifc() return {"FINISHED"} + def get_mesh_name(self): + representation = self.resolve_mapped_representation(self.file.by_id(self.ifc_definition_id)) + return "{}/{}".format(self.context_of_items.id(), representation.id()) + + def resolve_mapped_representation(self, representation): + if representation.RepresentationType == "MappedRepresentation": + return self.resolve_mapped_representation(representation.Items[0].MappingSource.MappedRepresentation) + return representation + def pull_mesh_from_ifc(self): self.file = IfcStore.get_file() logger = logging.getLogger("ImportIFC") @@ -194,9 +206,9 @@ class SwitchRepresentation(bpy.types.Operator): mesh = ifc_importer.create_mesh(element, shape) mesh.name = self.mesh_name mesh.BIMMeshProperties.ifc_definition_id = self.ifc_definition_id - self.obj.data.user_remap(mesh) + self.element_obj.data.user_remap(mesh) material_creator = import_ifc.MaterialCreator(ifc_import_settings, ifc_importer) - material_creator.create(element, self.obj, mesh) + material_creator.create(element, self.element_obj, mesh) if self.disable_opening_subtractions and self.context_of_items.ContextIdentifier == "Body": if self.oprops.ifc_definition_id not in VoidData.products: @@ -204,13 +216,13 @@ class SwitchRepresentation(bpy.types.Operator): 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.obj.modifiers.new("IfcOpeningElement", "BOOLEAN") + modifier = self.element_obj.modifiers.new("IfcOpeningElement", "BOOLEAN") modifier.operation = "DIFFERENCE" modifier.object = opening else: - for modifier in self.obj.modifiers: + for modifier in self.element_obj.modifiers: if modifier.type == "BOOLEAN" and "IfcOpeningElement" in modifier.name: - self.obj.modifiers.remove(modifier) + self.element_obj.modifiers.remove(modifier) class RemoveRepresentation(bpy.types.Operator): @@ -249,61 +261,6 @@ class RemoveRepresentation(bpy.types.Operator): return {"FINISHED"} -class MapRepresentations(bpy.types.Operator): - bl_idname = "bim.map_representations" - bl_label = "Map Representations" - product_id: bpy.props.IntProperty() - type_product_id: bpy.props.IntProperty() - - def execute(self, context): - related_object = IfcStore.id_map[self.product_id] - - if self.product_id not in Data.products: - Data.load(IfcStore.get_file(), self.product_id) - - for representation_id in Data.products[self.product_id]: - bpy.ops.bim.remove_representation(obj=related_object.name, representation_id=representation_id) - - if self.type_product_id not in Data.products: - Data.load(IfcStore.get_file(), self.type_product_id) - - for representation_id in Data.products[self.type_product_id]: - bpy.ops.bim.map_representation( - obj=related_object.name, - representation_id=representation_id, - obj_data=IfcStore.id_map[self.type_product_id].data.name, - ) - return {"FINISHED"} - - -class MapRepresentation(bpy.types.Operator): - bl_idname = "bim.map_representation" - bl_label = "Map Representation" - obj: bpy.props.StringProperty() - representation_id: bpy.props.IntProperty() - obj_data: bpy.props.StringProperty() - - def execute(self, context): - objs = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects - obj_data = bpy.data.meshes.get(self.obj_data) if self.obj_data else None - - self.file = IfcStore.get_file() - - for obj in objs: - bpy.ops.bim.edit_object_placement(obj=obj.name) - product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) - if obj_data: - obj.data = obj_data - result = ifcopenshell.api.run( - "geometry.map_representation", self.file, **{"representation": self.file.by_id(self.representation_id)} - ) - ifcopenshell.api.run( - "geometry.assign_representation", self.file, **{"product": product, "representation": result} - ) - Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) - return {"FINISHED"} - - class UpdateMeshRepresentation(bpy.types.Operator): bl_idname = "bim.update_mesh_representation" bl_label = "Update Mesh Representation" @@ -407,7 +364,7 @@ class UpdateParametricRepresentation(bpy.types.Operator): props = obj.data.BIMMeshProperties parameter = props.ifc_parameters[self.index] element = IfcStore.get_file().by_id(parameter.step_id)[parameter.index] = parameter.value - bpy.ops.bim.switch_representation(ifc_definition_id=props.ifc_definition_id) + bpy.ops.bim.switch_representation(ifc_definition_id=props.ifc_definition_id, should_reload=True) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/geometry/ui.py b/src/blenderbim/blenderbim/bim/module/geometry/ui.py index b07a8d1f82..c6285e3910 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/ui.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/ui.py @@ -39,6 +39,7 @@ class BIM_PT_representations(Panel): row.label(text=representation["ContextOfItems"]["TargetView"]) row.label(text=representation["RepresentationType"]) op = row.operator("bim.switch_representation", icon="OUTLINER_DATA_MESH", text="") + op.should_reload = True op.ifc_definition_id = ifc_definition_id op.disable_opening_subtractions = False row.operator("bim.remove_representation", icon="X", text="").representation_id = ifc_definition_id @@ -68,9 +69,11 @@ class BIM_PT_mesh(Panel): row = layout.row(align=True) op = row.operator("bim.switch_representation", text="Bake Voids", icon="SELECT_SUBTRACT") + op.should_reload = True op.ifc_definition_id = props.ifc_definition_id op.disable_opening_subtractions = False op = row.operator("bim.switch_representation", text="Dynamic Voids", icon="SELECT_INTERSECT") + op.should_reload = True op.ifc_definition_id = props.ifc_definition_id op.disable_opening_subtractions = True diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index baecdc954b..2d95abb798 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -245,9 +245,7 @@ class CopyClass(bpy.types.Operator): IfcStore.link_element(result, obj) relating_type = ifcopenshell.util.element.get_type(result) if relating_type and relating_type.RepresentationMaps: - bpy.ops.bim.map_representations( - product_id=result.id(), type_product_id=ifcopenshell.util.element.get_type(result).id() - ) + bpy.ops.bim.assign_type(relating_type=relating_type.id(), related_object=obj.name) else: bpy.ops.bim.add_representation(obj=obj.name) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index fdfd43fa6e..bd03a490e1 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -4,6 +4,7 @@ import ifcopenshell.util.type 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 blenderbim.bim.module.type.prop import getIfcTypes, getAvailableTypes, updateTypeInstanceIfcClass from mathutils import Vector @@ -31,8 +32,18 @@ class AssignType(bpy.types.Operator): }, ) Data.load(IfcStore.get_file(), oprops.ifc_definition_id) - if self.file.by_id(relating_type).RepresentationMaps: - bpy.ops.bim.map_representations(product_id=oprops.ifc_definition_id, type_product_id=relating_type) + GeometryData.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? + has_switched = False + for representation_id in representation_ids: + representation = GeometryData.representations[representation_id] + if representation["ContextOfItems"]["ContextIdentifier"] == "Body": + bpy.ops.bim.switch_representation(obj=related_object.name, ifc_definition_id=representation_id) + has_switched = True + if not has_switched and representation_ids: + bpy.ops.bim.switch_representation(obj=related_object.name, ifc_definition_id=representation_id) bpy.ops.bim.disable_editing_type(obj=related_object.name) return {"FINISHED"} diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/data.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/data.py index c72cc104cf..5a58b91eaa 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/data.py @@ -14,11 +14,8 @@ class Data: cls.products[product_id] = [] product = file.by_id(product_id) representations = [] - if product.is_a("IfcProduct"): - if product.Representation: - representations = product.Representation.Representations - else: - representations = [] + if product.is_a("IfcProduct") and product.Representation: + representations = product.Representation.Representations elif product.is_a("IfcTypeProduct"): representations = [rm.MappedRepresentation for rm in product.RepresentationMaps or []] for representation in representations: diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py index a162a373de..158a7087b2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py @@ -52,3 +52,30 @@ class Usecase: "RelatingType": self.settings["relating_type"], } ) + + self.map_representations() + + def map_representations(self): + if not self.settings["relating_type"].RepresentationMaps: + return + representations = [] + if self.settings["related_object"].Representation: + representations = self.settings["related_object"].Representation.Representations + for representation in representations: + # TODO: check if this is right? Surely this can be a single usecase? + ifcopenshell.api.run( + "geometry.unassign_representation", + self.file, + **{"product": self.settings["related_object"], "representation": representation} + ) + ifcopenshell.api.run("geometry.remove_representation", self.file, **{"representation": representation}) + for representation_map in self.settings["relating_type"].RepresentationMaps: + representation = representation_map.MappedRepresentation + result = ifcopenshell.api.run( + "geometry.map_representation", self.file, **{"representation": representation} + ) + ifcopenshell.api.run( + "geometry.assign_representation", + self.file, + **{"product": self.settings["related_object"], "representation": result} + )