Add calculate all qtos button (#2441)

* Add button to calculate all object qtos in qto n-panel

* Calculate all qtos button: now the schema is readed from the file

* Calculate all qtos button: now edit_qto runs only one time every object

* Add button to assign pset qto to selected objects

* Calculate all qtos button: small fixing and unable to execute if no selected objects

* Calculate all qtos button: first tool test

* Calculate all qtos button: use better built-in function to get ifc obj entity
This commit is contained in:
Massimo Fabbro
2022-09-26 08:05:08 +02:00
committed by GitHub
parent 4c7a5e8a1a
commit b673fc94a5
7 changed files with 202 additions and 1 deletions
@@ -26,6 +26,8 @@ classes = (
operator.CalculateObjectVolumes,
operator.ExecuteQtoMethod,
operator.QuantifyObjects,
operator.AssignPsetQto,
operator.CalculateAllQtos,
prop.BIMQtoProperties,
ui.BIM_PT_qto_utilities,
)
@@ -150,3 +150,31 @@ class QuantifyObjects(bpy.types.Operator):
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"}
class AssignPsetQto(bpy.types.Operator):
bl_idname = "bim.assign_pset_qto"
bl_label = "Assign Pset Qto"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Assign pset qto to selected object"
@classmethod
def poll(cls, context):
return context.active_object and context.selected_objects
def execute(self, context):
core.assign_pset_qto(tool.Qto, selected_objects = context.selected_objects)
return {"FINISHED"}
class CalculateAllQtos(bpy.types.Operator):
bl_idname = "bim.calculate_all_qtos"
bl_label = "Calculate All Qtos"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Calculate all pset qtos properties of objects assigned pset qto"
@classmethod
def poll(cls, context):
return context.active_object and context.selected_objects
def execute(self, context):
core.calculate_all_qtos(tool.Qto, selected_objects = context.selected_objects)
return {"FINISHED"}
@@ -51,3 +51,9 @@ class BIM_PT_qto_utilities(Panel):
row.prop(props, "qto_name", text="")
row.prop(props, "prop_name", text="")
row.operator("bim.quantify_objects", icon="COPYDOWN", text="")
row = layout.row(align=True)
row.operator("bim.assign_pset_qto")
row = layout.row(align=True)
row.operator("bim.calculate_all_qtos")
+19
View File
@@ -21,3 +21,22 @@ def calculate_circle_radius(qto, obj=None):
result = qto.get_radius_of_selected_vertices(obj)
qto.set_qto_result(result)
return result
def assign_pset_qto(qto, selected_objects):
for object in selected_objects:
qto.set_active_object(object)
qto.assign_pset_qto_to_selected_object(object)
def calculate_all_qtos(qto, selected_objects):
for object in selected_objects:
qto.set_active_object(object)
if not qto.get_pset_qto_object_ifc_info(object):
print("There is no pset qto instance associated to object " + object.name)
continue
pset_qto_properties = qto.get_pset_qto_properties(object)
calculated_quantities = qto.get_calculated_quantities(object, pset_qto_properties)
qto.edit_qto(object, calculated_quantities)
+13 -1
View File
@@ -401,7 +401,19 @@ class Pset:
class Qto:
def get_radius_of_selected_vertices(cls, obj): pass
def set_qto_result(cls, result): pass
def set_active_object(cls, object): pass
def get_pset_qto_object_ifc_info(cls, object): pass
def get_pset_qto_properties(cls, object): pass
def get_pset_qto_name(cls, object): pass
def get_applicable_pset_names(cls, object): pass
def edit_qto(cls, object, calculated_quantities): pass
def get_pset_qto_id(cls, object): pass
def get_pset_qto_name(cls, object): pass
def get_new_quantity(cls, object, quantity_name, alternative_prop_names): pass
def get_non_calculated_value(cls): pass
def get_rounded_value(cls, new_quantity): pass
def get_calculated_quantities(cls, object, pset_qto_properties): pass
def assign_pset_qto_to_selected_object(cls, object): pass
@interface
class Resource:
+115
View File
@@ -16,10 +16,15 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from types import ClassMethodDescriptorType
import bpy
import blenderbim.core.tool
import blenderbim.tool as tool
import ifcopenshell
from mathutils import Vector
from ifcopenshell import util
from blenderbim.bim.module.pset.qto_calculator import QtoCalculator
class Qto(blenderbim.core.tool.Qto):
@@ -35,3 +40,113 @@ class Qto(blenderbim.core.tool.Qto):
@classmethod
def set_qto_result(cls, result):
bpy.context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
@classmethod
def set_active_object(cls, object):
bpy.context.view_layer.objects.active = object
@classmethod
def get_pset_qto_object_ifc_info(cls, object):
element = tool.Ifc.get_entity(object)
pset_qto_ifc_instance = ifcopenshell.util.element.get_psets(element, qtos_only = True)
return pset_qto_ifc_instance
@classmethod
def get_pset_qto_properties(cls, object):
file = tool.Ifc.get()
schema = file.schema
pset_qto = util.pset.PsetQto(schema)
pset_qto_name = cls.get_pset_qto_name(object)
pset_qto_properties = pset_qto.get_by_name(pset_qto_name).get_info()['HasPropertyTemplates']
return pset_qto_properties
@classmethod
def get_pset_qto_name(cls, object):
applicable_pset_names = cls.get_applicable_pset_names(object)
for applicable_pset_name in applicable_pset_names:
if 'Qto_' in applicable_pset_name:
pset_qto_name = applicable_pset_name
return pset_qto_name
@classmethod
def get_applicable_pset_names(cls, object):
file = tool.Ifc.get()
schema = file.schema
pset_qto = util.pset.PsetQto(schema)
entity = tool.Ifc.get_entity(object)
ifc_object_type = entity.get_info()['type']
applicable_pset_names = pset_qto.get_applicable_names(ifc_object_type)
return applicable_pset_names
@classmethod
def edit_qto(cls, object, calculated_quantities):
file = tool.Ifc.get()
pset_qto_id = cls.get_pset_qto_id(object)
pset_qto_name = cls.get_pset_qto_name(object)
ifcopenshell.api.run("pset.edit_qto",
file,
**{"qto" : pset_qto_id, "name" : pset_qto_name, "properties": calculated_quantities}
)
@classmethod
def get_pset_qto_id(cls, object):
file = tool.Ifc.get()
pset_qto_name = cls.get_pset_qto_name(object)
pset_qto_object_ifc_instance = cls.get_pset_qto_object_ifc_info(object)
pset_qto_id = file.by_id(pset_qto_object_ifc_instance[pset_qto_name]['id'])
return pset_qto_id
@classmethod
def get_pset_qto_name(cls, object):
applicable_pset_names = cls.get_applicable_pset_names(object)
for applicable_pset_name in applicable_pset_names:
if 'Qto_' in applicable_pset_name:
pset_qto_name = applicable_pset_name
return pset_qto_name
@classmethod
def get_new_quantity(cls, object, quantity_name, alternative_prop_names):
calculator = QtoCalculator()
new_quantity = calculator.guess_quantity(quantity_name, alternative_prop_names, object)
return new_quantity
@classmethod
def get_non_calculated_value(cls):
return 0
@classmethod
def get_rounded_value(cls, new_quantity):
return round(new_quantity, 3)
@classmethod
def get_calculated_quantities(cls, object, pset_qto_properties):
calculated_quantities = {}
for pset_qto_property in pset_qto_properties:
quantity_name = pset_qto_property.get_info()['Name']
alternative_prop_names = [p.get_info()['Name'] for p in pset_qto_properties]
new_quantity = cls.get_new_quantity(object, quantity_name, alternative_prop_names)
if not new_quantity:
new_quantity = cls.get_non_calculated_value()
else:
new_quantity = cls.get_rounded_value(new_quantity)
calculated_quantities[quantity_name] = new_quantity
return calculated_quantities
@classmethod
def assign_pset_qto_to_selected_object(cls, object):
file = tool.Ifc.get()
entity = tool.Ifc.get_entity(object)
pset_qto_name = cls.get_pset_qto_name(object)
ifcopenshell.api.run(
"pset.add_qto",
file,
**{
"product": entity,
"name": pset_qto_name,
},
)
+19
View File
@@ -39,3 +39,22 @@ class TestSetQtoResult(test.bim.bootstrap.NewFile):
def test_run(self):
subject.set_qto_result(123.4567)
assert bpy.context.scene.BIMQtoProperties.qto_result == "123.457"
class TestGetPsetQtoObjectIfcInfo(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
wall = ifc.createIfcWall()
wall_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
tool.Ifc.link(wall, wall_obj)
pset_qto = ifcopenshell.api.run("pset.add_qto", ifc, product=wall, name="Qto_foo")
assert subject.get_pset_qto_object_ifc_info(wall_obj)['Qto_foo']['id'] == pset_qto.get_info()['id']
assert list(subject.get_pset_qto_object_ifc_info(wall_obj).keys())[0] == pset_qto.get_info()['Name']
def test_isempty(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
wall = ifc.createIfcWall()
wall_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
tool.Ifc.link(wall, wall_obj)
assert not subject.get_pset_qto_object_ifc_info(wall_obj) == True