diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 5638e2eca1..7829906a00 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -1498,6 +1498,7 @@ class IfcImportSettings: self.distance_limit = 1000 self.false_origin_mode = "AUTOMATIC" self.false_origin = None + self.project_north = None self.element_offset = 0 self.element_limit = 30000 self.has_filter = None @@ -1533,6 +1534,10 @@ class IfcImportSettings: settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]] except: 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_limit = props.element_limit return settings diff --git a/src/blenderbim/blenderbim/bim/module/georeference/data.py b/src/blenderbim/blenderbim/bim/module/georeference/data.py index c0c9080dcc..839f3cda02 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/data.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/data.py @@ -35,7 +35,6 @@ class GeoreferenceData: @classmethod def load(cls): 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["map_derived_angle"] = cls.map_derived_angle() cls.data["projected_crs"] = cls.projected_crs() @@ -56,19 +55,6 @@ class GeoreferenceData: version = tool.Ifc.get_schema() 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 def coordinate_operation(cls): if tool.Ifc.get_schema() == "IFC2X3": diff --git a/src/blenderbim/blenderbim/bim/module/georeference/prop.py b/src/blenderbim/blenderbim/bim/module/georeference/prop.py index 870d7b32eb..f62c002ac6 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/prop.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/prop.py @@ -119,11 +119,12 @@ class BIMGeoreferenceProperties(PropertyGroup): blender_eastings: StringProperty(name="Blender Eastings", default="0") blender_northings: StringProperty(name="Blender Northings", 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_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0") + blender_project_north: StringProperty(name="Blender Angle to Grid North", 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") + 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_abscissa: StringProperty(name="True North Abscissa", update=update_true_north_vector) true_north_ordinate: StringProperty(name="True North Ordinate", update=update_true_north_vector) diff --git a/src/blenderbim/blenderbim/bim/module/georeference/ui.py b/src/blenderbim/blenderbim/bim/module/georeference/ui.py index 66d3f35f8f..c1fce8bce6 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/ui.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/ui.py @@ -92,7 +92,7 @@ class BIM_PT_gis(Panel): if props.has_blender_offset: 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.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=props.blender_orthogonal_height) row = self.layout.row(align=True) - row.label(text="XAxisAbscissa") - row.label(text=props.blender_x_axis_abscissa) - 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"]) + row.label(text="Angle to Grid North") + row.label(text=props.blender_project_north) if GeoreferenceData.data["projected_crs"]: row = self.layout.row(align=True) @@ -144,7 +138,7 @@ class BIM_PT_gis(Panel): row.label(text=str(value)) if key == "XAxisOrdinate": 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"]) @@ -195,7 +189,7 @@ class BIM_PT_gis_true_north(Panel): row.operator("bim.enable_editing_true_north", icon="GREASEPENCIL", text="") row.operator("bim.remove_true_north", icon="X", text="") 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"]) else: row = self.layout.row(align=True) diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index ecd54550d7..b0ebb61039 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -918,6 +918,8 @@ class LinkIfc(bpy.types.Operator): if pprops.false_origin_mode == "MANUAL": row = self.layout.row() row.prop(pprops, "false_origin") + row = self.layout.row() + row.prop(pprops, "project_north") def execute(self, context): start = time.time() @@ -1071,6 +1073,7 @@ def run(): pprops.distance_limit = {pprops.distance_limit} pprops.false_origin_mode = "{pprops.false_origin_mode}" pprops.false_origin = "{pprops.false_origin}" + pprops.project_north = "{pprops.project_north}" bpy.ops.bim.load_linked_project(filepath="{self.filepath}") bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath}") @@ -1413,6 +1416,7 @@ class LoadLinkedProject(bpy.types.Operator): "distance_limit": pprops.distance_limit, "false_origin_mode": pprops.false_origin_mode, "false_origin": pprops.false_origin, + "project_north": pprops.project_north, } with open(self.json_filepath, "w") as f: json.dump(data, f) diff --git a/src/blenderbim/blenderbim/bim/module/project/prop.py b/src/blenderbim/blenderbim/bim/module/project/prop.py index 4669c9426f..32e3e9c77e 100644 --- a/src/blenderbim/blenderbim/bim/module/project/prop.py +++ b/src/blenderbim/blenderbim/bim/module/project/prop.py @@ -171,6 +171,11 @@ class BIMProjectProperties(PropertyGroup): description="False origin in project units that the Blender origin will correlate to", 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_limit: IntProperty(name="Element Offset", default=30000) should_disable_undo_on_save: BoolProperty( diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index b7403e07dc..b53e6f808e 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -175,6 +175,8 @@ class BIM_PT_project(Panel): if pprops.false_origin_mode == "MANUAL": row = self.layout.row() row.prop(pprops, "false_origin") + row = self.layout.row() + row.prop(pprops, "project_north") row = self.layout.row() row.label(text="Element Range") diff --git a/src/blenderbim/blenderbim/tool/georeference.py b/src/blenderbim/blenderbim/tool/georeference.py index 677d2a89fb..ee2dfaffb0 100644 --- a/src/blenderbim/blenderbim/tool/georeference.py +++ b/src/blenderbim/blenderbim/tool/georeference.py @@ -91,7 +91,7 @@ class Georeference(blenderbim.core.tool.Georeference): elif name == "XAxisAbscissa": props = bpy.context.scene.BIMGeoreferenceProperties 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 else: props.grid_north_angle = str( diff --git a/src/blenderbim/blenderbim/tool/loader.py b/src/blenderbim/blenderbim/tool/loader.py index 757f2fd9a7..7e17704c6b 100644 --- a/src/blenderbim/blenderbim/tool/loader.py +++ b/src/blenderbim/blenderbim/tool/loader.py @@ -568,15 +568,36 @@ class Loader(blenderbim.core.tool.Loader): 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: + has_offset = not np.allclose(model_offset, zero_origin) + + 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.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.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 @classmethod diff --git a/src/ifcopenshell-python/ifcopenshell/util/geolocation.py b/src/ifcopenshell-python/ifcopenshell/util/geolocation.py index 21eb2083e3..a74f75fc0c 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/geolocation.py +++ b/src/ifcopenshell-python/ifcopenshell/util/geolocation.py @@ -543,7 +543,9 @@ def xaxis2angle(x: float, y: float) -> float: the page?". See the diagram on the IfcGeometricRepresentationContext 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 y: The X axis ordinate @@ -562,6 +564,7 @@ def yaxis2angle(x: float, y: float) -> float: documentation for clarification. 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 y: The Y axis ordinate