mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-02 21:12:07 +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.CalculateObjectVolumes,
|
||||||
operator.ExecuteQtoMethod,
|
operator.ExecuteQtoMethod,
|
||||||
operator.QuantifyObjects,
|
operator.QuantifyObjects,
|
||||||
|
operator.AssignPsetQto,
|
||||||
|
operator.CalculateAllQtos,
|
||||||
prop.BIMQtoProperties,
|
prop.BIMQtoProperties,
|
||||||
ui.BIM_PT_qto_utilities,
|
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})
|
ifcopenshell.api.run("pset.edit_qto", self.file, qto=qto, properties={props.prop_name: result})
|
||||||
PsetData.load(self.file, obj.BIMObjectProperties.ifc_definition_id)
|
PsetData.load(self.file, obj.BIMObjectProperties.ifc_definition_id)
|
||||||
return {"FINISHED"}
|
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, "qto_name", text="")
|
||||||
row.prop(props, "prop_name", text="")
|
row.prop(props, "prop_name", text="")
|
||||||
row.operator("bim.quantify_objects", icon="COPYDOWN", 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)
|
result = qto.get_radius_of_selected_vertices(obj)
|
||||||
qto.set_qto_result(result)
|
qto.set_qto_result(result)
|
||||||
return 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:
|
class Qto:
|
||||||
def get_radius_of_selected_vertices(cls, obj): pass
|
def get_radius_of_selected_vertices(cls, obj): pass
|
||||||
def set_qto_result(cls, result): 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
|
@interface
|
||||||
class Resource:
|
class Resource:
|
||||||
|
|||||||
@@ -16,10 +16,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from types import ClassMethodDescriptorType
|
||||||
import bpy
|
import bpy
|
||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
import ifcopenshell
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
from ifcopenshell import util
|
||||||
|
from blenderbim.bim.module.pset.qto_calculator import QtoCalculator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Qto(blenderbim.core.tool.Qto):
|
class Qto(blenderbim.core.tool.Qto):
|
||||||
@@ -35,3 +40,113 @@ class Qto(blenderbim.core.tool.Qto):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def set_qto_result(cls, result):
|
def set_qto_result(cls, result):
|
||||||
bpy.context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
|
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):
|
def test_run(self):
|
||||||
subject.set_qto_result(123.4567)
|
subject.set_qto_result(123.4567)
|
||||||
assert bpy.context.scene.BIMQtoProperties.qto_result == "123.457"
|
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