feat(ifc5d): include quantity Formula in serialised Quantities

IfcQuantity* carries an optional Formula (IfcLabel) documenting how a
quantity was derived. Export it alongside each quantity so it survives
in the Quantities column.

The per-quantity entry shape grows from [name, value] to
[name, value, formula], which stays backward compatible for positional
consumers reading index 0/1. Formula is read with a schema-safe getattr
(it does not exist on IfcPhysicalComplexQuantity, nor in IFC2X3) and is
coalesced to "" when absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
carlopav
2026-06-16 08:35:13 +02:00
committed by Massimo Fabbro
parent 0b0e34f18d
commit 4d3bff4e3a
2 changed files with 26 additions and 4 deletions
+5 -2
View File
@@ -269,15 +269,18 @@ class IfcDataGetter:
if obj.is_a("IfcElement"):
prefix += (obj.Name or "") + " - "
name = prefix + (quantity.Name or "")
# Formula is an optional IfcLabel on IfcQuantity* in IFC4+; absent in
# IFC2X3, hence the schema-safe getattr.
formula = getattr(quantity, "Formula", None) or ""
if quantity.is_a("IfcPhysicalSimpleQuantity"):
value = quantity[3]
try:
value = float(value) if value is not None else 0.0
except (TypeError, ValueError):
value = 0.0
result.append([name, value])
result.append([name, value, formula])
else:
result.append([name + " ERROR: Only IfcPhysicalSimpleQuantity is supported", 0.0])
result.append([name + " ERROR: Only IfcPhysicalSimpleQuantity is supported", 0.0, formula])
return json.dumps(result, ensure_ascii=False)
+21 -2
View File
@@ -130,7 +130,7 @@ class TestSerialiseCostQuantities:
result = ifc5d.ifc5Dspreadsheet.IfcDataGetter.serialise_cost_quantities(ifc_file, cost_item)
assert json.loads(result) == [[name, 12.5]]
assert json.loads(result) == [[name, 12.5, ""]]
def test_unset_name_does_not_crash(self):
ifc_file = ifcopenshell.file()
@@ -140,4 +140,23 @@ class TestSerialiseCostQuantities:
result = ifc5d.ifc5Dspreadsheet.IfcDataGetter.serialise_cost_quantities(ifc_file, cost_item)
assert json.loads(result) == [["", 3.0]]
assert json.loads(result) == [["", 3.0, ""]]
def test_formula_is_included_when_present(self):
ifc_file = ifcopenshell.file()
quantity = ifc_file.create_entity("IfcQuantityArea", Name="Area", AreaValue=12.5, Formula="Length * Width")
cost_item = ifc_file.create_entity("IfcCostItem", CostQuantities=[quantity])
result = ifc5d.ifc5Dspreadsheet.IfcDataGetter.serialise_cost_quantities(ifc_file, cost_item)
assert json.loads(result) == [["Area", 12.5, "Length * Width"]]
def test_quantity_without_formula_attribute_does_not_crash(self):
# IfcPhysicalComplexQuantity has no Formula attribute and is unsupported.
ifc_file = ifcopenshell.file()
quantity = ifc_file.create_entity("IfcPhysicalComplexQuantity", Name="Complex", Discrimination="layer")
cost_item = ifc_file.create_entity("IfcCostItem", CostQuantities=[quantity])
result = ifc5d.ifc5Dspreadsheet.IfcDataGetter.serialise_cost_quantities(ifc_file, cost_item)
assert json.loads(result) == [["Complex ERROR: Only IfcPhysicalSimpleQuantity is supported", 0.0, ""]]