Compare commits

...

7 Commits

+25 -12
View File
@@ -92,24 +92,38 @@ def quantify(ifc_file: ifcopenshell.file, elements: set[ifcopenshell.entity_inst
for calculator, queries in rules["calculators"].items():
calculator = calculators[calculator]
if not set(m.lower() for m in queries.keys()) - lower_case_entity_names(ifc_file.schema_identifier):
# all defined queries are actually simple entity names: instead of looping over all
# calculators we loop over the entity types so that we don't have to repeatedly query
# the model, especially when the set of elements is small.
# Cache schema entity names once per file
schema_entity_names = lower_case_entity_names(ifc_file.schema_identifier)
# Fast path: all queries are simple entity names
if not set(m.lower() for m in queries.keys()) - schema_entity_names:
casenorm = {k.lower(): k for k in queries.keys()}
pred = lambda inst: inst.is_a().lower()
for ty, elements in itertools.groupby(sorted(elements, key=pred), key=pred):
for ty, group in itertools.groupby(sorted(elements, key=pred), key=pred):
group_elements = list(group)
# check entity type and its supertypes for matching QTO rules
for sty in entity_supertypes(ifc_file.schema_identifier, ty):
if qtos := queries.get(casenorm.get(sty)):
calculator.calculate(ifc_file, list(elements), qtos, results)
calculator.calculate(ifc_file, group_elements, qtos, results)
# Fallback: per-query evaluation
for query, qtos in queries.items():
if query.lower() in lower_case_entity_names(ifc_file.schema_identifier):
# by_type is faster than selector parsing
filtered_elements = ifc_file.by_type(query)
# Simple entity name: use by_type but restrict to incoming elements
if query.lower() in schema_entity_names:
by_type_all = ifc_file.by_type(query)
# ensure we don't expand beyond provided elements subset
if isinstance(elements, set):
filtered_elements = [e for e in by_type_all if e in elements]
else:
elements_set = set(elements)
filtered_elements = [e for e in by_type_all if e in elements_set]
else:
filtered_elements = ifcopenshell.util.selector.filter_elements(ifc_file, query, elements)
if filtered_elements:
calculator.calculate(ifc_file, filtered_elements, qtos, results)
return results
@@ -159,8 +173,7 @@ class IteratorForTypes:
element: Union[ifcopenshell.entity_instance, None] = None
shape: Union[ifcopenshell.geom.ShapeType, None] = None
def __init__(
self,
def __init__(self,
ifc_file: ifcopenshell.file,
settings: ifcopenshell.geom.settings,
elements: Iterable[ifcopenshell.entity_instance],
@@ -560,4 +573,4 @@ class Blender(QtoCalculator):
calculators: dict[str, type[QtoCalculator]] = {
"Blender": Blender,
"IfcOpenShell": IfcOpenShell,
}
}