From d21c24b070ff4c5de0bcb54999095631e18dc979 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 24 Jan 2025 16:31:55 +0500 Subject: [PATCH] Bonsai - support editing IfcPresentationLayerWithStyle attributes Example - https://imgur.com/a/JRs8RZm --- src/bonsai/bonsai/bim/module/layer/data.py | 30 +++++++++---------- .../bonsai/bim/module/layer/operator.py | 10 ++++++- src/bonsai/bonsai/bim/module/layer/prop.py | 23 ++++++++++++++ src/bonsai/bonsai/bim/module/layer/ui.py | 7 +++-- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/layer/data.py b/src/bonsai/bonsai/bim/module/layer/data.py index 5ab0fd6302..8aece515bb 100644 --- a/src/bonsai/bonsai/bim/module/layer/data.py +++ b/src/bonsai/bonsai/bim/module/layer/data.py @@ -35,22 +35,20 @@ class LayersData: cls.is_loaded = True @classmethod - def total_layers(cls): + def total_layers(cls) -> int: return len(tool.Ifc.get().by_type("IfcPresentationLayerAssignment")) @classmethod - def active_layers(cls): - if not bpy.context.active_object: - return [] - data = bpy.context.active_object.data - if not data: - return [] - if not isinstance(data, bpy.types.Mesh) or not data.BIMMeshProperties.ifc_definition_id: - return [] - results = dict() - shape = tool.Ifc.get().by_id(data.BIMMeshProperties.ifc_definition_id) - for inverse in getattr(shape, "LayerAssignments", []): - results[inverse.id()] = inverse.Name or "Unnamed" - for inverse in getattr(shape, "LayerAssignment", []): - results[inverse.id()] = inverse.Name or "Unnamed" - return results + def active_layers(cls) -> dict[int, str]: + results = {} + if not (obj := bpy.context.active_object) or not (shape := tool.Geometry.get_active_representation(obj)): + return results + + attr_name = None + if shape.is_a("IfcShapeModel"): + attr_name = "LayerAssignments" + elif shape.is_a("IfcRepresentationItem"): + attr_name = "LayerAssignment" + if attr_name is None: + return results + return {layer.id(): layer.Name for layer in getattr(shape, attr_name)} diff --git a/src/bonsai/bonsai/bim/module/layer/operator.py b/src/bonsai/bonsai/bim/module/layer/operator.py index 8d73a21385..e73f043912 100644 --- a/src/bonsai/bonsai/bim/module/layer/operator.py +++ b/src/bonsai/bonsai/bim/module/layer/operator.py @@ -19,6 +19,7 @@ import bpy import json import ifcopenshell.api +import ifcopenshell.api.layer import ifcopenshell.util.element import ifcopenshell.util.attribute import bonsai.bim.helper @@ -37,8 +38,15 @@ class LoadLayers(bpy.types.Operator): props.layers.clear() for layer in tool.Ifc.get().by_type("IfcPresentationLayerAssignment"): new = props.layers.add() - new.name = layer.Name or "Unnamed" + new.name = layer.Name new.ifc_definition_id = layer.id() + if layer.is_a("IfcPresentationLayerWithStyle"): + new.with_style = True + # IfcLogical can also be UNKNOWN, not just bool. + ifc_logical_is_true = lambda x: x is True + new["on"] = ifc_logical_is_true(layer.LayerOn) + new["frozen"] = ifc_logical_is_true(layer.LayerFrozen) + new["blocked"] = ifc_logical_is_true(layer.LayerBlocked) props.is_editing = True bpy.ops.bim.disable_editing_layer() return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/layer/prop.py b/src/bonsai/bonsai/bim/module/layer/prop.py index f8bea1a4dd..acdeb79163 100644 --- a/src/bonsai/bonsai/bim/module/layer/prop.py +++ b/src/bonsai/bonsai/bim/module/layer/prop.py @@ -17,6 +17,7 @@ # along with Bonsai. If not, see . import bpy +import bonsai.tool as tool from bonsai.bim.prop import StrProperty, Attribute from bpy.types import PropertyGroup from bpy.props import ( @@ -31,9 +32,31 @@ from bpy.props import ( ) +def update_layer_property(self: "Layer", context: bpy.types.Context, *, property: str) -> None: + # TODO: make use of those attributes in Bonsai somehow? + layer = tool.Ifc.get().by_id(self.ifc_definition_id) + setattr(layer, f"Layer{property.capitalize()}", getattr(self, property)) + + class Layer(PropertyGroup): name: StringProperty(name="Name") ifc_definition_id: IntProperty(name="IFC Definition ID") + with_style: BoolProperty(description="Whether it's IfcPresentationLayerWithStyle.", default=False) + on: BoolProperty( + name="Layer Visibility", + description="Currently has no effect in Bonsai.", + update=lambda self, context: update_layer_property(self, context, property="on"), + ) + frozen: BoolProperty( + name="Layer Frozen", + description="Currently has no effect in Bonsai.", + update=lambda self, context: update_layer_property(self, context, property="frozen"), + ) + blocked: BoolProperty( + name="Layer Blocked", + description="Currently has not effect in Bonsai", + update=lambda self, context: update_layer_property(self, context, property="blocked"), + ) class BIMLayerProperties(PropertyGroup): diff --git a/src/bonsai/bonsai/bim/module/layer/ui.py b/src/bonsai/bonsai/bim/module/layer/ui.py index 383fb671a4..8c3b77d30a 100644 --- a/src/bonsai/bonsai/bim/module/layer/ui.py +++ b/src/bonsai/bonsai/bim/module/layer/ui.py @@ -85,9 +85,10 @@ class BIM_UL_layers(UIList): op = row.operator("bim.assign_presentation_layer", text="", icon="KEYFRAME", emboss=False) op.layer = item.ifc_definition_id - # TODO: replace placeholder UI for hiding presentation layers - row.operator("bim.disable_editing_layer", text="", icon="HIDE_OFF", emboss=False) - row.operator("bim.disable_editing_layer", text="", icon="FREEZE", emboss=False) + if item.with_style: + row.prop(item, "on", text="", icon="HIDE_OFF" if item.on else "HIDE_ON", emboss=False) + row.prop(item, "frozen", text="", icon="FREEZE" if item.frozen else "MESH_PLANE", emboss=False) + row.prop(item, "blocked", text="", icon="LOCKED" if item.blocked else "UNLOCKED", emboss=False) if context.scene.BIMLayerProperties.active_layer_id == item.ifc_definition_id: op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")