Add IfcTester support and test cases for bounded, table, and reference props

This commit is contained in:
Dion Moult
2022-09-12 22:35:05 +10:00
parent c7c59d9496
commit 91fac6d4bd
4 changed files with 135 additions and 2 deletions
@@ -86,6 +86,11 @@ def get_quantities(quantities):
for quantity in quantities or []:
if quantity.is_a("IfcPhysicalSimpleQuantity"):
results[quantity.Name] = quantity[3]
elif quantity.is_a("IfcPhysicalComplexQuantity"):
data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_quantities(quantity.HasQuantities)
del data["HasQuantities"]
results[quantity.Name] = data
return results
@@ -98,6 +103,12 @@ def get_properties(properties):
results[prop.Name] = [v.wrappedValue for v in prop.EnumerationValues] or None
elif prop.is_a("IfcPropertyListValue"):
results[prop.Name] = [v.wrappedValue for v in prop.ListValues] or None
elif prop.is_a("IfcPropertyBoundedValue"):
data = prop.get_info()
del data["Unit"]
results[prop.Name] = data
elif prop.is_a("IfcPropertyTableValue"):
results[prop.Name] = prop.get_info()
elif prop.is_a("IfcComplexProperty"):
data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_properties(prop.HasProperties)
@@ -341,6 +341,29 @@ def get_property_unit(prop, ifc_file):
measure_class = prop.EnumerationValues[0].is_a()
elif prop.is_a("IfcPropertyListValue") and prop.ListValues:
measure_class = prop.ListValues[0].is_a()
elif prop.is_a("IfcPropertyBoundedValue"):
if prop.UpperBoundValue:
measure_class = prop.UpperBoundValue.is_a()
elif prop.LowerBoundValue:
measure_class = prop.LowerBoundValue.is_a()
elif prop.SetPointValue:
measure_class = prop.SetPointValue.is_a()
elif prop.is_a("IfcPropertyTableValue"):
table_units = {}
for attribute in ["Defining", "Defined"]:
if getattr(prop, f"{attribute}Unit"):
table_units[f"{attribute}Unit"] = getattr(prop, f"{attribute}Unit")
elif getattr(prop, f"{attribute}Values"):
measure_class = getattr(prop, f"{attribute}Values")[0].is_a()
unit_type = get_measure_unit_type(measure_class)
units = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == unit_type]
if units:
table_units[f"{attribute}Unit"] = units[0]
else:
table_units[f"{attribute}Unit"] = None
else:
table_units[f"{attribute}Unit"] = None
return table_units
unit_type = get_measure_unit_type(measure_class)
units = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == unit_type]
if units:
+64 -2
View File
@@ -517,7 +517,68 @@ class Property(Facet):
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(v, getattr(unit, "Prefix", None), unit.Name, None, ifcopenshell.util.unit.si_type_names[unit.UnitType]) for v in props[pset_name][prop_entity.Name]]
props[pset_name][prop_entity.Name] = [
ifcopenshell.util.unit.convert(
v,
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
for v in props[pset_name][prop_entity.Name]
]
elif prop_entity.is_a("IfcPropertyBoundedValue"):
values = []
for attribute in ["UpperBoundValue", "LowerBoundValue", "SetPointValue"]:
value = getattr(prop_entity, attribute)
if value is not None:
data_type = value.is_a()
values.append(value.wrappedValue)
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:
values = [
ifcopenshell.util.unit.convert(
v,
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
for v in values
]
props[pset_name][prop_entity.Name] = values
elif prop_entity.is_a("IfcPropertyTableValue"):
values = []
units = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
for attribute in ["Defining", "Defined"]:
column_values = props[pset_name][prop_entity.Name][f"{attribute}Values"]
if not column_values:
continue
data_type = column_values[0].is_a()
if data_type == self.measure:
column_values = [v.wrappedValue for v in column_values]
unit = units[f"{attribute}Unit"]
if unit:
column_values = [
ifcopenshell.util.unit.convert(
v,
getattr(unit, "Prefix", None),
unit.Name,
None,
ifcopenshell.util.unit.si_type_names[unit.UnitType],
)
for v in column_values
]
values.extend(column_values)
if not values:
is_pass = False
reason = {"type": "MEASURE", "actual": data_type}
break
props[pset_name][prop_entity.Name] = values
else:
is_property_supported_class = False
@@ -538,7 +599,8 @@ class Property(Facet):
break
elif isinstance(self.value, str) and isinstance(value, list):
# "i_require_foo" = ["a", "b"] such as in enumerated properties
if self.value not in value:
cast_value = cast_to_value(self.value, value[0])
if cast_value not in value:
is_pass = False
reason = {"type": "VALUE", "actual": value}
break
+37
View File
@@ -1039,6 +1039,43 @@ class TestProperty:
facet = Property(propertySet="Foo_Bar", name="Foo", value="Z", measure="IfcLabel")
run("Any matching value in a list property will pass 3/3", facet=facet, inst=element, expected=False)
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
bounded_property = ifc.createIfcPropertyBoundedValue(
Name="Foo",
UpperBoundValue=ifc.createIfcLengthMeasure(5000),
LowerBoundValue=ifc.createIfcLengthMeasure(1000),
SetPointValue=ifc.createIfcLengthMeasure(3000),
)
pset.HasProperties = [bounded_property]
facet = Property(propertySet="Foo_Bar", name="Foo", value="1", measure="IfcLengthMeasure")
run("Any matching value in a bounded property will pass 1/4", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", value="5", measure="IfcLengthMeasure")
run("Any matching value in a bounded property will pass 2/4", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", value="3", measure="IfcLengthMeasure")
run("Any matching value in a bounded property will pass 3/4", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", value="2", measure="IfcLengthMeasure")
run("Any matching value in a bounded property will pass 4/4", facet=facet, inst=element, expected=False)
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
table_property = ifc.createIfcPropertyTableValue(
Name="Foo", DefiningValues=[ifc.createIfcLabel("X")], DefinedValues=[ifc.createIfcLengthMeasure(1000)]
)
pset.HasProperties = [table_property]
facet = Property(propertySet="Foo_Bar", name="Foo", value="X", measure="IfcLabel")
run("Any matching value in a table property will pass 1/3", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", value="1", measure="IfcLengthMeasure")
run("Any matching value in a table property will pass 2/3", facet=facet, inst=element, expected=True)
facet = Property(propertySet="Foo_Bar", name="Foo", value="Y", measure="IfcLabel")
run("Any matching value in a table property will pass 3/3", facet=facet, inst=element, expected=False)
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
pset.HasProperties = [ifc.createIfcPropertyReferenceValue(Name="Foo")]
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLabel")
run("Reference properties are treated as objects and not supported", 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")