mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 02:07:36 +00:00
You can now specify custom project norths when loading in models in absolute terms
This commit is contained in:
@@ -1498,6 +1498,7 @@ class IfcImportSettings:
|
|||||||
self.distance_limit = 1000
|
self.distance_limit = 1000
|
||||||
self.false_origin_mode = "AUTOMATIC"
|
self.false_origin_mode = "AUTOMATIC"
|
||||||
self.false_origin = None
|
self.false_origin = None
|
||||||
|
self.project_north = None
|
||||||
self.element_offset = 0
|
self.element_offset = 0
|
||||||
self.element_limit = 30000
|
self.element_limit = 30000
|
||||||
self.has_filter = None
|
self.has_filter = None
|
||||||
@@ -1533,6 +1534,10 @@ class IfcImportSettings:
|
|||||||
settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]]
|
settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]]
|
||||||
except:
|
except:
|
||||||
settings.false_origin = [0, 0, 0]
|
settings.false_origin = [0, 0, 0]
|
||||||
|
try:
|
||||||
|
settings.project_north = float(props.project_north)
|
||||||
|
except:
|
||||||
|
settings.project_north = 0
|
||||||
settings.element_offset = props.element_offset
|
settings.element_offset = props.element_offset
|
||||||
settings.element_limit = props.element_limit
|
settings.element_limit = props.element_limit
|
||||||
return settings
|
return settings
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class GeoreferenceData:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
cls.data["coordinate_operation_class"] = cls.coordinate_operation_class()
|
cls.data["coordinate_operation_class"] = cls.coordinate_operation_class()
|
||||||
cls.data["blender_derived_angle"] = cls.blender_derived_angle()
|
|
||||||
cls.data["coordinate_operation"] = cls.coordinate_operation()
|
cls.data["coordinate_operation"] = cls.coordinate_operation()
|
||||||
cls.data["map_derived_angle"] = cls.map_derived_angle()
|
cls.data["map_derived_angle"] = cls.map_derived_angle()
|
||||||
cls.data["projected_crs"] = cls.projected_crs()
|
cls.data["projected_crs"] = cls.projected_crs()
|
||||||
@@ -56,19 +55,6 @@ class GeoreferenceData:
|
|||||||
version = tool.Ifc.get_schema()
|
version = tool.Ifc.get_schema()
|
||||||
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)]
|
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)]
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def blender_derived_angle(cls):
|
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
|
||||||
if props.has_blender_offset:
|
|
||||||
return str(
|
|
||||||
round(
|
|
||||||
ifcopenshell.util.geolocation.xaxis2angle(
|
|
||||||
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate)
|
|
||||||
),
|
|
||||||
3,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def coordinate_operation(cls):
|
def coordinate_operation(cls):
|
||||||
if tool.Ifc.get_schema() == "IFC2X3":
|
if tool.Ifc.get_schema() == "IFC2X3":
|
||||||
|
|||||||
@@ -119,11 +119,12 @@ class BIMGeoreferenceProperties(PropertyGroup):
|
|||||||
blender_eastings: StringProperty(name="Blender Eastings", default="0")
|
blender_eastings: StringProperty(name="Blender Eastings", default="0")
|
||||||
blender_northings: StringProperty(name="Blender Northings", default="0")
|
blender_northings: StringProperty(name="Blender Northings", default="0")
|
||||||
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_project_north: StringProperty(name="Blender Angle to Grid North", 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_x: StringProperty(name="Blender Offset X", default="0")
|
||||||
blender_offset_y: StringProperty(name="Blender Offset Y", default="0")
|
blender_offset_y: StringProperty(name="Blender Offset Y", default="0")
|
||||||
blender_offset_z: StringProperty(name="Blender Offset Z", default="0")
|
blender_offset_z: StringProperty(name="Blender Offset Z", 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")
|
||||||
true_north_angle: StringProperty(name="True North Angle", update=update_true_north_angle)
|
true_north_angle: StringProperty(name="True North Angle", update=update_true_north_angle)
|
||||||
true_north_abscissa: StringProperty(name="True North Abscissa", update=update_true_north_vector)
|
true_north_abscissa: StringProperty(name="True North Abscissa", update=update_true_north_vector)
|
||||||
true_north_ordinate: StringProperty(name="True North Ordinate", update=update_true_north_vector)
|
true_north_ordinate: StringProperty(name="True North Ordinate", update=update_true_north_vector)
|
||||||
|
|||||||
@@ -92,7 +92,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 Session Origin", icon="TRACKING_REFINE_FORWARDS")
|
row.label(text="Blender Session Coordinates", icon="TRACKING_REFINE_FORWARDS")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=f"Eastings ({GeoreferenceData.data['local_unit_symbol']})")
|
row.label(text=f"Eastings ({GeoreferenceData.data['local_unit_symbol']})")
|
||||||
@@ -104,14 +104,8 @@ class BIM_PT_gis(Panel):
|
|||||||
row.label(text=f"OrthogonalHeight ({GeoreferenceData.data['local_unit_symbol']})")
|
row.label(text=f"OrthogonalHeight ({GeoreferenceData.data['local_unit_symbol']})")
|
||||||
row.label(text=props.blender_orthogonal_height)
|
row.label(text=props.blender_orthogonal_height)
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="XAxisAbscissa")
|
row.label(text="Angle to Grid North")
|
||||||
row.label(text=props.blender_x_axis_abscissa)
|
row.label(text=props.blender_project_north)
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.label(text="XAxisOrdinate")
|
|
||||||
row.label(text=props.blender_x_axis_ordinate)
|
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.label(text="Derived Grid North")
|
|
||||||
row.label(text=GeoreferenceData.data["blender_derived_angle"])
|
|
||||||
|
|
||||||
if GeoreferenceData.data["projected_crs"]:
|
if GeoreferenceData.data["projected_crs"]:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -144,7 +138,7 @@ class BIM_PT_gis(Panel):
|
|||||||
row.label(text=str(value))
|
row.label(text=str(value))
|
||||||
if key == "XAxisOrdinate":
|
if key == "XAxisOrdinate":
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="Derived Angle")
|
row.label(text="*Angle to Grid North")
|
||||||
row.label(text=GeoreferenceData.data["map_derived_angle"])
|
row.label(text=GeoreferenceData.data["map_derived_angle"])
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +189,7 @@ class BIM_PT_gis_true_north(Panel):
|
|||||||
row.operator("bim.enable_editing_true_north", icon="GREASEPENCIL", text="")
|
row.operator("bim.enable_editing_true_north", icon="GREASEPENCIL", text="")
|
||||||
row.operator("bim.remove_true_north", icon="X", text="")
|
row.operator("bim.remove_true_north", icon="X", text="")
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="Derived Angle")
|
row.label(text="*Angle to True North")
|
||||||
row.label(text=GeoreferenceData.data["true_derived_angle"])
|
row.label(text=GeoreferenceData.data["true_derived_angle"])
|
||||||
else:
|
else:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
|
|||||||
@@ -918,6 +918,8 @@ class LinkIfc(bpy.types.Operator):
|
|||||||
if pprops.false_origin_mode == "MANUAL":
|
if pprops.false_origin_mode == "MANUAL":
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.prop(pprops, "false_origin")
|
row.prop(pprops, "false_origin")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(pprops, "project_north")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
@@ -1071,6 +1073,7 @@ def run():
|
|||||||
pprops.distance_limit = {pprops.distance_limit}
|
pprops.distance_limit = {pprops.distance_limit}
|
||||||
pprops.false_origin_mode = "{pprops.false_origin_mode}"
|
pprops.false_origin_mode = "{pprops.false_origin_mode}"
|
||||||
pprops.false_origin = "{pprops.false_origin}"
|
pprops.false_origin = "{pprops.false_origin}"
|
||||||
|
pprops.project_north = "{pprops.project_north}"
|
||||||
bpy.ops.bim.load_linked_project(filepath="{self.filepath}")
|
bpy.ops.bim.load_linked_project(filepath="{self.filepath}")
|
||||||
bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath}")
|
bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath}")
|
||||||
|
|
||||||
@@ -1413,6 +1416,7 @@ class LoadLinkedProject(bpy.types.Operator):
|
|||||||
"distance_limit": pprops.distance_limit,
|
"distance_limit": pprops.distance_limit,
|
||||||
"false_origin_mode": pprops.false_origin_mode,
|
"false_origin_mode": pprops.false_origin_mode,
|
||||||
"false_origin": pprops.false_origin,
|
"false_origin": pprops.false_origin,
|
||||||
|
"project_north": pprops.project_north,
|
||||||
}
|
}
|
||||||
with open(self.json_filepath, "w") as f:
|
with open(self.json_filepath, "w") as f:
|
||||||
json.dump(data, f)
|
json.dump(data, f)
|
||||||
|
|||||||
@@ -171,6 +171,11 @@ class BIMProjectProperties(PropertyGroup):
|
|||||||
description="False origin in project units that the Blender origin will correlate to",
|
description="False origin in project units that the Blender origin will correlate to",
|
||||||
default="0,0,0",
|
default="0,0,0",
|
||||||
)
|
)
|
||||||
|
project_north: StringProperty(
|
||||||
|
name="Angle to Grid North",
|
||||||
|
description="The angle (postive is anticlockwise) pointing to grid north relative to project north",
|
||||||
|
default="0",
|
||||||
|
)
|
||||||
element_offset: IntProperty(name="Element Offset", default=0)
|
element_offset: IntProperty(name="Element Offset", default=0)
|
||||||
element_limit: IntProperty(name="Element Offset", default=30000)
|
element_limit: IntProperty(name="Element Offset", default=30000)
|
||||||
should_disable_undo_on_save: BoolProperty(
|
should_disable_undo_on_save: BoolProperty(
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ class BIM_PT_project(Panel):
|
|||||||
if pprops.false_origin_mode == "MANUAL":
|
if pprops.false_origin_mode == "MANUAL":
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.prop(pprops, "false_origin")
|
row.prop(pprops, "false_origin")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(pprops, "project_north")
|
||||||
|
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.label(text="Element Range")
|
row.label(text="Element Range")
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class Georeference(blenderbim.core.tool.Georeference):
|
|||||||
elif name == "XAxisAbscissa":
|
elif name == "XAxisAbscissa":
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
props.is_changing_angle = True
|
props.is_changing_angle = True
|
||||||
if data["XAxisAbscissa"] is None or data["XAxisOrdinate"]:
|
if data["XAxisAbscissa"] is None or data["XAxisOrdinate"] is None:
|
||||||
props.x_axis_is_null = True
|
props.x_axis_is_null = True
|
||||||
else:
|
else:
|
||||||
props.grid_north_angle = str(
|
props.grid_north_angle = str(
|
||||||
|
|||||||
@@ -568,15 +568,36 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
false_origin = np.array(cls.settings.false_origin)
|
false_origin = np.array(cls.settings.false_origin)
|
||||||
model_offset = false_origin - model_origin
|
model_offset = false_origin - model_origin
|
||||||
zero_origin = np.array((0, 0, 0))
|
zero_origin = np.array((0, 0, 0))
|
||||||
has_model_offset = not np.allclose(model_offset, zero_origin)
|
has_offset = not np.allclose(model_offset, zero_origin)
|
||||||
if has_model_offset:
|
|
||||||
|
parameters = ifcopenshell.util.geolocation.get_helmert_transformation_parameters(ifc_file)
|
||||||
|
model_north = ifcopenshell.util.geolocation.xaxis2angle(parameters.xaa, parameters.xao)
|
||||||
|
project_north = cls.settings.project_north
|
||||||
|
model_rotation = project_north - model_north
|
||||||
|
if model_rotation > 180:
|
||||||
|
model_rotation = (360 - model_rotation) * -1
|
||||||
|
elif model_rotation < -180:
|
||||||
|
model_rotation = (model_rotation * -1) - 360
|
||||||
|
has_rotation = not np.isclose(model_north, project_north)
|
||||||
|
|
||||||
|
if not has_offset:
|
||||||
|
model_offset = false_origin = (0, 0, 0)
|
||||||
|
|
||||||
|
if not has_rotation:
|
||||||
|
project_north = 0
|
||||||
|
|
||||||
|
if has_offset or has_rotation:
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
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_eastings = str(false_origin[0])
|
||||||
props.blender_northings = str(false_origin[1])
|
props.blender_northings = str(false_origin[1])
|
||||||
props.blender_orthogonal_height = str(false_origin[2])
|
props.blender_orthogonal_height = str(false_origin[2])
|
||||||
|
props.blender_project_north = str(project_north)
|
||||||
|
props.blender_offset_x = str(model_offset[0])
|
||||||
|
props.blender_offset_y = str(model_offset[1])
|
||||||
|
props.blender_offset_z = str(model_offset[2])
|
||||||
|
xaa, xao = ifcopenshell.util.geolocation.angle2xaxis(model_rotation)
|
||||||
|
props.blender_x_axis_abscissa = str(xaa)
|
||||||
|
props.blender_x_axis_ordinate = str(xao)
|
||||||
props.has_blender_offset = True
|
props.has_blender_offset = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -543,7 +543,9 @@ def xaxis2angle(x: float, y: float) -> float:
|
|||||||
the page?". See the diagram on the IfcGeometricRepresentationContext
|
the page?". See the diagram on the IfcGeometricRepresentationContext
|
||||||
documentation for clarification.
|
documentation for clarification.
|
||||||
|
|
||||||
The angle indicates "how do I rotate grid east to get to project east?".
|
The angle indicates "how do I rotate project east to get to grid east?".
|
||||||
|
Alternatively: "how do I rotate project north to get to grid north?".
|
||||||
|
Positive angles are anticlockwise.
|
||||||
|
|
||||||
:param x: The X axis abscissa
|
:param x: The X axis abscissa
|
||||||
:param y: The X axis ordinate
|
:param y: The X axis ordinate
|
||||||
@@ -562,6 +564,7 @@ def yaxis2angle(x: float, y: float) -> float:
|
|||||||
documentation for clarification.
|
documentation for clarification.
|
||||||
|
|
||||||
The angle indicates "how do I rotate project north to get to true north?".
|
The angle indicates "how do I rotate project north to get to true north?".
|
||||||
|
Positive angles are anticlockwise.
|
||||||
|
|
||||||
:param x: The Y axis abscissa
|
:param x: The Y axis abscissa
|
||||||
:param y: The Y axis ordinate
|
:param y: The Y axis ordinate
|
||||||
|
|||||||
Reference in New Issue
Block a user