mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
Implement getting and setting true north rotation independent of grid north
This commit is contained in:
@@ -5,8 +5,10 @@ classes = (
|
||||
operator.EnableEditingGeoreferencing,
|
||||
operator.DisableEditingGeoreferencing,
|
||||
operator.EditGeoreferencing,
|
||||
operator.SetNorthOffset,
|
||||
operator.GetNorthOffset,
|
||||
operator.SetIfcGridNorth,
|
||||
operator.SetBlenderGridNorth,
|
||||
operator.SetIfcTrueNorth,
|
||||
operator.SetBlenderTrueNorth,
|
||||
operator.RemoveGeoreferencing,
|
||||
operator.AddGeoreferencing,
|
||||
operator.ConvertLocalToGlobal,
|
||||
|
||||
@@ -69,6 +69,11 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
||||
elif data_type == "boolean":
|
||||
new.bool_value = False if new.is_null else Data.map_conversion[attribute.name()]
|
||||
|
||||
props.has_true_north = bool(Data.true_north)
|
||||
if Data.true_north:
|
||||
props.true_north_abscissa = str(Data.true_north[0])
|
||||
props.true_north_ordinate = str(Data.true_north[1])
|
||||
|
||||
props.is_editing = True
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -129,19 +134,31 @@ class EditGeoreferencing(bpy.types.Operator):
|
||||
elif blender_attribute.data_type == "boolean":
|
||||
map_conversion[attribute.name()] = blender_attribute.bool_value
|
||||
|
||||
true_north = None
|
||||
if props.has_true_north:
|
||||
try:
|
||||
true_north = [float(props.true_north_abscissa), float(props.true_north_ordinate)]
|
||||
except:
|
||||
pass
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"georeference.edit_georeferencing",
|
||||
self.file,
|
||||
**{"map_conversion": map_conversion, "projected_crs": projected_crs, "map_unit": map_unit}
|
||||
**{
|
||||
"map_conversion": map_conversion,
|
||||
"projected_crs": projected_crs,
|
||||
"map_unit": map_unit,
|
||||
"true_north": true_north,
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_georeferencing()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetNorthOffset(bpy.types.Operator):
|
||||
bl_idname = "bim.set_north_offset"
|
||||
bl_label = "Set North Offset"
|
||||
class SetBlenderGridNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_blender_grid_north"
|
||||
bl_label = "Set Blender Grid North"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.sun_pos_properties.north_offset = -radians(
|
||||
@@ -153,9 +170,9 @@ class SetNorthOffset(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GetNorthOffset(bpy.types.Operator):
|
||||
bl_idname = "bim.get_north_offset"
|
||||
bl_label = "Get North Offset"
|
||||
class SetIfcGridNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_ifc_grid_north"
|
||||
bl_label = "Set IFC Grid North"
|
||||
|
||||
def execute(self, context):
|
||||
x_angle = -context.scene.sun_pos_properties.north_offset
|
||||
@@ -164,6 +181,31 @@ class GetNorthOffset(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetBlenderTrueNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_blender_true_north"
|
||||
bl_label = "Set Blender True North"
|
||||
|
||||
def execute(self, context):
|
||||
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),
|
||||
)
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetIfcTrueNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_ifc_true_north"
|
||||
bl_label = "Set IFC True North"
|
||||
|
||||
def execute(self, context):
|
||||
y_angle = -context.scene.sun_pos_properties.north_offset + radians(90)
|
||||
context.scene.BIMGeoreferenceProperties.true_north_abscissa = str(cos(y_angle))
|
||||
context.scene.BIMGeoreferenceProperties.true_north_ordinate = str(sin(y_angle))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveGeoreferencing(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_georeferencing"
|
||||
bl_label = "Remove Georeferencing"
|
||||
|
||||
@@ -46,3 +46,6 @@ class BIMGeoreferenceProperties(PropertyGroup):
|
||||
blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0")
|
||||
blender_x_axis_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1")
|
||||
blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0")
|
||||
has_true_north: BoolProperty(name="Has True North", default=True)
|
||||
true_north_abscissa: StringProperty(name="True North Abscissa")
|
||||
true_north_ordinate: StringProperty(name="True North Ordinate")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import ifcopenshell.util.geolocation
|
||||
from bpy.types import Panel
|
||||
from ifcopenshell.api.georeference.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_gis(Panel):
|
||||
bl_label = "IFC Georeferencing"
|
||||
bl_idname = "BIM_PT_gis"
|
||||
@@ -58,8 +60,8 @@ class BIM_PT_gis(Panel):
|
||||
for attribute in props.map_conversion:
|
||||
if attribute.name == "Scale" 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.operator("bim.set_ifc_grid_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_grid_north", text="Set Blender North")
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
@@ -72,6 +74,18 @@ class BIM_PT_gis(Panel):
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "has_true_north")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_abscissa")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_ordinate")
|
||||
if hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_true_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_true_north", text="Set Blender North")
|
||||
|
||||
def draw_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
@@ -103,6 +117,17 @@ class BIM_PT_gis(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="XAxisOrdinate")
|
||||
row.label(text=props.blender_x_axis_ordinate)
|
||||
row.label(text="Derived Grid North")
|
||||
row.label(
|
||||
text=str(
|
||||
round(
|
||||
ifcopenshell.util.geolocation.xaxis2angle(
|
||||
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate)
|
||||
),
|
||||
3,
|
||||
)
|
||||
)
|
||||
)
|
||||
elif IfcStore.get_file().schema == "IFC2X3":
|
||||
row = self.layout.row()
|
||||
row.label(text="Not Georeferenced")
|
||||
@@ -152,6 +177,15 @@ class BIM_PT_gis(Panel):
|
||||
)
|
||||
)
|
||||
|
||||
if Data.true_north:
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Vector")
|
||||
row.label(text=str(Data.true_north[0:2])[1:-1])
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Derived Angle")
|
||||
row.label(text=str(round(ifcopenshell.util.geolocation.yaxis2angle(*Data.true_north[0:2]), 3)))
|
||||
|
||||
|
||||
class BIM_PT_gis_utilities(Panel):
|
||||
|
||||
@@ -2,12 +2,14 @@ class Data:
|
||||
is_loaded = False
|
||||
map_conversion = {}
|
||||
projected_crs = {}
|
||||
true_north = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.map_conversion = {}
|
||||
cls.projected_crs = {}
|
||||
cls.true_north = None
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
@@ -15,6 +17,7 @@ class Data:
|
||||
return
|
||||
cls.map_conversion = {}
|
||||
cls.projected_crs = {}
|
||||
cls.true_north = {}
|
||||
if file.schema == "IFC2X3":
|
||||
return
|
||||
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
@@ -28,4 +31,9 @@ class Data:
|
||||
if cls.projected_crs["MapUnit"]:
|
||||
cls.projected_crs["MapUnit"] = map_conversion.TargetCRS.MapUnit.get_info()
|
||||
break
|
||||
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
if not context.TrueNorth:
|
||||
continue
|
||||
cls.true_north = context.TrueNorth.DirectionRatios
|
||||
break
|
||||
cls.is_loaded = True
|
||||
|
||||
@@ -7,6 +7,7 @@ class Usecase:
|
||||
self.settings = {
|
||||
"map_conversion": {},
|
||||
"projected_crs": {},
|
||||
"true_north": [],
|
||||
"map_unit": "",
|
||||
}
|
||||
for key, value in settings.items():
|
||||
@@ -21,6 +22,7 @@ class Usecase:
|
||||
setattr(projected_crs, name, value)
|
||||
self.remove_existing_map_unit(projected_crs)
|
||||
self.set_map_unit(projected_crs)
|
||||
self.set_true_north()
|
||||
|
||||
def remove_existing_map_unit(self, projected_crs):
|
||||
if projected_crs.MapUnit and len(self.file.get_inverse(projected_crs.MapUnit)) == 1:
|
||||
@@ -50,3 +52,20 @@ class Usecase:
|
||||
self.settings["map_unit"],
|
||||
self.file.createIfcMeasureWithUnit(value_component, si_unit),
|
||||
)
|
||||
|
||||
def set_true_north(self):
|
||||
if self.settings["true_north"] == []:
|
||||
return
|
||||
for context in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
if context.TrueNorth:
|
||||
if len(self.file.get_inverse(context.TrueNorth)) != 1:
|
||||
context.TrueNorth = self.file.create_entity("IfcDirection")
|
||||
else:
|
||||
context.TrueNorth = self.file.create_entity("IfcDirection")
|
||||
direction = context.TrueNorth
|
||||
if self.settings["true_north"] is None:
|
||||
context.TrueNorth = self.settings["true_north"]
|
||||
elif context.CoordinateSpaceDimension == 2:
|
||||
direction.DirectionRatios = self.settings["true_north"][0:2]
|
||||
else:
|
||||
direction.DirectionRatios = self.settings["true_north"][0:2] + [0.0]
|
||||
|
||||
Reference in New Issue
Block a user