mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 03:05:33 +00:00
False origin is always in terms of map coordinates, not as an offset.
Previously, the false origin would be in terms of local coordinates. This means that the same false origin would give two different results on files with different map conversions. Now, false origin is ... well, a true map coordinate and works equally for both IFCs with and without a map conversion.
This commit is contained in:
@@ -539,7 +539,7 @@ class IfcImporter:
|
|||||||
elif self.ifc_import_settings.false_origin_mode == "DISABLED":
|
elif self.ifc_import_settings.false_origin_mode == "DISABLED":
|
||||||
return
|
return
|
||||||
elif self.ifc_import_settings.false_origin_mode == "MANUAL":
|
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)
|
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:
|
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"
|
obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT"
|
||||||
matrix = ifcopenshell.util.geolocation.global2local(
|
matrix = ifcopenshell.util.geolocation.global2local(
|
||||||
matrix,
|
matrix,
|
||||||
float(props.blender_eastings) * self.unit_scale,
|
float(props.blender_offset_x) * self.unit_scale,
|
||||||
float(props.blender_northings) * self.unit_scale,
|
float(props.blender_offset_y) * self.unit_scale,
|
||||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
float(props.blender_offset_z) * self.unit_scale,
|
||||||
float(props.blender_x_axis_abscissa),
|
float(props.blender_x_axis_abscissa),
|
||||||
float(props.blender_x_axis_ordinate),
|
float(props.blender_x_axis_ordinate),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import Attribute
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -49,6 +49,9 @@ class BIMGeoreferenceProperties(PropertyGroup):
|
|||||||
blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0")
|
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_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1")
|
||||||
blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0")
|
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)
|
has_true_north: BoolProperty(name="Has True North", default=True)
|
||||||
true_north_abscissa: StringProperty(name="True North Abscissa")
|
true_north_abscissa: StringProperty(name="True North Abscissa")
|
||||||
true_north_ordinate: StringProperty(name="True North Ordinate")
|
true_north_ordinate: StringProperty(name="True North Ordinate")
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class BIM_PT_gis(Panel):
|
|||||||
|
|
||||||
if props.has_blender_offset:
|
if props.has_blender_offset:
|
||||||
row = self.layout.row()
|
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 = self.layout.row(align=True)
|
||||||
row.label(text="Eastings")
|
row.label(text="Eastings")
|
||||||
|
|||||||
@@ -555,24 +555,33 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_manual_blender_offset(cls) -> None:
|
def set_manual_blender_offset(cls, ifc_file: ifcopenshell.file) -> None:
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
model_origin = np.array(ifcopenshell.util.geolocation.auto_xyz2enh(ifc_file, 0, 0, 0))
|
||||||
props.blender_eastings = str(cls.settings.false_origin[0])
|
false_origin = np.array(cls.settings.false_origin)
|
||||||
props.blender_northings = str(cls.settings.false_origin[1])
|
model_offset = false_origin - model_origin
|
||||||
props.blender_orthogonal_height = str(cls.settings.false_origin[2])
|
zero_origin = np.array((0, 0, 0))
|
||||||
props.has_blender_offset = True
|
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
|
@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"):
|
if not element.ObjectPlacement or not element.ObjectPlacement.is_a("IfcLocalPlacement"):
|
||||||
return
|
return
|
||||||
placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
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 = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
props.blender_eastings = str(placement[0][3])
|
x_axis = Vector(placement[:, 0][0:3])
|
||||||
props.blender_northings = str(placement[1][3])
|
default_x_axis = Vector((1, 0, 0))
|
||||||
props.blender_orthogonal_height = str(placement[2][3])
|
|
||||||
x_axis = mathutils.Vector(placement[:, 0][0:3])
|
|
||||||
default_x_axis = mathutils.Vector((1, 0, 0))
|
|
||||||
if (default_x_axis - x_axis).length > 0.01:
|
if (default_x_axis - x_axis).length > 0.01:
|
||||||
props.blender_x_axis_abscissa = str(placement[0][0])
|
props.blender_x_axis_abscissa = str(placement[0][0])
|
||||||
props.blender_x_axis_ordinate = str(placement[1][0])
|
props.blender_x_axis_ordinate = str(placement[1][0])
|
||||||
@@ -622,9 +631,10 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
elements_checked += 1
|
elements_checked += 1
|
||||||
mat = ifcopenshell.util.shape.get_shape_matrix(shape)
|
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 = 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=True):
|
||||||
if cls.is_point_far_away(point, is_meters=False):
|
# Arbitrary origins should be to the nearest millimeter.
|
||||||
return point
|
# 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
|
@classmethod
|
||||||
def guess_false_origin_from_elements(cls, ifc_file: ifcopenshell.file) -> None:
|
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)
|
offset_point = cls.get_offset_point(ifc_file)
|
||||||
if offset_point is None:
|
if offset_point is None:
|
||||||
return
|
return
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
cls.settings.false_origin = ifcopenshell.util.geolocation.auto_xyz2enh(ifc_file, *offset_point)
|
||||||
props.blender_eastings = str(offset_point[0])
|
cls.set_manual_blender_offset(ifc_file)
|
||||||
props.blender_northings = str(offset_point[1])
|
|
||||||
props.blender_orthogonal_height = str(offset_point[2])
|
|
||||||
props.has_blender_offset = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def guess_false_origin(cls, ifc_file: ifcopenshell.file) -> None:
|
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]
|
project = ifc_file.by_type("IfcContext")[0]
|
||||||
site = cls.find_decomposed_ifc_class(project, "IfcSite")
|
site = cls.find_decomposed_ifc_class(project, "IfcSite")
|
||||||
if site and cls.is_element_far_away(site):
|
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")
|
building = cls.find_decomposed_ifc_class(project, "IfcBuilding")
|
||||||
if building and cls.is_element_far_away(building):
|
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)
|
return cls.guess_false_origin_from_elements(ifc_file)
|
||||||
|
|||||||
Reference in New Issue
Block a user