ifcopenshell.util - make ifc_file argument optional if it can be deduced from ifc element

This commit is contained in:
Andrej730
2025-03-07 12:07:14 +05:00
parent 590288496e
commit eb0d3c38b2
4 changed files with 43 additions and 13 deletions
@@ -66,7 +66,7 @@ class Clipping:
raise Exception(f"Unexpected clipping type provided: {raw_data}")
def apply(
self, ifc_file: ifcopenshell.file, first_operand: ifcopenshell.entity_instance, unit_scale: float
self, ifc_file: Union[ifcopenshell.file, None], first_operand: ifcopenshell.entity_instance, unit_scale: float
) -> ifcopenshell.entity_instance:
"""Applies the clipping data as an IfcBooleanClippingResult to an operand
@@ -76,6 +76,9 @@ class Clipping:
:return: An IfcBooleanClippingResult which uses an IfcHalfSpaceSolid to clip the first operand
"""
if not ifc_file:
ifc_file = first_operand.file
location = ifc_file.createIfcCartesianPoint([i / unit_scale for i in self.location])
direction = ifc_file.createIfcDirection(self.normal)
@@ -689,7 +689,7 @@ def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
# TODO: ifc_file argument is unnecessary for some methods now
# since we have entity_instance.file, so we can deprecate it.
def get_elements_by_material(
ifc_file: ifcopenshell.file, material: ifcopenshell.entity_instance
ifc_file: Union[ifcopenshell.file, None], material: ifcopenshell.entity_instance
) -> set[ifcopenshell.entity_instance]:
"""Retrieves the elements related to a material.
@@ -707,6 +707,8 @@ def get_elements_by_material(
material = file.by_type("IfcMaterial")[0]
elements = ifcopenshell.util.element.get_elements_by_material(file, material)
"""
if not ifc_file:
ifc_file = material.file
results = set()
for inverse in ifc_file.get_inverse(material):
if inverse.is_a("IfcRelAssociatesMaterial"):
@@ -730,7 +732,7 @@ def get_elements_by_material(
def get_elements_by_style(
ifc_file: ifcopenshell.file, style: ifcopenshell.entity_instance
ifc_file: Union[ifcopenshell.file, None], style: ifcopenshell.entity_instance
) -> set[ifcopenshell.entity_instance]:
"""Retrieves the elements whose geometric representation uses a style
@@ -745,6 +747,8 @@ def get_elements_by_style(
style = file.by_type("IfcSurfaceStyle")[0]
elements = ifcopenshell.util.element.get_elements_by_style(file, style)
"""
if not ifc_file:
ifc_file = style.file
results = set()
inverses = list(ifc_file.get_inverse(style))
while inverses:
@@ -778,7 +782,7 @@ def get_elements_by_style(
def get_elements_by_representation(
ifc_file: ifcopenshell.file, representation: ifcopenshell.entity_instance
ifc_file: Union[ifcopenshell.file, None], representation: ifcopenshell.entity_instance
) -> set[ifcopenshell.entity_instance]:
"""Gets all elements using a geometric representation
@@ -793,6 +797,8 @@ def get_elements_by_representation(
representation = file.by_type("IfcShapeRepresentation")[0]
elements = ifcopenshell.util.element.get_elements_by_representation(file, representation)
"""
if not ifc_file:
ifc_file = representation.file
results = set()
[results.update(pr.ShapeOfProduct) for pr in representation.OfProductRepresentation]
for rep_map in representation.RepresentationMap:
@@ -838,7 +844,7 @@ def get_elements_by_profile(profile: ifcopenshell.entity_instance) -> set[ifcope
def get_elements_by_layer(
ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance
ifc_file: Union[ifcopenshell.file, None], layer: ifcopenshell.entity_instance
) -> set[ifcopenshell.entity_instance]:
"""Get all the elements that are used by a presentation layer
@@ -846,6 +852,8 @@ def get_elements_by_layer(
:param layer: The IfcPresentationLayerAssignment layer
:return: The elements using the geometric representation
"""
if not ifc_file:
ifc_file = layer.file
results = set()
for item in layer.AssignedItems or []:
if item.is_a("IfcShapeRepresentation"):
@@ -858,7 +866,7 @@ def get_elements_by_layer(
def get_layers(
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance
ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance
) -> list[ifcopenshell.entity_instance]:
"""Get the CAD layers that an element is part of
@@ -876,6 +884,8 @@ def get_layers(
element = ifcopenshell.by_type("IfcWall")[0]
layers = ifcopenshell.util.element.get_layers(element)
"""
if not ifc_file:
ifc_file = element.file
layers = []
representations = []
if representation := getattr(element, "Representation", None):
@@ -1352,12 +1362,14 @@ def has_element_reference(value: Any, element: ifcopenshell.entity_instance) ->
return value == element
def remove_deep(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> None:
def remove_deep(ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance) -> None:
"""Recursively purges a subgraph safely.
Do not use, use remove_deep2() instead.
"""
# @todo maybe some sort of try-finally mechanism.
if not ifc_file:
ifc_file = element.file
ifc_file.batch()
subgraph = list(ifc_file.traverse(element, breadth_first=True))
subgraph_set = set(subgraph)
@@ -1431,7 +1443,7 @@ def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file:
def remove_deep2(
ifc_file: ifcopenshell.file,
ifc_file: Union[ifcopenshell.file, None],
element: ifcopenshell.entity_instance,
also_consider: list[ifcopenshell.entity_instance] = [],
do_not_delete: set[ifcopenshell.entity_instance] = set(),
@@ -1468,6 +1480,8 @@ def remove_deep2(
:param element: The starting element that defines the subgraph
"""
# ifc_file.batch()
if not ifc_file:
ifc_file = element.file
total_inverses = ifc_file.get_total_inverses(element)
if total_inverses > 0:
@@ -1527,7 +1541,9 @@ def remove_deep2(
# ifc_file.unbatch()
def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
def copy(
ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
"""
Copy a single element. Any referenced elements are not copied.
@@ -1537,6 +1553,8 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) ->
:param element: The IFC element to copy
:return: The newly copied element
"""
if not ifc_file:
ifc_file = element.file
new = ifc_file.create_entity(element.is_a())
for i, attribute in enumerate(element):
if attribute is None:
@@ -1549,7 +1567,7 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) ->
def copy_deep(
ifc_file: ifcopenshell.file,
ifc_file: Union[ifcopenshell.file, None],
element: ifcopenshell.entity_instance,
exclude: Optional[Sequence[str]] = None,
exclude_callback: Optional[Callable[[ifcopenshell.entity_instance], bool]] = None,
@@ -1572,6 +1590,8 @@ def copy_deep(
be left as None.
:return: The newly copied element
"""
if not ifc_file:
ifc_file = element.file
if copied_entities is None:
copied_entities = {}
else:
@@ -140,7 +140,7 @@ def get_subtypes(
def reassign_class(
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance, new_class: str
ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance, new_class: str
) -> ifcopenshell.entity_instance:
"""
Attempts to change the class (entity name) of `element` to `new_class` by
@@ -156,6 +156,9 @@ def reassign_class(
It's unlikely that this affects real-world usage of this function.
"""
if not ifc_file:
ifc_file = element.file
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
try:
declaration = schema.declaration_by_name(new_class)
@@ -456,7 +456,7 @@ def get_project_unit(
def get_property_unit(
prop: ifcopenshell.entity_instance, ifc_file: ifcopenshell.file, use_cache: bool = False
prop: ifcopenshell.entity_instance, ifc_file: Union[ifcopenshell.file, None], use_cache: bool = False
) -> Union[ifcopenshell.entity_instance, None]:
"""Gets the unit definition of a property or quantity
@@ -499,11 +499,13 @@ def get_property_unit(
measure_class = value.is_a()
if measure_class and (unit_type := get_measure_unit_type(measure_class)):
if not ifc_file:
ifc_file = prop.file
return get_project_unit(ifc_file, unit_type, use_cache=use_cache)
def get_property_table_unit(
prop: ifcopenshell.entity_instance, ifc_file: ifcopenshell.file, use_cache: bool = False
prop: ifcopenshell.entity_instance, ifc_file: Union[ifcopenshell.file, None], use_cache: bool = False
) -> Dict[str, Union[ifcopenshell.entity_instance, None]]:
"""
Gets the unit definition of a property table
@@ -523,6 +525,8 @@ def get_property_table_unit(
If a unit-entity is missing,
the value associated to the key is `null`.
"""
if not ifc_file:
ifc_file = prop.file
defining_unit = None
if unit := prop.DefiningUnit:
defining_unit = unit