Georeference module now supports IFC2X3 georeferencing / conversion utilities.

This commit is contained in:
Dion Moult
2023-10-05 16:15:16 +11:00
parent 8119b3199a
commit 74ca102f6a
8 changed files with 68 additions and 96 deletions
@@ -56,7 +56,12 @@ class GeoreferenceData:
@classmethod
def map_conversion(cls):
if tool.Ifc.get_schema() == "IFC2X3":
return {}
project = tool.Ifc.get().by_type("IfcProject")[0]
map_conversion = ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion")
if not map_conversion:
return {}
del map_conversion["id"]
return map_conversion
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.HasCoordinateOperation:
@@ -72,8 +77,8 @@ class GeoreferenceData:
def map_derived_angle(cls):
if (
cls.data["map_conversion"]
and cls.data["map_conversion"]["XAxisAbscissa"] is not None
and cls.data["map_conversion"]["XAxisOrdinate"] is not None
and cls.data["map_conversion"].get("XAxisAbscissa", None) is not None
and cls.data["map_conversion"].get("XAxisOrdinate", None) is not None
):
return str(
round(
@@ -88,7 +93,12 @@ class GeoreferenceData:
@classmethod
def projected_crs(cls):
if tool.Ifc.get_schema() == "IFC2X3":
return {}
project = tool.Ifc.get().by_type("IfcProject")[0]
projected_crs = ifcopenshell.util.element.get_pset(project, "ePSet_ProjectedCRS")
if not projected_crs:
return {}
del projected_crs["id"]
return projected_crs
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.HasCoordinateOperation:
@@ -78,10 +78,14 @@ class BIM_PT_gis(Panel):
def draw_ui(self, context):
props = context.scene.BIMGeoreferenceProperties
if tool.Ifc.get_schema() == "IFC2X3":
row = self.layout.row()
row.label(text="IFC2X3 Fallback In Use", icon="ERROR")
if not GeoreferenceData.data["projected_crs"]:
row = self.layout.row(align=True)
row.label(text="Not Georeferenced")
if tool.Ifc.get_schema != "IFC2X3":
if tool.Ifc.get_schema() != "IFC2X3":
row.operator("bim.add_georeferencing", icon="ADD", text="")
if props.has_blender_offset:
@@ -110,8 +114,9 @@ class BIM_PT_gis(Panel):
if GeoreferenceData.data["projected_crs"]:
row = self.layout.row(align=True)
row.label(text="Projected CRS", icon="WORLD")
row.operator("bim.enable_editing_georeferencing", icon="GREASEPENCIL", text="")
row.operator("bim.remove_georeferencing", icon="X", text="")
if tool.Ifc.get_schema() != "IFC2X3":
row.operator("bim.enable_editing_georeferencing", icon="GREASEPENCIL", text="")
row.operator("bim.remove_georeferencing", icon="X", text="")
for key, value in GeoreferenceData.data["projected_crs"].items():
if not value:
@@ -184,4 +189,4 @@ class BIM_PT_gis_utilities(Panel):
row = self.layout.row(align=True)
row.prop(props, "y_axis_abscissa_output", text="North Abscissa")
row = self.layout.row(align=True)
row.prop(props, "y_axis_ordinate_output", text="North Ordinate")
row.prop(props, "y_axis_ordinate_output", text="North Ordinate")
@@ -71,13 +71,13 @@ def set_cursor_location(georeference):
def convert_local_to_global(georeference):
coordinates = georeference.xyz2enh(georeference.get_coordinates("input"), georeference.get_map_conversion())
coordinates = georeference.xyz2enh(georeference.get_coordinates("input"))
georeference.set_coordinates("output", coordinates)
georeference.set_cursor_location(coordinates)
def convert_global_to_local(georeference):
coordinates = georeference.enh2xyz(georeference.get_coordinates("input"), georeference.get_map_conversion())
coordinates = georeference.enh2xyz(georeference.get_coordinates("input"))
georeference.set_coordinates("output", coordinates)
georeference.set_cursor_location(coordinates)
@@ -86,4 +86,4 @@ def convert_angle_to_coord(georeference, type):
georeference.set_vector_coordinates(vector_coordinates,type)
def import_plot(georeference, filepath):
georeference.import_plot(filepath, georeference.get_map_conversion())
georeference.import_plot(filepath)
+13 -6
View File
@@ -17,7 +17,6 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.core
import bpy
def reference_structure(ifc, spatial, structure=None, element=None):
@@ -98,33 +97,43 @@ def select_similar_container(ifc, spatial, obj=None):
def select_product(spatial, product):
spatial.select_products([product])
def load_container_manager(spatial):
spatial.load_container_manager()
def edit_container_attributes(spatial, entity=None):
spatial.edit_container_attributes(entity)
spatial.load_container_manager()
def contract_container(spatial, container=None):
spatial.contract_container(container)
spatial.load_container_manager()
def expand_container(spatial, container=None):
spatial.expand_container(container)
spatial.load_container_manager()
def delete_container(ifc, spatial, geometry, container=None):
geometry.delete_ifc_object(ifc.get_object(container))
spatial.load_container_manager()
def select_decomposed_elements(spatial):
container = spatial.get_active_container()
if container:
spatial.select_products(spatial.get_decomposed_elements(container))
#HERE STARTS SPATIAL TOOL
# HERE STARTS SPATIAL TOOL
def generate_spaces_from_walls(ifc, spatial, collector):
import bpy
active_obj = bpy.context.active_object
element = ifc.get_entity(active_obj)
container = spatial.get_container(element)
@@ -172,9 +181,8 @@ def generate_spaces_from_walls(ifc, spatial, collector):
bpy.context.view_layer.active_layer_collection.collection.objects.link(obj)
bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcSpace")
container_obj = ifc.get_object(container)
blenderbim.core.spatial.assign_container(
ifc, collector, spatial, structure_obj=container_obj, element_obj=obj
)
blenderbim.core.spatial.assign_container(ifc, collector, spatial, structure_obj=container_obj, element_obj=obj)
def toggle_space_visibility(ifc, spatial):
model = ifc.get()
@@ -182,4 +190,3 @@ def toggle_space_visibility(ifc, spatial):
if not spaces:
return
spatial.toggle_spaces_visibility_wired_and_textured(spaces)
+2 -3
View File
@@ -384,12 +384,11 @@ class Georeference:
def angle2coords(cls, angle, type): pass
def disable_editing(cls): pass
def enable_editing(cls): pass
def enh2xyz(cls, map_conversion, coordinates): pass
def enh2xyz(cls, coordinates): pass
def get_angle(cls, type): pass
def get_coordinates(cls, io): pass
def get_cursor_location(cls): pass
def get_map_conversion_attributes(cls): pass
def get_map_conversion(cls): pass
def get_projected_crs_attributes(cls): pass
def get_true_north_attributes(cls): pass
def import_map_conversion(cls): pass
@@ -402,7 +401,7 @@ class Georeference:
def set_ifc_grid_north(cls): pass
def set_ifc_true_north(cls): pass
def set_vector_coordinates(cls, vector_coordinates, type): pass
def xyz2enh(cls, map_conversion, coordinates): pass
def xyz2enh(cls, coordinates): pass
@interface
+5 -54
View File
@@ -174,15 +174,7 @@ class Georeference(blenderbim.core.tool.Georeference):
)
@classmethod
def get_map_conversion(cls):
if tool.Ifc.get_schema() == "IFC2X3":
return
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.HasCoordinateOperation:
return context.HasCoordinateOperation[0]
@classmethod
def xyz2enh(cls, coordinates, map_conversion):
def xyz2enh(cls, coordinates):
props = bpy.context.scene.BIMGeoreferenceProperties
if props.has_blender_offset:
coordinates = ifcopenshell.util.geolocation.xyz2enh(
@@ -196,53 +188,12 @@ class Georeference(blenderbim.core.tool.Georeference):
float(props.blender_x_axis_ordinate),
1.0,
)
if map_conversion:
unit = map_conversion.TargetCRS.MapUnit
e = map_conversion.Eastings
n = map_conversion.Northings
h = map_conversion.OrthogonalHeight
if unit:
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
e = ifcopenshell.util.unit.convert(e, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
n = ifcopenshell.util.unit.convert(n, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
h = ifcopenshell.util.unit.convert(h, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
coordinates = ifcopenshell.util.geolocation.xyz2enh(
coordinates[0],
coordinates[1],
coordinates[2],
e,
n,
h,
map_conversion.XAxisAbscissa or 1.0,
map_conversion.XAxisOrdinate or 0.0,
map_conversion.Scale or 1.0,
)
return coordinates
return ifcopenshell.util.geolocation.auto_xyz2enh(tool.Ifc.get(), *coordinates)
@classmethod
def enh2xyz(cls, coordinates, map_conversion):
def enh2xyz(cls, coordinates):
coordinates = ifcopenshell.util.geolocation.auto_enh2xyz(tool.Ifc.get(), *coordinates)
props = bpy.context.scene.BIMGeoreferenceProperties
if map_conversion:
unit = map_conversion.TargetCRS.MapUnit
e = map_conversion.Eastings
n = map_conversion.Northings
h = map_conversion.OrthogonalHeight
if unit:
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
e = ifcopenshell.util.unit.convert(e, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
n = ifcopenshell.util.unit.convert(n, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
h = ifcopenshell.util.unit.convert(h, getattr(unit, "Prefix", None), unit.Name, None, None) / scale
coordinates = ifcopenshell.util.geolocation.enh2xyz(
coordinates[0],
coordinates[1],
coordinates[2],
e,
n,
h,
map_conversion.XAxisAbscissa or 1.0,
map_conversion.XAxisOrdinate or 0.0,
map_conversion.Scale or 1.0,
)
if props.has_blender_offset:
coordinates = ifcopenshell.util.geolocation.enh2xyz(
coordinates[0],
@@ -316,7 +267,7 @@ class Georeference(blenderbim.core.tool.Georeference):
rows = parse_csv(filepath)
vertices = []
for row in rows:
coordinates = cls.enh2xyz([float(row[0]), float(row[1]), float(row[2])], map_conversion)
coordinates = cls.enh2xyz([float(row[0]), float(row[1]), float(row[2])])
vertices.append(coordinates)
mesh = bpy.data.meshes.new("mesh")
@@ -97,8 +97,7 @@ class TestSetCursorLocation:
class TestConvertLocalToGlobal:
def test_run(self, georeference):
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
georeference.get_map_conversion().should_be_called().will_return("map_conversion")
georeference.xyz2enh("coordinates", "map_conversion").should_be_called().will_return("enh")
georeference.xyz2enh("coordinates").should_be_called().will_return("enh")
georeference.set_coordinates("output", "enh").should_be_called()
georeference.set_cursor_location("enh").should_be_called()
subject.convert_local_to_global(georeference)
@@ -107,8 +106,7 @@ class TestConvertLocalToGlobal:
class TestConvertGlobalToLocal:
def test_run(self, georeference):
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
georeference.get_map_conversion().should_be_called().will_return("map_conversion")
georeference.enh2xyz("coordinates", "map_conversion").should_be_called().will_return("xyz")
georeference.enh2xyz("coordinates").should_be_called().will_return("xyz")
georeference.set_coordinates("output", "xyz").should_be_called()
georeference.set_cursor_location("xyz").should_be_called()
subject.convert_global_to_local(georeference)
+20 -18
View File
@@ -247,25 +247,21 @@ class TestSetBlenderTrueNorth(NewFile):
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == 45
class TestGetMapConversion(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
assert subject.get_map_conversion().is_a("IfcMapConversion")
class TestXyz2Enh(NewFile):
def test_run(self):
assert subject.xyz2enh([0.0, 0.0, 0.0], None) == [0.0, 0.0, 0.0]
ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc)
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (0.0, 0.0, 0.0)
def test_using_the_blender_offset(self):
ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc)
props = bpy.context.scene.BIMGeoreferenceProperties
props.has_blender_offset = True
props.blender_eastings = "1.0"
assert subject.xyz2enh([0.0, 0.0, 0.0], None) == (1.0, 0.0, 0.0)
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 0.0, 0.0)
def test_using_the_map_conversion(self):
ifc = ifcopenshell.file()
@@ -275,7 +271,7 @@ class TestXyz2Enh(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Eastings = 1.0
assert subject.xyz2enh([0.0, 0.0, 0.0], map_conversion) == (1.0, 0.0, 0.0)
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 0.0, 0.0)
def test_applying_both_blender_offset_and_map_conversion(self):
props = bpy.context.scene.BIMGeoreferenceProperties
@@ -288,18 +284,24 @@ class TestXyz2Enh(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Northings = 1.0
assert subject.xyz2enh([0.0, 0.0, 0.0], map_conversion) == (1.0, 1.0, 0.0)
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 1.0, 0.0)
class TestEnh2Xyz(NewFile):
def test_run(self):
assert subject.enh2xyz([0.0, 0.0, 0.0], None) == [0.0, 0.0, 0.0]
ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc)
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (0.0, 0.0, 0.0)
def test_using_the_blender_offset(self):
ifc = ifcopenshell.file()
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
tool.Ifc.set(ifc)
props = bpy.context.scene.BIMGeoreferenceProperties
props.has_blender_offset = True
props.blender_eastings = "1.0"
assert subject.enh2xyz([0.0, 0.0, 0.0], None) == (-1.0, 0.0, 0.0)
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, 0.0, 0.0)
def test_using_the_map_conversion(self):
ifc = ifcopenshell.file()
@@ -309,7 +311,7 @@ class TestEnh2Xyz(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Eastings = 1.0
assert subject.enh2xyz([0.0, 0.0, 0.0], map_conversion) == (-1.0, 0.0, 0.0)
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, 0.0, 0.0)
def test_applying_both_blender_offset_and_map_conversion(self):
props = bpy.context.scene.BIMGeoreferenceProperties
@@ -322,7 +324,7 @@ class TestEnh2Xyz(NewFile):
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
map_conversion = ifc.by_type("IfcMapConversion")[0]
map_conversion.Northings = 1.0
assert subject.enh2xyz([0.0, 0.0, 0.0], map_conversion) == (-1.0, -1.0, 0.0)
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, -1.0, 0.0)
class TestSetIfcGridNorth(NewFile):