mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Georeference module now supports IFC2X3 georeferencing / conversion utilities.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user