mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
typing
This commit is contained in:
+24
-7
@@ -29,6 +29,7 @@ import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from statistics import mean
|
||||
from typing import Optional, Union
|
||||
|
||||
try:
|
||||
from odf.namespaces import OFFICENS
|
||||
@@ -269,7 +270,7 @@ class IfcCsv:
|
||||
elif not include_global_id:
|
||||
self.results = sorted(self.results, key=lambda x: x[0])
|
||||
|
||||
def export_csv(self, output, delimiter=None):
|
||||
def export_csv(self, output: str, delimiter: Optional[str] = None) -> None:
|
||||
with open(output, "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.writer(f, delimiter=delimiter)
|
||||
writer.writerow(self.headers)
|
||||
@@ -387,8 +388,16 @@ class IfcCsv:
|
||||
self.import_xlsx(ifc_file, table, attributes, null, empty, bool_true, bool_false)
|
||||
|
||||
def import_csv(
|
||||
self, ifc_file, table, attributes=None, delimiter=",", null="-", empty="", bool_true="YES", bool_false="NO"
|
||||
):
|
||||
self,
|
||||
ifc_file: ifcopenshell.file,
|
||||
table: str,
|
||||
attributes: Optional[list[Union[str, None]]] = None,
|
||||
delimiter: str = ",",
|
||||
null: str = "-",
|
||||
empty: str = "",
|
||||
bool_true: str = "YES",
|
||||
bool_false: str = "NO",
|
||||
) -> None:
|
||||
with open(table, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f, delimiter=delimiter)
|
||||
headers = []
|
||||
@@ -421,7 +430,17 @@ class IfcCsv:
|
||||
for _, row in df.iterrows():
|
||||
self.process_row(ifc_file, row.tolist(), headers, attributes, null, empty, bool_true, bool_false)
|
||||
|
||||
def process_row(self, ifc_file, row, headers, attributes, null, empty, bool_true, bool_false):
|
||||
def process_row(
|
||||
self,
|
||||
ifc_file: ifcopenshell.file,
|
||||
row: list[str],
|
||||
headers: list[str],
|
||||
attributes: list[Union[str, None]],
|
||||
null: str,
|
||||
empty: str,
|
||||
bool_true: str,
|
||||
bool_false: str,
|
||||
) -> None:
|
||||
try:
|
||||
element = ifc_file.by_guid(row[0])
|
||||
except:
|
||||
@@ -448,9 +467,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument("-s", "--spreadsheet", type=str, default="data.csv", help="The spreadsheet file")
|
||||
parser.add_argument("-f", "--format", type=str, default="csv", help="The format, chosen from csv, ods, or xlsx")
|
||||
parser.add_argument("-d", "--delimiter", type=str, default=",", help="The delimiter in CSV. Defaults to a comma.")
|
||||
parser.add_argument(
|
||||
"-n", "--null", type=str, default="N/A", help="How to represent null values. Defaults to N/A."
|
||||
)
|
||||
parser.add_argument("-n", "--null", type=str, default="N/A", help="How to represent null values. Defaults to N/A.")
|
||||
parser.add_argument(
|
||||
"-e", "--empty", type=str, default="-", help="How to represent empty strings. Defaults to a hyphen."
|
||||
)
|
||||
|
||||
@@ -17,14 +17,15 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.element
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def get_references(element, should_inherit=True):
|
||||
def get_references(element: ifcopenshell.entity_instance, should_inherit=True) -> set[ifcopenshell.entity_instance]:
|
||||
results = set()
|
||||
if not element.is_a("IfcRoot"):
|
||||
if hasattr(element, "HasExternalReferences"):
|
||||
return {r.RelatingReference for r in element.HasExternalReferences or []}
|
||||
elif hasattr(element, "HasExternalReference"): # Seriously, IFC?
|
||||
elif hasattr(element, "HasExternalReference"): # Seriously, IFC?
|
||||
return {r.RelatingReference for r in element.HasExternalReference or []}
|
||||
if should_inherit:
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
@@ -50,13 +51,13 @@ def get_references(element, should_inherit=True):
|
||||
return occurrence_results
|
||||
|
||||
|
||||
def get_classification(reference):
|
||||
def get_classification(reference: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
if reference.is_a("IfcClassification"):
|
||||
return reference
|
||||
return get_classification(reference.ReferencedSource)
|
||||
|
||||
|
||||
def get_inherited_references(reference):
|
||||
def get_inherited_references(reference: Optional[ifcopenshell.entity_instance]) -> list[ifcopenshell.entity_instance]:
|
||||
results = []
|
||||
while True:
|
||||
if not reference or reference.is_a("IfcClassification"):
|
||||
@@ -64,4 +65,3 @@ def get_inherited_references(reference):
|
||||
results.append(reference)
|
||||
reference = reference.ReferencedSource
|
||||
return results
|
||||
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
from typing import Literal, Iterable
|
||||
|
||||
|
||||
def a2p(o, z, x):
|
||||
def a2p(o: Iterable[float], z: Iterable[float], x: Iterable[float]) -> np.array:
|
||||
"""Converts a location, X, and Z axis vector to a 4x4 transformation matrix
|
||||
|
||||
IFC uses a right-handed coordinate system, so it is not necessary to
|
||||
@@ -73,7 +74,7 @@ def get_axis2placement(placement: ifcopenshell.entity_instance) -> np.array:
|
||||
return a2p(o, z, x)
|
||||
|
||||
|
||||
def get_local_placement(placement):
|
||||
def get_local_placement(placement: ifcopenshell.entity_instance) -> np.array:
|
||||
"""Parse a local placement into a 4x4 transformation matrix
|
||||
|
||||
This is typically used to find the location and rotation of an element. The
|
||||
@@ -107,7 +108,7 @@ def get_local_placement(placement):
|
||||
return np.dot(parent, get_axis2placement(placement.RelativePlacement))
|
||||
|
||||
|
||||
def get_cartesiantransformationoperator3d(inst):
|
||||
def get_cartesiantransformationoperator3d(inst: ifcopenshell.entity_instance) -> np.array:
|
||||
"""Parses an IfcCartesianTransformationOperator into a 4x4 transformation matrix
|
||||
|
||||
Note that in general you will not need to call this directly. See
|
||||
@@ -152,7 +153,7 @@ def get_cartesiantransformationoperator3d(inst):
|
||||
return m4
|
||||
|
||||
|
||||
def get_mappeditem_transformation(item):
|
||||
def get_mappeditem_transformation(item: ifcopenshell.entity_instance) -> np.array:
|
||||
"""Parse an IfcMappedItem into a 4x4 transformation matrix
|
||||
|
||||
Mapped items take a representation with an origin and transform them with a
|
||||
@@ -170,7 +171,7 @@ def get_mappeditem_transformation(item):
|
||||
return get_cartesiantransformationoperator3d(item.MappingTarget) @ m4
|
||||
|
||||
|
||||
def get_storey_elevation(storey):
|
||||
def get_storey_elevation(storey: ifcopenshell.entity_instance) -> float:
|
||||
"""Get the Z elevation in project units of a buildling storey
|
||||
|
||||
Building storeys store elevation in two possible locations: the Z value of
|
||||
@@ -187,7 +188,7 @@ def get_storey_elevation(storey):
|
||||
return getattr(storey, "Elevation", 0.0) or 0.0
|
||||
|
||||
|
||||
def rotation(angle, axis, is_degrees=True):
|
||||
def rotation(angle: float, axis: Literal["X", "Y", "Z"], is_degrees=True) -> np.array:
|
||||
"""Create a 4x4 numpy matrix representing an euler rotation
|
||||
|
||||
:param angle: The angle of rotation
|
||||
|
||||
@@ -21,6 +21,7 @@ import json
|
||||
import time
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||
|
||||
# This is highly experimental and incomplete, however, it may work for simple datasets.
|
||||
# In this simple implementation, we only support 2X3<->4 right now
|
||||
@@ -28,7 +29,7 @@ import ifcopenshell.util.attribute
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def get_fallback_schema(version):
|
||||
def get_fallback_schema(version: str) -> str:
|
||||
"""fallback to the schema version we do have docs and mapping for,
|
||||
needed to support IFC versions like 4X3_RC1, 4X1 etc"""
|
||||
if version.startswith("IFC4X3"):
|
||||
@@ -38,7 +39,7 @@ def get_fallback_schema(version):
|
||||
return version
|
||||
|
||||
|
||||
def is_a(entity, ifc_class):
|
||||
def is_a(entity: ifcopenshell.entity_instance, ifc_class: str) -> bool:
|
||||
ifc_class = ifc_class.upper()
|
||||
if entity.name_uc() == ifc_class:
|
||||
return True
|
||||
@@ -59,7 +60,9 @@ def get_subtypes(entity):
|
||||
return get_classes(entity)
|
||||
|
||||
|
||||
def reassign_class(ifc_file, element, new_class):
|
||||
def reassign_class(
|
||||
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance, new_class: str
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
Attempts to change the class (entity name) of `element` to `new_class` by
|
||||
removing element and recreating a similar instance of type `new_class`
|
||||
@@ -74,7 +77,7 @@ def reassign_class(ifc_file, element, new_class):
|
||||
It's unlikely that this affects real-world usage of this function.
|
||||
"""
|
||||
|
||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||
try:
|
||||
declaration = schema.declaration_by_name(new_class)
|
||||
except:
|
||||
@@ -116,11 +119,11 @@ def reassign_class(ifc_file, element, new_class):
|
||||
|
||||
|
||||
class BatchReassignClass:
|
||||
def __init__(self, file):
|
||||
def __init__(self, file: ifcopenshell.file):
|
||||
self.file = file
|
||||
self.purge()
|
||||
|
||||
def reassign(self, element, new_class):
|
||||
def reassign(self, element: ifcopenshell.entity_instance, new_class: str) -> ifcopenshell.entity_instance:
|
||||
try:
|
||||
new_element = self.file.create_entity(new_class)
|
||||
except:
|
||||
@@ -150,9 +153,12 @@ class BatchReassignClass:
|
||||
self.file.remove(element)
|
||||
self.purge()
|
||||
|
||||
def purge(self):
|
||||
self.replacements = {}
|
||||
self.to_delete = set()
|
||||
def purge(self) -> None:
|
||||
# mapping {inverse: {attribute_index: {old_element: new_element} } }
|
||||
self.replacements: dict[
|
||||
ifcopenshell.entity_instance, dict[int, dict[ifcopenshell.entity_instance, ifcopenshell.entity_instance]]
|
||||
] = {}
|
||||
self.to_delete: set[ifcopenshell.entity_instance] = set()
|
||||
|
||||
|
||||
class Migrator:
|
||||
@@ -217,7 +223,7 @@ class Migrator:
|
||||
"User": None,
|
||||
}
|
||||
|
||||
def migrate(self, element, new_file):
|
||||
def migrate(self, element: ifcopenshell.entity_instance, new_file: ifcopenshell.file) -> ifcopenshell.entity_instance:
|
||||
if element.id() == 0:
|
||||
return new_file.create_entity(element.is_a(), element.wrappedValue)
|
||||
try:
|
||||
|
||||
@@ -25,8 +25,9 @@ import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.classification
|
||||
import ifcopenshell.util.schema
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
from typing import Optional, Any, Union
|
||||
|
||||
|
||||
filter_elements_grammar = lark.Lark(
|
||||
@@ -258,8 +259,8 @@ def format(query):
|
||||
return FormatTransformer().transform(format_grammar.parse(query))
|
||||
|
||||
|
||||
def get_element_value(element, query):
|
||||
keys = GetElementTransformer().transform(get_element_grammar.parse(query))
|
||||
def get_element_value(element: ifcopenshell.entity_instance, query: str) -> Any:
|
||||
keys: list[str] = GetElementTransformer().transform(get_element_grammar.parse(query))
|
||||
return Selector.get_element_value(element, keys)
|
||||
|
||||
|
||||
@@ -309,7 +310,12 @@ def filter_elements(
|
||||
return transformer.elements
|
||||
|
||||
|
||||
def set_element_value(ifc_file, element, query, value):
|
||||
def set_element_value(
|
||||
ifc_file: ifcopenshell.file,
|
||||
element: ifcopenshell.entity_instance,
|
||||
query: Union[str, list[str]],
|
||||
value: Optional[str],
|
||||
) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if isinstance(query, (list, tuple)):
|
||||
keys = query
|
||||
else:
|
||||
@@ -885,7 +891,7 @@ class Selector:
|
||||
return {"keys": keys, "is_regex": is_regex}
|
||||
|
||||
@classmethod
|
||||
def get_element_value(cls, element, keys):
|
||||
def get_element_value(cls, element: ifcopenshell.entity_instance, keys: list[str]) -> Any:
|
||||
value = element
|
||||
for key in keys:
|
||||
if value is None:
|
||||
|
||||
Reference in New Issue
Block a user