mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
typing
This commit is contained in:
@@ -18,10 +18,11 @@
|
|||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, name="foot", conversion_offset=None):
|
def __init__(self, file: ifcopenshell.file, name: str = "foot", conversion_offset: Optional[float] = None):
|
||||||
"""Add a conversion based unit
|
"""Add a conversion based unit
|
||||||
|
|
||||||
If you're in one of those countries who don't use SI units, you're
|
If you're in one of those countries who don't use SI units, you're
|
||||||
@@ -41,7 +42,7 @@ class Usecase:
|
|||||||
that this is just an example and you don't actually need to specify
|
that this is just an example and you don't actually need to specify
|
||||||
that for fahrenheit as it's built into this API function. For
|
that for fahrenheit as it's built into this API function. For
|
||||||
advanced users only.
|
advanced users only.
|
||||||
:type conversion_offset: float
|
:type conversion_offset: float, optional
|
||||||
:return: The new IfcConversionBasedUnit or
|
:return: The new IfcConversionBasedUnit or
|
||||||
IfcConversionBasedUnitWithOffset
|
IfcConversionBasedUnitWithOffset
|
||||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||||
@@ -60,7 +61,7 @@ class Usecase:
|
|||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {"name": name, "conversion_offset": conversion_offset}
|
self.settings = {"name": name, "conversion_offset": conversion_offset}
|
||||||
|
|
||||||
def execute(self):
|
def execute(self) -> ifcopenshell.entity_instance:
|
||||||
unit_type = ifcopenshell.util.unit.imperial_types.get(self.settings["name"], "USERDEFINED")
|
unit_type = ifcopenshell.util.unit.imperial_types.get(self.settings["name"], "USERDEFINED")
|
||||||
dimensions = ifcopenshell.util.unit.named_dimensions[unit_type]
|
dimensions = ifcopenshell.util.unit.named_dimensions[unit_type]
|
||||||
exponents = self.file.createIfcDimensionalExponents(*dimensions)
|
exponents = self.file.createIfcDimensionalExponents(*dimensions)
|
||||||
|
|||||||
@@ -17,10 +17,11 @@
|
|||||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, unit_type="LENGTHUNIT", prefix=None):
|
def __init__(self, file: ifcopenshell.file, unit_type: str = "LENGTHUNIT", prefix: Optional[str] = None):
|
||||||
"""Add a new SI unit
|
"""Add a new SI unit
|
||||||
|
|
||||||
The supported types are ABSORBEDDOSEUNIT, AMOUNTOFSUBSTANCEUNIT,
|
The supported types are ABSORBEDDOSEUNIT, AMOUNTOFSUBSTANCEUNIT,
|
||||||
@@ -59,7 +60,7 @@ class Usecase:
|
|||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {"unit_type": unit_type, "prefix": prefix}
|
self.settings = {"unit_type": unit_type, "prefix": prefix}
|
||||||
|
|
||||||
def execute(self):
|
def execute(self) -> ifcopenshell.entity_instance:
|
||||||
name = ifcopenshell.util.unit.si_type_names.get(self.settings["unit_type"], None)
|
name = ifcopenshell.util.unit.si_type_names.get(self.settings["unit_type"], None)
|
||||||
return self.file.create_entity(
|
return self.file.create_entity(
|
||||||
"IfcSIUnit", UnitType=self.settings["unit_type"], Name=name, Prefix=self.settings["prefix"]
|
"IfcSIUnit", UnitType=self.settings["unit_type"], Name=name, Prefix=self.settings["prefix"]
|
||||||
|
|||||||
@@ -18,10 +18,18 @@
|
|||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, units=None, length=None, area=None, volume=None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
file: ifcopenshell.file,
|
||||||
|
units: Optional[list[ifcopenshell.entity_instance]] = None,
|
||||||
|
length: Optional[dict] = None,
|
||||||
|
area: Optional[dict] = None,
|
||||||
|
volume: Optional[dict] = None,
|
||||||
|
):
|
||||||
"""Assign default project units
|
"""Assign default project units
|
||||||
|
|
||||||
Whenever a unitised quantity is specified, such as a length, area,
|
Whenever a unitised quantity is specified, such as a length, area,
|
||||||
@@ -67,7 +75,7 @@ class Usecase:
|
|||||||
self.settings["area"] = area or {"is_metric": True, "raw": "METERS"}
|
self.settings["area"] = area or {"is_metric": True, "raw": "METERS"}
|
||||||
self.settings["volume"] = volume or {"is_metric": True, "raw": "METERS"}
|
self.settings["volume"] = volume or {"is_metric": True, "raw": "METERS"}
|
||||||
|
|
||||||
def execute(self):
|
def execute(self) -> ifcopenshell.entity_instance:
|
||||||
# We're going to refactor this to split unit creation and assignment
|
# We're going to refactor this to split unit creation and assignment
|
||||||
if self.settings["units"]:
|
if self.settings["units"]:
|
||||||
units = self.settings["units"]
|
units = self.settings["units"]
|
||||||
@@ -84,7 +92,7 @@ class Usecase:
|
|||||||
self.assign_units(unit_assignment, units)
|
self.assign_units(unit_assignment, units)
|
||||||
return unit_assignment
|
return unit_assignment
|
||||||
|
|
||||||
def get_unit_assignment(self):
|
def get_unit_assignment(self) -> ifcopenshell.entity_instance:
|
||||||
unit_assignment = self.file.by_type("IfcUnitAssignment")
|
unit_assignment = self.file.by_type("IfcUnitAssignment")
|
||||||
if unit_assignment:
|
if unit_assignment:
|
||||||
unit_assignment = unit_assignment[0]
|
unit_assignment = unit_assignment[0]
|
||||||
@@ -97,13 +105,15 @@ class Usecase:
|
|||||||
self.file.by_type("IfcContext")[0].UnitsInContext = unit_assignment
|
self.file.by_type("IfcContext")[0].UnitsInContext = unit_assignment
|
||||||
return unit_assignment
|
return unit_assignment
|
||||||
|
|
||||||
def assign_units(self, unit_assignment, new_units):
|
def assign_units(
|
||||||
|
self, unit_assignment: ifcopenshell.entity_instance, new_units: list[ifcopenshell.entity_instance]
|
||||||
|
) -> None:
|
||||||
units = set(unit_assignment.Units or [])
|
units = set(unit_assignment.Units or [])
|
||||||
for unit in new_units:
|
for unit in new_units:
|
||||||
units.add(unit)
|
units.add(unit)
|
||||||
unit_assignment.Units = list(units)
|
unit_assignment.Units = list(units)
|
||||||
|
|
||||||
def create_metric_unit(self, unit_type, data):
|
def create_metric_unit(self, unit_type: str, data: dict) -> ifcopenshell.entity_instance:
|
||||||
type_prefix = ""
|
type_prefix = ""
|
||||||
if unit_type == "area":
|
if unit_type == "area":
|
||||||
type_prefix = "SQUARE_"
|
type_prefix = "SQUARE_"
|
||||||
@@ -116,7 +126,7 @@ class Usecase:
|
|||||||
type_prefix + ifcopenshell.util.unit.get_unit_name(data["raw"]),
|
type_prefix + ifcopenshell.util.unit.get_unit_name(data["raw"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_imperial_unit(self, unit_type, data):
|
def create_imperial_unit(self, unit_type: str, data: dict) -> ifcopenshell.entity_instance:
|
||||||
if unit_type == "length":
|
if unit_type == "length":
|
||||||
dimensional_exponents = self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0)
|
dimensional_exponents = self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0)
|
||||||
name_prefix = ""
|
name_prefix = ""
|
||||||
|
|||||||
@@ -15,10 +15,12 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import ifcopenshell
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, units=None):
|
def __init__(self, file: ifcopenshell.file, units: Optional[list[ifcopenshell.entity_instance]] = None):
|
||||||
"""Unassigns units as default units for the project
|
"""Unassigns units as default units for the project
|
||||||
|
|
||||||
:param units: A list of units to assign as project defaults.
|
:param units: A list of units to assign as project defaults.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from math import pi
|
|||||||
from typing import Iterable, Any, Union, Literal, Optional
|
from typing import Iterable, Any, Union, Literal, Optional
|
||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
|
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
|
||||||
prefixes = {
|
prefixes = {
|
||||||
@@ -353,7 +354,7 @@ def get_prefix_multiplier(text):
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def get_unit_name(text):
|
def get_unit_name(text: str) -> Union[str, None]:
|
||||||
text = text.upper().replace("METER", "METRE")
|
text = text.upper().replace("METER", "METRE")
|
||||||
for name in unit_names:
|
for name in unit_names:
|
||||||
if name.replace("_", " ") in text:
|
if name.replace("_", " ") in text:
|
||||||
@@ -368,13 +369,13 @@ def get_named_dimensions(name):
|
|||||||
return named_dimensions.get(name, (0, 0, 0, 0, 0, 0, 0))
|
return named_dimensions.get(name, (0, 0, 0, 0, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
def get_unit_assignment(ifc_file):
|
def get_unit_assignment(ifc_file: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
unit_assignments = ifc_file.by_type("IfcUnitAssignment")
|
unit_assignments = ifc_file.by_type("IfcUnitAssignment")
|
||||||
if unit_assignments:
|
if unit_assignments:
|
||||||
return unit_assignments[0]
|
return unit_assignments[0]
|
||||||
|
|
||||||
|
|
||||||
def get_project_unit(ifc_file, unit_type):
|
def get_project_unit(ifc_file: ifcopenshell.file, unit_type: str) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
"""Get the default project unit of a particular unit type
|
"""Get the default project unit of a particular unit type
|
||||||
|
|
||||||
:param ifc_file: The IFC file.
|
:param ifc_file: The IFC file.
|
||||||
@@ -384,7 +385,7 @@ def get_project_unit(ifc_file, unit_type):
|
|||||||
:type unit_type: str
|
:type unit_type: str
|
||||||
:return: The IFC unit entity, or nothing if there is no default project unit
|
:return: The IFC unit entity, or nothing if there is no default project unit
|
||||||
defined.
|
defined.
|
||||||
:rtype: ifcopenshell.entity_instance,None
|
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||||
"""
|
"""
|
||||||
unit_assignment = get_unit_assignment(ifc_file)
|
unit_assignment = get_unit_assignment(ifc_file)
|
||||||
if unit_assignment:
|
if unit_assignment:
|
||||||
@@ -393,7 +394,9 @@ def get_project_unit(ifc_file, unit_type):
|
|||||||
return unit
|
return unit
|
||||||
|
|
||||||
|
|
||||||
def get_property_unit(prop, ifc_file):
|
def get_property_unit(
|
||||||
|
prop: ifcopenshell.entity_instance, ifc_file: ifcopenshell.file
|
||||||
|
) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
unit = getattr(prop, "Unit", None)
|
unit = getattr(prop, "Unit", None)
|
||||||
if unit:
|
if unit:
|
||||||
return unit
|
return unit
|
||||||
@@ -446,14 +449,14 @@ def get_property_unit(prop, ifc_file):
|
|||||||
return units[0]
|
return units[0]
|
||||||
|
|
||||||
|
|
||||||
def get_unit_measure_class(unit_type):
|
def get_unit_measure_class(unit_type: str) -> str:
|
||||||
if unit_type == "USERDEFINED":
|
if unit_type == "USERDEFINED":
|
||||||
# See https://github.com/buildingSMART/IFC4.3.x-development/issues/71
|
# See https://github.com/buildingSMART/IFC4.3.x-development/issues/71
|
||||||
return "IfcNumericMeasure"
|
return "IfcNumericMeasure"
|
||||||
return "Ifc" + unit_type[0:-4].lower().capitalize() + "Measure"
|
return "Ifc" + unit_type[0:-4].lower().capitalize() + "Measure"
|
||||||
|
|
||||||
|
|
||||||
def get_measure_unit_type(measure_class):
|
def get_measure_unit_type(measure_class: str) -> str:
|
||||||
if measure_class == "IfcNumericMeasure":
|
if measure_class == "IfcNumericMeasure":
|
||||||
# See https://github.com/buildingSMART/IFC4.3.x-development/issues/71
|
# See https://github.com/buildingSMART/IFC4.3.x-development/issues/71
|
||||||
return "USERDEFINED"
|
return "USERDEFINED"
|
||||||
@@ -462,7 +465,7 @@ def get_measure_unit_type(measure_class):
|
|||||||
return measure_class.upper() + "UNIT"
|
return measure_class.upper() + "UNIT"
|
||||||
|
|
||||||
|
|
||||||
def get_symbol_measure_class(symbol):
|
def get_symbol_measure_class(symbol: Optional[str] = None) -> str:
|
||||||
# Dumb, but everybody gets it, unlike regex golf
|
# Dumb, but everybody gets it, unlike regex golf
|
||||||
if not symbol:
|
if not symbol:
|
||||||
return "IfcNumericMeasure"
|
return "IfcNumericMeasure"
|
||||||
@@ -480,7 +483,7 @@ def get_symbol_measure_class(symbol):
|
|||||||
return "IfcNumericMeasure"
|
return "IfcNumericMeasure"
|
||||||
|
|
||||||
|
|
||||||
def get_symbol_quantity_class(symbol):
|
def get_symbol_quantity_class(symbol: Optional[str] = None) -> str:
|
||||||
# Dumb, but everybody gets it, unlike regex golf
|
# Dumb, but everybody gets it, unlike regex golf
|
||||||
if not symbol:
|
if not symbol:
|
||||||
return "IfcQuantityCount"
|
return "IfcQuantityCount"
|
||||||
@@ -498,7 +501,7 @@ def get_symbol_quantity_class(symbol):
|
|||||||
return "IfcQuantityCount"
|
return "IfcQuantityCount"
|
||||||
|
|
||||||
|
|
||||||
def get_unit_symbol(unit):
|
def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str:
|
||||||
symbol = ""
|
symbol = ""
|
||||||
if unit.is_a("IfcSIUnit"):
|
if unit.is_a("IfcSIUnit"):
|
||||||
symbol += prefix_symbols.get(unit.Prefix, "")
|
symbol += prefix_symbols.get(unit.Prefix, "")
|
||||||
@@ -508,7 +511,7 @@ def get_unit_symbol(unit):
|
|||||||
return symbol
|
return symbol
|
||||||
|
|
||||||
|
|
||||||
def convert_unit(value, from_unit, to_unit):
|
def convert_unit(value: float, from_unit: ifcopenshell.entity_instance, to_unit: ifcopenshell.entity_instance) -> float:
|
||||||
"""Convert from one unit to another unit
|
"""Convert from one unit to another unit
|
||||||
|
|
||||||
:param value: The numeric value you want to convert
|
:param value: The numeric value you want to convert
|
||||||
@@ -668,9 +671,9 @@ def format_length(
|
|||||||
|
|
||||||
|
|
||||||
def is_attr_type(
|
def is_attr_type(
|
||||||
content_type: Union[ifcopenshell.ifcopenshell_wrapper.named_type, ifcopenshell.ifcopenshell_wrapper.type_declaration],
|
content_type: ifcopenshell_wrapper.parameter_type,
|
||||||
ifc_unit_type_name: str,
|
ifc_unit_type_name: str,
|
||||||
) -> Union[ifcopenshell.ifcopenshell_wrapper.type_declaration, None]:
|
) -> Union[ifcopenshell_wrapper.type_declaration, None]:
|
||||||
cur_decl = content_type
|
cur_decl = content_type
|
||||||
while hasattr(cur_decl, "declared_type") is True:
|
while hasattr(cur_decl, "declared_type") is True:
|
||||||
cur_decl = cur_decl.declared_type()
|
cur_decl = cur_decl.declared_type()
|
||||||
@@ -679,7 +682,7 @@ def is_attr_type(
|
|||||||
if cur_decl.name() == ifc_unit_type_name:
|
if cur_decl.name() == ifc_unit_type_name:
|
||||||
return cur_decl
|
return cur_decl
|
||||||
|
|
||||||
if isinstance(cur_decl, ifcopenshell.ifcopenshell_wrapper.aggregation_type):
|
if isinstance(cur_decl, ifcopenshell_wrapper.aggregation_type):
|
||||||
res = cur_decl.type_of_element()
|
res = cur_decl.type_of_element()
|
||||||
cur_decl = res.declared_type()
|
cur_decl = res.declared_type()
|
||||||
if hasattr(cur_decl, "name") and cur_decl.name() == ifc_unit_type_name:
|
if hasattr(cur_decl, "name") and cur_decl.name() == ifc_unit_type_name:
|
||||||
@@ -696,13 +699,13 @@ def is_attr_type(
|
|||||||
|
|
||||||
def iter_element_and_attributes_per_type(
|
def iter_element_and_attributes_per_type(
|
||||||
ifc_file: ifcopenshell.file, attr_type_name: str
|
ifc_file: ifcopenshell.file, attr_type_name: str
|
||||||
) -> Iterable[tuple[ifcopenshell.entity_instance, ifcopenshell.ifcopenshell_wrapper.attribute, Any, str]]:
|
) -> Iterable[tuple[ifcopenshell.entity_instance, ifcopenshell_wrapper.attribute, Any]]:
|
||||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||||
|
|
||||||
for element in ifc_file:
|
for element in ifc_file:
|
||||||
entity = schema.declaration_by_name(element.is_a())
|
entity = schema.declaration_by_name(element.is_a())
|
||||||
attrs = entity.all_attributes()
|
attrs = entity.all_attributes()
|
||||||
for i, (attr, val, is_derived) in enumerate(zip(attrs, list(element), entity.derived())):
|
for attr, val, is_derived in zip(attrs, list(element), entity.derived()):
|
||||||
if is_derived:
|
if is_derived:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -725,7 +728,7 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str) ->
|
|||||||
# Copy all elements from the original file to the patched file
|
# Copy all elements from the original file to the patched file
|
||||||
file_patched = ifcopenshell.file.from_string(ifc_file.wrapped_data.to_string())
|
file_patched = ifcopenshell.file.from_string(ifc_file.wrapped_data.to_string())
|
||||||
|
|
||||||
unit_assignment = ifcopenshell.util.unit.get_unit_assignment(file_patched)
|
unit_assignment = get_unit_assignment(file_patched)
|
||||||
|
|
||||||
old_length = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == "LENGTHUNIT"][0]
|
old_length = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == "LENGTHUNIT"][0]
|
||||||
new_length = ifcopenshell.api.run("unit.add_si_unit", file_patched, unit_type="LENGTHUNIT", prefix=prefix)
|
new_length = ifcopenshell.api.run("unit.add_si_unit", file_patched, unit_type="LENGTHUNIT", prefix=prefix)
|
||||||
@@ -733,10 +736,10 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str) ->
|
|||||||
# Traverse all elements and their nested attributes in the file and convert them
|
# Traverse all elements and their nested attributes in the file and convert them
|
||||||
for element, attr, val in iter_element_and_attributes_per_type(file_patched, "IfcLengthMeasure"):
|
for element, attr, val in iter_element_and_attributes_per_type(file_patched, "IfcLengthMeasure"):
|
||||||
if isinstance(val, tuple):
|
if isinstance(val, tuple):
|
||||||
new_value = [ifcopenshell.util.unit.convert_unit(v, old_length, new_length) for v in val]
|
new_value = [convert_unit(v, old_length, new_length) for v in val]
|
||||||
setattr(element, attr.name(), tuple(new_value))
|
setattr(element, attr.name(), tuple(new_value))
|
||||||
else:
|
else:
|
||||||
new_value = ifcopenshell.util.unit.convert_unit(val, old_length, new_length)
|
new_value = convert_unit(val, old_length, new_length)
|
||||||
setattr(element, attr.name(), new_value)
|
setattr(element, attr.name(), new_value)
|
||||||
|
|
||||||
file_patched.remove(old_length)
|
file_patched.remove(old_length)
|
||||||
|
|||||||
@@ -26,7 +26,13 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, unit: str = "METERS"):
|
def __init__(
|
||||||
|
self,
|
||||||
|
src: str,
|
||||||
|
file: ifcopenshell.file,
|
||||||
|
logger: Logger,
|
||||||
|
unit: str = "METERS",
|
||||||
|
):
|
||||||
"""Converts the length unit of a model to the specified unit
|
"""Converts the length unit of a model to the specified unit
|
||||||
|
|
||||||
Allowed metric units include METERS, MILLIMETERS, CENTIMETERS, etc.
|
Allowed metric units include METERS, MILLIMETERS, CENTIMETERS, etc.
|
||||||
|
|||||||
Reference in New Issue
Block a user