diff --git a/src/ifcopenshell-python/ifcopenshell/api/georeference/add_georeferencing.py b/src/ifcopenshell-python/ifcopenshell/api/georeference/add_georeferencing.py
index 38f766d4e8..1c4656f625 100644
--- a/src/ifcopenshell-python/ifcopenshell/api/georeference/add_georeferencing.py
+++ b/src/ifcopenshell-python/ifcopenshell/api/georeference/add_georeferencing.py
@@ -17,6 +17,8 @@
# along with IfcOpenShell. If not, see .
import ifcopenshell
+import ifcopenshell.api.pset
+import ifcopenshell.util.element
def add_georeferencing(file: ifcopenshell.file) -> None:
@@ -42,6 +44,25 @@ def add_georeferencing(file: ifcopenshell.file) -> None:
ifcopenshell.api.run("georeference.add_georeferencing", model)
"""
+ if file.schema == "IFC2X3":
+ if not (project := file.by_type("IfcProject")):
+ return
+ project = project[0]
+ if ifcopenshell.util.element.get_pset(project, "ePSet_ProjectedCRS"):
+ return
+ conversion = ifcopenshell.api.pset.add_pset(file, project, "ePSet_MapConversion")
+ crs = ifcopenshell.api.pset.add_pset(file, project, "ePSet_ProjectedCRS")
+ ifcopenshell.api.pset.edit_pset(file, crs, properties={"Name": ""})
+ ifcopenshell.api.pset.edit_pset(
+ file,
+ conversion,
+ properties={
+ "Eastings": file.createIfcLengthMeasure(0),
+ "Northings": file.createIfcLengthMeasure(0),
+ "OrthogonalHeight": file.createIfcLengthMeasure(0),
+ },
+ )
+ return
if file.by_type("IfcProjectedCRS"):
return
source_crs = None
diff --git a/src/ifcopenshell-python/ifcopenshell/api/georeference/edit_georeferencing.py b/src/ifcopenshell-python/ifcopenshell/api/georeference/edit_georeferencing.py
index 12ac54693a..ec01435505 100644
--- a/src/ifcopenshell-python/ifcopenshell/api/georeference/edit_georeferencing.py
+++ b/src/ifcopenshell-python/ifcopenshell/api/georeference/edit_georeferencing.py
@@ -100,13 +100,36 @@ def edit_georeferencing(
class Usecase:
def execute(self):
+ self.set_true_north()
+ if self.file.schema == "IFC2X3":
+ if not (project := self.file.by_type("IfcProject")):
+ return
+ project = project[0]
+ if (crs := ifcopenshell.util.element.get_pset(project, "ePSet_ProjectedCRS")):
+ crs = self.file.by_id(crs["id"])
+ for k, v in self.settings["projected_crs"].items():
+ if k == "Description":
+ v = self.file.createIfcText(v)
+ elif k == "Name":
+ v = self.file.createIfcLabel(v)
+ else:
+ v = self.file.createIfcIdentifier(v)
+ ifcopenshell.api.pset.edit_pset(self.file, crs, properties=self.settings["projected_crs"])
+ if (conversion := ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion")):
+ conversion = self.file.by_id(conversion["id"])
+ for k, v in self.settings["map_conversion"].items():
+ if k in ("XAxisAbscissa", "XAxisOrdinate", "Scale"):
+ v = self.file.createIfcReal(v)
+ else:
+ v = self.file.createIfcLengthMeasure(v)
+ ifcopenshell.api.pset.edit_pset(self.file, conversion, properties=self.settings["map_conversion"])
+ return
map_conversion = self.file.by_type("IfcMapConversion")[0]
projected_crs = self.file.by_type("IfcProjectedCRS")[0]
for name, value in self.settings["map_conversion"].items():
setattr(map_conversion, name, value)
for name, value in self.settings["projected_crs"].items():
setattr(projected_crs, name, value)
- self.set_true_north()
def set_true_north(self):
if not self.settings["true_north"]:
diff --git a/src/ifcopenshell-python/test/api/georeference/__init__.py b/src/ifcopenshell-python/test/api/georeference/__init__.py
new file mode 100644
index 0000000000..8bed51a56f
--- /dev/null
+++ b/src/ifcopenshell-python/test/api/georeference/__init__.py
@@ -0,0 +1,17 @@
+# IfcOpenShell - IFC toolkit and geometry engine
+# Copyright (C) 2021 Dion Moult
+#
+# This file is part of IfcOpenShell.
+#
+# IfcOpenShell is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# IfcOpenShell is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with IfcOpenShell. If not, see .
diff --git a/src/ifcopenshell-python/test/api/georeference/test_add_georeferencing.py b/src/ifcopenshell-python/test/api/georeference/test_add_georeferencing.py
new file mode 100644
index 0000000000..df2c6de583
--- /dev/null
+++ b/src/ifcopenshell-python/test/api/georeference/test_add_georeferencing.py
@@ -0,0 +1,69 @@
+# IfcOpenShell - IFC toolkit and geometry engine
+# Copyright (C) 2022 Dion Moult
+#
+# This file is part of IfcOpenShell.
+#
+# IfcOpenShell is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# IfcOpenShell is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with IfcOpenShell. If not, see .
+
+import test.bootstrap
+import ifcopenshell.api.root
+import ifcopenshell.api.context
+import ifcopenshell.api.georeference
+import ifcopenshell.util.element
+
+
+class TestAddGeoreferencing(test.bootstrap.IFC4):
+ def test_adding_georeferencing(self):
+ ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.context.add_context(self.file, "Model")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ assert len(self.file.by_type("IfcMapConversion")) == 1
+ assert len(self.file.by_type("IfcProjectedCRS")) == 1
+ assert (conversion := self.file.by_type("IfcMapConversion")[0])
+ assert (crs := self.file.by_type("IfcProjectedCRS")[0])
+ assert conversion.Eastings == conversion.Northings == conversion.OrthogonalHeight == 0
+ assert crs.Name == ""
+
+ def test_not_doing_anything_if_no_model_context(self):
+ ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ ifcopenshell.api.context.add_context(self.file, "Plan")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ assert len(self.file.by_type("IfcMapConversion")) == 0
+ assert len(self.file.by_type("IfcProjectedCRS")) == 0
+
+ def test_not_adding_georeferencing_twice(self):
+ ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.context.add_context(self.file, "Model")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ assert len(self.file.by_type("IfcMapConversion")) == 1
+ assert len(self.file.by_type("IfcProjectedCRS")) == 1
+
+
+class TestAddGeoreferencingIFC2X3(test.bootstrap.IFC2X3):
+ def test_adding_georeferencing(self):
+ project = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ conversion = ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion", verbose=True)
+ crs = ifcopenshell.util.element.get_pset(project, "ePSet_ProjectedCRS", verbose=True)
+ assert len(self.file.by_type("IfcPropertySet")) == 2
+ assert conversion
+ assert crs
+ assert crs["Name"]["value"] == ""
+ assert self.file.by_id(crs["Name"]["id"]).NominalValue.is_a("IfcLabel")
+ assert conversion["Eastings"]["value"] == 0
+ assert self.file.by_id(conversion["Eastings"]["id"]).NominalValue.is_a("IfcLengthMeasure")
+ assert conversion["Northings"]["value"] == 0
+ assert conversion["OrthogonalHeight"]["value"] == 0
diff --git a/src/ifcopenshell-python/test/api/georeference/test_edit_georeferencing.py b/src/ifcopenshell-python/test/api/georeference/test_edit_georeferencing.py
new file mode 100644
index 0000000000..55fd79a6a9
--- /dev/null
+++ b/src/ifcopenshell-python/test/api/georeference/test_edit_georeferencing.py
@@ -0,0 +1,74 @@
+# IfcOpenShell - IFC toolkit and geometry engine
+# Copyright (C) 2022 Dion Moult
+#
+# This file is part of IfcOpenShell.
+#
+# IfcOpenShell is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# IfcOpenShell is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with IfcOpenShell. If not, see .
+
+import test.bootstrap
+import ifcopenshell.api.root
+import ifcopenshell.api.context
+import ifcopenshell.api.georeference
+import ifcopenshell.util.element
+
+
+class TestEditGeoreferencing(test.bootstrap.IFC4):
+ def test_editing_georeferencing(self):
+ ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.context.add_context(self.file, "Model")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ ifcopenshell.api.georeference.edit_georeferencing(
+ self.file,
+ projected_crs={"Name": "EPSG:7856"},
+ map_conversion={
+ "Eastings": 123.45,
+ "Northings": 234.56,
+ },
+ )
+ crs = self.file.by_type("IfcProjectedCRS")[0]
+ assert crs.Name == "EPSG:7856"
+ conversion = self.file.by_type("IfcMapConversion")[0]
+ assert conversion.Eastings == 123.45
+ assert conversion.Northings == 234.56
+
+ def test_editing_true_north(self):
+ ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ model = ifcopenshell.api.context.add_context(self.file, "Model")
+ plan = ifcopenshell.api.context.add_context(self.file, "Plan")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ ifcopenshell.api.georeference.edit_georeferencing(self.file, true_north=[0., 1.])
+ assert model.TrueNorth[0] == (0., 1., 0.)
+ assert plan.TrueNorth[0] == (0., 1.)
+
+
+class TestEditGeoreferencingIFC2X3(test.bootstrap.IFC2X3):
+ def test_editing_georeferencing(self):
+ project = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
+ ifcopenshell.api.georeference.add_georeferencing(self.file)
+ ifcopenshell.api.georeference.edit_georeferencing(
+ self.file,
+ projected_crs={"Name": "EPSG:7856"},
+ map_conversion={
+ "Eastings": 123.45,
+ "Northings": 234.56,
+ },
+ )
+ conversion = ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion", verbose=True)
+ crs = ifcopenshell.util.element.get_pset(project, "ePSet_ProjectedCRS", verbose=True)
+ assert crs["Name"]["value"] == "EPSG:7856"
+ assert self.file.by_id(crs["Name"]["id"]).NominalValue.is_a("IfcLabel")
+ assert conversion["Eastings"]["value"] == 123.45
+ assert self.file.by_id(conversion["Eastings"]["id"]).NominalValue.is_a("IfcLengthMeasure")
+ assert conversion["Northings"]["value"] == 234.56
+ assert conversion["OrthogonalHeight"]["value"] == 0