diff --git a/src/blenderbim/blenderbim/bim/module/qto/__init__.py b/src/blenderbim/blenderbim/bim/module/qto/__init__.py index cc11de2cde..2cd6381ffb 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/qto/__init__.py @@ -5,6 +5,8 @@ classes = ( operator.CalculateEdgeLengths, operator.CalculateFaceAreas, operator.CalculateObjectVolumes, + operator.ExecuteQtoMethod, + operator.QuantifyObjects, prop.BIMQtoProperties, ui.BIM_PT_qto_utilities, ) diff --git a/src/blenderbim/blenderbim/bim/module/qto/helper.py b/src/blenderbim/blenderbim/bim/module/qto/helper.py new file mode 100644 index 0000000000..ac95e84b2c --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/qto/helper.py @@ -0,0 +1,13 @@ +import bmesh + + +def calculate_height(obj): + return obj.dimensions[2] + + +def calculate_volume(obj): + bm = bmesh.new() + bm.from_mesh(obj.data) + result = bm.calc_volume() + bm.free() + return result diff --git a/src/blenderbim/blenderbim/bim/module/qto/operator.py b/src/blenderbim/blenderbim/bim/module/qto/operator.py index a83c3183ff..210ac1240c 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/operator.py +++ b/src/blenderbim/blenderbim/bim/module/qto/operator.py @@ -1,5 +1,10 @@ import bpy import bmesh +import ifcopenshell +import ifcopenshell.api +from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.qto import helper +from ifcopenshell.api.pset.data import Data as PsetData class CalculateEdgeLengths(bpy.types.Operator): @@ -49,3 +54,53 @@ class CalculateObjectVolumes(bpy.types.Operator): bm.free() bpy.context.scene.BIMQtoProperties.qto_result = str(round(result, 3)) return {"FINISHED"} + + +class ExecuteQtoMethod(bpy.types.Operator): + bl_idname = "bim.execute_qto_method" + bl_label = "Execute Qto Method" + + def execute(self, context): + props = bpy.context.scene.BIMQtoProperties + result = 0 + if props.qto_methods == "HEIGHT": + for obj in bpy.context.selected_objects: + result += helper.calculate_height(obj) + elif props.qto_methods == "VOLUME": + for obj in bpy.context.selected_objects: + result += helper.calculate_volume(obj) + props.qto_result = str(round(result, 3)) + return {"FINISHED"} + + +class QuantifyObjects(bpy.types.Operator): + bl_idname = "bim.quantify_objects" + bl_label = "Quantify Objects" + + def execute(self, context): + props = bpy.context.scene.BIMQtoProperties + self.file = IfcStore.get_file() + for obj in bpy.context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + result = 0 + if props.qto_methods == "HEIGHT": + result = helper.calculate_height(obj) + elif props.qto_methods == "VOLUME": + result = helper.calculate_volume(obj) + if not result: + continue + qto = ifcopenshell.api.run( + "pset.add_qto", + self.file, + product=self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), + Name=props.qto_name, + ) + ifcopenshell.api.run( + "pset.edit_qto", + self.file, + qto=qto, + Properties={props.prop_name: result} + ) + PsetData.load(self.file, obj.BIMObjectProperties.ifc_definition_id) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/qto/prop.py b/src/blenderbim/blenderbim/bim/module/qto/prop.py index 205d3e39ef..a081e0cb54 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/prop.py +++ b/src/blenderbim/blenderbim/bim/module/qto/prop.py @@ -14,3 +14,13 @@ from bpy.props import ( class BIMQtoProperties(PropertyGroup): qto_result: StringProperty(default="", name="Qto Result") + qto_methods: EnumProperty( + items=[ + ("HEIGHT", "Height", "Calculate the Z height of an object"), + ("VOLUME", "Volume", "Calculate the volume of an object"), + ("FORMWORK", "Formwork", "Calculate the exposed formwork for all bottoms and sides of one or more objects"), + ], + name="Qto Methods", + ) + qto_name: StringProperty(name="Qto Name") + prop_name: StringProperty(name="Prop Name") diff --git a/src/blenderbim/blenderbim/bim/module/qto/ui.py b/src/blenderbim/blenderbim/bim/module/qto/ui.py index d31283183a..567d2eee11 100644 --- a/src/blenderbim/blenderbim/bim/module/qto/ui.py +++ b/src/blenderbim/blenderbim/bim/module/qto/ui.py @@ -21,3 +21,12 @@ class BIM_PT_qto_utilities(Panel): row.operator("bim.calculate_face_areas") row = layout.row(align=True) row.operator("bim.calculate_object_volumes") + + row = layout.row(align=True) + row.prop(props, "qto_methods", text="") + row.operator("bim.execute_qto_method", icon="PROPERTIES", text="") + + row = layout.row(align=True) + row.prop(props, "qto_name", text="") + row.prop(props, "prop_name", text="") + row.operator("bim.quantify_objects", icon="COPYDOWN", text="") diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset/add_pset.py b/src/ifcopenshell-python/ifcopenshell/api/pset/add_pset.py index 73c9c3cf19..b5b5cfd3e2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset/add_pset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset/add_pset.py @@ -10,6 +10,13 @@ class Usecase: def execute(self): if self.settings["product"].is_a("IfcObject"): + for rel in self.settings["product"].IsDefinedBy or []: + if ( + rel.is_a("IfcRelDefinesByProperties") + and rel.RelatingPropertyDefinition.Name == self.settings["Name"] + ): + return rel.RelatingPropertyDefinition + pset = self.file.create_entity( "IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]} ) @@ -24,6 +31,10 @@ class Usecase: ) return pset elif self.settings["product"].is_a("IfcTypeObject"): + for definition in self.settings["product"].HasPropertySets or []: + if definition.Name == self.settings["Name"]: + return definition + pset = self.file.create_entity( "IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]} ) @@ -32,6 +43,10 @@ class Usecase: self.settings["product"].HasPropertySets = has_property_sets return pset elif self.settings["product"].is_a("IfcMaterialDefinition"): + for definition in self.settings["product"].HasPropertySets or []: + if definition.Name == self.settings["Name"]: + return definition + return self.file.create_entity( "IfcMaterialProperties", **{ diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset/add_qto.py b/src/ifcopenshell-python/ifcopenshell/api/pset/add_qto.py index 53b8246722..4105985674 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset/add_qto.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset/add_qto.py @@ -10,6 +10,13 @@ class Usecase: def execute(self): if self.settings["product"].is_a("IfcObject"): + for rel in self.settings["product"].IsDefinedBy or []: + if ( + rel.is_a("IfcRelDefinesByProperties") + and rel.RelatingPropertyDefinition.Name == self.settings["Name"] + ): + return rel.RelatingPropertyDefinition + qto = self.file.create_entity( "IfcElementQuantity", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]} )