IfcTester now supports new entityType data in partof facet

This commit is contained in:
Dion Moult
2022-10-07 13:11:52 +11:00
parent 61f4c48a4a
commit 1677a6c83f
3 changed files with 77 additions and 12 deletions
+42 -5
View File
@@ -302,8 +302,8 @@ class Classification(Facet):
class PartOf(Facet):
def __init__(self, entity=None, relation="IfcRelAggregates", minOccurs=None, maxOccurs=None, instructions=None):
self.parameters = ["entity", "@relation", "@minOccurs", "@maxOccurs", "@instructions"]
def __init__(self, entity=None, predefinedType=None, relation="IfcRelAggregates", minOccurs=None, maxOccurs=None, instructions=None):
self.parameters = ["entity", "predefinedType", "@relation", "@minOccurs", "@maxOccurs", "@instructions"]
self.applicability_templates = [
"An element with an {relation} relationship with an {entity}",
"An element with an {relation} relationship",
@@ -312,7 +312,26 @@ class PartOf(Facet):
"An element must have an {relation} relationship with an {entity}",
"An element must have an {relation} relationship",
]
super().__init__(entity, relation, minOccurs, maxOccurs, instructions)
super().__init__(entity, predefinedType, relation, minOccurs, maxOccurs, instructions)
def asdict(self):
results = super().asdict()
entity = {}
if "entity" in results:
entity["name"] = results["entity"]
del results["entity"]
if "predefinedType" in results:
entity["predefinedType"] = results["predefinedType"]
del results["predefinedType"]
if entity:
results["entity"] = entity
return results
def parse(self, xml):
if "entity" in xml:
super().parse(xml["entity"])
del xml["entity"]
super().parse(xml)
def __call__(self, inst, logger=None):
if self.minOccurs == 0 and self.maxOccurs != 0:
@@ -330,7 +349,11 @@ class PartOf(Facet):
while aggregate is not None:
ancestors.append(aggregate.is_a())
if aggregate.is_a().upper() == self.entity:
is_pass = True
if self.predefinedType:
if ifcopenshell.util.element.get_predefined_type(aggregate) == self.predefinedType:
is_pass = True
else:
is_pass = True
break
aggregate = ifcopenshell.util.element.get_aggregate(aggregate)
if not is_pass:
@@ -348,6 +371,11 @@ class PartOf(Facet):
if group.is_a().upper() != self.entity:
is_pass = False
reason = {"type": "ENTITY", "actual": group.is_a().upper()}
if self.predefinedType:
predefined_type = ifcopenshell.util.element.get_predefined_type(group)
if predefined_type != self.predefinedType:
is_pass = False
reason = {"type": "PREDEFINEDTYPE", "actual": predefined_type}
elif self.relation == "IfcRelContainedInSpatialStructure":
container = ifcopenshell.util.element.get_container(inst)
is_pass = container is not None
@@ -357,6 +385,11 @@ class PartOf(Facet):
if container.is_a().upper() != self.entity:
is_pass = False
reason = {"type": "ENTITY", "actual": container.is_a().upper()}
if self.predefinedType:
predefined_type = ifcopenshell.util.element.get_predefined_type(container)
if predefined_type != self.predefinedType:
is_pass = False
reason = {"type": "PREDEFINEDTYPE", "actual": predefined_type}
elif self.relation == "IfcRelNests":
nest = self.get_nested_whole(inst)
is_pass = nest is not None
@@ -368,7 +401,11 @@ class PartOf(Facet):
while nest is not None:
ancestors.append(nest.is_a())
if nest.is_a().upper() == self.entity:
is_pass = True
if self.predefinedType:
if ifcopenshell.util.element.get_predefined_type(nest) == self.predefinedType:
is_pass = True
else:
is_pass = True
break
nest = self.get_nested_whole(nest)
if not is_pass:
+6 -6
View File
@@ -1,6 +1,6 @@
<!-- edited with XMLSpy v2022 (x64) (http://www.altova.com) by Leon van Berlo (Overleaf Investments B.V.) -->
<!-- August 2, 2022 - DRAFT -->
<xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.9.0">
<!-- edited with XMLSpy v2022 (x64) (http://www.altova.com) -->
<!-- September 26, 2022 - DRAFT -->
<xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.9.3">
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="https://www.w3.org/2001/XMLSchema.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/>
@@ -58,7 +58,7 @@
</xs:complexType>
<xs:complexType name="partOfType">
<xs:sequence>
<xs:element name="entity" type="ids:idsValue" minOccurs="0"/>
<xs:element name="entity" type="ids:entityType" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="relation" type="ids:relations" use="required"/>
</xs:complexType>
@@ -198,7 +198,7 @@
<xs:complexType name="specificationType">
<xs:sequence>
<xs:element name="applicability" type="ids:applicabilityType"/>
<xs:element name="requirements">
<xs:element name="requirements" minOccurs="0">
<xs:complexType>
<xs:complexContent>
<xs:extension base="ids:requirementsType">
@@ -248,4 +248,4 @@
<xs:enumeration value="IfcRelNests"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
</xs:schema>
+29 -1
View File
@@ -1404,13 +1404,17 @@ class TestPartOf:
assert facet.asdict() == {"@relation": "IfcRelAggregates"}
facet = PartOf(
entity="IfcGroup",
predefinedType="predefinedType",
relation="IfcRelAssignsToGroup",
minOccurs="0",
maxOccurs="unbounded",
instructions="instructions",
)
assert facet.asdict() == {
"entity": {"simpleValue": "IfcGroup"},
"entity": {
"name": {"simpleValue": "IfcGroup"},
"predefinedType": {"simpleValue": "predefinedType"},
},
"@relation": "IfcRelAssignsToGroup",
"@minOccurs": "0",
"@maxOccurs": "unbounded",
@@ -1446,6 +1450,12 @@ class TestPartOf:
facet = PartOf(entity="IFCWALL", relation="IfcRelAggregates")
run("An aggregate may specify the entity of the whole 2/2", facet=facet, inst=subelement, expected=False)
element.PredefinedType = "BASESLAB"
facet = PartOf(entity="IFCSLAB", predefinedType="BASESLAB", relation="IfcRelAggregates")
run("An aggregate may specify the predefined type of the whole 1/2", facet=facet, inst=subelement, expected=True)
facet = PartOf(entity="IFCSLAB", predefinedType="SLABRADOR", relation="IfcRelAggregates")
run("An aggregate may specify the predefined type of the whole 2/2", facet=facet, inst=subelement, expected=False)
ifc = ifcopenshell.file()
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
@@ -1472,6 +1482,12 @@ class TestPartOf:
facet = PartOf(entity="IFCINVENTORY", relation="IfcRelAssignsToGroup")
run("A group entity must match exactly 2/2", facet=facet, inst=element, expected=True)
group.ObjectType = "BUNNY"
facet = PartOf(entity="IFCINVENTORY", predefinedType="BUNNARY", relation="IfcRelAssignsToGroup")
run("A group predefined type must match exactly 2/2", facet=facet, inst=element, expected=False)
facet = PartOf(entity="IFCINVENTORY", predefinedType="BUNNY", relation="IfcRelAssignsToGroup")
run("A group predefined type must match exactly 2/2", facet=facet, inst=element, expected=True)
ifc = ifcopenshell.file()
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
container = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSpace")
@@ -1490,6 +1506,12 @@ class TestPartOf:
facet = PartOf(relation="IfcRelContainedInSpatialStructure", entity="IFCSPACE")
run("The container entity must match exactly 2/2", facet=facet, inst=element, expected=True)
container.ObjectType = "BURROW"
facet = PartOf(relation="IfcRelContainedInSpatialStructure", entity="IFCSPACE", predefinedType="WARREN")
run("The container predefined type must match exactly 1/2", facet=facet, inst=element, expected=False)
facet = PartOf(relation="IfcRelContainedInSpatialStructure", entity="IFCSPACE", predefinedType="BURROW")
run("The container predefined type must match exactly 2/2", facet=facet, inst=element, expected=True)
ifc = ifcopenshell.file()
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBeam")
@@ -1516,6 +1538,12 @@ class TestPartOf:
facet = PartOf(relation="IfcRelNests", entity="IFCFURNITURE")
run("The nest entity must match exactly 2/2", facet=facet, inst=subelement, expected=True)
element.ObjectType = "WATERBOTTLE"
facet = PartOf(relation="IfcRelNests", entity="IFCFURNITURE", predefinedType="LITTERBOX")
run("The nest predefined type must match exactly 1/2", facet=facet, inst=subelement, expected=False)
facet = PartOf(relation="IfcRelNests", entity="IFCFURNITURE", predefinedType="WATERBOTTLE")
run("The nest predefined type must match exactly 2/2", facet=facet, inst=subelement, expected=True)
ifc = ifcopenshell.file()
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcFurniture")
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcDiscreteAccessory")