mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
New utility functions for automatic local to global elevation conversions and easier unit conversions
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
def dms2dd(degrees, minutes, seconds, ms=0):
|
||||
@@ -52,6 +54,45 @@ def xyz2enh(x, y, z, eastings, northings, orthogonal_height, x_axis_abscissa, x_
|
||||
return (eastings, northings, height)
|
||||
|
||||
|
||||
def auto_z2e(ifc_file, z):
|
||||
"""Convert a Z coordinate to an elevation using model georeferencing data
|
||||
|
||||
The necessary georeferencing map conversion is automatically detected from
|
||||
the IFC map conversion parameters present in the IFC model. If no map
|
||||
conversion is present, then the Z coordinate is returned unchanged.
|
||||
|
||||
:param ifc_file: The IFC file
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param z: The Z local engineering coordinate provided in project length units.
|
||||
:type z: float
|
||||
:return: The elevation in project length units.
|
||||
:rtype: float
|
||||
"""
|
||||
try:
|
||||
conversion = ifc_file.by_type("IfcMapConversion")
|
||||
except:
|
||||
return z
|
||||
if not conversion or not conversion[0].OrthogonalHeight:
|
||||
return z
|
||||
conversion = conversion[0]
|
||||
h = conversion.OrthogonalHeight
|
||||
map_unit = conversion.TargetCRS.MapUnit
|
||||
if map_unit:
|
||||
project_unit = ifcopenshell.util.unit.get_project_unit(ifc_file, "LENGTHUNIT")
|
||||
h = ifcopenshell.util.unit.convert(
|
||||
h,
|
||||
getattr(map_unit, "Prefix", None),
|
||||
map_unit.Name,
|
||||
getattr(project_unit, "Prefix", None),
|
||||
project_unit.Name,
|
||||
)
|
||||
return z2e(z, h)
|
||||
|
||||
|
||||
def z2e(z, h):
|
||||
return z + h
|
||||
|
||||
|
||||
def enh2xyz(e, n, h, eastings, northings, orthogonal_height, x_axis_abscissa, x_axis_ordinate, scale=None):
|
||||
if scale is None:
|
||||
scale = 1.0
|
||||
|
||||
@@ -325,6 +325,25 @@ def get_unit_assignment(ifc_file):
|
||||
return unit_assignments[0]
|
||||
|
||||
|
||||
def get_project_unit(ifc_file, unit_type):
|
||||
"""Get the default project unit of a particular unit type
|
||||
|
||||
:param ifc_file: The IFC file.
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param unit_type: The type of unit, taken from the list of IFC unit types,
|
||||
such as "LENGTHUNIT".
|
||||
:type unit_type: str
|
||||
:return: The IFC unit entity, or nothing if there is no default project unit
|
||||
defined.
|
||||
:rtype: ifcopenshell.entity_instance,None
|
||||
"""
|
||||
unit_assignment = get_unit_assignment(ifc_file)
|
||||
if unit_assignment:
|
||||
for unit in unit_assignment.Units or []:
|
||||
if getattr(unit, "UnitType", None) == unit_type:
|
||||
return unit
|
||||
|
||||
|
||||
def get_property_unit(prop, ifc_file):
|
||||
unit = getattr(prop, "Unit", None)
|
||||
if unit:
|
||||
@@ -431,19 +450,42 @@ def get_unit_symbol(unit):
|
||||
return "?"
|
||||
|
||||
|
||||
def convert_unit(value, from_unit, to_unit):
|
||||
"""Convert from one unit to another unit
|
||||
|
||||
:param value: The numeric value you want to convert
|
||||
:type value: float
|
||||
:param from_unit: The IfcNamedUnit to confirm from.
|
||||
:type from_unit: ifcopenshell.entity_instance.entity_instance
|
||||
:param to_unit: The IfcNamedUnit to confirm from.
|
||||
:type to_unit: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The converted value.
|
||||
:rtype: float
|
||||
"""
|
||||
return convert(
|
||||
value, getattr(from_unit, "Prefix", None), from_unit.Name, getattr(to_unit, "Prefix", None), to_unit.Name
|
||||
)
|
||||
|
||||
|
||||
def convert(value, from_prefix, from_unit, to_prefix, to_unit):
|
||||
"""Converts between length, area, and volume units
|
||||
|
||||
In this case, you manually specify the names and (optionally) prefixes to
|
||||
convert to and from. In case you want to automatically convert to units
|
||||
already available as IFC entities, consider using convert_unit() instead.
|
||||
|
||||
:param value: The numeric value you want to convert
|
||||
:type value: float
|
||||
:param from_prefix: A prefix from IfcSIPrefix. Can be None.
|
||||
:type from_prefix: string
|
||||
:type from_prefix: str,optional
|
||||
:param from_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
|
||||
:type from_unit: string
|
||||
:type from_unit: str
|
||||
:param to_prefix: A prefix from IfcSIPrefix. Can be None.
|
||||
:type to_prefix: string
|
||||
:type to_prefix: str,optional
|
||||
:param to_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
|
||||
:type to_unit: string
|
||||
:type to_unit: str
|
||||
:return: The converted value.
|
||||
:rtype: float
|
||||
"""
|
||||
if from_unit in si_conversions:
|
||||
value *= si_conversions[from_unit]
|
||||
|
||||
Reference in New Issue
Block a user