mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
See #3334. Optimise pset getting and add simple "broadphase" filtering for all facets for faster validation.
This commit is contained in:
@@ -77,7 +77,9 @@ def get_pset(element, name, prop=None, should_inherit=True):
|
||||
|
||||
if not prop:
|
||||
if type_pset:
|
||||
type_pset.update(get_property_definition(pset))
|
||||
occurrence_pset = get_property_definition(pset)
|
||||
if occurrence_pset:
|
||||
type_pset.update(occurrence_pset)
|
||||
return type_pset
|
||||
return get_property_definition(pset)
|
||||
|
||||
@@ -128,9 +130,10 @@ def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True):
|
||||
continue
|
||||
psets[definition.Name] = get_property_definition(definition)
|
||||
elif hasattr(element, "IsDefinedBy"):
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
if element_type and should_inherit:
|
||||
psets = get_psets(element_type, psets_only=psets_only, qtos_only=qtos_only, should_inherit=False)
|
||||
if should_inherit:
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
if element_type:
|
||||
psets = get_psets(element_type, psets_only=psets_only, qtos_only=qtos_only, should_inherit=False)
|
||||
for relationship in element.IsDefinedBy:
|
||||
if relationship.is_a("IfcRelDefinesByProperties"):
|
||||
definition = relationship.RelatingPropertyDefinition
|
||||
|
||||
@@ -131,6 +131,9 @@ class Entity(Facet):
|
||||
super().__init__(name, predefinedType, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
|
||||
if isinstance(self.name, str):
|
||||
try:
|
||||
results = ifc_file.by_type(self.name, include_subtypes=False)
|
||||
@@ -180,6 +183,21 @@ class Attribute(Facet):
|
||||
]
|
||||
super().__init__(name, value, minOccurs, maxOccurs, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
|
||||
results = []
|
||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||
for entity in schema.entities():
|
||||
for attribute in entity.attributes():
|
||||
if attribute.name() == self.name:
|
||||
results.extend(ifc_file.by_type(entity.name(), include_subtypes=False))
|
||||
|
||||
# TODO: perhaps we should consider value in the filter
|
||||
|
||||
return results
|
||||
|
||||
def __call__(self, inst, logger=None):
|
||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
||||
return AttributeResult(True)
|
||||
@@ -285,7 +303,9 @@ class Classification(Facet):
|
||||
super().__init__(value, system, uri, minOccurs, maxOccurs, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
pass
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
return ifc_file.by_type("IfcObjectDefinition")
|
||||
|
||||
def __call__(self, inst, logger=None):
|
||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
||||
@@ -341,6 +361,11 @@ class PartOf(Facet):
|
||||
]
|
||||
super().__init__(entity, predefinedType, relation, minOccurs, maxOccurs, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
return list(ifc_file) # Lazy
|
||||
|
||||
def asdict(self):
|
||||
results = super().asdict()
|
||||
entity = {}
|
||||
@@ -479,16 +504,26 @@ class Property(Facet):
|
||||
]
|
||||
super().__init__(propertySet, name, value, measure, uri, minOccurs, maxOccurs, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
if ifc_file.schema == "IFC2X3":
|
||||
return ifc_file.by_type("IfcObjectDefinition")
|
||||
return (
|
||||
ifc_file.by_type("IfcObjectDefinition")
|
||||
+ ifc_file.by_type("IfcMaterialDefinition")
|
||||
+ ifc_file.by_type("IfcProfileDef")
|
||||
)
|
||||
|
||||
def __call__(self, inst, logger=None):
|
||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
||||
return PropertyResult(True)
|
||||
|
||||
all_psets = ifcopenshell.util.element.get_psets(inst)
|
||||
|
||||
if isinstance(self.propertySet, str):
|
||||
pset = all_psets.get(self.propertySet, None)
|
||||
pset = ifcopenshell.util.element.get_pset(inst, self.propertySet)
|
||||
psets = {self.propertySet: pset} if pset else {}
|
||||
else:
|
||||
all_psets = ifcopenshell.util.element.get_psets(inst)
|
||||
psets = {k: v for k, v in all_psets.items() if k == self.propertySet}
|
||||
|
||||
is_pass = bool(psets)
|
||||
@@ -730,6 +765,11 @@ class Material(Facet):
|
||||
]
|
||||
super().__init__(value, uri, minOccurs, maxOccurs, instructions)
|
||||
|
||||
def filter(self, ifc_file, elements):
|
||||
if isinstance(elements, list):
|
||||
return super().filter(ifc_file, elements)
|
||||
return ifc_file.by_type("IfcObjectDefinition")
|
||||
|
||||
def __call__(self, inst, logger=None):
|
||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
||||
return MaterialResult(True)
|
||||
|
||||
@@ -200,18 +200,14 @@ class Specification:
|
||||
if filter_version and ifc_file.schema not in self.ifcVersion:
|
||||
return
|
||||
|
||||
elements = []
|
||||
elements = None
|
||||
|
||||
# This is a broadphase filter of applicability. We almost never want to
|
||||
# test every single class in an IFC model.
|
||||
for i, facet in enumerate(self.applicability):
|
||||
# Usually, we rely on an entity applicability to give us our first
|
||||
# shortlist of elements, as it's the most efficient way to filter
|
||||
# elements. If this does not exist, then we have no choice but to
|
||||
# check everything.
|
||||
if i == 0 and not isinstance(facet, Entity):
|
||||
elements = list(ifc_file)
|
||||
elements = facet.filter(ifc_file, elements)
|
||||
|
||||
for element in elements:
|
||||
for element in elements or []:
|
||||
is_applicable = True
|
||||
for facet in self.applicability:
|
||||
if isinstance(facet, Entity):
|
||||
|
||||
Reference in New Issue
Block a user