Support editing representation's presentation layers from UI

Example - https://imgur.com/a/QgtSUoq
This commit is contained in:
Andrej730
2025-01-28 17:19:08 +05:00
parent f43e33b969
commit ab0549daa6
5 changed files with 129 additions and 9 deletions
@@ -26,6 +26,7 @@ classes = (
operator.AddMeshlikeItem,
operator.AddRepresentation,
operator.AddSweptAreaSolidItem,
operator.AssignRepresentationLayer,
operator.CopyRepresentation,
operator.DisableEditingRepresentationItemShapeAspect,
operator.DisableEditingRepresentationItemStyle,
@@ -70,6 +71,7 @@ classes = (
operator.SwitchRepresentation,
operator.UnassignRepresentationItemLayer,
operator.UnassignRepresentationItemStyle,
operator.UnassignRepresentationLayer,
operator.UpdateItemAttributes,
operator.UpdateParametricRepresentation,
operator.UpdateRepresentation,
@@ -3259,3 +3259,52 @@ class UnassignRepresentationItemLayer(bpy.types.Operator, tool.Ifc.Operator):
ifcopenshell.api.layer.unassign_layer(ifc_file, [item], layer)
bpy.ops.bim.enable_editing_representation_items()
return {"FINISHED"}
class AssignRepresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_representation_layer"
bl_label = "Assign Representation Layer"
bl_description = "Assign presentation layer to the active representation."
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
ifc_file = tool.Ifc.get()
obj = context.active_object
assert obj
props = tool.Geometry.get_object_geometry_props(obj)
new_layer = ifc_file.by_id(int(props.representation_layer))
representation = tool.Geometry.get_active_representation(obj)
assert representation
item_layers = representation.LayerAssignments
# On practice enum doesn't display already assigned layers
# but let's double check.
if new_layer in item_layers:
props.is_adding_representation_layer = False
return {"FINISHED"}
ifcopenshell.api.layer.assign_layer(ifc_file, [representation], new_layer)
props.is_adding_representation_layer = False
return {"FINISHED"}
class UnassignRepresentationLayer(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_representation_layer"
bl_label = "Unassign Representation Layer"
bl_description = "Unassign presentation layer from the active representation."
bl_options = {"REGISTER", "UNDO"}
layer_id: bpy.props.IntProperty()
def _execute(self, context):
ifc_file = tool.Ifc.get()
obj = context.active_object
assert obj
representation = tool.Geometry.get_active_representation(obj)
assert representation
layer = ifc_file.by_id(self.layer_id)
ifcopenshell.api.layer.unassign_layer(ifc_file, [representation], layer)
return {"FINISHED"}
@@ -113,6 +113,14 @@ def get_layers(self, context):
return LayersData.data["layers_enum"]
def get_layers_no_active(self, context):
from bonsai.bim.module.layer.data import LayersData
if not LayersData.is_loaded:
LayersData.load()
return LayersData.data["layers_enum_no_active"]
def update_shape_aspect(self, context):
shape_aspect_id = self.representation_item_shape_aspect
attrs = self.shape_aspect_attrs
@@ -169,6 +177,15 @@ class ShapeAspect(PropertyGroup):
)
def update_is_editing_representation_layer(self: "BIMObjectGeometryProperties", context: bpy.types.Context) -> None:
if self.is_adding_representation_layer:
return
if "representation_layer" in self:
del self["representation_layer"]
del self["is_adding_representation_layer"]
def update_is_editing_item_layer(self: "BIMObjectGeometryProperties", context: bpy.types.Context) -> None:
if self.is_editing_item_layer:
ifc_file = tool.Ifc.get()
@@ -181,10 +198,25 @@ def update_is_editing_item_layer(self: "BIMObjectGeometryProperties", context: b
if "representation_item_layer" in self:
del self["representation_item_layer"]
del self["is_editing_item_layer"]
class BIMObjectGeometryProperties(PropertyGroup):
# Representations UI.
contexts: EnumProperty(items=get_contexts, name="Contexts")
is_adding_representation_layer: BoolProperty(
name="Is Adding Representation's Layer",
description="Toggle adding presentation layer for the representation.",
default=False,
)
representation_layer: EnumProperty(
items=get_layers_no_active,
name="Representation's Presentation Layer",
description="Presentation layer to add.",
update=update_is_editing_representation_layer,
)
# Representation items UI.
is_editing: BoolProperty(name="Is Editing", default=False)
items: CollectionProperty(name="Representation Items", type=RepresentationItem)
active_item_index: IntProperty(name="Active Representation Item Index")
@@ -210,6 +242,8 @@ class BIMObjectGeometryProperties(PropertyGroup):
if TYPE_CHECKING:
contexts: str
is_adding_representation_layer: bool
representation_layer: str
is_editing: bool
items: bpy.types.bpy_prop_collection_idprop[RepresentationItem]
active_item_index: int
+34 -6
View File
@@ -122,11 +122,16 @@ class BIM_PT_representations(Panel):
return tool.Ifc.get() and (obj := tool.Blender.get_active_object()) and tool.Ifc.get_entity(obj)
def draw(self, context):
layout = self.layout
if not RepresentationsData.is_loaded:
RepresentationsData.load()
obj = context.active_object
assert obj
props = tool.Geometry.get_object_geometry_props(obj)
row = self.layout.row(align=True)
prop_with_search(row, context.active_object.BIMGeometryProperties, "contexts", text="")
prop_with_search(row, props, "contexts", text="")
row.operator("bim.add_representation", icon="ADD", text="")
if not RepresentationsData.data["representations"]:
@@ -150,15 +155,38 @@ class BIM_PT_representations(Panel):
op.disable_opening_subtractions = False
row.operator("bim.remove_representation", icon="X", text="").representation_id = representation["id"]
# Presentation layers.
self.layout.separator()
if not LayersData.is_loaded:
LayersData.load()
if LayersData.data["active_layers"]:
self.layout.label(text="Representation Presentation Layers:")
for layer_name in LayersData.data["active_layers"].values():
self.layout.label(text=layer_name, icon="STICKY_UVS_LOC")
if active_layers := LayersData.data["active_layers"]:
row = layout.row(align=True)
row.label(text="Representation Presentation Layers:")
if props.is_adding_representation_layer:
row = layout.row(align=True)
row.prop(props, "representation_layer", text="")
op = row.operator("bim.assign_representation_layer", icon="CHECKMARK", text="")
row.prop(props, "is_adding_representation_layer", icon="CANCEL", text="")
else:
row.prop(props, "is_adding_representation_layer", icon="ADD", text="")
for layer_id, layer_name in active_layers.items():
row = layout.row(align=True)
row.label(text=layer_name, icon="STICKY_UVS_LOC")
op = row.operator("bim.layer_ui_select", icon="ZOOM_SELECTED", text="")
op.layer_id = layer_id
op = row.operator("bim.unassign_representation_layer", icon="X", text="")
op.layer_id = layer_id
else:
self.layout.label(text="Representation Has No Presentation Layers", icon="STICKY_UVS_LOC")
row = layout.row(align=True)
if props.is_adding_representation_layer:
row.prop(props, "representation_layer", text="")
op = row.operator("bim.assign_representation_layer", icon="CHECKMARK", text="")
row.prop(props, "is_adding_representation_layer", icon="CANCEL", text="")
else:
row.label(text="Representation Has No Presentation Layers", icon="STICKY_UVS_LOC")
row.prop(props, "is_adding_representation_layer", icon="GREASEPENCIL", text="")
class BIM_PT_representation_items(Panel):
+10 -3
View File
@@ -38,7 +38,9 @@ class LayersData:
}
# After .layers().
cls.data["total_layers"] = cls.total_layers()
# After .layers() and .active_layers().
cls.data["layers_enum"] = cls.layers_enum()
cls.data["layers_enum_no_active"] = cls.layers_enum(skip_active=True)
cls.is_loaded = True
@@ -55,8 +57,13 @@ class LayersData:
return results
@classmethod
def layers_enum(cls) -> list[tuple[str, str, str]]:
return list((str(data["id"]), data["Name"], data["Description"] or "") for data in cls.data["layers"].values())
def layers_enum(cls, skip_active: bool = False) -> list[tuple[str, str, str]]:
active_layers = cls.data["active_layers"]
return list(
(str(data["id"]), data["Name"], data["Description"] or "")
for data in cls.data["layers"].values()
if not skip_active or (data["id"] not in active_layers)
)
@classmethod
def active_layers(cls) -> dict[int, str]:
@@ -71,4 +78,4 @@ class LayersData:
attr_name = "LayerAssignment"
if attr_name is None:
return results
return {layer.id(): layer.Name for layer in getattr(shape, attr_name)}
return {layer.id(): layer.Name or "Unnamed" for layer in getattr(shape, attr_name)}