diff --git a/src/blenderbim/blenderbim/bim/module/resource/prop.py b/src/blenderbim/blenderbim/bim/module/resource/prop.py index 8f5f3df6b2..08a6a480ce 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/prop.py +++ b/src/blenderbim/blenderbim/bim/module/resource/prop.py @@ -41,20 +41,7 @@ quantitytypes_enum = {} def setup_quantity_types_enum(): - # https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcConstructionResource.htm#Table-7.3.3.7.1.3.H - resources = { - "IfcCrewResource": ("IfcQuantityTime",), - "IfcLaborResource": ("IfcQuantityTime",), - "IfcSubContractResource": ("IfcQuantityTime",), - "IfcConstructionEquipmentResource": ("IfcQuantityTime",), - "IfcConstructionMaterialResource": ( - "IfcQuantityVolume", - "IfcQuantityArea", - "IfcQuantityLength", - "IfcQuantityWeight", - ), - "IfcConstructionProductResource": ("IfcQuantityCount",), - } + resources = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES for resource, quantities in resources.items(): quantitytypes_enum[resource] = [(q, q, "") for q in quantities] diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource_quantity.py index 8d3d6de9e9..72eb582af6 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource_quantity.py @@ -17,6 +17,7 @@ # along with IfcOpenShell. If not, see . import ifcopenshell.util.element +import ifcopenshell.util.resource def add_resource_quantity( @@ -66,6 +67,14 @@ def add_resource_quantity( """ settings = {"resource": resource, "ifc_class": ifc_class} + resource_type = resource.is_a() + supported_quantities = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES[resource_type] + if ifc_class not in supported_quantities: + raise ValueError( + f"Resource type '{resource_type}' does not support quantity type '{ifc_class}'. " + f"Supported quantities: {','.join(supported_quantities)}" + ) + quantity = file.create_entity(settings["ifc_class"], Name="Unnamed") # 3 IfcPhysicalSimpleQuantity Value if settings["ifc_class"] == "IfcQuantityCount": diff --git a/src/ifcopenshell-python/ifcopenshell/util/resource.py b/src/ifcopenshell-python/ifcopenshell/util/resource.py index bfc1aabed6..adce5bfa3f 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/resource.py +++ b/src/ifcopenshell-python/ifcopenshell/util/resource.py @@ -23,6 +23,20 @@ from typing import Union, Any PRODUCTIVITY_PSET_DATA = Union[dict[str, Any], None] +# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcConstructionResource.htm#Table-7.3.3.7.1.3.H +RESOURCES_TO_QUANTITIES: dict[str, tuple[str, ...]] = { + "IfcCrewResource": ("IfcQuantityTime",), + "IfcLaborResource": ("IfcQuantityTime",), + "IfcSubContractResource": ("IfcQuantityTime",), + "IfcConstructionEquipmentResource": ("IfcQuantityTime",), + "IfcConstructionMaterialResource": ( + "IfcQuantityVolume", + "IfcQuantityArea", + "IfcQuantityLength", + "IfcQuantityWeight", + ), + "IfcConstructionProductResource": ("IfcQuantityCount",), +} def get_productivity(resource: ifcopenshell.entity_instance, should_inherit: bool = True) -> PRODUCTIVITY_PSET_DATA: diff --git a/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py b/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py index bde9451d11..e843e5828b 100644 --- a/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py +++ b/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py @@ -16,27 +16,45 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import pytest import test.bootstrap import ifcopenshell.api +import ifcopenshell.api.resource +import ifcopenshell.util.resource class TestAddResourceQuantity(test.bootstrap.IFC4): def test_run(self): schema = ifcopenshell.schema_by_name(self.file.schema) quantity_types = [t.name() for t in schema.declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()] - self.file.create_entity("IfcProject") # add_resource - resource = ifcopenshell.api.run("resource.add_resource", self.file, ifc_class="IfcCrewResource") + resource_types = [t.name() for t in schema.declaration_by_name("IfcConstructionResource").subtypes()] - for quantity_type in quantity_types: - quantity = ifcopenshell.api.run( - "resource.add_resource_quantity", self.file, resource=resource, ifc_class=quantity_type - ) - assert quantity.is_a(quantity_type) - assert quantity.Name == "Unnamed" - assert quantity[3] == 0.0 - # previous quantity is reassigned and removed - assert resource.BaseQuantity == quantity - assert len(self.file.by_type("IfcPhysicalSimpleQuantity")) == 1 + self.file.create_entity("IfcProject") # add_resource + + for resource_type in resource_types: + resource = ifcopenshell.api.resource.add_resource(self.file, ifc_class=resource_type) + available_quantities = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES[resource_type] + + for quantity_type in quantity_types: + if quantity_type not in available_quantities: + with pytest.raises(ValueError): + quantity = ifcopenshell.api.resource.add_resource_quantity( + self.file, resource=resource, ifc_class=quantity_type + ) + continue + else: + quantity = ifcopenshell.api.resource.add_resource_quantity( + self.file, resource=resource, ifc_class=quantity_type + ) + + assert quantity.is_a(quantity_type) + assert quantity.Name == "Unnamed" + assert quantity[3] == 0.0 + # previous quantity is reassigned and removed + assert resource.BaseQuantity == quantity + assert len(self.file.by_type("IfcPhysicalSimpleQuantity")) == 1 + + ifcopenshell.api.resource.remove_resource(self.file, resource) class TestAddResourceQuantityIFC2X3(test.bootstrap.IFC2X3, TestAddResourceQuantity):