ifc5d - add ifc4x3 base quantities #6325

This commit is contained in:
Andrej730
2025-03-13 17:17:37 +05:00
parent 4eae112087
commit 6c04669543
7 changed files with 771 additions and 209 deletions
@@ -24,7 +24,7 @@ import ifcopenshell.util.schema
import ifcopenshell.util.type
from ifcopenshell.entity_instance import entity_instance
from functools import lru_cache
from typing import Optional, Literal
from typing import Optional, Literal, NamedTuple, Union
templates: dict[str, "PsetQto"] = {}
@@ -111,11 +111,17 @@ class PsetQto:
template_type: str = "NOTDEFINED",
schema: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4",
) -> bool:
"""applicables can have multiple possible patterns :
IfcBoilerType (IfcClass)
IfcBoilerType/STEAM (IfcClass/PREDEFINEDTYPE)
IfcBoilerType[PerformanceHistory] (IfcClass[PerformanceHistory])
IfcBoilerType/STEAM[PerformanceHistory] (IfcClass/PREDEFINEDTYPE[PerformanceHistory])
"""
applicables can have multiple possible patterns :
.. code-block:: text
IfcBoilerType (IfcClass)
IfcBoilerType/STEAM (IfcClass/PREDEFINEDTYPE)
IfcBoilerType[PerformanceHistory] (IfcClass[PerformanceHistory])
IfcBoilerType/STEAM[PerformanceHistory] (IfcClass/PREDEFINEDTYPE[PerformanceHistory])
"""
for applicable in applicables.split(","):
match = re.match(r"(\w+)(\[\w+\])*/*(\w+)*(\[\w+\])*", applicable)
@@ -194,3 +200,37 @@ def get_pset_template_type(pset_template: entity_instance) -> Literal["PSET", "Q
pset_type = next(iter(pset_types)) if len(pset_types) == 1 else None
return pset_type
class ApplicableEntity(NamedTuple):
value: str
ifc_class: str
predefined_type: Union[str, None]
performance_history: bool
def parse_applicable_entity(applicable_entity: str) -> list[ApplicableEntity]:
"""Parse ApplicableEntity string query to tuples.
:param applicable_entity: IfcPropertySetTemplate.ApplicableEntity query.
:return: List of ApplicableEntity tuples.
"""
items: list[ApplicableEntity] = []
for item in applicable_entity.split(","):
value = item
item, predefined_type = parts if len(parts := item.split("/")) > 1 else (item, None)
ifc_class, performance_history = (parts[0], True) if len(parts := item.split("[")) > 1 else (item, False)
items.append(ApplicableEntity(value, ifc_class, predefined_type, performance_history))
return items
def convert_applicable_entities_to_query(applicable_entities: list[ApplicableEntity]) -> str:
"""Get query supported by :func:`ifcopenshell.util.selector.filter_elements`."""
parts: list[str] = []
for entity in applicable_entities:
# NOTE: selector currently doesn't support checking if element has performance history.
part = entity.ifc_class
if entity.predefined_type:
part += f', PredefinedType="{entity.predefined_type}"'
parts.append(part)
return " + ".join(parts)
@@ -19,6 +19,7 @@
"""Run this test from src/ifcopenshell-python folder: pytest --durations=0 ifcopenshell/util/test_pset.py"""
from ifcopenshell.util import pset
from ifcopenshell import util
from ifcopenshell.util.pset import ApplicableEntity
class TestPsetQto:
@@ -66,3 +67,72 @@ class TestPsetQto:
assert "Pset_MaterialConcrete" not in names
names = self.pset_qto.get_applicable_names("IfcMaterial", "concrete")
assert "Pset_MaterialConcrete" in names
class TestParseApplicableEntity:
def test_run(self):
assert pset.parse_applicable_entity("IfcBoilerType") == [
ApplicableEntity("IfcBoilerType", "IfcBoilerType", None, False)
]
def test_two_entities(self):
assert pset.parse_applicable_entity("IfcBoilerType,IfcWallType") == [
ApplicableEntity("IfcBoilerType", "IfcBoilerType", None, False),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
def test_two_entities_with_performance_history(self):
assert pset.parse_applicable_entity("IfcBoilerType[PerformanceHistory],IfcWallType") == [
ApplicableEntity("IfcBoilerType[PerformanceHistory]", "IfcBoilerType", None, True),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
def test_two_entities_with_predefined_type(self):
assert pset.parse_applicable_entity("IfcBoilerType/STEAM,IfcWallType") == [
ApplicableEntity("IfcBoilerType/STEAM", "IfcBoilerType", "STEAM", False),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
def test_two_entities_with_predefined_type_and_performance_history(self):
assert pset.parse_applicable_entity("IfcBoilerType[PerformanceHistory]/STEAM,IfcWallType") == [
ApplicableEntity("IfcBoilerType[PerformanceHistory]/STEAM", "IfcBoilerType", "STEAM", True),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
class TestConvertApplicableEntitiesToQuery:
def test_run(self):
entities = [ApplicableEntity("IfcBoilerType", "IfcBoilerType", None, False)]
assert pset.convert_applicable_entities_to_query(entities) == "IfcBoilerType"
def test_two_entities(self):
entities = [
ApplicableEntity("IfcBoilerType", "IfcBoilerType", None, False),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
assert pset.convert_applicable_entities_to_query(entities) == "IfcBoilerType + IfcWallType"
def test_two_entities_with_performance_history(self):
entities = [
ApplicableEntity("IfcBoilerType[PerformanceHistory]", "IfcBoilerType", None, True),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
assert pset.convert_applicable_entities_to_query(entities) == "IfcBoilerType + IfcWallType"
def test_two_entities_with_predefined_type(self):
entities = [
ApplicableEntity("IfcBoilerType/STEAM", "IfcBoilerType", "STEAM", False),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
assert (
pset.convert_applicable_entities_to_query(entities) == 'IfcBoilerType, PredefinedType="STEAM" + IfcWallType'
)
def test_two_entities_with_predefined_type_and_performance_history(self):
entities = [
ApplicableEntity("IfcBoilerType[PerformanceHistory]/STEAM", "IfcBoilerType", "STEAM", True),
ApplicableEntity("IfcWallType", "IfcWallType", None, False),
]
assert (
pset.convert_applicable_entities_to_query(entities) == 'IfcBoilerType, PredefinedType="STEAM" + IfcWallType'
)