From 2540ba3467b511b30ffa7db4a8f0daa9e553c1cc Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Fri, 25 Nov 2022 17:22:13 +0100 Subject: [PATCH] Finish mapping quantities Qto_SpaceBaseQuantities --- .../pset/calc_quantity_function_mapper.py | 20 ++-- ...tes_about_mapped_calculated_quantities.txt | 13 ++ .../bim/module/pset/qto_calculator.py | 113 +++++++++++++++++- 3 files changed, 135 insertions(+), 11 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/pset/calc_quantity_function_mapper.py b/src/blenderbim/blenderbim/bim/module/pset/calc_quantity_function_mapper.py index 10bd9fdcd9..aec9aac5b2 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/calc_quantity_function_mapper.py +++ b/src/blenderbim/blenderbim/bim/module/pset/calc_quantity_function_mapper.py @@ -434,19 +434,19 @@ mapper = { 'GrossWeight' : None, }, 'Qto_SpaceBaseQuantities' : { - 'Height' : None, - 'FinishCeilingHeight' : None, - 'FinishFloorHeight' : None, - 'GrossPerimeter' : None, + 'Height' : "get_height", + 'FinishCeilingHeight' : "get_finish_ceiling_height", + 'FinishFloorHeight' : "get_finish_floor_height", + 'GrossPerimeter' : "get_gross_perimeter", 'NetPerimeter' : None, - 'GrossFloorArea' : None, - 'NetFloorArea' : None, + 'GrossFloorArea' : "get_gross_footprint_area", + 'NetFloorArea' : "get_net_floor_area", 'GrossWallArea' : None, 'NetWallArea' : None, - 'GrossCeilingArea' : None, - 'NetCeilingArea' : None, - 'GrossVolume' : None, - 'NetVolume' : None, + 'GrossCeilingArea' : "get_gross_ceiling_area", + 'NetCeilingArea' : "get_net_ceiling_area", + 'GrossVolume' : "get_gross_volume", + 'NetVolume' : "get_space_net_volume", }, 'Qto_CourseBaseQuantities' : { 'Length' : None, diff --git a/src/blenderbim/blenderbim/bim/module/pset/notes_about_mapped_calculated_quantities.txt b/src/blenderbim/blenderbim/bim/module/pset/notes_about_mapped_calculated_quantities.txt index 07c078bb13..8c123085c9 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/notes_about_mapped_calculated_quantities.txt +++ b/src/blenderbim/blenderbim/bim/module/pset/notes_about_mapped_calculated_quantities.txt @@ -21,6 +21,19 @@ It shouldn't be like that so we should find a method to only external lateral ar DOORS AND WINDOWS Doors and Windows have to have the main axis along 'x' and the height is measured along 'z' axis +SPACES +For calculating FinishFloorHeight and FinishCeilingHeight it substract the related IfcCovering with predefined type 'CEILING' and 'FLOORING'. +NetPerimeter needs to substract related doors so basically it's needed to get the bounding walls. At this moment, i don't know how to do that. +I created btw a "get_space_net_perimeter" that does nothing, only for reminder. +Also GrossWallArea and NetWallArea need bounding object so for the moment is still in the todo list. +GrossFloorArea: following the definition, it should exclude the wall claddings, but for now, this is not considered into the calculation. +NetFloorArea: it doesn't count the following entities contained in the spatial entity: IfcColumn and IfcWall. Just add other entities into 'get_net_floor_area' if it's needed +NetVolume: like NetFloorArea, it doesn't count the following entities contained in the spatial entity: IfcColumn and IfcWall +REMAINING TODO FUNCTIONS +IfcSpace - NetPerimeter +IfcSpace - GrossWallArea +IfcSpace - NetWallArea + diff --git a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py index 884272dba1..3a3f99b651 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py @@ -138,6 +138,41 @@ class QtoCalculator: """ return (Vector(o.bound_box[1]) - Vector(o.bound_box[0])).length + def get_finish_ceiling_height(self, obj): + space_height = self.get_height(obj) + floor_height = self.get_finish_floor_height(obj) + ceiling_height = self.get_ceiling_height(obj) + finish_ceiling_height = space_height - floor_height - ceiling_height + return finish_ceiling_height + + def get_finish_floor_height(self, obj): + element = tool.Ifc.get_entity(obj) + decompositions = ifcopenshell.util.element.get_decomposition(element) + finish_floor_height = 0 + for decomposition in decompositions: + if decomposition.get_info()['PredefinedType'] == 'FLOORING' and decomposition.get_info()['type'] == 'IfcCovering' : + floor_obj = tool.Ifc.get_object(decomposition) + new_finish_floor_height = self.get_height(floor_obj) + if new_finish_floor_height > finish_floor_height: + finish_floor_height = new_finish_floor_height + + return finish_floor_height + + def get_ceiling_height(self, obj): + element = tool.Ifc.get_entity(obj) + decompositions = ifcopenshell.util.element.get_decomposition(element) + finish_ceiling_height = 0 + for decomposition in decompositions: + if decomposition.get_info()['PredefinedType'] == 'CEILING' and decomposition.get_info()['type'] == 'IfcCovering' : + ceiling_obj = tool.Ifc.get_object(decomposition) + new_finish_ceiling_height = self.get_height(ceiling_obj) + if new_finish_ceiling_height > finish_ceiling_height: + finish_ceiling_height = new_finish_ceiling_height + + return finish_ceiling_height + + + def get_net_perimeter(self, o): parsed_edges = [] shared_edges = [] @@ -161,6 +196,9 @@ class QtoCalculator: self.delete_obj(gross_obj) return gross_perimeter + def get_space_net_perimeter(self, obj): + pass + def get_rectangular_perimeter(self, obj): length = self.get_length(obj, main_axis='x') height = self.get_height(obj) @@ -205,6 +243,73 @@ class QtoCalculator: def get_edge_distance(self, obj, edge): return (obj.data.vertices[edge.vertices[1]].co - obj.data.vertices[edge.vertices[0]].co).length + def get_net_floor_area(self, obj): + decompositions = self.get_obj_decompositions(obj) + if not decompositions: + return self.get_gross_footprint_area(obj) + + total_net_floor_area = self.get_net_footprint_area(obj) + + for decomposition in decompositions: + decomposition_type = decomposition.get_info()['type'] + if decomposition_type == 'IfcColumn' or decomposition_type == 'IfcColumn': + decomposition_obj = tool.Ifc.get_object(decomposition) + net_footprint_obj_area = self.get_net_footprint_area(decomposition_obj) + total_net_floor_area -= net_footprint_obj_area + + return total_net_floor_area + + def get_gross_ceiling_area(self, obj): + decompositions = self.get_obj_decompositions(obj) + if not decompositions: + return self.get_gross_top_area(obj) + + total_gross_ceiling_area = 0 + + for decomposition in decompositions: + decomposition_type = decomposition.get_info()['type'] + decomposition_predefined_type = decomposition.get_info()['PredefinedType'] + if decomposition_type == 'IfcCovering' and decomposition_predefined_type == 'CEILING': + decomposition_obj = tool.Ifc.get_object(decomposition) + total_gross_ceiling_area += self.get_gross_footprint_area(decomposition_obj) + + return total_gross_ceiling_area + + def get_net_ceiling_area(self, obj): + decompositions = self.get_obj_decompositions(obj) + if not decompositions: + return self.get_net_top_area(obj) + + total_net_ceiling_area = 0 + + for decomposition in decompositions: + decomposition_type = decomposition.get_info()['type'] + decomposition_predefined_type = decomposition.get_info()['PredefinedType'] + if decomposition_type == 'IfcCovering' and decomposition_predefined_type == 'CEILING': + decomposition_obj = tool.Ifc.get_object(decomposition) + total_net_ceiling_area += self.get_net_footprint_area(decomposition_obj) + + if decomposition_type == 'IfcWall' or decomposition_type == 'IfcColumn': + decomposition_obj = tool.Ifc.get_object(decomposition) + total_net_ceiling_area -= self.get_net_roofprint_area(decomposition_obj) + + return total_net_ceiling_area + + def get_space_net_volume(self, obj): + decompositions = self.get_obj_decompositions(obj) + if not decompositions: + return self.get_gross_volume(obj) + + total_space_net_volume = self.get_gross_volume(obj) + + for decomposition in decompositions: + decomposition_type = decomposition.get_info()['type'] + if decomposition_type == 'IfcWall' or decomposition_type == 'IfcColumn': + decomposition_obj = tool.Ifc.get_object(decomposition) + total_space_net_volume -= self.get_net_volume(decomposition_obj) + + return total_space_net_volume + def get_net_footprint_area(self, o): """_summary_: Returns the area of the footprint of the object, excluding any holes @@ -265,7 +370,7 @@ class QtoCalculator: elif item.is_a("IfcBooleanClippingResult"): item = item.FirstOperand else: - area = self.get_end_area(obj, exclude_side_areas = True) + area = self.get_end_area(obj) return area # TODO handle other types of sections, and then fall back to mesh parsing @@ -327,6 +432,12 @@ class QtoCalculator: element = tool.Ifc.get_entity(obj) return element and getattr(element, "HasOpenings", []) + def get_obj_decompositions(self, obj): + element = tool.Ifc.get_entity(obj) + decompositions = ifcopenshell.util.element.get_decomposition(element) + return decompositions + + # The following is @Moult's older code. Keeping it here just in case the bmesh function is buggy. -vulevukusej