diff --git a/src/ifcblenderexport/blenderbim/bim/module/aggregate/operator.py b/src/ifcblenderexport/blenderbim/bim/module/aggregate/operator.py index 861b114179..4c546a61bf 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/aggregate/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/aggregate/operator.py @@ -25,6 +25,7 @@ class AssignObject(bpy.types.Operator): "relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id), }, ).execute() + bpy.ops.bim.edit_object_placement(obj=related_object.name) Data.load(props.ifc_definition_id) bpy.ops.bim.disable_editing_aggregate(obj=related_object.name) diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py index 3bb4be8ab0..4a8ff84b2a 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/__init__.py @@ -2,6 +2,7 @@ import bpy from . import ui, operator classes = ( + operator.EditObjectPlacement, operator.AddRepresentation, operator.SwitchRepresentation, operator.RemoveRepresentation, @@ -14,8 +15,8 @@ classes = ( def register(): - pass + bpy.types.OBJECT_PT_transform.append(ui.BIM_PT_transform) def unregister(): - pass + bpy.types.OBJECT_PT_transform.remove(ui.BIM_PT_transform) diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/add_object_placement.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/edit_object_placement.py similarity index 57% rename from src/ifcblenderexport/blenderbim/bim/module/geometry/add_object_placement.py rename to src/ifcblenderexport/blenderbim/bim/module/geometry/edit_object_placement.py index 4c3d2c8866..42865299ea 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/add_object_placement.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/edit_object_placement.py @@ -1,4 +1,5 @@ import numpy as np +import ifcopenshell.util.element import ifcopenshell.util.placement @@ -13,12 +14,38 @@ class Usecase: if not hasattr(self.settings["product"], "ObjectPlacement"): return self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) - if not self.settings["product"].ObjectPlacement: - placement_rel_to = None - else: - placement_rel_to = self.settings["product"].ObjectPlacement.PlacementRelTo + + dependent_objects = [] + if self.settings["product"].ObjectPlacement: + for referenced_placement in self.settings["product"].ObjectPlacement.ReferencedByPlacements: + for placed_obj in referenced_placement.PlacesObject: + dependent_objects.append( + { + "product": placed_obj, + "matrix": ifcopenshell.util.placement.get_local_placement(referenced_placement), + } + ) + + placement_rel_to = None + if hasattr(self.settings["product"], "ContainedInStructure") and self.settings["product"].ContainedInStructure: + placement_rel_to = self.settings["product"].ContainedInStructure[0].RelatingStructure.ObjectPlacement + elif hasattr(self.settings["product"], "Decomposes") and self.settings["product"].Decomposes: + relating_object = self.settings["product"].Decomposes[0].RelatingObject + placement_rel_to = relating_object.ObjectPlacement if hasattr(relating_object, "ObjectPlacement") else None + placement = self.file.createIfcLocalPlacement(placement_rel_to, self.get_relative_placement(placement_rel_to)) + if self.settings["product"].ObjectPlacement: + for inverse in self.file.get_inverse(self.settings["product"]): + ifcopenshell.util.element.replace_attribute( + inverse, self.settings["product"].ObjectPlacement, placement + ) + self.file.remove(self.settings["product"].ObjectPlacement) self.settings["product"].ObjectPlacement = placement + + for settings in dependent_objects: + self.settings = settings + self.execute() + return placement def get_relative_placement(self, placement_rel_to): @@ -34,7 +61,7 @@ class Usecase: z = np.array((m[0][2], m[1][2], m[2][2])) o = np.array((m[0][3], m[1][3], m[2][3])) object_matrix = ifcopenshell.util.placement.a2p(o, z, x) - relative_placement_matrix = relating_object_matrix @ object_matrix + relative_placement_matrix = np.linalg.inv(relating_object_matrix) @ object_matrix return self.create_ifc_axis_2_placement_3d( relative_placement_matrix[:, 3][0:3], relative_placement_matrix[:, 2][0:3], diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py index f319294f00..552d502530 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/operator.py @@ -2,7 +2,7 @@ import bpy import numpy as np import ifcopenshell import logging -import blenderbim.bim.module.geometry.add_object_placement as add_object_placement +import blenderbim.bim.module.geometry.edit_object_placement as edit_object_placement import blenderbim.bim.module.geometry.add_representation as add_representation import blenderbim.bim.module.geometry.assign_styles as assign_styles import blenderbim.bim.module.geometry.assign_representation as assign_representation @@ -12,6 +12,24 @@ from blenderbim.bim import import_ifc from blenderbim.bim.module.geometry.data import Data +class EditObjectPlacement(bpy.types.Operator): + bl_idname = "bim.edit_object_placement" + bl_label = "Edit Object Placement" + obj: bpy.props.StringProperty() + + def execute(self, context): + obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object + self.file = IfcStore.get_file() + edit_object_placement.Usecase( + self.file, + { + "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), + "matrix": np.array(obj.matrix_world), + }, + ).execute() + return {"FINISHED"} + + class AddRepresentation(bpy.types.Operator): bl_idname = "bim.add_representation" bl_label = "Add Representation" @@ -22,13 +40,7 @@ class AddRepresentation(bpy.types.Operator): self.file = IfcStore.get_file() self.context_id = bpy.context.scene.BIMProperties.contexts - add_object_placement.Usecase( - self.file, - { - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "matrix": np.array(obj.matrix_world), - }, - ).execute() + bpy.ops.bim.edit_object_placement(obj=obj.name) if obj.data: result = add_representation.Usecase( @@ -134,13 +146,7 @@ class UpdateMeshRepresentation(bpy.types.Operator): obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object self.file = IfcStore.get_file() - add_object_placement.Usecase( - self.file, - { - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "matrix": np.array(obj.matrix_world), - }, - ).execute() + bpy.ops.bim.edit_object_placement(obj=obj.name) element = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id) result = add_representation.Usecase( diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py index d8d97a572f..d9b27ac7e2 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/ui.py @@ -67,3 +67,9 @@ class BIM_PT_mesh(Panel): row.prop(ifc_parameter, "name", text="") row.prop(ifc_parameter, "value", text="") row.operator("bim.update_parametric_representation", icon="FILE_REFRESH", text="").index = index + + +def BIM_PT_transform(self, context): + if context.active_object and context.active_object.BIMObjectProperties.ifc_definition_id: + row = self.layout.row() + row.operator("bim.edit_object_placement") diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py index 36ae83103f..333a1ea9f7 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py @@ -5,11 +5,6 @@ import ifcopenshell.util.schema import blenderbim.bim.module.root.create_product as create_product import blenderbim.bim.module.root.remove_product as remove_product import blenderbim.bim.module.root.reassign_class as reassign_class -import blenderbim.bim.module.geometry.add_representation as add_representation -import blenderbim.bim.module.geometry.assign_styles as assign_styles -import blenderbim.bim.module.geometry.assign_representation as assign_representation -import blenderbim.bim.module.geometry.add_object_placement as add_object_placement -import blenderbim.bim.module.spatial.assign_container as assign_container from blenderbim.bim.ifc import IfcStore diff --git a/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py b/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py index fa7e87a9f0..7fc90d84f5 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/spatial/operator.py @@ -29,6 +29,7 @@ class AssignContainer(bpy.types.Operator): "relating_structure": self.file.by_id(relating_structure.BIMObjectProperties.ifc_definition_id), }, ).execute() + bpy.ops.bim.edit_object_placement(obj=related_element.name) Data.load(props.ifc_definition_id) bpy.ops.bim.disable_editing_container(obj=related_element.name) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 9a885c2e02..30b4582df8 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1522,6 +1522,7 @@ class BIM_PT_patch(Panel): class BIM_PT_mvd(Panel): bl_label = "Model View Definitions (MVD)" bl_idname = "BIM_PT_mvd" + bl_options = {"DEFAULT_CLOSED"} bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "scene"