diff --git a/src/ifcblenderexport/blenderbim/bim/export_ifc.py b/src/ifcblenderexport/blenderbim/bim/export_ifc.py index 38c8fb4f24..bd5f8e6b04 100644 --- a/src/ifcblenderexport/blenderbim/bim/export_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/export_ifc.py @@ -974,11 +974,11 @@ class IfcParser: def load_presentation_layer_assignments(self): for representation in self.representations.values(): - if representation["presentation_layer"]: - layer = representation["presentation_layer"] - if layer.name == "": - continue - self.presentation_layer_assignments.setdefault(layer.name, []).append(representation) + if representation["presentation_layer"] is False: + continue + self.presentation_layer_assignments.setdefault(representation["presentation_layer"], []).append( + representation + ) def load_representations(self): if not self.ifc_export_settings.has_representations: @@ -1110,9 +1110,9 @@ class IfcParser: "is_native": mesh.BIMMeshProperties.is_native if hasattr(mesh, "BIMMeshProperties") else False, "is_swept_solid": mesh.BIMMeshProperties.is_swept_solid if hasattr(mesh, "BIMMeshProperties") else False, "is_generated": False, - "presentation_layer": obj.BIMObjectProperties.presentation_layer - if hasattr(obj, "BIMObjectProperties") - else None, + "presentation_layer": mesh.BIMMeshProperties.presentation_layer_index + if hasattr(mesh, "BIMMeshProperties") and mesh.BIMMeshProperties.presentation_layer_index != -1 + else False, "attributes": {"Name": mesh.name}, } @@ -1163,7 +1163,6 @@ class IfcParser: "raw": material, "attributes": self.get_material_attributes(material), } - print(material.name) self.materials[material.name] = data self.get_material_psets(data, material) @@ -1662,7 +1661,6 @@ class IfcExporter: if not properties: continue pset["attributes"].update({"Properties": properties, "Material": pset["material"]["ifc"]}) - print(pset["attributes"]) pset["ifc"] = self.file.create_entity("IfcMaterialProperties", **pset["attributes"]) def create_qto_properties(self, qto): @@ -2034,28 +2032,22 @@ class IfcExporter: return self.file.createIfcStyledItem(representation_item, [surface_style], item["attributes"]["Name"]) def create_presentation_layer_assignments(self): - scene_props = bpy.context.scene.BIMProperties - for name, assigned_items in self.ifc_parser.presentation_layer_assignments.items(): - if name == "": - continue - layer = scene_props.presentation_layers[name] - - with_style = False - if layer.layer_on is False: - with_style = True - - if with_style is False: + for layer_index, representations in self.ifc_parser.presentation_layer_assignments.items(): + layer = bpy.context.scene.BIMProperties.presentation_layers[int(layer_index)] + assigned_items = [] + for representation in representations: + for usage in representation["ifc"].MapUsage: + for inverse in self.file.get_inverse(usage): + assigned_items.append(inverse) + if layer.layer_on: self.file.createIfcPresentationLayerAssignment( - name, - layer.description or None, - [i["ifc"].MappedRepresentation for i in assigned_items], - layer.identifier or None, + layer.name, layer.description or None, assigned_items, layer.identifier or None, ) else: self.file.createIfcPresentationLayerWithStyle( - name, + layer.name, layer.description or None, - [i["ifc"].MappedRepresentation for i in assigned_items], + assigned_items, layer.identifier or None, layer.layer_on, layer.layer_frozen, diff --git a/src/ifcblenderexport/blenderbim/bim/import_ifc.py b/src/ifcblenderexport/blenderbim/bim/import_ifc.py index 7703431627..1871d6b945 100644 --- a/src/ifcblenderexport/blenderbim/bim/import_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/import_ifc.py @@ -479,8 +479,8 @@ class IfcImporter: self.profile_code("Merging by colour") self.add_project_to_scene() self.profile_code("Add project to scene") - self.get_presentation_layers() - self.profile_code("Get presentation layers") + self.create_presentation_layers() + self.profile_code("Create presentation layers") if self.ifc_import_settings.should_clean_mesh and len(self.file.by_type("IfcElement")) < 10000: self.clean_mesh() self.profile_code("Mesh cleaning") @@ -1328,9 +1328,10 @@ class IfcImporter: self.type_collection.name ].hide_viewport = True - def get_presentation_layers(self): + def create_presentation_layers(self): for assignment in self.file.by_type("IfcPresentationLayerAssignment"): layer = bpy.context.scene.BIMProperties.presentation_layers.add() + layer_index = len(bpy.context.scene.BIMProperties.presentation_layers) - 1 layer.name = assignment.Name layer.description = assignment.Description or "" layer.identifier = assignment.Identifier or "" @@ -1340,19 +1341,18 @@ class IfcImporter: layer.layer_blocked = assignment.LayerBlocked if assignment.LayerBlocked is not None else False for item in assignment.AssignedItems: - # TODO: This is a simplified and incorrect implementation of assigning presentation layers to objects - # themselves, and will need to be rewritten in the future. See bug #1109. This code also does not - # consider mapped representations. + # TODO: This is a simplified implementation of assigning presentation layers that ignores assigned + # representation items, does not consider mapped representations, and assumes a Body context. See #1109. guids = [] - if not hasattr(item, "OfProductRepresentation"): - continue # TODO: At the moment we ignore representation items + if not hasattr(item, "OfProductRepresentation") or item.RepresentationIdentifier != "Body": + continue for product_representation in item.OfProductRepresentation: for product in product_representation.ShapeOfProduct: guids.append(product.GlobalId) for obj in bpy.context.selectable_objects: global_id = obj.BIMObjectProperties.attributes.get("GlobalId") if global_id and global_id.string_value in guids: - obj.BIMObjectProperties.presentation_layer.name = layer.name + obj.data.BIMMeshProperties.presentation_layer_index = layer_index obj.hide_set(not layer.layer_on) def clean_mesh(self): diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index d63df5c993..6add1cb62f 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -4328,11 +4328,12 @@ class AssignPresentationLayer(bpy.types.Operator): index: bpy.props.IntProperty() def execute(self, context): - presentation_layer = bpy.context.scene.BIMProperties.presentation_layers[self.index] + layer = bpy.context.scene.BIMProperties.presentation_layers[self.index] for obj in bpy.context.selected_objects: - # TODO: assign using a different strategy than name association - obj.BIMObjectProperties.presentation_layer.name = presentation_layer.name - obj.hide_set(not presentation_layer.layer_on) + if not obj.data or not hasattr(obj.data, "BIMMeshProperties"): + continue + obj.data.BIMMeshProperties.presentation_layer_index = self.index + obj.hide_set(not layer.layer_on) return {"FINISHED"} @@ -4341,9 +4342,10 @@ class UnassignPresentationLayer(bpy.types.Operator): bl_label = "Unassign Presentation Layer" def execute(self, context): - for el in bpy.context.selected_objects: - if el.BIMObjectProperties.presentation_layer.name != "": - el.BIMObjectProperties.presentation_layer.name = "" + for obj in bpy.context.selected_objects: + if not obj.data or not hasattr(obj.data, "BIMMeshProperties"): + continue + obj.data.BIMMeshProperties.presentation_layer_index = -1 return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 1c72b9c4e8..00633a009a 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -1679,8 +1679,6 @@ class BIMObjectProperties(PropertyGroup): qto_name: EnumProperty(items=getQtoNames, name="Qto Name") has_boundary_condition: BoolProperty(name="Has Boundary Condition") boundary_condition: PointerProperty(name="Boundary Condition", type=BoundaryCondition) - # TODO: presentation layers should belong to a mesh, not an object - presentation_layer: PointerProperty(name="Presentation Layer", type=PresentationLayer) structural_member_connection: PointerProperty(name="Structural Member Connection", type=bpy.types.Object) representation_contexts: CollectionProperty(name="Representation Contexts", type=Subcontext) # Address applies to IfcSite's SiteAddress and IfcBuilding's BuildingAddress @@ -1729,3 +1727,4 @@ class BIMMeshProperties(PropertyGroup): ifc_definition_id: IntProperty(name="IFC Definition ID") ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter) active_representation_item_index: IntProperty(name="Active Representation Item Index") + presentation_layer_index: IntProperty(name="Presentation Layer Index", default=-1) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 3fa5ed05ff..5e82f43aed 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -815,23 +815,25 @@ class BIM_PT_presentation_layer_data(Panel): if not context.active_object.data: return layout = self.layout - elem_props = context.active_object.BIMObjectProperties.presentation_layer - props = context.scene.BIMProperties + props = context.active_object.data.BIMMeshProperties + scene_props = context.scene.BIMProperties - if elem_props.name != "": - layout.label(text=f'Object is part of Presentation layer "{elem_props.name}"') + if props.presentation_layer_index != -1: + layer = scene_props.presentation_layers[props.presentation_layer_index] + layout.label(text=f"Assigned to: {layer.name}") layout.row().operator("bim.unassign_presentation_layer") - else: - if not props.presentation_layers: - layout.label(text=f"No presentation layers are available") - return + return - layout.template_list( - "BIM_UL_generic", "", props, "presentation_layers", props, "active_presentation_layer_index", - ) - if props.active_presentation_layer_index < len(props.presentation_layers): - op = layout.row().operator("bim.assign_presentation_layer") - op.index = props.active_presentation_layer_index + if not scene_props.presentation_layers: + layout.label(text=f"No presentation layers are available") + return + + layout.template_list( + "BIM_UL_generic", "", scene_props, "presentation_layers", scene_props, "active_presentation_layer_index", + ) + if scene_props.active_presentation_layer_index < len(scene_props.presentation_layers): + op = layout.row().operator("bim.assign_presentation_layer") + op.index = scene_props.active_presentation_layer_index class BIM_PT_material(Panel):