diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 6e955cfaef..5f25a89bf7 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -539,7 +539,7 @@ class IfcImporter: 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() + return tool.Loader.set_manual_blender_offset(self.file) return tool.Loader.guess_false_origin(self.file) def apply_blender_offset_to_matrix_world(self, obj: bpy.types.Object, matrix: np.ndarray) -> mathutils.Matrix: @@ -569,9 +569,9 @@ class IfcImporter: obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT" matrix = ifcopenshell.util.geolocation.global2local( matrix, - float(props.blender_eastings) * self.unit_scale, - float(props.blender_northings) * self.unit_scale, - float(props.blender_orthogonal_height) * self.unit_scale, + float(props.blender_offset_x) * self.unit_scale, + float(props.blender_offset_y) * self.unit_scale, + float(props.blender_offset_z) * self.unit_scale, float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate), ) diff --git a/src/blenderbim/blenderbim/bim/module/georeference/prop.py b/src/blenderbim/blenderbim/bim/module/georeference/prop.py index efac699ed3..c845914740 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/prop.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/prop.py @@ -17,7 +17,7 @@ # along with BlenderBIM Add-on. If not, see . import bpy -from blenderbim.bim.prop import StrProperty, Attribute +from blenderbim.bim.prop import Attribute from bpy.types import PropertyGroup from bpy.props import ( PointerProperty, @@ -49,6 +49,9 @@ class BIMGeoreferenceProperties(PropertyGroup): blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0") blender_x_axis_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1") blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0") + blender_offset_x: StringProperty(name="Blender Offset X", default="0") + blender_offset_y: StringProperty(name="Blender Offset Y", default="0") + blender_offset_z: StringProperty(name="Blender Offset Z", default="0") has_true_north: BoolProperty(name="Has True North", default=True) true_north_abscissa: StringProperty(name="True North Abscissa") true_north_ordinate: StringProperty(name="True North Ordinate") diff --git a/src/blenderbim/blenderbim/bim/module/georeference/ui.py b/src/blenderbim/blenderbim/bim/module/georeference/ui.py index abae08e25f..d2fc14c4fc 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/ui.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/ui.py @@ -90,7 +90,7 @@ class BIM_PT_gis(Panel): if props.has_blender_offset: row = self.layout.row() - row.label(text="Blender Offset", icon="TRACKING_REFINE_FORWARDS") + row.label(text="Blender Session Origin", icon="TRACKING_REFINE_FORWARDS") row = self.layout.row(align=True) row.label(text="Eastings") diff --git a/src/blenderbim/blenderbim/tool/loader.py b/src/blenderbim/blenderbim/tool/loader.py index c29bc26867..2d21db661e 100644 --- a/src/blenderbim/blenderbim/tool/loader.py +++ b/src/blenderbim/blenderbim/tool/loader.py @@ -555,24 +555,33 @@ class Loader(blenderbim.core.tool.Loader): return results @classmethod - def set_manual_blender_offset(cls) -> None: - props = bpy.context.scene.BIMGeoreferenceProperties - props.blender_eastings = str(cls.settings.false_origin[0]) - props.blender_northings = str(cls.settings.false_origin[1]) - props.blender_orthogonal_height = str(cls.settings.false_origin[2]) - props.has_blender_offset = True + def set_manual_blender_offset(cls, ifc_file: ifcopenshell.file) -> None: + model_origin = np.array(ifcopenshell.util.geolocation.auto_xyz2enh(ifc_file, 0, 0, 0)) + false_origin = np.array(cls.settings.false_origin) + model_offset = false_origin - model_origin + zero_origin = np.array((0, 0, 0)) + has_model_offset = not np.allclose(model_offset, zero_origin) + if has_model_offset: + props = bpy.context.scene.BIMGeoreferenceProperties + props.blender_offset_x = str(model_offset[0]) + props.blender_offset_y = str(model_offset[1]) + props.blender_offset_z = str(model_offset[2]) + props.blender_eastings = str(false_origin[0]) + props.blender_northings = str(false_origin[1]) + props.blender_orthogonal_height = str(false_origin[2]) + props.has_blender_offset = True @classmethod - def guess_false_origin_and_project_north(cls, element: ifcopenshell.entity_instance) -> None: + def guess_false_origin_and_project_north(cls, ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> None: if not element.ObjectPlacement or not element.ObjectPlacement.is_a("IfcLocalPlacement"): return placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) + offset_point = [placement[0][3], placement[1][3], placement[2][3]] + cls.settings.false_origin = ifcopenshell.util.geolocation.auto_xyz2enh(ifc_file, *offset_point) + cls.set_manual_blender_offset(ifc_file) props = bpy.context.scene.BIMGeoreferenceProperties - props.blender_eastings = str(placement[0][3]) - props.blender_northings = str(placement[1][3]) - props.blender_orthogonal_height = str(placement[2][3]) - x_axis = mathutils.Vector(placement[:, 0][0:3]) - default_x_axis = mathutils.Vector((1, 0, 0)) + x_axis = Vector(placement[:, 0][0:3]) + default_x_axis = Vector((1, 0, 0)) if (default_x_axis - x_axis).length > 0.01: props.blender_x_axis_abscissa = str(placement[0][0]) props.blender_x_axis_ordinate = str(placement[1][0]) @@ -622,9 +631,10 @@ class Loader(blenderbim.core.tool.Loader): elements_checked += 1 mat = ifcopenshell.util.shape.get_shape_matrix(shape) point = mat @ np.array((shape.geometry.verts[0], shape.geometry.verts[1], shape.geometry.verts[2], 1.0)) - point = point / cls.unit_scale - if cls.is_point_far_away(point, is_meters=False): - return point + if cls.is_point_far_away(point, is_meters=True): + # Arbitrary origins should be to the nearest millimeter. + # Anything more precise is just ridiculous from a practical surveying perspective. + return [round(float(p), 3) / cls.unit_scale for p in point[:3]] @classmethod def guess_false_origin_from_elements(cls, ifc_file: ifcopenshell.file) -> None: @@ -635,11 +645,8 @@ class Loader(blenderbim.core.tool.Loader): offset_point = cls.get_offset_point(ifc_file) if offset_point is None: return - props = bpy.context.scene.BIMGeoreferenceProperties - props.blender_eastings = str(offset_point[0]) - props.blender_northings = str(offset_point[1]) - props.blender_orthogonal_height = str(offset_point[2]) - props.has_blender_offset = True + cls.settings.false_origin = ifcopenshell.util.geolocation.auto_xyz2enh(ifc_file, *offset_point) + cls.set_manual_blender_offset(ifc_file) @classmethod def guess_false_origin(cls, ifc_file: ifcopenshell.file) -> None: @@ -649,8 +656,8 @@ class Loader(blenderbim.core.tool.Loader): project = ifc_file.by_type("IfcContext")[0] site = cls.find_decomposed_ifc_class(project, "IfcSite") if site and cls.is_element_far_away(site): - return cls.guess_false_origin_and_project_north(site) + return cls.guess_false_origin_and_project_north(ifc_file, site) building = cls.find_decomposed_ifc_class(project, "IfcBuilding") if building and cls.is_element_far_away(building): - return cls.guess_false_origin_and_project_north(building) + return cls.guess_false_origin_and_project_north(ifc_file, building) return cls.guess_false_origin_from_elements(ifc_file)