IfcTester Add support for qto checks

This commit is contained in:
Dion Moult
2022-09-12 18:26:11 +10:00
parent 5ee4e2704d
commit cb447fe902
2 changed files with 65 additions and 22 deletions
+51 -22
View File
@@ -443,7 +443,9 @@ class Property(Facet):
if isinstance(self.name, str):
prop = pset_props.get(self.name)
if prop == "UNKNOWN" and [
p for p in inst.wrapped_data.file.by_id(pset_props["id"]).HasProperties if p.Name == self.name
p
for p in self.get_properties(inst.wrapped_data.file.by_id(pset_props["id"]))
if p.Name == self.name
][0].NominalValue.is_a("IfcLogical"):
pass
elif prop is not None and prop != "":
@@ -457,30 +459,49 @@ class Property(Facet):
break
pset_entity = inst.wrapped_data.file.by_id(pset_props["id"])
for prop_entity in pset_entity.HasProperties:
if (
prop_entity.Name not in props[pset_name].keys()
or not prop_entity.is_a("IfcPropertySingleValue")
or prop_entity.NominalValue is None
):
continue
data_type = prop_entity.NominalValue.is_a()
for prop_entity in self.get_properties(pset_entity):
if prop_entity.is_a("IfcPropertySingleValue"):
if prop_entity.Name not in props[pset_name].keys() or prop_entity.NominalValue is None:
continue
if data_type != self.measure:
is_pass = False
reason = {"type": "MEASURE", "actual": data_type}
break
data_type = prop_entity.NominalValue.is_a()
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
if unit:
props[pset_name][prop_entity.Name] = ifcopenshell.util.unit.convert(
prop_entity.NominalValue.wrappedValue,
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
if data_type != self.measure:
is_pass = False
reason = {"type": "MEASURE", "actual": data_type}
break
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
if unit:
props[pset_name][prop_entity.Name] = ifcopenshell.util.unit.convert(
prop_entity.NominalValue.wrappedValue,
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
elif prop_entity.is_a("IfcPhysicalSimpleQuantity"):
if prop_entity.Name not in props[pset_name].keys():
continue
prop_schema = prop_entity.wrapped_data.declaration().as_entity()
data_type = prop_schema.attribute_by_index(3).type_of_attribute().declared_type().name()
if data_type != self.measure:
is_pass = False
reason = {"type": "MEASURE", "actual": data_type}
break
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
if unit:
props[pset_name][prop_entity.Name] = ifcopenshell.util.unit.convert(
prop_entity[3],
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
if not is_pass:
break
@@ -512,6 +533,14 @@ class Property(Facet):
return PropertyResult(not is_pass, {"type": "PROHIBITED"})
return PropertyResult(is_pass, reason)
def get_properties(self, pset):
if pset.is_a("IfcPropertySet"):
return pset.HasProperties
elif pset.is_a("IfcElementQuantity"):
return pset.Quantities
elif pset.is_a("IfcMaterialProperties") or pset.is_a("IfcProfileProperties"):
return pset.Properties
class Material(Facet):
def __init__(self, value=None, uri=None, minOccurs=None, maxOccurs=None, instructions=None):
+14
View File
@@ -881,6 +881,10 @@ class TestProperty:
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
run("A name check will match any property with any string value", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLabel")
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLabel", minOccurs=0, maxOccurs=0)
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
@@ -1005,6 +1009,14 @@ class TestProperty:
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("P2D")})
run("Durations are treated as strings 1/2", facet=facet, inst=element, expected=False)
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLengthMeasure")
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
qto = ifcopenshell.api.run("pset.add_qto", ifc, product=element, name="Foo_Bar")
ifcopenshell.api.run("pset.edit_qto", ifc, qto=qto, properties={"Foo": ifc.createIfcLengthMeasure(42)})
run("A name check will match any quantity with any value", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcAreaMeasure")
run("Quantities must also match the appropriate measure", facet=facet, inst=element, expected=False)
restriction = Restriction(options="Foo_.*", type="pattern")
facet = Property(propertySet=restriction, name="Foo", measure="IfcLabel")
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
@@ -1288,7 +1300,9 @@ class TestPartOf:
run("The aggregated part passes an aggregate relationship", facet=facet, inst=subelement, expected=True)
run("A required facet checks all parameters as normal", facet=facet, inst=subelement, expected=True)
facet = PartOf(relation="IfcRelAggregates", minOccurs=0, maxOccurs=0)
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=subelement, expected=False)
facet = PartOf(relation="IfcRelAggregates", minOccurs=0)
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=subelement, expected=True)