WIP implement georeference module for correctly geolocated files. See #1222.

This commit is contained in:
Dion Moult
2021-01-19 11:18:26 +11:00
parent 45bba127ff
commit ea524767a0
14 changed files with 548 additions and 217 deletions
@@ -20,6 +20,7 @@ if bpy is not None:
"bimtester": None,
"debug": None,
"geometry": None,
"georeference": None,
"material": None,
"model": None,
"owner": None,
@@ -146,8 +147,6 @@ if bpy is not None:
operator.AddVariable,
operator.RemoveVariable,
operator.PropagateTextData,
operator.ConvertLocalToGlobal,
operator.ConvertGlobalToLocal,
operator.SelectIfcPatchInput,
operator.SelectIfcPatchOutput,
operator.ExecuteIfcPatch,
@@ -170,8 +169,6 @@ if bpy is not None:
operator.BuildSchedule,
operator.AddScheduleToSheet,
operator.SetViewportShadowFromSun,
operator.SetNorthOffset,
operator.GetNorthOffset,
operator.AddPresentationLayer,
operator.AssignPresentationLayer,
operator.UnassignPresentationLayer,
@@ -216,8 +213,6 @@ if bpy is not None:
prop.BIMProperties,
prop.DocProperties,
prop.BIMLibrary,
prop.MapConversion,
prop.TargetCRS,
prop.IfcParameter,
prop.BoundaryCondition,
prop.PsetQto,
@@ -242,7 +237,6 @@ if bpy is not None:
ui.BIM_PT_search,
ui.BIM_PT_ifcclash,
ui.BIM_PT_library,
ui.BIM_PT_gis,
ui.BIM_PT_presentation_layers,
ui.BIM_PT_diff,
ui.BIM_PT_patch,
@@ -294,8 +288,6 @@ if bpy is not None:
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
bpy.types.Scene.BIMLibrary = bpy.props.PointerProperty(type=prop.BIMLibrary)
bpy.types.Scene.MapConversion = bpy.props.PointerProperty(type=prop.MapConversion)
bpy.types.Scene.TargetCRS = bpy.props.PointerProperty(type=prop.TargetCRS)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Collection.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties) # Check if we need this
@@ -319,8 +311,6 @@ if bpy is not None:
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
del bpy.types.Scene.BIMProperties
del bpy.types.Scene.DocProperties
del bpy.types.Scene.MapConversion
del bpy.types.Scene.TargetCRS
del bpy.types.Object.BIMObjectProperties
del bpy.types.Material.BIMObjectProperties
del bpy.types.Collection.BIMObjectProperties # Check if we need this
@@ -371,8 +371,6 @@ class IfcImporter:
if self.ifc_import_settings.should_import_native:
self.parse_native_elements()
self.profile_code("Parsing native elements")
self.create_georeferencing()
self.profile_code("Georeferencing ifc")
self.create_groups()
self.profile_code("Creating groups")
self.create_grids()
@@ -645,46 +643,6 @@ class IfcImporter:
if element.ObjectPlacement.RelativePlacement.RefDirection:
element.ObjectPlacement.RelativePlacement.RefDirection.DirectionRatios = (1.0, 0.0, 0.0)
def create_georeferencing(self):
try:
map_conversion = self.file.by_type("IfcMapConversion")
projected_crs = self.file.by_type("IfcProjectedCRS")
if not map_conversion or not projected_crs:
return
except:
return # For example, in IFC2X3
map_conversion = map_conversion[0]
projected_crs = projected_crs[0]
scene = bpy.context.scene
scene.BIMProperties.has_georeferencing = True
map_conversion_map = {
"Eastings": "eastings",
"Northings": "northings",
"OrthogonalHeight": "orthogonal_height",
"XAxisAbscissa": "x_axis_abscissa",
"XAxisOrdinate": "x_axis_ordinate",
"Scale": "scale",
}
target_crs_map = {
"Name": "name",
"Description": "description",
"GeodeticDatum": "geodetic_datum",
"VerticalDatum": "vertical_datum",
"MapProjection": "map_projection",
"MapZone": "map_zone",
"MapUnit": "map_unit",
}
for keyA, keyB in map_conversion_map.items():
value = getattr(map_conversion, keyA)
if value is not None:
setattr(scene.MapConversion, keyB, str(value))
for keyA, keyB in target_crs_map.items():
value = getattr(projected_crs, keyA)
if value is not None:
if keyA == "MapUnit":
value = self.get_unit_name(value)
setattr(scene.TargetCRS, keyB, str(value))
def get_unit_name(self, named_unit):
name = ""
if hasattr(named_unit, "Prefix") and named_unit.Prefix:
@@ -710,7 +668,6 @@ class IfcImporter:
else:
obj = bpy.data.objects.new(f"{element.is_a()}/{element.Name}", None)
obj.BIMObjectProperties.ifc_definition_id = element.id()
self.add_element_attributes(element, obj.BIMObjectProperties)
group_collection.objects.link(obj)
self.groups[element.GlobalId] = {"ifc": element, "blender": obj}
@@ -748,7 +705,6 @@ class IfcImporter:
obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh)
obj.BIMObjectProperties.ifc_definition_id = element.id()
obj.matrix_world = matrix_world
self.add_element_attributes(axis, obj.BIMObjectProperties)
grid.objects.link(obj)
def create_type_products(self):
@@ -1756,21 +1712,6 @@ class IfcImporter:
self.ifc_import_settings.logger.warning("Warning: this object is outside the spatial hierarchy %s", element)
bpy.context.scene.collection.objects.link(obj)
def add_element_attributes(self, element, props):
attributes = element.get_info()
for key, value in attributes.items():
if (
value is None
or isinstance(value, (tuple, ifcopenshell.entity_instance))
or key == "id"
or key == "type"
):
continue
attribute = props.attributes.add()
attribute.name = key
attribute.data_type = "string"
attribute.string_value = str(self.cast_edge_case_attribute(element.is_a(), key, value))
def cast_edge_case_attribute(self, ifc_class, key, value):
if key == "RefLatitude" or key == "RefLongitude":
return ifcopenshell.util.geolocation.dms2dd(*value)
@@ -0,0 +1,25 @@
import bpy
from . import ui, prop, operator
classes = (
operator.EnableEditingGeoreferencing,
operator.DisableEditingGeoreferencing,
operator.EditGeoreferencing,
operator.SetNorthOffset,
operator.GetNorthOffset,
operator.RemoveGeoreferencing,
operator.AddGeoreferencing,
operator.ConvertLocalToGlobal,
operator.ConvertGlobalToLocal,
prop.BIMGeoreferenceProperties,
ui.BIM_PT_gis,
ui.BIM_PT_gis_utilities,
)
def register():
bpy.types.Scene.BIMGeoreferenceProperties = bpy.props.PointerProperty(type=prop.BIMGeoreferenceProperties)
def unregister():
del bpy.types.Scene.BIMGeoreferenceProperties
@@ -0,0 +1,20 @@
class Usecase:
def __init__(self, file, settings=None):
self.file = file
def execute(self):
source_crs = None
for context in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.ContextType == "Model":
source_crs = context
break
if not source_crs:
return
projected_crs = self.file.create_entity("IfcProjectedCRS", **{"Name": ""})
self.file.create_entity("IfcMapConversion", **{
"SourceCRS": source_crs,
"TargetCRS": projected_crs,
"Eastings": 0,
"Northings": 0,
"OrthogonalHeight": 0,
})
@@ -0,0 +1,29 @@
from blenderbim.bim.ifc import IfcStore
class Data:
is_loaded = False
map_conversion = {}
projected_crs = {}
@classmethod
def load(cls):
file = IfcStore.get_file()
if not file:
return
cls.map_conversion = {}
cls.projected_crs = {}
if file.schema == "IFC2X3":
return
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if not context.HasCoordinateOperation:
continue
map_conversion = context.HasCoordinateOperation[0]
cls.map_conversion = map_conversion.get_info()
cls.map_conversion["SourceCRS"] = cls.map_conversion["SourceCRS"].id()
cls.map_conversion["TargetCRS"] = cls.map_conversion["TargetCRS"].id()
cls.projected_crs = map_conversion.TargetCRS.get_info()
if cls.projected_crs["MapUnit"]:
cls.projected_crs["MapUnit"] = map_conversion.TargetCRS.MapUnit.get_info()
break
cls.is_loaded = True
@@ -0,0 +1,52 @@
import ifcopenshell.util.unit
class Usecase:
def __init__(self, file, settings=None):
self.file = file
self.settings = {
"map_conversion": {},
"projected_crs": {},
"map_unit": "",
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
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.remove_existing_map_unit(projected_crs)
self.set_map_unit(projected_crs)
def remove_existing_map_unit(self, projected_crs):
if projected_crs.MapUnit and len(self.file.get_inverse(projected_crs.MapUnit)) == 1:
# TODO: go deeper for conversion units
self.file.remove(projected_crs.MapUnit)
def set_map_unit(self, projected_crs):
if not self.settings["map_unit"]:
return
if "METRE" in self.settings["map_unit"]:
projected_crs.MapUnit = self.file.createIfcSIUnit(
None,
"LENGTHUNIT",
ifcopenshell.util.unit.get_prefix(self.settings["map_unit"]),
ifcopenshell.util.unit.get_unit_name(self.settings["map_unit"]),
)
return
value_component = self.file.create_entity(
"IfcReal", **{"wrappedValue": ifcopenshell.util.unit.si_conversions[self.settings["map_unit"]]}
)
si_unit = self.file.createIfcSIUnit(None, "LENGTHUNIT", None, "METRE")
projected_crs.MapUnit = self.file.createIfcConversionBasedUnit(
self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0),
"LENGTHUNIT",
self.settings["map_unit"],
self.file.createIfcMeasureWithUnit(value_component, si_unit),
)
@@ -0,0 +1,242 @@
import bpy
import json
import ifcopenshell
import ifcopenshell.util.unit
import blenderbim.bim.module.georeference.add_georeferencing as add_georeferencing
import blenderbim.bim.module.georeference.edit_georeferencing as edit_georeferencing
import blenderbim.bim.module.georeference.remove_georeferencing as remove_georeferencing
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.georeference.data import Data
from math import radians, degrees, atan, tan, cos, sin
class EnableEditingGeoreferencing(bpy.types.Operator):
bl_idname = "bim.enable_editing_georeferencing"
bl_label = "Enable Editing Georeferencing"
def execute(self, context):
self.file = IfcStore.get_file()
props = context.scene.BIMGeoreferenceProperties
while len(props.map_conversion) > 0:
props.map_conversion.remove(0)
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
continue
new = props.map_conversion.add()
new.name = attribute.name()
new.is_null = Data.map_conversion[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.string_value = "" if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "string"
elif "<real>" in data_type:
new.float_value = 0.0 if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "float"
elif "<integer>" in data_type:
new.int_value = 0 if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
new.bool_value = False if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "boolean"
while len(props.projected_crs) > 0:
props.projected_crs.remove(0)
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
continue
new = props.projected_crs.add()
new.name = attribute.name()
new.is_null = Data.projected_crs[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.string_value = "" if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "string"
elif "<real>" in data_type:
new.float_value = 0.0 if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "float"
elif "<integer>" in data_type:
new.int_value = 0 if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
new.bool_value = False if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "boolean"
props.is_map_unit_null = Data.projected_crs["MapUnit"] is None
if not props.is_map_unit_null:
props.map_unit_type = Data.projected_crs["MapUnit"]["type"]
if props.map_unit_type == "IfcSIUnit":
prefix = ifcopenshell.util.unit.get_prefix(Data.projected_crs["MapUnit"]["Prefix"]) or ""
name = ifcopenshell.util.unit.get_unit_name(Data.projected_crs["MapUnit"]["Name"])
props.map_unit_si = prefix + name
elif props.map_unit_type == "IfcConversionBasedUnit":
props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"]
props.is_editing = True
return {"FINISHED"}
class DisableEditingGeoreferencing(bpy.types.Operator):
bl_idname = "bim.disable_editing_georeferencing"
bl_label = "Disable Editing Georeferencing"
def execute(self, context):
props = context.scene.BIMGeoreferenceProperties
props.is_editing = False
return {"FINISHED"}
class EditGeoreferencing(bpy.types.Operator):
bl_idname = "bim.edit_georeferencing"
bl_label = "Edit Georeferencing"
def execute(self, context):
self.file = IfcStore.get_file()
props = context.scene.BIMGeoreferenceProperties
map_conversion = {}
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
continue
blender_attribute = props.map_conversion.get(attribute.name())
if blender_attribute.is_null:
map_conversion[attribute.name()] = None
elif blender_attribute.data_type == "string":
map_conversion[attribute.name()] = blender_attribute.string_value
elif blender_attribute.data_type == "float":
map_conversion[attribute.name()] = blender_attribute.float_value
elif blender_attribute.data_type == "integer":
map_conversion[attribute.name()] = blender_attribute.int_value
elif blender_attribute.data_type == "boolean":
map_conversion[attribute.name()] = blender_attribute.bool_value
projected_crs = {}
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
continue
blender_attribute = props.projected_crs.get(attribute.name())
if blender_attribute.is_null:
projected_crs[attribute.name()] = None
elif blender_attribute.data_type == "string":
projected_crs[attribute.name()] = blender_attribute.string_value
elif blender_attribute.data_type == "float":
projected_crs[attribute.name()] = blender_attribute.float_value
elif blender_attribute.data_type == "integer":
projected_crs[attribute.name()] = blender_attribute.int_value
elif blender_attribute.data_type == "boolean":
projected_crs[attribute.name()] = blender_attribute.bool_value
map_unit = ""
if not props.is_map_unit_null:
map_unit = props.map_unit_si if props.map_unit_type == "IfcSIUnit" else props.map_unit_imperial
edit_georeferencing.Usecase(self.file, {
"map_conversion": map_conversion,
"projected_crs": projected_crs,
"map_unit": map_unit
}).execute()
Data.load()
bpy.ops.bim.disable_editing_georeferencing()
return {"FINISHED"}
class SetNorthOffset(bpy.types.Operator):
bl_idname = "bim.set_north_offset"
bl_label = "Set North Offset"
def execute(self, context):
context.scene.sun_pos_properties.north_offset = -radians(
ifcopenshell.util.geolocation.xy2angle(
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").float_value,
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").float_value
)
)
return {"FINISHED"}
class GetNorthOffset(bpy.types.Operator):
bl_idname = "bim.get_north_offset"
bl_label = "Get North Offset"
def execute(self, context):
x_angle = -context.scene.sun_pos_properties.north_offset
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").float_value = cos(x_angle)
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").float_value = sin(x_angle)
return {"FINISHED"}
class RemoveGeoreferencing(bpy.types.Operator):
bl_idname = "bim.remove_georeferencing"
bl_label = "Remove Georeferencing"
def execute(self, context):
remove_georeferencing.Usecase(IfcStore.get_file()).execute()
Data.load()
return {"FINISHED"}
class AddGeoreferencing(bpy.types.Operator):
bl_idname = "bim.add_georeferencing"
bl_label = "Add Georeferencing"
def execute(self, context):
add_georeferencing.Usecase(IfcStore.get_file()).execute()
Data.load()
return {"FINISHED"}
class ConvertLocalToGlobal(bpy.types.Operator):
bl_idname = "bim.convert_local_to_global"
bl_label = "Convert Local To Global"
def execute(self, context):
if not Data.is_loaded:
Data.load()
props = context.scene.BIMGeoreferenceProperties
x, y, z = [float(co) for co in props.coordinate_input.split(",")]
results = ifcopenshell.util.geolocation.xyz2enh(
x,
y,
z,
Data.map_conversion["Eastings"],
Data.map_conversion["Northings"],
Data.map_conversion["OrthogonalHeight"],
Data.map_conversion.get("XAxisAbscissa", 1.0),
Data.map_conversion.get("XAxisAbscissa", 0.0),
Data.map_conversion.get("Scale", 1.0),
)
props.coordinate_output = ",".join([str(r) for r in results])
bpy.context.scene.cursor.location = results
return {"FINISHED"}
class ConvertGlobalToLocal(bpy.types.Operator):
bl_idname = "bim.convert_global_to_local"
bl_label = "Convert Global To Local"
def execute(self, context):
if not Data.is_loaded:
Data.load()
props = context.scene.BIMGeoreferenceProperties
x, y, z = [float(co) for co in props.coordinate_input.split(",")]
results = ifcopenshell.util.geolocation.enh2xyz(
x,
y,
z,
Data.map_conversion["Eastings"],
Data.map_conversion["Northings"],
Data.map_conversion["OrthogonalHeight"],
Data.map_conversion.get("XAxisAbscissa", 1.0),
Data.map_conversion.get("XAxisAbscissa", 0.0),
Data.map_conversion.get("Scale", 1.0),
)
props.coordinate_output = ",".join([str(r) for r in results])
bpy.context.scene.cursor.location = results
return {"FINISHED"}
@@ -0,0 +1,37 @@
import bpy
from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
class BIMGeoreferenceProperties(PropertyGroup):
is_editing: BoolProperty(name="Is Editing")
map_conversion: CollectionProperty(name="Map Conversion", type=Attribute)
projected_crs: CollectionProperty(name="Projected CRS", type=Attribute)
map_unit_type: EnumProperty(
items=[(n, n, "") for n in ["IfcSIUnit", "IfcConversionBasedUnit"]],
name="Map Unit Type",
default="IfcSIUnit",
)
map_unit_si: EnumProperty(
items=[(n, n.lower().capitalize(), "") for n in ["MILLIMETRE", "CENTIMETRE", "METRE", "KILOMETRE"]],
name="Map Unit SI",
default="METRE",
)
map_unit_imperial: EnumProperty(
items=[(n, n.lower().capitalize(), "") for n in ["inch", "foot", "yard", "mile"]],
name="Map Unit SI",
default="foot",
)
is_map_unit_null: BoolProperty(name="Is Map Unit Null")
coordinate_input: StringProperty(name="Coordinate Input")
coordinate_output: StringProperty(name="Coordinate Output")
@@ -0,0 +1,12 @@
class Usecase:
def __init__(self, file, settings=None):
self.file = file
def execute(self):
map_conversion = self.file.by_type("IfcMapConversion")[0]
projected_crs = self.file.by_type("IfcProjectedCRS")[0]
if projected_crs.MapUnit and len(self.file.get_inverse(projected_crs.MapUnit)) == 1:
# TODO: go deeper for conversion units
self.file.remove(projected_crs.MapUnit)
self.file.remove(projected_crs)
self.file.remove(map_conversion)
@@ -0,0 +1,125 @@
from bpy.types import Panel
from blenderbim.bim.module.georeference.data import Data
from blenderbim.bim.ifc import IfcStore
class BIM_PT_gis(Panel):
bl_label = "IFC Georeferencing"
bl_idname = "BIM_PT_gis"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
props = context.scene.BIMGeoreferenceProperties
if not Data.is_loaded:
Data.load()
if props.is_editing:
return self.draw_editable_ui(context)
self.draw_ui()
def draw_editable_ui(self, context):
props = context.scene.BIMGeoreferenceProperties
row = self.layout.row(align=True)
row.label(text="Map Conversion", icon="GRID")
row.operator("bim.edit_georeferencing", icon="CHECKMARK", text="")
row.operator("bim.disable_editing_georeferencing", icon="X", text="")
for attribute in props.map_conversion:
if attribute.name == "XAxisAbscissa" and hasattr(context.scene, "sun_pos_properties"):
row = self.layout.row(align=True)
row.operator("bim.get_north_offset", text="Set IFC North")
row.operator("bim.set_north_offset", text="Set Blender North")
row = self.layout.row(align=True)
if attribute.data_type == "string":
row.prop(attribute, "string_value", text=attribute.name)
elif attribute.data_type == "integer":
row.prop(attribute, "int_value", text=attribute.name)
elif attribute.data_type == "float":
row.prop(attribute, "float_value", text=attribute.name)
elif attribute.data_type == "boolean":
row.prop(attribute, "bool_value", text=attribute.name)
if attribute.is_optional:
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
row = self.layout.row(align=True)
row.label(text="Projected CRS", icon="WORLD")
for attribute in props.projected_crs:
row = self.layout.row(align=True)
if attribute.data_type == "string":
row.prop(attribute, "string_value", text=attribute.name)
elif attribute.data_type == "integer":
row.prop(attribute, "int_value", text=attribute.name)
elif attribute.data_type == "float":
row.prop(attribute, "float_value", text=attribute.name)
elif attribute.data_type == "boolean":
row.prop(attribute, "bool_value", text=attribute.name)
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
row = self.layout.row(align=True)
row.prop(props, "map_unit_type", text="MapUnit")
if props.map_unit_type == "IfcSIUnit":
row.prop(props, "map_unit_si", text="")
elif props.map_unit_type == "IfcConversionBasedUnit":
row.prop(props, "map_unit_imperial", text="")
row.prop(props, "is_map_unit_null", icon="RADIOBUT_OFF" if props.is_map_unit_null else "RADIOBUT_ON", text="")
def draw_ui(self):
if not Data.map_conversion:
row = self.layout.row(align=True)
row.label(text="Not Georeferenced")
row.operator("bim.add_georeferencing", icon="ADD", text="")
if Data.map_conversion:
row = self.layout.row(align=True)
row.label(text="Map Conversion", icon="GRID")
row.operator("bim.enable_editing_georeferencing", icon="GREASEPENCIL", text="")
row.operator("bim.remove_georeferencing", icon="X", text="")
for key, value in Data.map_conversion.items():
if key == "id" or key == "type" or key == "SourceCRS" or key == "TargetCRS" or not value:
continue
row = self.layout.row(align=True)
row.label(text=key)
row.label(text=str(value))
if Data.projected_crs:
row = self.layout.row(align=True)
row.label(text="Projected CRS", icon="WORLD")
for key, value in Data.projected_crs.items():
if key == "id" or key == "type" or not value:
continue
if key == "MapUnit":
unit_value = value.get("Prefix", "") or ""
unit_value += value["Name"]
value = unit_value
row = self.layout.row(align=True)
row.label(text=key)
row.label(text=str(value))
class BIM_PT_gis_utilities(Panel):
bl_idname = "BIM_PT_gis_utilities"
bl_label = "Georeferencing Utilities"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "BlenderBIM"
def draw(self, context):
props = context.scene.BIMGeoreferenceProperties
row = self.layout.row()
row.prop(props, "coordinate_input", text="Input")
row = self.layout.row()
row.prop(props, "coordinate_output", text="Output")
row = self.layout.row(align=True)
row.operator("bim.convert_local_to_global", text="Local to Global")
row.operator("bim.convert_global_to_local", text="Global to Local")
@@ -2519,56 +2519,6 @@ class PropagateTextData(bpy.types.Operator):
return {"FINISHED"}
class ConvertLocalToGlobal(bpy.types.Operator):
bl_idname = "bim.convert_local_to_global"
bl_label = "Convert Local To Global"
def execute(self, context):
if bpy.context.scene.MapConversion.scale:
scale = float(bpy.context.scene.MapConversion.scale)
else:
scale = 1.0
results = ifcopenshell.util.geolocation.xyz2enh(
bpy.context.scene.cursor.location[0],
bpy.context.scene.cursor.location[1],
bpy.context.scene.cursor.location[2],
float(bpy.context.scene.MapConversion.eastings),
float(bpy.context.scene.MapConversion.northings),
float(bpy.context.scene.MapConversion.orthogonal_height),
float(bpy.context.scene.MapConversion.x_axis_abscissa),
float(bpy.context.scene.MapConversion.x_axis_ordinate),
scale,
)
print("Coordinates:", results)
bpy.context.scene.cursor.location = results
return {"FINISHED"}
class ConvertGlobalToLocal(bpy.types.Operator):
bl_idname = "bim.convert_global_to_local"
bl_label = "Convert Global To Local"
def execute(self, context):
if bpy.context.scene.MapConversion.scale:
scale = float(bpy.context.scene.MapConversion.scale)
else:
scale = 1.0
results = ifcopenshell.util.geolocation.enh2xyz(
float(bpy.context.scene.BIMProperties.eastings),
float(bpy.context.scene.BIMProperties.northings),
float(bpy.context.scene.BIMProperties.orthogonal_height),
float(bpy.context.scene.MapConversion.eastings),
float(bpy.context.scene.MapConversion.northings),
float(bpy.context.scene.MapConversion.orthogonal_height),
float(bpy.context.scene.MapConversion.x_axis_abscissa),
float(bpy.context.scene.MapConversion.x_axis_ordinate),
scale,
)
print("Coordinates:", results)
bpy.context.scene.cursor.location = results
return {"FINISHED"}
class SelectIfcPatchInput(bpy.types.Operator):
bl_idname = "bim.select_ifc_patch_input"
bl_label = "Select IFC Patch Input"
@@ -3110,31 +3060,6 @@ class SetViewportShadowFromSun(bpy.types.Operator):
return {"FINISHED"}
class SetNorthOffset(bpy.types.Operator):
bl_idname = "bim.set_north_offset"
bl_label = "Set North Offset"
def execute(self, context):
context.scene.sun_pos_properties.north_offset = -radians(
ifcopenshell.util.geolocation.xy2angle(
float(bpy.context.scene.MapConversion.x_axis_abscissa),
float(bpy.context.scene.MapConversion.x_axis_ordinate),
)
)
return {"FINISHED"}
class GetNorthOffset(bpy.types.Operator):
bl_idname = "bim.get_north_offset"
bl_label = "Get North Offset"
def execute(self, context):
x_angle = -context.scene.sun_pos_properties.north_offset
bpy.context.scene.MapConversion.x_axis_abscissa = str(cos(x_angle))
bpy.context.scene.MapConversion.x_axis_ordinate = str(sin(x_angle))
return {"FINISHED"}
class AssignPresentationLayer(bpy.types.Operator):
bl_idname = "bim.assign_presentation_layer"
bl_label = "Assign Presentation Layer"
+1 -22
View File
@@ -478,6 +478,7 @@ class Attribute(PropertyGroup):
int_value: IntProperty(name="Value")
float_value: FloatProperty(name="Value")
is_null: BoolProperty(name="Is Null")
is_optional: BoolProperty(name="Is Optional")
enum_items: StringProperty(name="Value")
enum_value: EnumProperty(items=getAttributeEnumValues, name="Value")
@@ -1207,9 +1208,6 @@ class BIMProperties(PropertyGroup):
smart_clash_grouping_max_distance: IntProperty(name="Smart Clash Grouping Max Distance", default=3, soft_min=1, soft_max=10)
constraints: CollectionProperty(name="Constraints", type=Constraint)
active_constraint_index: IntProperty(name="Active Constraint Index")
eastings: StringProperty(name="Eastings")
northings: StringProperty(name="Northings")
orthogonal_height: StringProperty(name="Orthogonal Height")
ifc_patch_recipes: EnumProperty(items=getIfcPatchRecipes, name="Recipes")
ifc_patch_input: StringProperty(default="", name="IFC Patch Input IFC")
ifc_patch_output: StringProperty(default="", name="IFC Patch Output IFC")
@@ -1265,25 +1263,6 @@ class BIMProperties(PropertyGroup):
presentation_layers: CollectionProperty(name="Presentation Layers", type=PresentationLayer)
class MapConversion(PropertyGroup):
eastings: StringProperty(name="Eastings")
northings: StringProperty(name="Northings")
orthogonal_height: StringProperty(name="Orthogonal Height")
x_axis_abscissa: StringProperty(name="X Axis Abscissa")
x_axis_ordinate: StringProperty(name="X Axis Ordinate")
scale: StringProperty(name="Scale")
class TargetCRS(PropertyGroup):
name: StringProperty(name="Name")
description: StringProperty(name="Description")
geodetic_datum: StringProperty(name="Geodetic Datum")
vertical_datum: StringProperty(name="Vertical Datum")
map_projection: StringProperty(name="Map Projection")
map_zone: StringProperty(name="Map Zone")
map_unit: StringProperty(name="Map Unit")
class BIMLibrary(PropertyGroup):
name: StringProperty(name="Name")
version: StringProperty(name="Version")
-47
View File
@@ -437,53 +437,6 @@ class BIM_PT_presentation_layer_data(Panel):
op.index = scene_props.active_presentation_layer_index
class BIM_PT_gis(Panel):
bl_label = "IFC Georeferencing"
bl_idname = "BIM_PT_gis"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
scene = context.scene
layout.row().prop(scene.BIMProperties, "has_georeferencing")
layout.label(text="Map Conversion:")
layout.row().prop(scene.MapConversion, "eastings")
layout.row().prop(scene.MapConversion, "northings")
layout.row().prop(scene.MapConversion, "orthogonal_height")
layout.row().prop(scene.MapConversion, "x_axis_abscissa")
layout.row().prop(scene.MapConversion, "x_axis_ordinate")
layout.row().prop(scene.MapConversion, "scale")
layout.label(text="Target CRS:")
layout.row().prop(scene.TargetCRS, "name")
layout.row().prop(scene.TargetCRS, "description")
layout.row().prop(scene.TargetCRS, "geodetic_datum")
layout.row().prop(scene.TargetCRS, "vertical_datum")
layout.row().prop(scene.TargetCRS, "map_projection")
layout.row().prop(scene.TargetCRS, "map_zone")
layout.row().prop(scene.TargetCRS, "map_unit")
row = layout.row(align=True)
row.operator("bim.convert_local_to_global")
layout.row().prop(scene.BIMProperties, "eastings")
layout.row().prop(scene.BIMProperties, "northings")
layout.row().prop(scene.BIMProperties, "orthogonal_height")
row = layout.row(align=True)
row.operator("bim.convert_global_to_local")
if hasattr(bpy.context.scene, "sun_pos_properties"):
row = layout.row(align=True)
row.operator("bim.get_north_offset")
row.operator("bim.set_north_offset")
class BIM_PT_presentation_layers(Panel):
bl_label = "IFC Presentation Layers"
bl_idname = "BIM_PT_presentation_layer"
@@ -89,9 +89,10 @@ si_conversions = {
def get_prefix(text):
for prefix in prefixes.keys():
if prefix in text.upper():
return prefix
if text:
for prefix in prefixes.keys():
if prefix in text.upper():
return prefix
def get_prefix_multiplier(text):