From c5773b56651f1fee576d5d4471f5cf5fb1f5c8c3 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 3 May 2022 16:50:55 +1000 Subject: [PATCH] Port locations are now auto synchronised when hiding ports --- src/blenderbim/blenderbim/bim/export_ifc.py | 13 +------------ .../blenderbim/bim/module/model/mep.py | 9 +++------ .../blenderbim/bim/module/model/product.py | 3 ++- .../blenderbim/bim/module/system/operator.py | 2 +- src/blenderbim/blenderbim/core/system.py | 18 ++++++++++++++---- src/blenderbim/blenderbim/core/tool.py | 3 ++- src/blenderbim/blenderbim/tool/system.py | 12 ++++++++++-- src/blenderbim/test/core/test_system.py | 17 +++++++++++++---- src/blenderbim/test/tool/test_system.py | 10 ++++++++-- 9 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index 063c793c80..941f3ca485 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -148,7 +148,7 @@ class IfcExporter: return checksum != str([s.id() for s in tool.Geometry.get_styles(obj) if s]) def sync_object_placement(self, obj): - if not self.has_object_moved(obj): + if not tool.Ifc.is_moved(obj): return blender_matrix = np.array(obj.matrix_world) element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) @@ -162,17 +162,6 @@ class IfcExporter: blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) return element - def has_object_moved(self, obj): - if not obj.BIMObjectProperties.location_checksum: - return True # Let's be conservative - loc_check = np.frombuffer(eval(obj.BIMObjectProperties.location_checksum)) - rot_check = np.frombuffer(eval(obj.BIMObjectProperties.rotation_checksum)) - loc_real = np.array(obj.matrix_world.translation).flatten() - rot_real = np.array(obj.matrix_world.to_3x3()).flatten() - if np.allclose(loc_check, loc_real, atol=1e-4) and np.allclose(rot_check, rot_real, atol=1e-2): - return False - return True - def sync_grid_axis_object_placement(self, obj, element): grid = (element.PartOfU or element.PartOfV or element.PartOfW)[0] grid_obj = tool.Ifc.get_object(grid) diff --git a/src/blenderbim/blenderbim/bim/module/model/mep.py b/src/blenderbim/blenderbim/bim/module/model/mep.py index 4d3c03d8af..b653eadbb6 100644 --- a/src/blenderbim/blenderbim/bim/module/model/mep.py +++ b/src/blenderbim/blenderbim/bim/module/model/mep.py @@ -106,16 +106,13 @@ class MepGenerator: pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.Mep"}) - start_port_matrix = obj.matrix_world - end_port_matrix = obj.matrix_world.copy() - end_port_location = end_port_matrix @ Vector((0, 0, self.length)) - end_port_matrix[0][3] = end_port_location[0] - end_port_matrix[1][3] = end_port_location[1] - end_port_matrix[2][3] = end_port_location[2] + start_port_matrix = Matrix() + end_port_matrix = Matrix.Translation((0, 0, self.length)) for mat in [start_port_matrix, end_port_matrix]: port_obj = bpy.data.objects.new("Port", None) port_obj.matrix_world = mat + port_obj.parent = obj port = tool.System.run_root_assign_class(obj=port_obj, ifc_class="IfcDistributionPort") tool.Ifc.run("system.assign_port", element=element, port=port) diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 1415d407c9..d9fe8797db 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -143,7 +143,8 @@ class AddTypeInstance(bpy.types.Operator): mat[1][3] *= unit_scale mat[2][3] *= unit_scale port_obj = bpy.data.objects.new("Port", None) - port_obj.matrix_world = obj.matrix_world @ mathutils.Matrix(mat) + port_obj.matrix_world = mathutils.Matrix(mat) + port_obj.parent = obj port = tool.System.run_root_assign_class(obj=port_obj, ifc_class="IfcDistributionPort") tool.Ifc.run("system.assign_port", element=element, port=port) diff --git a/src/blenderbim/blenderbim/bim/module/system/operator.py b/src/blenderbim/blenderbim/bim/module/system/operator.py index 290654884e..12e78cda4d 100644 --- a/src/blenderbim/blenderbim/bim/module/system/operator.py +++ b/src/blenderbim/blenderbim/bim/module/system/operator.py @@ -149,7 +149,7 @@ class HidePorts(bpy.types.Operator, Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - core.hide_ports(tool.System, element=tool.Ifc.get_entity(context.active_object)) + core.hide_ports(tool.Ifc, tool.System, element=tool.Ifc.get_entity(context.active_object)) class AddPort(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/core/system.py b/src/blenderbim/blenderbim/core/system.py index cde210638f..7153ab8c53 100644 --- a/src/blenderbim/blenderbim/core/system.py +++ b/src/blenderbim/blenderbim/core/system.py @@ -68,16 +68,26 @@ def select_system_products(system_tool, system=None): def show_ports(system, element=None): ports = system.get_ports(element) - system.load_ports(ports) + system.load_ports(element, ports) system.select_elements(ports) -def hide_ports(system, element=None): - system.delete_element_objects(system.get_ports(element)) +def hide_ports(ifc, system, element=None): + obj = ifc.get_object(element) + if obj and ifc.is_moved(obj): + system.run_geometry_edit_object_placement(obj=obj) + + ports = system.get_ports(element) + for port in ports: + obj = ifc.get_object(port) + if obj and ifc.is_moved(obj): + system.run_geometry_edit_object_placement(obj=obj) + + system.delete_element_objects(ports) def add_port(ifc, system, element=None): - system.load_ports(system.get_ports(element)) + system.load_ports(element, system.get_ports(element)) obj = system.create_empty_at_cursor_with_element_orientation(element) port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort") ifc.run("system.assign_port", element=element, port=port) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 29129a2ec5..790b702ea3 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -473,7 +473,8 @@ class System: def get_ports(cls, element): pass def import_system_attributes(cls, system): pass def import_systems(cls): pass - def load_ports(cls, port): pass + def load_ports(cls, element, ports): pass + def run_geometry_edit_object_placement(cls, obj=None): pass def run_root_assign_class(cls, obj=None, ifc_class=None, predefined_type=None, should_add_representation=True, context=None, ifc_representation_class=None): pass def select_elements(cls, elements): pass def select_system_products(cls, system): pass diff --git a/src/blenderbim/blenderbim/tool/system.py b/src/blenderbim/blenderbim/tool/system.py index b2109330a1..74ec903033 100644 --- a/src/blenderbim/blenderbim/tool/system.py +++ b/src/blenderbim/blenderbim/tool/system.py @@ -81,9 +81,10 @@ class System(blenderbim.core.tool.System): new.ifc_class = system.is_a() @classmethod - def load_ports(cls, ports): + def load_ports(cls, element, ports): if not ports: return + obj = tool.Ifc.get_object(element) ifc_import_settings = import_ifc.IfcImportSettings.factory() ifc_importer = import_ifc.IfcImporter(ifc_import_settings) ifc_importer.file = tool.Ifc.get() @@ -93,9 +94,16 @@ class System(blenderbim.core.tool.System): for port in ports or []: if tool.Ifc.get_object(port): continue - ifc_importer.create_product(port) + port_obj = ifc_importer.create_product(port) + if obj: + port_obj.parent = obj + port_obj.matrix_parent_inverse = obj.matrix_world.inverted() ifc_importer.place_objects_in_collections() + @classmethod + def run_geometry_edit_object_placement(cls, obj=None): + return blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) + @classmethod def run_root_assign_class( cls, diff --git a/src/blenderbim/test/core/test_system.py b/src/blenderbim/test/core/test_system.py index 2cf955bf4b..3d818fe301 100644 --- a/src/blenderbim/test/core/test_system.py +++ b/src/blenderbim/test/core/test_system.py @@ -93,22 +93,31 @@ class TestSelectSystemProducts: class TestShowPorts: def test_run(self, system): system.get_ports("element").should_be_called().will_return(["port"]) - system.load_ports(["port"]).should_be_called() + system.load_ports("element", ["port"]).should_be_called() system.select_elements(["port"]).should_be_called() subject.show_ports(system, element="element") class TestHidePorts: - def test_run(self, system): + def test_run(self, ifc, system): + ifc.get_object("element").should_be_called().will_return("obj") + ifc.is_moved("obj").should_be_called().will_return(True) + system.run_geometry_edit_object_placement(obj="obj").should_be_called() + system.get_ports("element").should_be_called().will_return(["port"]) + + ifc.get_object("port").should_be_called().will_return("port_obj") + ifc.is_moved("port_obj").should_be_called().will_return(True) + system.run_geometry_edit_object_placement(obj="port_obj").should_be_called() + system.delete_element_objects(["port"]).should_be_called() - subject.hide_ports(system, element="element") + subject.hide_ports(ifc, system, element="element") class TestAddPort: def test_run(self, ifc, system): system.get_ports("element").should_be_called().will_return(["port"]) - system.load_ports(["port"]).should_be_called() + system.load_ports("element", ["port"]).should_be_called() system.create_empty_at_cursor_with_element_orientation("element").should_be_called().will_return("obj") system.run_root_assign_class(obj="obj", ifc_class="IfcDistributionPort").should_be_called().will_return("port") ifc.run("system.assign_port", element="element", port="port").should_be_called() diff --git a/src/blenderbim/test/tool/test_system.py b/src/blenderbim/test/tool/test_system.py index 0e8fc3f021..2d70c6adde 100644 --- a/src/blenderbim/test/tool/test_system.py +++ b/src/blenderbim/test/tool/test_system.py @@ -177,15 +177,21 @@ class TestLoadPorts(NewFile): ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject") ifcopenshell.api.run("unit.assign_unit", ifc) tool.Ifc().set(ifc) + element = ifc.createIfcChiller() port = ifc.createIfcDistributionPort() - subject.load_ports([port]) + subject.load_ports(element, [port]) obj = tool.Ifc.get_object(port) assert obj assert obj.users_collection assert list(obj.location) == [0, 0, 0] -class TestRunAssignClassOperator(NewFile): +class TestRunGeometryEditObjectPlacement(NewFile): + def test_nothing(self): + pass + + +class TestRunRootAssignClass(NewFile): def test_nothing(self): pass