mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 15:28:19 +00:00
ifcopenshell.util.element optimization
Tried to reduce amount of IFC attributes retrieved by reusing already retrieved values. E.g. previously get_nest() was retrieving same attribute 3 times on each call, now it does it only once and it's 2 times faster (2.4 ms -> 1.2 ms).
This commit is contained in:
@@ -75,12 +75,12 @@ def get_pset(
|
|||||||
if definition.Name == name:
|
if definition.Name == name:
|
||||||
pset = definition
|
pset = definition
|
||||||
break
|
break
|
||||||
elif hasattr(element, "IsDefinedBy"):
|
elif (is_defined_by := getattr(element, "IsDefinedBy", None)) is not None:
|
||||||
if should_inherit:
|
if should_inherit:
|
||||||
element_type = ifcopenshell.util.element.get_type(element)
|
element_type = ifcopenshell.util.element.get_type(element)
|
||||||
if element_type:
|
if element_type:
|
||||||
type_pset = get_pset(element_type, name, prop, should_inherit=False, verbose=verbose)
|
type_pset = get_pset(element_type, name, prop, should_inherit=False, verbose=verbose)
|
||||||
for relationship in element.IsDefinedBy:
|
for relationship in is_defined_by:
|
||||||
if relationship.is_a("IfcRelDefinesByProperties"):
|
if relationship.is_a("IfcRelDefinesByProperties"):
|
||||||
definition = relationship.RelatingPropertyDefinition
|
definition = relationship.RelatingPropertyDefinition
|
||||||
if definition.Name == name:
|
if definition.Name == name:
|
||||||
@@ -157,12 +157,12 @@ def get_psets(
|
|||||||
if qtos_only:
|
if qtos_only:
|
||||||
continue
|
continue
|
||||||
psets[definition.Name] = get_property_definition(definition, verbose=verbose)
|
psets[definition.Name] = get_property_definition(definition, verbose=verbose)
|
||||||
elif hasattr(element, "IsDefinedBy"):
|
elif (is_defined_by := getattr(element, "IsDefinedBy", None)) is not None:
|
||||||
if should_inherit:
|
if should_inherit:
|
||||||
element_type = ifcopenshell.util.element.get_type(element)
|
element_type = ifcopenshell.util.element.get_type(element)
|
||||||
if element_type:
|
if element_type:
|
||||||
psets = get_psets(element_type, psets_only=psets_only, qtos_only=qtos_only, should_inherit=False)
|
psets = get_psets(element_type, psets_only=psets_only, qtos_only=qtos_only, should_inherit=False)
|
||||||
for relationship in element.IsDefinedBy:
|
for relationship in is_defined_by:
|
||||||
if relationship.is_a("IfcRelDefinesByProperties"):
|
if relationship.is_a("IfcRelDefinesByProperties"):
|
||||||
definition = relationship.RelatingPropertyDefinition
|
definition = relationship.RelatingPropertyDefinition
|
||||||
if psets_only and not definition.is_a("IfcPropertySet"):
|
if psets_only and not definition.is_a("IfcPropertySet"):
|
||||||
@@ -345,9 +345,12 @@ def get_predefined_type(element: ifcopenshell.entity_instance) -> str:
|
|||||||
if element_type:
|
if element_type:
|
||||||
predefined_type = getattr(element_type, "PredefinedType", None)
|
predefined_type = getattr(element_type, "PredefinedType", None)
|
||||||
if predefined_type == "USERDEFINED" or not predefined_type:
|
if predefined_type == "USERDEFINED" or not predefined_type:
|
||||||
predefined_type = getattr(element_type, "ElementType", getattr(element_type, "ProcessType", None))
|
predefined_type = getattr(element_type, "ElementType", ...)
|
||||||
|
if predefined_type == ...:
|
||||||
|
predefined_type = getattr(element_type, "ProcessType", None)
|
||||||
if predefined_type and predefined_type != "NOTDEFINED":
|
if predefined_type and predefined_type != "NOTDEFINED":
|
||||||
return predefined_type
|
return predefined_type
|
||||||
|
|
||||||
predefined_type = getattr(element, "PredefinedType", None)
|
predefined_type = getattr(element, "PredefinedType", None)
|
||||||
if predefined_type == "USERDEFINED" or not predefined_type:
|
if predefined_type == "USERDEFINED" or not predefined_type:
|
||||||
predefined_type = getattr(element, "ObjectType", None)
|
predefined_type = getattr(element, "ObjectType", None)
|
||||||
@@ -371,10 +374,10 @@ def get_type(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_insta
|
|||||||
"""
|
"""
|
||||||
if element.is_a("IfcTypeObject"):
|
if element.is_a("IfcTypeObject"):
|
||||||
return element
|
return element
|
||||||
elif hasattr(element, "IsTypedBy") and element.IsTypedBy:
|
elif (is_typed_by := getattr(element, "IsTypedBy", None)) is not None and is_typed_by:
|
||||||
return element.IsTypedBy[0].RelatingType
|
return is_typed_by[0].RelatingType
|
||||||
elif hasattr(element, "IsDefinedBy") and element.IsDefinedBy: # IFC2X3
|
elif (is_defined_by := getattr(element, "IsDefinedBy", None)) is not None and is_defined_by: # IFC2X3
|
||||||
for relationship in element.IsDefinedBy:
|
for relationship in is_defined_by:
|
||||||
if relationship.is_a("IfcRelDefinesByType"):
|
if relationship.is_a("IfcRelDefinesByType"):
|
||||||
return relationship.RelatingType
|
return relationship.RelatingType
|
||||||
|
|
||||||
@@ -418,8 +421,8 @@ def get_shape_aspects(element: ifcopenshell.entity_instance) -> list[ifcopenshel
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# IfcProduct
|
# IfcProduct
|
||||||
if hasattr(element, "Representation"):
|
if (representation := getattr(element, "Representation", ...)) != ...:
|
||||||
return element.Representation.HasShapeAspects
|
return representation.HasShapeAspects
|
||||||
|
|
||||||
# IfcTypeProduct
|
# IfcTypeProduct
|
||||||
shape_aspects = []
|
shape_aspects = []
|
||||||
@@ -456,18 +459,19 @@ def get_material(
|
|||||||
element = ifcopenshell.by_type("IfcWall")[0]
|
element = ifcopenshell.by_type("IfcWall")[0]
|
||||||
material = ifcopenshell.util.element.get_material(element)
|
material = ifcopenshell.util.element.get_material(element)
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "HasAssociations") and element.HasAssociations:
|
if (has_associations := getattr(element, "HasAssociations", None)) is not None and has_associations:
|
||||||
for relationship in element.HasAssociations:
|
for relationship in has_associations:
|
||||||
if relationship.is_a("IfcRelAssociatesMaterial"):
|
if relationship.is_a("IfcRelAssociatesMaterial"):
|
||||||
if should_skip_usage:
|
if should_skip_usage:
|
||||||
if relationship.RelatingMaterial.is_a("IfcMaterialLayerSetUsage"):
|
relating_material = relationship.RelatingMaterial
|
||||||
return relationship.RelatingMaterial.ForLayerSet
|
if relating_material.is_a("IfcMaterialLayerSetUsage"):
|
||||||
elif relationship.RelatingMaterial.is_a("IfcMaterialProfileSetUsage"):
|
return relating_material.ForLayerSet
|
||||||
return relationship.RelatingMaterial.ForProfileSet
|
elif relating_material.is_a("IfcMaterialProfileSetUsage"):
|
||||||
|
return relating_material.ForProfileSet
|
||||||
return relationship.RelatingMaterial
|
return relationship.RelatingMaterial
|
||||||
if should_inherit:
|
if should_inherit:
|
||||||
relating_type = get_type(element)
|
relating_type = get_type(element)
|
||||||
if relating_type != element and hasattr(relating_type, "HasAssociations") and relating_type.HasAssociations:
|
if relating_type != element and (has_associations := getattr(relating_type, "HasAssociations", None)):
|
||||||
return get_material(relating_type, should_skip_usage)
|
return get_material(relating_type, should_skip_usage)
|
||||||
|
|
||||||
|
|
||||||
@@ -717,10 +721,10 @@ def get_layers(
|
|||||||
"""
|
"""
|
||||||
layers = []
|
layers = []
|
||||||
representations = []
|
representations = []
|
||||||
if getattr(element, "Representation", None):
|
if representation := getattr(element, "Representation", None):
|
||||||
representations = [element.Representation]
|
representations = [representation]
|
||||||
elif getattr(element, "RepresentationMaps", None):
|
elif representation_maps := getattr(element, "RepresentationMaps", None):
|
||||||
representations = element.RepresentationMaps
|
representations = representation_maps
|
||||||
for representation in representations:
|
for representation in representations:
|
||||||
for subelement in ifc_file.traverse(representation):
|
for subelement in ifc_file.traverse(representation):
|
||||||
if subelement.is_a("IfcShapeRepresentation"):
|
if subelement.is_a("IfcShapeRepresentation"):
|
||||||
@@ -761,8 +765,10 @@ def get_container(
|
|||||||
container = ifcopenshell.util.element.get_container(element)
|
container = ifcopenshell.util.element.get_container(element)
|
||||||
"""
|
"""
|
||||||
if should_get_direct:
|
if should_get_direct:
|
||||||
if hasattr(element, "ContainedInStructure") and element.ContainedInStructure:
|
if (
|
||||||
container = element.ContainedInStructure[0].RelatingStructure
|
contained_in_structure := getattr(element, "ContainedInStructure", None)
|
||||||
|
) is not None and contained_in_structure:
|
||||||
|
container = contained_in_structure[0].RelatingStructure
|
||||||
if not ifc_class:
|
if not ifc_class:
|
||||||
return container
|
return container
|
||||||
if container.is_a(ifc_class):
|
if container.is_a(ifc_class):
|
||||||
@@ -774,8 +780,10 @@ def get_container(
|
|||||||
nest = get_nest(element)
|
nest = get_nest(element)
|
||||||
if nest:
|
if nest:
|
||||||
return get_container(nest, should_get_direct)
|
return get_container(nest, should_get_direct)
|
||||||
if hasattr(element, "ContainedInStructure") and element.ContainedInStructure:
|
if (
|
||||||
container = element.ContainedInStructure[0].RelatingStructure
|
contained_in_structure := getattr(element, "ContainedInStructure", None)
|
||||||
|
) is not None and contained_in_structure:
|
||||||
|
container = contained_in_structure[0].RelatingStructure
|
||||||
if not ifc_class:
|
if not ifc_class:
|
||||||
return container
|
return container
|
||||||
while container:
|
while container:
|
||||||
@@ -803,9 +811,7 @@ def get_referenced_structures(element: ifcopenshell.entity_instance) -> list[ifc
|
|||||||
element = file.by_type("IfcWall")[0]
|
element = file.by_type("IfcWall")[0]
|
||||||
print(ifcopenshell.util.element.get_referenced_structures(element))
|
print(ifcopenshell.util.element.get_referenced_structures(element))
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "ReferencedInStructures"):
|
return [r.RelatingStructure for r in getattr(element, "ReferencedInStructures", [])]
|
||||||
return [r.RelatingStructure for r in element.ReferencedInStructures]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True) -> list[ifcopenshell.entity_instance]:
|
def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True) -> list[ifcopenshell.entity_instance]:
|
||||||
@@ -831,20 +837,25 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True)
|
|||||||
while queue:
|
while queue:
|
||||||
element = queue.pop()
|
element = queue.pop()
|
||||||
for rel in getattr(element, "ContainsElements", []):
|
for rel in getattr(element, "ContainsElements", []):
|
||||||
queue.extend(rel.RelatedElements)
|
related = rel.RelatedElements
|
||||||
results.extend(rel.RelatedElements)
|
queue.extend(related)
|
||||||
|
results.extend(related)
|
||||||
for rel in getattr(element, "IsDecomposedBy", []):
|
for rel in getattr(element, "IsDecomposedBy", []):
|
||||||
queue.extend(rel.RelatedObjects)
|
related = rel.RelatedObjects
|
||||||
results.extend(rel.RelatedObjects)
|
queue.extend(related)
|
||||||
|
results.extend(related)
|
||||||
for rel in getattr(element, "HasOpenings", []):
|
for rel in getattr(element, "HasOpenings", []):
|
||||||
queue.append(rel.RelatedOpeningElement)
|
related = rel.RelatedOpeningElement
|
||||||
results.append(rel.RelatedOpeningElement)
|
queue.append(related)
|
||||||
|
results.append(related)
|
||||||
for rel in getattr(element, "HasFillings", []):
|
for rel in getattr(element, "HasFillings", []):
|
||||||
queue.append(rel.RelatedBuildingElement)
|
related = rel.RelatedBuildingElement
|
||||||
results.append(rel.RelatedBuildingElement)
|
queue.append(related)
|
||||||
|
results.append(related)
|
||||||
for rel in getattr(element, "IsNestedBy", []):
|
for rel in getattr(element, "IsNestedBy", []):
|
||||||
queue.extend(rel.RelatedObjects)
|
related = rel.RelatedObjects
|
||||||
results.extend(rel.RelatedObjects)
|
queue.extend(related)
|
||||||
|
results.extend(related)
|
||||||
if not is_recursive:
|
if not is_recursive:
|
||||||
break
|
break
|
||||||
return results
|
return results
|
||||||
@@ -870,8 +881,9 @@ def get_grouped_by(element: ifcopenshell.entity_instance) -> list[ifcopenshell.e
|
|||||||
while queue:
|
while queue:
|
||||||
element = queue.pop()
|
element = queue.pop()
|
||||||
for rel in getattr(element, "IsGroupedBy", []):
|
for rel in getattr(element, "IsGroupedBy", []):
|
||||||
queue.extend(rel.RelatedObjects)
|
related_objects = rel.RelatedObjects
|
||||||
results.extend(rel.RelatedObjects)
|
queue.extend(related_objects)
|
||||||
|
results.extend(related_objects)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@@ -891,9 +903,9 @@ def get_aggregate(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_
|
|||||||
element = file.by_type("IfcBeam")[0]
|
element = file.by_type("IfcBeam")[0]
|
||||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "Decomposes") and element.Decomposes:
|
if decomposes := getattr(element, "Decomposes", None):
|
||||||
if element.Decomposes[0].is_a("IfcRelAggregates"): # IFC2X3
|
if decomposes[0].is_a("IfcRelAggregates"): # IFC2X3
|
||||||
return element.Decomposes[0].RelatingObject
|
return decomposes[0].RelatingObject
|
||||||
|
|
||||||
|
|
||||||
def get_nest(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
def get_nest(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||||
@@ -912,12 +924,12 @@ def get_nest(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_insta
|
|||||||
element = file.by_type("IfcBeam")[0]
|
element = file.by_type("IfcBeam")[0]
|
||||||
aggregate = ifcopenshell.util.element.get_nest(element)
|
aggregate = ifcopenshell.util.element.get_nest(element)
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "Nests"):
|
if (nests := getattr(element, "Nests", None)) is not None:
|
||||||
if element.Nests:
|
if nests:
|
||||||
return element.Nests[0].RelatingObject
|
return nests[0].RelatingObject
|
||||||
elif hasattr(element, "Decomposes") and element.Decomposes: # IFC2X3
|
elif (decomposes := getattr(element, "Decomposes", None)) is not None and decomposes: # IFC2X3
|
||||||
if element.Decomposes[0].is_a("IfcRelNests"):
|
if decomposes[0].is_a("IfcRelNests"):
|
||||||
return element.Decomposes[0].RelatingObject
|
return decomposes[0].RelatingObject
|
||||||
|
|
||||||
|
|
||||||
def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||||
@@ -936,9 +948,9 @@ def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity
|
|||||||
element = file.by_type("IfcElementAssembly")[0]
|
element = file.by_type("IfcElementAssembly")[0]
|
||||||
parts = ifcopenshell.util.element.get_parts(element)
|
parts = ifcopenshell.util.element.get_parts(element)
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy:
|
if (is_decomposed_by := getattr(element, "IsDecomposedBy", None)) is not None and is_decomposed_by:
|
||||||
if element.IsDecomposedBy[0].is_a("IfcRelAggregates"):
|
if is_decomposed_by[0].is_a("IfcRelAggregates"):
|
||||||
return element.IsDecomposedBy[0].RelatedObjects
|
return is_decomposed_by[0].RelatedObjects
|
||||||
|
|
||||||
|
|
||||||
def get_components(element: ifcopenshell.entity_instance, include_ports=False) -> list[ifcopenshell.entity_instance]:
|
def get_components(element: ifcopenshell.entity_instance, include_ports=False) -> list[ifcopenshell.entity_instance]:
|
||||||
@@ -960,14 +972,14 @@ def get_components(element: ifcopenshell.entity_instance, include_ports=False) -
|
|||||||
element = file.by_type("IfcElementAssembly")[0]
|
element = file.by_type("IfcElementAssembly")[0]
|
||||||
components = ifcopenshell.util.element.get_components(element)
|
components = ifcopenshell.util.element.get_components(element)
|
||||||
"""
|
"""
|
||||||
if hasattr(element, "IsNestedBy"):
|
if (is_nested_by := getattr(element, "IsNestedBy", None)) is not None:
|
||||||
if element.IsNestedBy:
|
if is_nested_by:
|
||||||
if include_ports:
|
if include_ports:
|
||||||
return element.IsNestedBy[0].RelatedObjects
|
return is_nested_by[0].RelatedObjects
|
||||||
return [e for e in element.IsNestedBy[0].RelatedObjects if not e.is_a("IfcPort")]
|
return [e for e in is_nested_by[0].RelatedObjects if not e.is_a("IfcPort")]
|
||||||
elif hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy:
|
elif (is_decomposed_by := getattr(element, "IsDecomposedBy", None)) is not None and is_decomposed_by:
|
||||||
if element.IsDecomposedBy[0].is_a("IfcRelNests"):
|
if is_decomposed_by[0].is_a("IfcRelNests"):
|
||||||
return element.IsDecomposedBy[0].RelatedObjects
|
return is_decomposed_by[0].RelatedObjects
|
||||||
|
|
||||||
|
|
||||||
def replace_attribute(element: ifcopenshell.entity_instance, old: Any, new: Any) -> None:
|
def replace_attribute(element: ifcopenshell.entity_instance, old: Any, new: Any) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user