Finish refactor georeference module

This commit is contained in:
maxfb87
2022-04-15 14:52:15 +02:00
committed by Dion Moult
parent dfb980e0d1
commit fcd5908ac9
7 changed files with 276 additions and 69 deletions
@@ -25,14 +25,14 @@ classes = (
operator.EditGeoreferencing, operator.EditGeoreferencing,
operator.SetIfcGridNorth, operator.SetIfcGridNorth,
operator.SetBlenderGridNorth, operator.SetBlenderGridNorth,
# operator.SetIfcTrueNorth, operator.SetIfcTrueNorth,
# operator.SetBlenderTrueNorth, operator.SetBlenderTrueNorth,
operator.RemoveGeoreferencing, operator.RemoveGeoreferencing,
operator.AddGeoreferencing, operator.AddGeoreferencing,
# operator.ConvertLocalToGlobal, operator.ConvertLocalToGlobal,
# operator.ConvertGlobalToLocal, operator.ConvertGlobalToLocal,
# operator.GetCursorLocation, operator.GetCursorLocation,
# operator.SetCursorLocation, operator.SetCursorLocation,
prop.BIMGeoreferenceProperties, prop.BIMGeoreferenceProperties,
ui.BIM_PT_gis, ui.BIM_PT_gis,
ui.BIM_PT_gis_utilities, ui.BIM_PT_gis_utilities,
@@ -16,8 +16,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
# ############################################################################ #
import blenderbim.tool as tool import blenderbim.tool as tool
def refresh(): def refresh():
@@ -35,20 +33,6 @@ class GeoreferenceData:
"true_north" : cls.true_north(), "true_north" : cls.true_north(),
} }
cls.is_loaded = True cls.is_loaded = True
@classmethod
def is_georeferenced(cls):
ifc = tool.Ifc.get()
if ifc.schema == "IFC2X3":
return
map_conversions = []
for context in ifc.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if not context.HasCoordinateOperation:
continue
map_conversions.append(context)
return True if map_conversions else False
@classmethod @classmethod
def map_conversion(cls): def map_conversion(cls):
@@ -19,7 +19,6 @@
import bpy import bpy
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.core.georeference as core import blenderbim.core.georeference as core
import blenderbim.bim.handler
class AddGeoreferencing(bpy.types.Operator, tool.Ifc.Operator): class AddGeoreferencing(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_georeferencing" bl_idname = "bim.add_georeferencing"
@@ -79,10 +78,85 @@ class SetBlenderGridNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_blender_grid_north" bl_idname = "bim.set_blender_grid_north"
bl_label = "Set Blender Grid North" bl_label = "Set Blender Grid North"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Set Blender grif north" bl_description = "Set Blender grid north"
def _execute(self, context): def _execute(self, context):
core.set_blender_grid_north() core.set_blender_grid_north()
class GetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.get_cursor_location"
bl_label = "Get Cursor Location"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Insert the current cursor coordinates"
@classmethod
def poll(cls, context): #TODO is it right to use the poll method?
file = tool.Ifc.get()
return file and file.by_type("IfcUnitAssignment")
def _execute(self, context):
core.get_cursor_location(tool.Georeference)
class SetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_cursor_location"
bl_label = "Set Cursor Location"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Set curson location to coordinates"
@classmethod
def poll(cls, context): #TODO is it right to use the poll method?
file = tool.Ifc.get()
props = context.scene.BIMGeoreferenceProperties
return file and file.by_type("IfcUnitAssignment") and props.coordinate_output.count(",") == 2
def _execute(self, context):
core.set_cursor_location(tool.Georeference)
class SetIfcTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_ifc_true_north"
bl_label = "Set IFC True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Set IFC True north"
def _execute(self, context):
core.set_ifc_true_north(tool.Georeference)
class SetBlenderTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_blender_true_north"
bl_label = "Set Blender True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Set Blender true north"
def _execute(self, context):
core.set_blender_true_north(tool.Georeference)
class ConvertLocalToGlobal(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.convert_local_to_global"
bl_label = "Convert Local To Global"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Convert local coordinate to global coordinate"
@classmethod
def poll(cls, context):
file = tool.Ifc.get()
props = context.scene.BIMGeoreferenceProperties
return file and props.coordinate_input.count(",") == 2
def _execute(self, context):
core.convert_local_to_global(tool.Georeference)
class ConvertGlobalToLocal(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.convert_global_to_local"
bl_label = "Convert Global To Local"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Convert global coordinate to local coordinate"
@classmethod
def poll(cls, context):
file = tool.Ifc.get()
props = context.scene.BIMGeoreferenceProperties
return file and file.by_type("IfcUnitAssignment") and props.coordinate_input.count(",") == 2
def _execute(self, context):
core.convert_global_to_local(tool.Georeference)
@@ -18,7 +18,6 @@
import ifcopenshell.util.geolocation import ifcopenshell.util.geolocation
from bpy.types import Panel from bpy.types import Panel
#from ifcopenshell.api.georeference.data import Data
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.helper import draw_attributes, draw_attribute from blenderbim.bim.helper import draw_attributes, draw_attribute
from blenderbim.bim.module.georeference.data import GeoreferenceData from blenderbim.bim.module.georeference.data import GeoreferenceData
@@ -73,8 +72,8 @@ class BIM_PT_gis(Panel):
row.prop(props, "true_north_ordinate") row.prop(props, "true_north_ordinate")
if hasattr(context.scene, "sun_pos_properties"): if hasattr(context.scene, "sun_pos_properties"):
row = self.layout.row(align=True) row = self.layout.row(align=True)
# row.operator("bim.set_ifc_true_north", text="Set IFC North") row.operator("bim.set_ifc_true_north", text="Set IFC North")
# row.operator("bim.set_blender_true_north", text="Set Blender North") row.operator("bim.set_blender_true_north", text="Set Blender North")
def draw_ui(self, context): def draw_ui(self, context):
@@ -83,7 +82,7 @@ class BIM_PT_gis(Panel):
if not GeoreferenceData.data["projected_crs"]: if not GeoreferenceData.data["projected_crs"]:
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="Not Georeferenced") row.label(text="Not Georeferenced")
if IfcStore.get_file().schema != "IFC2X3": if IfcStore.get_file().schema != "IFC2X3": #TODO Is it correct to use IfcStore.get_file() or is it better tool.Ifc.get()?
row.operator("bim.add_georeferencing", icon="ADD", text="") row.operator("bim.add_georeferencing", icon="ADD", text="")
if props.has_blender_offset: if props.has_blender_offset:
@@ -179,16 +178,19 @@ class BIM_PT_gis_utilities(Panel):
bl_category = "BlenderBIM" bl_category = "BlenderBIM"
def draw(self, context): def draw(self, context):
if not GeoreferenceData.is_loaded:
GeoreferenceData.load()
props = context.scene.BIMGeoreferenceProperties props = context.scene.BIMGeoreferenceProperties
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "coordinate_input", text="Input") row.prop(props, "coordinate_input", text="Input")
#row.operator("bim.get_cursor_location", text="", icon="TRACKER") row.operator("bim.get_cursor_location", text="", icon="TRACKER")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "coordinate_output", text="Output") row.prop(props, "coordinate_output", text="Output")
#row.operator("bim.set_cursor_location", text="", icon="TRACKER") row.operator("bim.set_cursor_location", text="", icon="TRACKER")
row = self.layout.row(align=True) row = self.layout.row(align=True)
#row.operator("bim.convert_local_to_global", text="Local to Global") row.operator("bim.convert_local_to_global", text="Local to Global")
#row.operator("bim.convert_global_to_local", text="Global to Local") row.operator("bim.convert_global_to_local", text="Global to Local")
+35 -29
View File
@@ -18,71 +18,60 @@
import bpy import bpy
import blenderbim.bim.helper import blenderbim.bim.helper
import ifcopenshell
from blenderbim.bim.module.georeference.data import GeoreferenceData from blenderbim.bim.module.georeference.data import GeoreferenceData
from math import radians, degrees, atan, tan, cos, sin
def add_georeferencing(ifc): def add_georeferencing(ifc):
ifc.run("georeference.add_georeferencing") ifc.run("georeference.add_georeferencing")
def enable_editing_georeferencing(georeference): #TODO simplify this function def enable_editing_georeferencing(georeference):
props = bpy.context.scene.BIMGeoreferenceProperties
georeference.clear_projected_crs() georeference.clear_projected_crs()
blenderbim.bim.helper.import_attributes( blenderbim.bim.helper.import_attributes(
"IfcProjectedCRS", "IfcProjectedCRS",
bpy.context.scene.BIMGeoreferenceProperties.projected_crs, props.projected_crs,
GeoreferenceData.data["projected_crs"], GeoreferenceData.data["projected_crs"],
georeference.import_projected_crs_attributes, georeference.import_projected_crs_attributes,
) )
georeference.clear_map_conversion() georeference.clear_map_conversion()
blenderbim.bim.helper.import_attributes( blenderbim.bim.helper.import_attributes(
"IfcMapConversion", "IfcMapConversion",
bpy.context.scene.BIMGeoreferenceProperties.map_conversion, props.map_conversion,
GeoreferenceData.data["map_conversion"], GeoreferenceData.data["map_conversion"],
georeference.import_map_conversion_attributes, georeference.import_map_conversion_attributes,
) )
bpy.context.scene.BIMGeoreferenceProperties.has_true_north = bool(GeoreferenceData.data["true_north"]) georeference.set_has_true_north_prop(GeoreferenceData.data["true_north"])
georeference.set_true_north_prop(GeoreferenceData.data["true_north"])
if GeoreferenceData.data["true_north"]: georeference.enable_editing()
bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa = str(GeoreferenceData.data["true_north"][0])
bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate = str(GeoreferenceData.data["true_north"][1])
bpy.context.scene.BIMGeoreferenceProperties.is_editing = True
def remove_georeferencing(ifc): def remove_georeferencing(ifc):
ifc.run("georeference.remove_georeferencing") ifc.run("georeference.remove_georeferencing")
def edit_georeferencing(ifc, georeference): def edit_georeferencing(ifc, georeference):
props = bpy.context.scene.BIMGeoreferenceProperties props = bpy.context.scene.BIMGeoreferenceProperties
ifc_file = georeference.get_file()
projected_crs = blenderbim.bim.helper.export_attributes(props.projected_crs, georeference.export_crs_attributes) projected_crs = blenderbim.bim.helper.export_attributes(props.projected_crs, georeference.export_crs_attributes)
map_conversion = blenderbim.bim.helper.export_attributes(props.map_conversion, georeference.export_map_attributes) map_conversion = blenderbim.bim.helper.export_attributes(props.map_conversion, georeference.export_map_attributes)
true_north = None true_north = georeference.get_true_north_props(props)
# if props.has_true_north:
# try: ifc.run(
# true_north = [float(props.true_north_abscissa), float(props.true_north_ordinate)]
# except ValueError:
# self.report({"ERROR"}, "True North Abscissa and Ordinate expect a number")
ifcopenshell.api.run( #TODO use ifc.run
"georeference.edit_georeferencing", "georeference.edit_georeferencing",
ifc_file,
**{ **{
"map_conversion": map_conversion, "map_conversion": map_conversion,
"projected_crs": projected_crs, "projected_crs": projected_crs,
"true_north": true_north, "true_north": true_north,
} }
) )
bpy.ops.bim.disable_editing_georeferencing() georeference.disable_editing()
def disable_editing_georeferencing(georeference):
georeference.set_false_is_editing()
def set_ifc_grid_north(georeference): def set_ifc_grid_north(georeference):
georeference.set_ifc_grid_north() georeference.set_ifc_grid_north()
@@ -90,4 +79,21 @@ def set_ifc_grid_north(georeference):
def set_blender_grid_north(georeference): def set_blender_grid_north(georeference):
georeference.set_blender_grid_north() georeference.set_blender_grid_north()
def get_cursor_location(georeference):
georeference.get_cursor_location()
def set_cursor_location(georeference):
georeference.set_cursor_location()
def set_ifc_true_north(georeference):
georeference.set_ifc_true_north()
def set_blender_true_north(georeference):
georeference.set_blender_true_north()
def convert_local_to_global(georeference):
georeference.convert_local_to_global(GeoreferenceData.data["map_conversion"])
def convert_global_to_local(georeference):
georeference.convert_global_to_local(GeoreferenceData.data["map_conversion"])
+11 -2
View File
@@ -250,15 +250,24 @@ class Geometry:
class Georeference: class Georeference:
def clear_projected_crs(cls): pass def clear_projected_crs(cls): pass
def clear_map_conversion(cls): pass def clear_map_conversion(cls): pass
def set_has_true_north_prop(cls, data): pass
def set_true_north_prop(cls, data): pass
def get_true_north_props(cls, props): pass
def enable_editing(cls): pass
def disable_editing(cls): pass
def get_file(cls): pass def get_file(cls): pass
def set_false_is_editing(cls): pass
def import_projected_crs_attributes(cls, name, prop, data): pass def import_projected_crs_attributes(cls, name, prop, data): pass
def import_map_conversion_attributes(cls, name, prop, data): pass def import_map_conversion_attributes(cls, name, prop, data): pass
def export_crs_attributes(cls, attributes, prop): pass def export_crs_attributes(cls, attributes, prop): pass
def export_map_attributes(cls, attributes, prop): pass def export_map_attributes(cls, attributes, prop): pass
def set_ifc_grid_north(cls): pass def set_ifc_grid_north(cls): pass
def set_blender_grid_north(cls): pass def set_blender_grid_north(cls): pass
def get_cursor_location(cls): pass
def set_cursor_location(cls): pass
def set_ifc_true_north(cls): pass
def set_blender_true_north(cls): pass
def convert_local_to_global(cls, map_conversion): pass
def convert_global_to_local(cls, map_conversion): pass
@interface @interface
class Ifc: class Ifc:
+138 -6
View File
@@ -17,11 +17,13 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import json import json
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
import ifcopenshell import ifcopenshell
import blenderbim.bim.helper
from ifcopenshell.api.unit.data import Data as UnitData from ifcopenshell.api.unit.data import Data as UnitData
@@ -35,6 +37,34 @@ class Georeference(blenderbim.core.tool.Georeference):
def clear_map_conversion(cls): def clear_map_conversion(cls):
bpy.context.scene.BIMGeoreferenceProperties.map_conversion.clear() bpy.context.scene.BIMGeoreferenceProperties.map_conversion.clear()
@classmethod
def set_has_true_north_prop(cls, data):
bpy.context.scene.BIMGeoreferenceProperties.has_true_north = bool(data)
@classmethod
def set_true_north_prop(cls, data):
if data:
bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa = str(data[0])
bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate = str(data[1])
@classmethod
def get_true_north_props(cls, props):
true_north = None
if props.has_true_north:
try:
true_north = [float(props.true_north_abscissa), float(props.true_north_ordinate)]
except ValueError:
self.report({"ERROR"}, "True North Abscissa and Ordinate expect a number") #TODO use the correct report method
return true_north
@classmethod
def enable_editing(cls):
bpy.context.scene.BIMGeoreferenceProperties.is_editing = True
@classmethod
def disable_editing(cls):
bpy.context.scene.BIMGeoreferenceProperties.is_editing = False
@classmethod @classmethod
def get_file(cls): def get_file(cls):
return tool.Ifc.get() return tool.Ifc.get()
@@ -63,7 +93,7 @@ class Georeference(blenderbim.core.tool.Georeference):
return True return True
@classmethod @classmethod
def export_crs_attributes(cls, attributes, prop,): def export_crs_attributes(cls, attributes, prop):
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
if not prop.is_null and prop.name == "MapUnit": if not prop.is_null and prop.name == "MapUnit":
attributes[prop.name] = ifc_file.by_id(int(prop.enum_value)) attributes[prop.name] = ifc_file.by_id(int(prop.enum_value))
@@ -76,11 +106,6 @@ class Georeference(blenderbim.core.tool.Georeference):
attributes[prop.name] = float(prop.string_value) attributes[prop.name] = float(prop.string_value)
return True return True
@classmethod
def set_false_is_editing(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
props.is_editing = False
@classmethod @classmethod
def set_ifc_grid_north(cls): def set_ifc_grid_north(cls):
x_angle = -bpy.context.scene.sun_pos_properties.north_offset x_angle = -bpy.context.scene.sun_pos_properties.north_offset
@@ -96,4 +121,111 @@ class Georeference(blenderbim.core.tool.Georeference):
) )
) )
@classmethod
def get_cursor_location(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
project_coordinates = [o / scale for o in bpy.context.scene.cursor.location]
props.coordinate_input = ",".join([str(o) for o in project_coordinates])
@classmethod
def set_cursor_location(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
bpy.context.scene.cursor.location = [float(co) * scale for co in props.coordinate_output.split(",")]
@classmethod
def set_ifc_true_north(cls):
y_angle = -bpy.context.scene.sun_pos_properties.north_offset + radians(90)
bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa = str(cos(y_angle))
bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate = str(sin(y_angle))
@classmethod
def set_blender_true_north(cls):
bpy.context.scene.sun_pos_properties.north_offset = -radians(
ifcopenshell.util.geolocation.yaxis2angle(
float(context.scene.BIMGeoreferenceProperties.true_north_abscissa),
float(context.scene.BIMGeoreferenceProperties.true_north_ordinate),
)
)
@classmethod
def convert_local_to_global(cls, map_conversion):
props = bpy.context.scene.BIMGeoreferenceProperties
x, y, z = [float(co) for co in props.coordinate_input.split(",")]
if props.has_blender_offset:
results = ifcopenshell.util.geolocation.xyz2enh(
x,
y,
z,
float(props.blender_eastings),
float(props.blender_northings),
float(props.blender_orthogonal_height),
float(props.blender_x_axis_abscissa),
float(props.blender_x_axis_ordinate),
1.0,
)
x, y, z = results
# TODO: what if the project CRS units and the project units are different?
if map_conversion:
results = ifcopenshell.util.geolocation.xyz2enh(
x,
y,
z,
map_conversion["Eastings"],
map_conversion["Northings"],
map_conversion["OrthogonalHeight"],
map_conversion.get("XAxisAbscissa", 1.0),
map_conversion.get("XAxisOrdinate", 0.0),
map_conversion.get("Scale", 1.0),
)
else:
results = (x, y, z)
props.coordinate_output = ",".join([str(r) for r in results])
bpy.context.scene.cursor.location = results
@classmethod
def convert_global_to_local(cls, map_conversion):
props = bpy.context.scene.BIMGeoreferenceProperties
x, y, z = [float(co) for co in props.coordinate_input.split(",")]
if map_conversion:
results = ifcopenshell.util.geolocation.enh2xyz(
x,
y,
z,
map_conversion["Eastings"],
map_conversion["Northings"],
map_conversion["OrthogonalHeight"],
map_conversion.get("XAxisAbscissa", 1.0),
map_conversion.get("XAxisOrdinate", 0.0),
map_conversion.get("Scale", 1.0),
)
else:
results = (x, y, z)
if props.has_blender_offset:
results = ifcopenshell.util.geolocation.enh2xyz(
results[0],
results[1],
results[2],
float(props.blender_eastings),
float(props.blender_northings),
float(props.blender_orthogonal_height),
float(props.blender_x_axis_abscissa),
float(props.blender_x_axis_ordinate),
1.0,
)
props.coordinate_output = ",".join([str(r) for r in results])
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
bpy.context.scene.cursor.location = [o * scale for o in results]