diff --git a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py index 9faf7dbe59..34c94add88 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/__init__.py @@ -49,6 +49,10 @@ classes = ( operator.SwitchRepresentation, operator.UpdateParametricRepresentation, operator.UpdateRepresentation, + operator.EnableEditingRepresentationItemStyle, + operator.EditRepresentationItemStyle, + operator.DisableEditingRepresentationItemStyle, + operator.UnassignRepresentationItemStyle, prop.RepresentationItem, prop.BIMObjectGeometryProperties, prop.BIMGeometryProperties, diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index f269f9c8f7..c699bc0da0 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -1605,3 +1605,77 @@ class DisableEditingRepresentationItems(bpy.types.Operator, Operator): def _execute(self, context): obj = context.active_object obj.BIMGeometryProperties.is_editing = False + + +class EnableEditingRepresentationItemStyle(bpy.types.Operator, Operator): + bl_idname = "bim.enable_editing_representation_item_style" + bl_label = "Enable Editing Representation Item Style" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + props = context.active_object.BIMGeometryProperties + props.is_editing_item_style = True + ifc_file = tool.Ifc.get() + + # set dropdown to currently active style + representation_item_id = props.items[props.active_item_index].ifc_definition_id + representation_item = ifc_file.by_id(representation_item_id) + style = tool.Style.get_representation_item_style(representation_item) + if style: + props.representation_item_style = str(style.id()) + + +class EditRepresentationItemStyle(bpy.types.Operator, Operator): + bl_idname = "bim.edit_representation_item_style" + bl_label = "Edit Representation Item Style" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + obj = context.active_object + props = obj.BIMGeometryProperties + props.is_editing_item_style = False + ifc_file = tool.Ifc.get() + + surface_style = ifc_file.by_id(int(props.representation_item_style)) + representation_item_id = props.items[props.active_item_index].ifc_definition_id + representation_item = ifc_file.by_id(representation_item_id) + + tool.Style.assign_style_to_representation_item(representation_item, surface_style) + tool.Geometry.reload_representation(obj) + # reload style ui + bpy.ops.bim.disable_editing_representation_items() + bpy.ops.bim.enable_editing_representation_items() + + +class DisableEditingRepresentationItemStyle(bpy.types.Operator, Operator): + bl_idname = "bim.disable_editing_representation_item_style" + bl_label = "Disable Editing Representation Item Style" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + props = context.active_object.BIMGeometryProperties + props.is_editing_item_style = False + + +class UnassignRepresentationItemStyle(bpy.types.Operator, Operator): + bl_idname = "bim.unassign_representation_item_style" + bl_label = "Unassign Representation Item Style" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + obj = context.active_object + props = obj.BIMGeometryProperties + props.is_editing_item_style = False + + # get active representation item + representation_item_id = props.items[props.active_item_index].ifc_definition_id + representation_item = tool.Ifc.get_entity_by_id(representation_item_id) + if not representation_item: + self.report({"ERROR"}, f"Couldn't find representation item by id {representation_item_id}.") + return {"CANCELLED"} + + tool.Style.assign_style_to_representation_item(representation_item, None) + tool.Geometry.reload_representation(obj) + # reload style ui + bpy.ops.bim.disable_editing_representation_items() + bpy.ops.bim.enable_editing_representation_items() diff --git a/src/blenderbim/blenderbim/bim/module/geometry/prop.py b/src/blenderbim/blenderbim/bim/module/geometry/prop.py index b3a676e0d3..aa31db11c3 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/prop.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/prop.py @@ -47,6 +47,15 @@ def update_mode(self, context): bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT") +def get_styles(self, context): + # postponed import to avoid circular import + from blenderbim.bim.module.material.data import MaterialsData + + if not MaterialsData.is_loaded: + MaterialsData.load() + return MaterialsData.data["styles"] + + class RepresentationItem(PropertyGroup): name: StringProperty(name="Name") surface_style: StringProperty(name="Surface Style") @@ -59,6 +68,8 @@ class BIMObjectGeometryProperties(PropertyGroup): is_editing: BoolProperty(name="Is Editing", default=False) items: CollectionProperty(name="Representation Items", type=RepresentationItem) active_item_index: IntProperty(name="Active Representation Item Index") + is_editing_item_style: BoolProperty(name="Is Editing Item's Style", default=False) + representation_item_style: EnumProperty(items=get_styles, name="Representation Item Style") class BIMGeometryProperties(PropertyGroup): diff --git a/src/blenderbim/blenderbim/bim/module/geometry/ui.py b/src/blenderbim/blenderbim/bim/module/geometry/ui.py index a725a89118..a2eef0845d 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/ui.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/ui.py @@ -187,17 +187,27 @@ class BIM_PT_representation_items(Panel): self.layout.template_list("BIM_UL_representation_items", "", props, "items", props, "active_item_index") item_is_active = props.active_item_index < len(props.items) - if item_is_active: - surface_style = props.items[props.active_item_index].surface_style - presentation_layer = props.items[props.active_item_index].layer - else: - surface_style, presentation_layer = None, None + if not item_is_active: + return - row = self.layout.row() - if surface_style: - row.label(text=surface_style, icon="SHADING_RENDERED") + surface_style = props.items[props.active_item_index].surface_style + presentation_layer = props.items[props.active_item_index].layer + + row = self.layout.row(align=True) + if props.is_editing_item_style: + # NOTE: we currently support 1 item having just 1 style + # when IfcStyledItem can actually have multiple styles + row.prop(props, "representation_item_style", icon="SHADING_RENDERED", text="") + row.operator("bim.edit_representation_item_style", icon="CHECKMARK", text="") + row.operator("bim.disable_editing_representation_item_style", icon="CANCEL", text="") else: - row.label(text="No Surface Style", icon="MESH_UVSPHERE") + if surface_style: + row.label(text=surface_style, icon="SHADING_RENDERED") + else: + row.label(text="No Surface Style", icon="MESH_UVSPHERE") + row.operator("bim.enable_editing_representation_item_style", icon="GREASEPENCIL", text="") + if surface_style: + row.operator("bim.unassign_representation_item_style", icon="X", text="") row = self.layout.row() row.label(text=presentation_layer or "No Presentation Layer", icon="STICKY_UVS_LOC") diff --git a/src/blenderbim/blenderbim/tool/geometry.py b/src/blenderbim/blenderbim/tool/geometry.py index 6b352cb1a2..817956467a 100644 --- a/src/blenderbim/blenderbim/tool/geometry.py +++ b/src/blenderbim/blenderbim/tool/geometry.py @@ -716,3 +716,17 @@ class Geometry(blenderbim.core.tool.Geometry): obj.matrix_world.translation += original_min_point - new_max_point bpy.context.view_layer.update() + + @classmethod + def reload_representation(cls, obj): + representation = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id) + blenderbim.core.geometry.switch_representation( + tool.Ifc, + tool.Geometry, + obj=obj, + representation=representation, + should_reload=True, + is_global=True, + should_sync_changes_first=False, + apply_openings=True, + ) diff --git a/src/blenderbim/blenderbim/tool/style.py b/src/blenderbim/blenderbim/tool/style.py index a59ac734eb..ee7f0b021b 100644 --- a/src/blenderbim/blenderbim/tool/style.py +++ b/src/blenderbim/blenderbim/tool/style.py @@ -549,6 +549,27 @@ class Style(blenderbim.core.tool.Style): representation = tool.Geometry.get_active_representation(obj) tool.Ifc.run("style.assign_representation_styles", shape_representation=representation, styles=[style]) + @classmethod + def assign_style_to_representation_item(cls, representation_item, style=None): + ifc_file = tool.Ifc.get() + if not representation_item.StyledByItem: + if style is None: + return + ifc_file.createIfcStyledItem(representation_item, (style,)) + + styled_item = representation_item.StyledByItem[0] + if style is None: + ifc_file.remove(styled_item) + return + styled_item.Styles = (style,) + + @classmethod + def get_representation_item_style(cls, representation_item): + for inverse in tool.Ifc.get().get_inverse(representation_item): + if inverse.is_a("IfcStyledItem"): + for style in inverse.Styles: + return style + @classmethod def reload_material_from_ifc(cls, blender_material): blender_material.BIMStyleProperties.active_style_type = blender_material.BIMStyleProperties.active_style_type diff --git a/src/blenderbim/test/tool/test_style.py b/src/blenderbim/test/tool/test_style.py index c6ac04aac0..dd9b12f1db 100644 --- a/src/blenderbim/test/tool/test_style.py +++ b/src/blenderbim/test/tool/test_style.py @@ -23,6 +23,7 @@ import blenderbim.core.tool import blenderbim.tool as tool from test.bim.bootstrap import NewFile from blenderbim.tool.style import Style as subject +from ifcopenshell.util.shape_builder import ShapeBuilder class TestImplementsTool(NewFile): @@ -460,3 +461,37 @@ class TestIsEditingStyles(NewFile): subject.is_editing_styles() is False bpy.context.scene.BIMStylesProperties.is_editing = True subject.is_editing_styles() is True + + +class TestGetRepresentationStyleItem(NewFile): + def test_run(self): + tool.Ifc.set(ifc := ifcopenshell.file()) + builder = ShapeBuilder(ifc) + rectangle = builder.rectangle() + + assert subject.get_representation_item_style(rectangle) == None + style = ifc.createIfcSurfaceStyle() + subject.assign_style_to_representation_item(rectangle, style) + assert subject.get_representation_item_style(rectangle) == style + + +class TestAssignStyleToRepresentationItem(NewFile): + def test_run(self): + tool.Ifc.set(ifc := ifcopenshell.file()) + builder = ShapeBuilder(ifc) + rectangle = builder.rectangle() + + # assigning new style + style1 = ifc.createIfcSurfaceStyle() + subject.assign_style_to_representation_item(rectangle, style1) + assert subject.get_representation_item_style(rectangle) == style1 + + # changing style + style2 = ifc.createIfcSurfaceStyle() + subject.assign_style_to_representation_item(rectangle, style2) + assert subject.get_representation_item_style(rectangle) == style2 + + # unassigning styles + subject.assign_style_to_representation_item(rectangle, None) + assert subject.get_representation_item_style(rectangle) == None +