mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
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:
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user