From 2300411ce4bcfc6d153819120f8f1971968cf01f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 17 Jun 2024 17:10:14 +1000 Subject: [PATCH] Fix #4510. Linking in georeferenced models now reuses the host model's georeferencing settings In addition to reusing a constant false origin, because we now reuse the same logic as project loading, we also now get the ability to mix map-conversion and non-map-conversion coordinates and also link in rotated models, not just translated. --- src/blenderbim/blenderbim/bim/import_ifc.py | 12 ++-- .../bim/module/georeference/prop.py | 21 ++++-- .../blenderbim/bim/module/project/operator.py | 68 ++++++++++++++----- 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index c0898720b2..777d646185 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -534,13 +534,11 @@ class IfcImporter: def calculate_model_offset(self) -> None: props = bpy.context.scene.BIMGeoreferenceProperties - if props.has_blender_offset: - return - elif self.ifc_import_settings.false_origin_mode == "DISABLED": - return - elif self.ifc_import_settings.false_origin_mode == "MANUAL": - return tool.Loader.set_manual_blender_offset(self.file) - return tool.Loader.guess_false_origin(self.file) + if self.ifc_import_settings.false_origin_mode == "MANUAL": + tool.Loader.set_manual_blender_offset(self.file) + elif self.ifc_import_settings.false_origin_mode == "AUTOMATIC": + if not props.has_blender_offset: + tool.Loader.guess_false_origin(self.file) def create_grids(self): if not self.ifc_import_settings.should_load_geometry: diff --git a/src/blenderbim/blenderbim/bim/module/georeference/prop.py b/src/blenderbim/blenderbim/bim/module/georeference/prop.py index c845914740..051d502cfc 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/prop.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/prop.py @@ -39,10 +39,23 @@ class BIMGeoreferenceProperties(PropertyGroup): coordinate_output: StringProperty(name="Coordinate Output", description='Formatted "x,y,z" (without quotes)') angle_degree_input_x: FloatProperty(name="Angle Degree Input", description="Angle (in degrees) rel to Easting") angle_degree_input_y: FloatProperty(name="Angle Degree Input", description="Angle (in degrees) rel to +Y") - x_axis_abscissa_output: StringProperty(name="X Axis Abscissa Ordinate Output", description="X axis abscissa and ordinate", ) - x_axis_ordinate_output: StringProperty(name="X Axis Abscissa Ordinate Output", description="X axis abscissa and ordinate", ) - y_axis_abscissa_output: StringProperty(name="Y Axis Abscissa Ordinate Output", description="Y axis abscissa and ordinate", ) - y_axis_ordinate_output: StringProperty(name="Y Axis Abscissa Ordinate Output", description="Y axis abscissa and ordinate", ) + x_axis_abscissa_output: StringProperty( + name="X Axis Abscissa Ordinate Output", + description="X axis abscissa and ordinate", + ) + x_axis_ordinate_output: StringProperty( + name="X Axis Abscissa Ordinate Output", + description="X axis abscissa and ordinate", + ) + y_axis_abscissa_output: StringProperty( + name="Y Axis Abscissa Ordinate Output", + description="Y axis abscissa and ordinate", + ) + y_axis_ordinate_output: StringProperty( + name="Y Axis Abscissa Ordinate Output", + description="Y axis abscissa and ordinate", + ) + host_model_origin: StringProperty(name="Host Model Origin") has_blender_offset: BoolProperty(name="Has Blender Offset") blender_eastings: StringProperty(name="Blender Eastings", default="0") blender_northings: StringProperty(name="Blender Northings", default="0") diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index dce7b02dba..342fe2f5a2 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -856,7 +856,16 @@ class LinkIfc(bpy.types.Operator): directory: bpy.props.StringProperty(subtype="DIR_PATH") filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False) - false_origin: bpy.props.StringProperty(name="False Origin", default="0,0,0") + + def draw(self, context): + pprops = context.scene.BIMProjectProperties + row = self.layout.row() + row.prop(self, "use_relative_path") + row = self.layout.row() + row.prop(pprops, "false_origin_mode") + if pprops.false_origin_mode == "MANUAL": + row = self.layout.row() + row.prop(pprops, "false_origin") def execute(self, context): start = time.time() @@ -873,7 +882,7 @@ class LinkIfc(bpy.types.Operator): except: pass # Perhaps on another drive or something new.name = filepath - status = bpy.ops.bim.load_link(filepath=filepath, false_origin=self.false_origin) + status = bpy.ops.bim.load_link(filepath=filepath) if status == {"CANCELLED"}: error_msg = ( f'Error processing IFC file "{self.filepath}" ' @@ -951,7 +960,6 @@ class LoadLink(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} bl_description = "Load the selected file" filepath: bpy.props.StringProperty() - false_origin: bpy.props.StringProperty(name="False Origin", default="0,0,0") def execute(self, context): self.filepath = self.filepath.replace("\\", "/") @@ -984,12 +992,37 @@ class LoadLink(bpy.types.Operator): h5_filepath = self.filepath + ".cache.h5" if not os.path.exists(blend_filepath): + gprops = bpy.context.scene.BIMGeoreferenceProperties + pprops = bpy.context.scene.BIMProjectProperties + host_model_origin = "" + if tool.Ifc.get(): + if gprops.has_blender_offset: + host_model_origin = ( + f"{gprops.blender_eastings},{gprops.blender_northings},{gprops.blender_orthogonal_height}" + ) + else: + host_model_origin = ",".join( + map(str, ifcopenshell.util.geolocation.auto_xyz2enh(tool.Ifc.get(), 0, 0, 0)) + ) code = f""" import bpy def run(): - props = bpy.context.scene.BIMProjectProperties - props.false_origin = "{self.false_origin}" + gprops = bpy.context.scene.BIMGeoreferenceProperties + gprops.host_model_origin = "{host_model_origin}" + gprops.has_blender_offset = {gprops.has_blender_offset} + gprops.blender_eastings = "{gprops.blender_eastings}" + gprops.blender_northings = "{gprops.blender_northings}" + gprops.blender_orthogonal_height = "{gprops.blender_orthogonal_height}" + gprops.blender_offset_x = "{gprops.blender_offset_x}" + gprops.blender_offset_y = "{gprops.blender_offset_y}" + gprops.blender_offset_z = "{gprops.blender_offset_z}" + gprops.blender_x_axis_abscissa = "{gprops.blender_x_axis_abscissa}" + gprops.blender_x_axis_ordinate = "{gprops.blender_x_axis_ordinate}" + pprops = bpy.context.scene.BIMProjectProperties + pprops.distance_limit = {pprops.distance_limit} + pprops.false_origin_mode = "{pprops.false_origin_mode}" + pprops.false_origin = "{pprops.false_origin}" bpy.ops.bim.load_linked_project(filepath="{self.filepath}") bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath}") @@ -1255,6 +1288,8 @@ class LoadLinkedProject(bpy.types.Operator): start = time.time() + gprops = bpy.context.scene.BIMGeoreferenceProperties + self.filepath = self.filepath.replace("\\", "/") print("Processing", self.filepath) @@ -1270,6 +1305,8 @@ class LoadLinkedProject(bpy.types.Operator): print("Finished writing property database") logger = logging.getLogger("ImportIFC") + self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) + tool.Loader.set_unit_scale(self.unit_scale) tool.Loader.set_settings(import_ifc.IfcImportSettings.factory(context, IfcStore.path, logger)) tool.Loader.settings.contexts = ifcopenshell.util.representation.get_prioritised_contexts(self.file) tool.Loader.settings.context_settings = tool.Loader.create_settings() @@ -1283,25 +1320,20 @@ class LoadLinkedProject(bpy.types.Operator): self.elements |= set(self.file.by_type("IfcSpatialElement")) self.elements -= set(self.file.by_type("IfcFeatureElement")) - if tool.Loader.settings.false_origin: - model_origin = np.array(ifcopenshell.util.geolocation.auto_xyz2enh(self.file, 0, 0, 0)) - false_origin = np.array(tool.Loader.settings.false_origin) - model_offset = model_origin - false_origin - zero_origin = np.array((0, 0, 0)) - has_model_offset = not np.allclose(model_offset, zero_origin) - else: - has_model_offset = False + if tool.Loader.settings.false_origin_mode == "MANUAL" and tool.Loader.settings.false_origin: + tool.Loader.set_manual_blender_offset(self.file) + elif tool.Loader.settings.false_origin_mode == "AUTOMATIC": + if gprops.host_model_origin: + tool.Loader.settings.false_origin = list(map(float, gprops.host_model_origin.split(","))) + tool.Loader.set_manual_blender_offset(self.file) + else: + tool.Loader.guess_false_origin(self.file) for settings in tool.Loader.settings.context_settings: if not self.elements: break results = set() - if has_model_offset: - offset = ifcopenshell.ifcopenshell_wrapper.float_array_3() - offset[0], offset[1], offset[2] = model_offset - settings.offset = offset - iterator = ifcopenshell.geom.iterator( settings, self.file, multiprocessing.cpu_count(), include=self.elements )