From 4c53c2ab1f9baf0fc35804d8ddca31c37a2384b6 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 14 Mar 2025 12:37:56 +0500 Subject: [PATCH] ifc5d.qto.IfcOpenShell - get_weight function Added support for it in .json for the same elements that support it in IFC4QtoBaseQuantitiesBlender --- src/ifc5d/ifc5d/IFC4QtoBaseQuantities.json | 36 ++++++++-------- src/ifc5d/ifc5d/IFC4X3QtoBaseQuantities.json | 36 ++++++++-------- src/ifc5d/ifc5d/qto.py | 43 +++++++++++++++++--- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/ifc5d/ifc5d/IFC4QtoBaseQuantities.json b/src/ifc5d/ifc5d/IFC4QtoBaseQuantities.json index dfe870bbe2..2c3cdcd0f8 100644 --- a/src/ifc5d/ifc5d/IFC4QtoBaseQuantities.json +++ b/src/ifc5d/ifc5d/IFC4QtoBaseQuantities.json @@ -40,11 +40,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -134,11 +134,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -317,11 +317,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": null, "GrossVolume": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Height": "net_get_z", "Length": "net_get_max_xy", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null, "Width": null } @@ -368,11 +368,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -400,10 +400,10 @@ "CrossSectionArea": null, "GrossSurfaceArea": null, "GrossVolume": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_z", "NetVolume": null, - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null } }, @@ -420,10 +420,10 @@ "IfcPipeSegment": { "Qto_PipeSegmentBaseQuantities": { "GrossCrossSectionArea": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_segment_length", "NetCrossSectionArea": null, - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null } }, @@ -431,10 +431,10 @@ "Qto_PlateBaseQuantities": { "GrossArea": "gross_get_max_side_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "NetArea": "net_get_max_side_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Perimeter": null, "Width": "net_get_min_xyz" } @@ -510,11 +510,11 @@ "Depth": "net_get_z", "GrossArea": "gross_get_footprint_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_x", "NetArea": "net_get_footprint_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Perimeter": "net_get_footprint_perimeter", "Width": "net_get_y" } @@ -609,13 +609,13 @@ "GrossFootprintArea": null, "GrossSideArea": "gross_get_side_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Height": "net_get_z", "Length": "net_get_x", "NetFootprintArea": null, "NetSideArea": "net_get_side_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Width": "net_get_y" } }, diff --git a/src/ifc5d/ifc5d/IFC4X3QtoBaseQuantities.json b/src/ifc5d/ifc5d/IFC4X3QtoBaseQuantities.json index 90e791bce4..cf0bf7ebde 100644 --- a/src/ifc5d/ifc5d/IFC4X3QtoBaseQuantities.json +++ b/src/ifc5d/ifc5d/IFC4X3QtoBaseQuantities.json @@ -40,11 +40,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -140,11 +140,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -362,11 +362,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": null, "GrossVolume": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Height": "net_get_z", "Length": "net_get_max_xy", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null, "Width": null } @@ -457,11 +457,11 @@ "CrossSectionArea": null, "GrossSurfaceArea": "gross_get_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_max_xyz", "NetSurfaceArea": "net_get_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": "net_get_outer_surface_area" } }, @@ -500,10 +500,10 @@ "CrossSectionArea": null, "GrossSurfaceArea": null, "GrossVolume": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_z", "NetVolume": null, - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null } }, @@ -521,10 +521,10 @@ "Qto_PipeSegmentBaseQuantities": { "FootPrintArea": null, "GrossCrossSectionArea": null, - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_segment_length", "NetCrossSectionArea": null, - "NetWeight": null, + "NetWeight": "net_get_weight", "OuterSurfaceArea": null } }, @@ -532,10 +532,10 @@ "Qto_PlateBaseQuantities": { "GrossArea": "gross_get_max_side_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "NetArea": "net_get_max_side_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Perimeter": null, "Width": "net_get_min_xyz" } @@ -656,11 +656,11 @@ "Depth": "net_get_z", "GrossArea": "gross_get_footprint_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Length": "net_get_x", "NetArea": "net_get_footprint_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Perimeter": "net_get_footprint_perimeter", "Width": "net_get_y" } @@ -782,13 +782,13 @@ "GrossFootPrintArea": null, "GrossSideArea": "gross_get_side_area", "GrossVolume": "gross_get_volume", - "GrossWeight": null, + "GrossWeight": "gross_get_weight", "Height": "net_get_z", "Length": "net_get_x", "NetFootPrintArea": null, "NetSideArea": "net_get_side_area", "NetVolume": "net_get_volume", - "NetWeight": null, + "NetWeight": "net_get_weight", "Width": "net_get_y" } }, diff --git a/src/ifc5d/ifc5d/qto.py b/src/ifc5d/ifc5d/qto.py index 016fd06da2..84fa67879f 100644 --- a/src/ifc5d/ifc5d/qto.py +++ b/src/ifc5d/ifc5d/qto.py @@ -234,6 +234,12 @@ class IfcOpenShell(QtoCalculator): ), # IfcVolumeMeasure "get_volume": Function("IfcVolumeMeasure", "Volume", "Calculates the volume of a manifold shape"), + # IfcMassMeasure + "get_weight": Function( + "IfcMassMeasure", + "Weight", + "The weight of the object based on it's volume and material density (from Pset_MaterialCommon.MassDensity).", + ), } functions = {} @@ -241,6 +247,11 @@ class IfcOpenShell(QtoCalculator): functions[f"gross_{k}"] = Function(v.measure, f"Gross {v.name}", v.description) functions[f"net_{k}"] = Function(v.measure, f"Net {v.name}", v.description) + internal_functions = ( + "get_segment_length", + "get_weight", + ) + @classmethod def calculate(cls, ifc_file, elements, qtos, results): formula_functions: dict[str, types.FunctionType] = {} @@ -258,7 +269,7 @@ class IfcOpenShell(QtoCalculator): if not formula: continue gross_or_net_qtos = gross_qtos if formula.startswith("gross_") else net_qtos - if formula.endswith("get_segment_length"): + if formula.endswith(cls.internal_functions): gross_or_net_qtos.setdefault(name, {})[quantity] = formula.partition("_")[2] elif formula.startswith(("gross_", "net_")): formula = formula.partition("_")[2] @@ -280,6 +291,7 @@ class IfcOpenShell(QtoCalculator): for iterator, qtos_ in tasks: if iterator.initialize(): while True: + geometry: ifcopenshell.geom.main.ShapeType if isinstance(iterator, ifcopenshell.geom.iterator): shape = iterator.get() geometry = shape.geometry @@ -293,11 +305,15 @@ class IfcOpenShell(QtoCalculator): for quantity, formula in quantities.items(): if formula == "get_segment_length": results[element][name][quantity] = cls.get_segment_length(element) + elif formula == "get_weight": + value = cls.get_weight(element, geometry) + if value is None: + continue else: - results[element][name][quantity] = cls.unit_converter.convert( - formula_functions[formula](geometry), - IfcOpenShell.raw_functions[formula].measure, - ) + value = formula_functions[formula](geometry) + assert isinstance(value, (float, int)) + value = cls.unit_converter.convert(value, IfcOpenShell.raw_functions[formula].measure) + results[element][name][quantity] = value if not iterator.next(): break @@ -341,6 +357,23 @@ class IfcOpenShell(QtoCalculator): z = item.Depth return max([x, y, z]) + @classmethod + def get_weight( + cls, element: ifcopenshell.entity_instance, geometry: ifcopenshell.geom.ShapeType + ) -> Union[float, None]: + """Get element's weight. + + :param element: IFC element entity. + :return: ``float`` weight in project units + or ``None`` if mass density calculation for this element is not supported. + """ + + density = ifcopenshell.util.element.get_element_mass_density(element) + if density is None: + return + volume = ifcopenshell.util.shape.get_volume(geometry) + return volume * density + class Blender(QtoCalculator): """Calculates geometry based on currently loaded Blender objects."""