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.
This commit is contained in:
Dion Moult
2024-06-17 17:10:14 +10:00
parent 9c61a9eed7
commit 2300411ce4
3 changed files with 72 additions and 29 deletions
+5 -7
View File
@@ -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:
@@ -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")
@@ -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
)