From 8eb99730450950b525e051169c3e4f6740bca61b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 6 Jan 2021 10:28:22 +1100 Subject: [PATCH] WIP refactor mesh UI into geometry module and minor fixes. See #1222. --- .../blenderbim/bim/__init__.py | 1 - .../bim/module/geometry/__init__.py | 5 +- .../blenderbim/bim/module/geometry/data.py | 7 +- .../bim/module/geometry/operator.py | 105 +++++++++--------- .../blenderbim/bim/module/geometry/ui.py | 36 +++++- .../blenderbim/bim/module/root/operator.py | 38 +------ .../bim/module/spatial/assign_container.py | 2 +- .../blenderbim/bim/module/spatial/operator.py | 5 +- src/ifcblenderexport/blenderbim/bim/ui.py | 59 ---------- 9 files changed, 101 insertions(+), 157 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index b7d66894a5..035b498760 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -283,7 +283,6 @@ if bpy is not None: ui.BIM_PT_mvd, ui.BIM_PT_debug, ui.BIM_PT_material, - ui.BIM_PT_mesh, ui.BIM_PT_presentation_layer_data, ui.BIM_PT_object, ui.BIM_PT_object_material, diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py index 525f7aa8d5..3bb4be8ab0 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py @@ -5,10 +5,11 @@ classes = ( operator.AddRepresentation, operator.SwitchRepresentation, operator.RemoveRepresentation, - operator.BakeParametricGeometry, - operator.UpdateIfcRepresentation, + operator.UpdateMeshRepresentation, + operator.UpdateParametricRepresentation, operator.GetRepresentationIfcParameters, ui.BIM_PT_representations, + ui.BIM_PT_mesh, ) diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/data.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/data.py index 2e7837f9e6..4283d58ac5 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/data.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/data.py @@ -3,19 +3,21 @@ from blenderbim.bim.ifc import IfcStore class Data: products = {} + representations = {} @classmethod def load(cls, product_id): file = IfcStore.get_file() if not file: return - cls.products[product_id] = {"Representations": {}} + cls.products[product_id] = [] product = file.by_id(product_id) if not product.Representation: return for representation in product.Representation.Representations: c = representation.ContextOfItems - cls.products[product_id]["Representations"][int(representation.id())] = { + rep_id = int(representation.id()) + cls.representations[rep_id] = { "RepresentationIdentifier": representation.RepresentationIdentifier, "RepresentationType": representation.RepresentationType, "ContextOfItems": { @@ -24,3 +26,4 @@ class Data: "TargetView": c.TargetView if c.is_a("IfcGeometricRepresentationSubContext") else "", } } + cls.products[product_id].append(rep_id) diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py index 5c7f3eeafe..f319294f00 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py @@ -15,50 +15,53 @@ from blenderbim.bim.module.geometry.data import Data class AddRepresentation(bpy.types.Operator): bl_idname = "bim.add_representation" bl_label = "Add Representation" + obj: bpy.props.StringProperty() def execute(self, context): - obj = bpy.context.active_object + obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object self.file = IfcStore.get_file() self.context_id = bpy.context.scene.BIMProperties.contexts - element = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id) - usecase = add_representation.Usecase( + add_object_placement.Usecase( self.file, { - "context": self.file.by_id(int(self.context_id)), - "geometry": obj.data, - "total_items": max(1, len(obj.material_slots)), + "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), + "matrix": np.array(obj.matrix_world), }, - ) - result = usecase.execute() - if not result: - print("Failed to write shape representation") - return {"FINISHED"} + ).execute() - usecase = assign_styles.Usecase( - self.file, - { - "shape_representation": result, - "styles": [ - self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id) - for s in obj.material_slots - if s.material - ], - }, - ) - usecase.execute() + if obj.data: + result = add_representation.Usecase( + self.file, + { + "context": self.file.by_id(int(self.context_id)), + "geometry": obj.data, + "total_items": max(1, len(obj.material_slots)), + }, + ).execute() + if not result: + print("Failed to write shape representation") + return {"FINISHED"} + assign_styles.Usecase( + self.file, + { + "shape_representation": result, + "styles": [ + self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id) + for s in obj.material_slots + if s.material + ], + }, + ).execute() + assign_representation.Usecase( + self.file, {"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "representation": result} + ).execute() - usecase = assign_representation.Usecase( - self.file, {"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "representation": result} - ) - usecase.execute() - - existing_mesh = obj.data - existing_mesh.use_fake_user = True - mesh = obj.data.copy() - mesh.name = "{}/{}".format(self.context_id, result.id()) - mesh.BIMMeshProperties.ifc_definition_id = int(result.id()) - obj.data = mesh + existing_mesh = obj.data + mesh = obj.data.copy() + mesh.name = "{}/{}".format(self.context_id, result.id()) + mesh.BIMMeshProperties.ifc_definition_id = int(result.id()) + obj.data = mesh Data.load(obj.BIMObjectProperties.ifc_definition_id) return {"FINISHED"} @@ -117,44 +120,42 @@ class RemoveRepresentation(bpy.types.Operator): void_mesh = bpy.data.meshes.new("Void") obj.data = void_mesh bpy.data.meshes.remove(mesh) - usecase = remove_representation.Usecase(self.file, {"representation": representation}) - result = usecase.execute() + remove_representation.Usecase(self.file, {"representation": representation}).execute() Data.load(obj.BIMObjectProperties.ifc_definition_id) return {"FINISHED"} -class BakeParametricGeometry(bpy.types.Operator): - bl_idname = "bim.bake_parametric_geometry" - bl_label = "Bake Parametric Geometry" +class UpdateMeshRepresentation(bpy.types.Operator): + bl_idname = "bim.update_mesh_representation" + bl_label = "Update Mesh Representation" + obj: bpy.props.StringProperty() def execute(self, context): - obj = bpy.context.active_object + obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object self.file = IfcStore.get_file() - usecase = add_object_placement.Usecase( + add_object_placement.Usecase( self.file, { "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "matrix": np.array(obj.matrix_world), }, - ) - result = usecase.execute() + ).execute() element = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id) - usecase = add_representation.Usecase( + result = add_representation.Usecase( self.file, { "context": element.ContextOfItems, "geometry": obj.data, "total_items": max(1, len(obj.material_slots)), }, - ) - result = usecase.execute() + ).execute() if not result: print("Failed to write shape representation") return {"FINISHED"} - usecase = assign_styles.Usecase( + assign_styles.Usecase( self.file, { "shape_representation": result, @@ -164,9 +165,9 @@ class BakeParametricGeometry(bpy.types.Operator): if s.material ], }, - ) - usecase.execute() + ).execute() + # TODO: move this into a replace_representation usecase or something for inverse in self.file.get_inverse(element): ifcopenshell.util.element.replace_attribute(inverse, element, result) obj.data.BIMMeshProperties.ifc_definition_id = int(result.id()) @@ -174,9 +175,9 @@ class BakeParametricGeometry(bpy.types.Operator): return {"FINISHED"} -class UpdateIfcRepresentation(bpy.types.Operator): - bl_idname = "bim.update_ifc_representation" - bl_label = "Update IFC Representation" +class UpdateParametricRepresentation(bpy.types.Operator): + bl_idname = "bim.update_parametric_representation" + bl_label = "Update Parametric Representation" index: bpy.props.IntProperty() def execute(self, context): diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py index 61f0303af8..d8d97a572f 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py @@ -18,7 +18,7 @@ class BIM_PT_representations(Panel): if props.ifc_definition_id not in Data.products: Data.load(props.ifc_definition_id) - representations = Data.products[props.ifc_definition_id]["Representations"] + representations = Data.products[props.ifc_definition_id] if not representations: layout.label(text="No representations found") @@ -26,7 +26,8 @@ class BIM_PT_representations(Panel): row.prop(bpy.context.scene.BIMProperties, "contexts", text="") row.operator("bim.add_representation", icon="ADD", text="") - for ifc_definition_id, representation in representations.items(): + for ifc_definition_id in representations: + representation = Data.representations[ifc_definition_id] row = self.layout.row(align=True) row.label(text=representation["ContextOfItems"]["ContextType"]) row.label(text=representation["ContextOfItems"]["ContextIdentifier"]) @@ -35,3 +36,34 @@ class BIM_PT_representations(Panel): row.operator("bim.switch_representation", icon="OUTLINER_DATA_MESH", text="").ifc_definition_id = ifc_definition_id row.operator("bim.remove_representation", icon="X", text="").ifc_definition_id = ifc_definition_id + +class BIM_PT_mesh(Panel): + bl_label = "IFC Representation" + bl_idname = "BIM_PT_mesh" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "data" + + @classmethod + def poll(cls, context): + return ( + context.active_object is not None + and context.active_object.type == "MESH" + and hasattr(context.active_object.data, "BIMMeshProperties") + ) + + def draw(self, context): + if not context.active_object.data: + return + layout = self.layout + props = context.active_object.data.BIMMeshProperties + + row = layout.row() + row.operator("bim.get_representation_ifc_parameters") + row = layout.row() + row.operator("bim.update_mesh_representation") + for index, ifc_parameter in enumerate(props.ifc_parameters): + row = layout.row(align=True) + row.prop(ifc_parameter, "name", text="") + row.prop(ifc_parameter, "value", text="") + row.operator("bim.update_parametric_representation", icon="FILE_REFRESH", text="").index = index diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py index 537c9ed5d4..85594864cb 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py @@ -102,40 +102,10 @@ class AssignClass(bpy.types.Operator): "name": obj.name, }, ).execute() + obj.name = "{}/{}".format(product.is_a(), obj.name) + obj.BIMObjectProperties.ifc_definition_id = int(product.id()) - add_object_placement.Usecase( - self.file, - { - "product": product, - "matrix": np.array(obj.matrix_world), - }, - ).execute() - - if obj.data: - representation = add_representation.Usecase( - self.file, - { - "context": self.file.by_id(int(bpy.context.scene.BIMProperties.contexts)), - "geometry": obj.data, - "total_items": max(1, len(obj.material_slots)), - }, - ).execute() - - assign_styles.Usecase( - self.file, - { - "shape_representation": representation, - "styles": [ - self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id) - for s in obj.material_slots - if s.material - ], - }, - ).execute() - - assign_representation.Usecase( - self.file, {"product": product, "representation": representation} - ).execute() + bpy.ops.bim.add_representation(obj=obj.name) relating_structure = None for collection in obj.users_collection: @@ -154,8 +124,6 @@ class AssignClass(bpy.types.Operator): }, ).execute() - obj.name = "{}/{}".format(product.is_a(), obj.name) - obj.BIMObjectProperties.ifc_definition_id = int(product.id()) if bpy.context.scene.BIMProperties.ifc_product == "IfcElementType": self.place_in_types_collection(obj) return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/spatial/assign_container.py b/src/ifcblenderexport/blenderbim/bim/module/spatial/assign_container.py index 29192b9877..8fe283d9ac 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/spatial/assign_container.py +++ b/src/ifcblenderexport/blenderbim/bim/module/spatial/assign_container.py @@ -29,7 +29,7 @@ class Usecase: if contains_elements: related_elements = list(contains_elements[0].RelatedElements) related_elements.append(self.settings["product"]) - contains_elements.RelatedElements = related_elements + contains_elements[0].RelatedElements = related_elements else: contains_elements = self.file.create_entity( "IfcRelContainedInSpatialStructure", diff --git a/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py b/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py index 9b2fb50d0e..d0fb0d4548 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py @@ -21,13 +21,12 @@ class AssignContainer(bpy.types.Operator): break if not relating_structure: return {"FINISHED"} - usecase = assign_container.Usecase( + assign_container.Usecase( self.file, { "product": self.file.by_id(props.ifc_definition_id), "relating_structure": relating_structure, }, - ) - usecase.execute() + ).execute() Data.load(props.ifc_definition_id) return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index b2ba479146..35bb981c7f 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -678,65 +678,6 @@ class BIM_PT_classifications(Panel): row.prop(props, "classifications") -class BIM_PT_mesh(Panel): - bl_label = "IFC Representations" - bl_idname = "BIM_PT_mesh" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "data" - - @classmethod - def poll(cls, context): - return ( - context.active_object is not None - and context.active_object.type == "MESH" - and hasattr(context.active_object.data, "BIMMeshProperties") - ) - - def draw(self, context): - if not context.active_object.data: - return - layout = self.layout - props = context.active_object.data.BIMMeshProperties - - layout.label(text="IFC Parameters:") - row = layout.row() - row.operator("bim.get_representation_ifc_parameters") - row = layout.row() - row.operator("bim.bake_parametric_geometry") - for index, ifc_parameter in enumerate(props.ifc_parameters): - row = layout.row(align=True) - row.prop(ifc_parameter, "name", text="") - row.prop(ifc_parameter, "value", text="") - row.operator("bim.update_ifc_representation", icon="FILE_REFRESH", text="").index = index - - row = layout.row() - row.prop(props, "is_parametric") - row = layout.row() - row.prop(props, "is_native") - row = layout.row() - row.prop(props, "is_swept_solid") - - row = layout.row() - row.operator("bim.add_swept_solid") - for index, swept_solid in enumerate(props.swept_solids): - row = layout.row(align=True) - row.prop(swept_solid, "name", text="") - row.operator("bim.remove_swept_solid", icon="X", text="").index = index - row = layout.row() - sub = row.row(align=True) - sub.operator("bim.assign_swept_solid_outer_curve").index = index - sub.operator("bim.select_swept_solid_outer_curve", icon="RESTRICT_SELECT_OFF", text="").index = index - sub = row.row(align=True) - sub.operator("bim.add_swept_solid_inner_curve").index = index - sub.operator("bim.select_swept_solid_inner_curves", icon="RESTRICT_SELECT_OFF", text="").index = index - row = layout.row(align=True) - row.operator("bim.assign_swept_solid_extrusion").index = index - row.operator("bim.select_swept_solid_extrusion", icon="RESTRICT_SELECT_OFF", text="").index = index - row = layout.row() - row.prop(props, "swept_solids") - - class BIM_PT_presentation_layer_data(Panel): bl_label = "IFC Presentation Layers" bl_idname = "BIM_PT_presentation"