bulk property editor (#1896)

* first revision

* update incorporating review comments

* added a new feature - remove psets

* type dropdown now references ifc data types

* adopt new solution for enumerations and umlauts

* Revert "adopt new solution for enumerations and umlauts"

This reverts commit 203a31a2bf.
This commit is contained in:
Vukas Pajic
2022-01-04 02:59:55 +01:00
committed by GitHub
parent 03f5feca88
commit 0625e4153c
6 changed files with 443 additions and 114 deletions
@@ -29,12 +29,21 @@ classes = (
operator.GuessQuantity, operator.GuessQuantity,
operator.RemovePset, operator.RemovePset,
operator.TogglePsetExpansion, operator.TogglePsetExpansion,
operator.BIM_OT_add_property_to_edit,
operator.BIM_OT_remove_property_to_edit,
operator.BIM_OT_clear_list,
operator.BIM_OT_rename_parameters,
operator.BIM_OT_add_edit_custom_property,
operator.BIM_OT_bulk_remove_psets,
prop.PsetProperties, prop.PsetProperties,
prop.MaterialPsetProperties, prop.MaterialPsetProperties,
prop.TaskPsetProperties, prop.TaskPsetProperties,
prop.ResourcePsetProperties, prop.ResourcePsetProperties,
prop.ProfilePsetProperties, prop.ProfilePsetProperties,
prop.WorkSchedulePsetProperties, prop.WorkSchedulePsetProperties,
prop.RenameProperties,
prop.AddEditProperties,
prop.DeletePsets,
ui.BIM_PT_object_psets, ui.BIM_PT_object_psets,
ui.BIM_PT_object_qtos, ui.BIM_PT_object_qtos,
ui.BIM_PT_material_psets, ui.BIM_PT_material_psets,
@@ -43,6 +52,10 @@ classes = (
ui.BIM_PT_resource_psets, ui.BIM_PT_resource_psets,
ui.BIM_PT_profile_psets, ui.BIM_PT_profile_psets,
ui.BIM_PT_work_schedule_psets, ui.BIM_PT_work_schedule_psets,
ui.BIM_PT_bulk_property_editor,
ui.BIM_PT_rename_parameters,
ui.BIM_PT_add_edit_custom_properties,
ui.BIM_PT_delete_psets
) )
@@ -53,7 +66,9 @@ def register():
bpy.types.Scene.ResourcePsetProperties = bpy.props.PointerProperty(type=prop.ResourcePsetProperties) bpy.types.Scene.ResourcePsetProperties = bpy.props.PointerProperty(type=prop.ResourcePsetProperties)
bpy.types.Scene.ProfilePsetProperties = bpy.props.PointerProperty(type=prop.ProfilePsetProperties) bpy.types.Scene.ProfilePsetProperties = bpy.props.PointerProperty(type=prop.ProfilePsetProperties)
bpy.types.Scene.WorkSchedulePsetProperties = bpy.props.PointerProperty(type=prop.WorkSchedulePsetProperties) bpy.types.Scene.WorkSchedulePsetProperties = bpy.props.PointerProperty(type=prop.WorkSchedulePsetProperties)
bpy.types.Scene.RenameProperties = bpy.props.CollectionProperty(type=prop.RenameProperties)
bpy.types.Scene.AddEditProperties = bpy.props.CollectionProperty(type=prop.AddEditProperties)
bpy.types.Scene.DeletePsets = bpy.props.CollectionProperty(type=prop.DeletePsets)
def unregister(): def unregister():
del bpy.types.Object.PsetProperties del bpy.types.Object.PsetProperties
@@ -62,3 +77,6 @@ def unregister():
del bpy.types.Scene.ResourcePsetProperties del bpy.types.Scene.ResourcePsetProperties
del bpy.types.Scene.ProfilePsetProperties del bpy.types.Scene.ProfilePsetProperties
del bpy.types.Scene.WorkSchedulePsetProperties del bpy.types.Scene.WorkSchedulePsetProperties
del bpy.types.Scene.RenameProperties
del bpy.types.Scene.AddEditProperties
del bpy.types.Scene.DeletePsets
@@ -101,7 +101,6 @@ class EnablePsetEditing(bpy.types.Operator):
def execute(self, context): def execute(self, context):
self.props = get_pset_props(context, self.obj, self.obj_type) self.props = get_pset_props(context, self.obj, self.obj_type)
self.props.properties.clear() self.props.properties.clear()
data = Data.psets if self.pset_id in Data.psets else Data.qtos data = Data.psets if self.pset_id in Data.psets else Data.qtos
@@ -374,3 +373,159 @@ class CopyPropertyToSelection(bpy.types.Operator, Operator):
prop_name=self.name, prop_name=self.name,
prop_value=prop_value, prop_value=prop_value,
) )
class BIM_OT_add_property_to_edit(bpy.types.Operator):
bl_label = "Add new row"
bl_idname = "bim.add_property_to_edit"
bl_options = {"REGISTER", "UNDO"}
option: bpy.props.StringProperty()
def execute(self, context):
getattr(context.scene, self.option).add()
return {"FINISHED"}
class BIM_OT_remove_property_to_edit(bpy.types.Operator):
bl_label = "Remove property to be renamed"
bl_idname = "bim.remove_property_to_edit"
bl_options = {"REGISTER", "UNDO"}
index: bpy.props.IntProperty()
option: bpy.props.StringProperty()
def execute(self, context):
getattr(context.scene, self.option).remove(self.index)
return {"FINISHED"}
class BIM_OT_clear_list(bpy.types.Operator):
bl_label = "Clear list of properties"
bl_idname = "bim.clear_list"
bl_options = {"REGISTER", "UNDO"}
option: bpy.props.StringProperty()
def execute(self, context):
getattr(context.scene, self.option).clear()
return {"FINISHED"}
class BIM_OT_rename_parameters(bpy.types.Operator):
bl_label = "Rename Parameters"
bl_idname = "bim.rename_parameters"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Rename parameters that are subclasses of IfcElement"
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props_to_map = context.scene.RenameProperties
ifc_file = IfcStore.get_file()
all_ifc_elements = ifc_file.by_type("IfcElement")
for ifc_element in all_ifc_elements:
for definition in ifc_element.IsDefinedBy:
if definition.is_a('IfcRelDefinesByProperties'):
prop_set = definition.RelatingPropertyDefinition
self.rename_property(prop_set, props_to_map, ifc_element)
self.report({'INFO'}, 'Finished applying changes')
return {"FINISHED"}
def rename_property(self, property_set, properties_to_map, ifc_element):
if property_set.is_a() == "IfcPropertySet":
property_container = property_set.HasProperties
elif property_set.is_a() == "IfcElementQuantity":
property_container = property_set.Quantities
for obj_prop in property_container:
for prop2map in properties_to_map:
if prop2map.pset_name != property_set.Name:
continue
if prop2map.existing_property_name == obj_prop.Name:
obj_prop.Name = prop2map.new_property_name
Data.load(IfcStore.get_file(), ifc_element.id())
class BIM_OT_add_edit_custom_property(bpy.types.Operator):
bl_label = "Add or edit a custom property"
bl_idname = "bim.add_edit_custom_property"
bl_options = {"REGISTER", "UNDO"}
index: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
selected_objects = context.selected_objects
props = context.scene.AddEditProperties
for obj in selected_objects:
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
continue
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
for prop in props:
value = getattr(prop, prop.get_value_name())
primary_measure_type = prop.primary_measure_type
value_ifc_entity = getattr(self.file, f"create{primary_measure_type}")(value)
new_pset = ifcopenshell.api.run(
"pset.add_pset",
self.file,
product=ifc_element,
name=prop.pset_name
)
ifcopenshell.api.run(
"pset.edit_pset",
self.file,
pset=new_pset,
properties={prop.property_name:value_ifc_entity}
)
self.report({'INFO'}, 'Finished applying changes')
return {"FINISHED"}
class BIM_OT_bulk_remove_psets(bpy.types.Operator):
bl_label = "Bulk remove psets from selected objects"
bl_idname = "bim.bulk_remove_psets"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Bulk remove psets from selected objects"
index: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
selected_objects = context.selected_objects
props = context.scene.DeletePsets
for obj in selected_objects:
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
continue
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
psets = ifcopenshell.util.element.get_psets(ifc_element)
for prop in props:
pset = prop.pset_name
if pset in psets:
try:
ifcopenshell.api.run(
"pset.remove_pset",
self.file,
**{
"product": self.file.by_id(ifc_definition_id),
"pset": self.file.by_id(psets[pset]["id"]),
},
)
except KeyError:
pass #Sometimes the pset id is not found, I'm not sure why this happens though. - vulevukusej
Data.load(IfcStore.get_file(), ifc_definition_id)
self.report({'INFO'}, 'Finished applying changes')
return {"FINISHED"}
@@ -18,7 +18,8 @@
import bpy import bpy
import blenderbim.bim.schema import blenderbim.bim.schema
from blenderbim.bim.prop import Attribute from blenderbim.bim.prop import Attribute, PRIMARY_MEASURE_TYPE
import ifcopenshell
from ifcopenshell.api.pset.data import Data from ifcopenshell.api.pset.data import Data
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -173,3 +174,42 @@ class WorkSchedulePsetProperties(PropertyGroup):
active_pset_name: StringProperty(name="Pset Name") active_pset_name: StringProperty(name="Pset Name")
properties: CollectionProperty(name="Properties", type=Attribute) properties: CollectionProperty(name="Properties", type=Attribute)
pset_name: EnumProperty(items=getWorkSchedulePsetNames, name="Pset Name") pset_name: EnumProperty(items=getWorkSchedulePsetNames, name="Pset Name")
class RenameProperties(PropertyGroup):
pset_name: StringProperty(name="Pset")
existing_property_name: StringProperty(name="Existing Property Name")
new_property_name: StringProperty(name="New Property Name")
class AddEditProperties(PropertyGroup):
pset_name: StringProperty(name="Pset")
property_name: StringProperty(name="Property")
string_value: StringProperty(name="Value")
bool_value: BoolProperty(name="Value")
int_value: IntProperty(name="Value")
float_value: FloatProperty(name="Value")
primary_measure_type: EnumProperty(
items=[
(x, x, "")
for x in PRIMARY_MEASURE_TYPE
],
default="IfcLabel",
name="Primary Measure Type"
)
def get_value_name(self):
ifc_data_type = IfcStore.get_schema().declaration_by_name(self.primary_measure_type)
data_type = ifcopenshell.util.attribute.get_primitive_type(ifc_data_type)
if data_type == "string":
return "string_value"
elif data_type == "boolean":
return "bool_value"
elif data_type == "integer":
return "int_value"
elif data_type == "float":
return "float_value"
class DeletePsets(PropertyGroup):
pset_name: StringProperty(name="Pset")
@@ -375,3 +375,117 @@ class BIM_PT_work_schedule_psets(Panel):
for pset in WorkSchedulePsetsData.data["psets"]: for pset in WorkSchedulePsetsData.data["psets"]:
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "WorkSchedule") draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "WorkSchedule")
class BIM_PT_bulk_property_editor(Panel):
bl_label = "IFC Bulk Property Editor"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
def draw(self, context):
pass
class BIM_PT_rename_parameters(Panel):
bl_label = "Rename all building elements"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_parent_id = "BIM_PT_bulk_property_editor"
bl_options = {"DEFAULT_CLOSED"}
bl_order = 0
def draw(self, context):
layout = self.layout
props = context.scene.RenameProperties
if props:
for index, prop in enumerate(props):
row = layout.row()
row.prop(prop, "pset_name", text="")
row.prop(prop, "existing_property_name", text="")
row.prop(prop, "new_property_name", text="")
op = row.operator("bim.remove_property_to_edit",icon="PANEL_CLOSE", text="")
op.index = index
op.option = "RenameProperties"
row = layout.row()
row.label()
op = row.operator("bim.add_property_to_edit", icon="ADD",text="")
op.option = "RenameProperties"
if props:
row = layout.row()
clear = row.operator("bim.clear_list")
clear.option = "RenameProperties"
row.operator("bim.rename_parameters")
class BIM_PT_add_edit_custom_properties(Panel):
bl_label = "Add/Edit Custom Properties and Values (to selected objects)"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_parent_id = "BIM_PT_bulk_property_editor"
bl_options = {"DEFAULT_CLOSED"}
bl_order = 1
def draw(self, context):
layout = self.layout
props = context.scene.AddEditProperties
if props:
for index, prop in enumerate(props):
row = layout.row()
row.prop(prop, "pset_name", text="")
row.prop(prop, "property_name", text="")
row.prop(prop, prop.get_value_name(), text="")
row.prop(prop, "primary_measure_type", text="")
op = row.operator("bim.remove_property_to_edit",icon="PANEL_CLOSE", text="")
op.index = index
op.option = "AddEditProperties"
row = layout.row()
row.label()
op = row.operator("bim.add_property_to_edit", icon="ADD",text="")
op.option = "AddEditProperties"
if props:
row = layout.row()
clear = row.operator("bim.clear_list")
clear.option = "AddEditProperties"
op = row.operator("bim.add_edit_custom_property",icon="ADD", text="Apply Changes")
class BIM_PT_delete_psets(Panel):
bl_label = "Bulk remove psets from selected objects"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_parent_id = "BIM_PT_bulk_property_editor"
bl_options = {"DEFAULT_CLOSED"}
bl_order = 2
def draw(self, context):
layout = self.layout
props = context.scene.DeletePsets
if props:
for index, prop in enumerate(props):
row = layout.row()
row.prop(prop, "pset_name", text="Pset")
op = row.operator("bim.remove_property_to_edit",icon="PANEL_CLOSE", text="")
op.index = index
op.option = "DeletePsets"
row = layout.row(align=True)
row.label()
op = row.operator("bim.add_property_to_edit", icon="ADD",text="")
op.option = "DeletePsets"
if props:
row = layout.row()
clear = row.operator("bim.clear_list")
clear.option = "DeletePsets"
op = row.operator("bim.bulk_remove_psets", text="Apply Changes")
@@ -19,7 +19,7 @@
import os import os
import bpy import bpy
import ifcopenshell import ifcopenshell
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute, PRIMARY_MEASURE_TYPE
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
@@ -146,116 +146,7 @@ class PropTemplate(PropertyGroup):
primary_measure_type: EnumProperty( primary_measure_type: EnumProperty(
items=[ items=[
(x, x, "") (x, x, "")
for x in [ for x in PRIMARY_MEASURE_TYPE
"IfcInteger",
"IfcReal",
"IfcBoolean",
"IfcIdentifier",
"IfcText",
"IfcLabel",
"IfcLogical",
"IfcDateTime",
"IfcDate",
"IfcTime",
"IfcDuration",
"IfcTimeStamp",
"IfcPositiveInteger",
"IfcBinary",
"IfcVolumeMeasure",
"IfcTimeMeasure",
"IfcThermodynamicTemperatureMeasure",
"IfcSolidAngleMeasure",
"IfcPositiveRatioMeasure",
"IfcRatioMeasure",
"IfcPositivePlaneAngleMeasure",
"IfcPlaneAngleMeasure",
"IfcParameterValue",
"IfcNumericMeasure",
"IfcMassMeasure",
"IfcPositiveLengthMeasure",
"IfcLengthMeasure",
"IfcElectricCurrentMeasure",
"IfcDescriptiveMeasure",
"IfcCountMeasure",
"IfcContextDependentMeasure",
"IfcAreaMeasure",
"IfcAmountOfSubstanceMeasure",
"IfcLuminousIntensityMeasure",
"IfcNormalisedRatioMeasure",
"IfcComplexNumber",
"IfcNonNegativeLengthMeasure",
"IfcAbsorbedDoseMeasure",
"IfcAccelerationMeasure",
"IfcAngularVelocityMeasure",
"IfcAreaDensityMeasure",
"IfcCompoundPlaneAngleMeasure",
"IfcCurvatureMeasure",
"IfcDoseEquivalentMeasure",
"IfcDynamicViscosityMeasure",
"IfcElectricCapacitanceMeasure",
"IfcElectricChargeMeasure",
"IfcElectricConductanceMeasure",
"IfcElectricResistanceMeasure",
"IfcElectricVoltageMeasure",
"IfcEnergyMeasure",
"IfcForceMeasure",
"IfcFrequencyMeasure",
"IfcHeatFluxDensityMeasure",
"IfcHeatingValueMeasure",
"IfcIlluminanceMeasure",
"IfcInductanceMeasure",
"IfcIntegerCountRateMeasure",
"IfcIonConcentrationMeasure",
"IfcIsothermalMoistureCapacityMeasure",
"IfcKinematicViscosityMeasure",
"IfcLinearForceMeasure",
"IfcLinearMomentMeasure",
"IfcLinearStiffnessMeasure",
"IfcLinearVelocityMeasure",
"IfcLuminousFluxMeasure",
"IfcLuminousIntensityDistributionMeasure",
"IfcMagneticFluxDensityMeasure",
"IfcMagneticFluxMeasure",
"IfcMassDensityMeasure",
"IfcMassFlowRateMeasure",
"IfcMassPerLengthMeasure",
"IfcModulusOfElasticityMeasure",
"IfcModulusOfLinearSubgradeReactionMeasure",
"IfcModulusOfRotationalSubgradeReactionMeasure",
"IfcModulusOfSubgradeReactionMeasure",
"IfcMoistureDiffusivityMeasure",
"IfcMolecularWeightMeasure",
"IfcMomentOfInertiaMeasure",
"IfcMonetaryMeasure",
"IfcPHMeasure",
"IfcPlanarForceMeasure",
"IfcPowerMeasure",
"IfcPressureMeasure",
"IfcRadioActivityMeasure",
"IfcRotationalFrequencyMeasure",
"IfcRotationalMassMeasure",
"IfcRotationalStiffnessMeasure",
"IfcSectionModulusMeasure",
"IfcSectionalAreaIntegralMeasure",
"IfcShearModulusMeasure",
"IfcSoundPowerLevelMeasure",
"IfcSoundPowerMeasure",
"IfcSoundPressureLevelMeasure",
"IfcSoundPressureMeasure",
"IfcSpecificHeatCapacityMeasure",
"IfcTemperatureGradientMeasure",
"IfcTemperatureRateOfChangeMeasure",
"IfcThermalAdmittanceMeasure",
"IfcThermalConductivityMeasure",
"IfcThermalExpansionCoefficientMeasure",
"IfcThermalResistanceMeasure",
"IfcThermalTransmittanceMeasure",
"IfcTorqueMeasure",
"IfcVaporPermeabilityMeasure",
"IfcVolumetricFlowRateMeasure",
"IfcWarpingConstantMeasure",
"IfcWarpingMomentMeasure",
]
], ],
name="Primary Measure Type", name="Primary Measure Type",
) )
+111
View File
@@ -40,6 +40,117 @@ cwd = os.path.dirname(os.path.realpath(__file__))
materialpsetnames_enum = [] materialpsetnames_enum = []
PRIMARY_MEASURE_TYPE = [
"IfcInteger",
"IfcReal",
"IfcBoolean",
"IfcIdentifier",
"IfcText",
"IfcLabel",
"IfcLogical",
"IfcDateTime",
"IfcDate",
"IfcTime",
"IfcDuration",
"IfcTimeStamp",
"IfcPositiveInteger",
"IfcBinary",
"IfcVolumeMeasure",
"IfcTimeMeasure",
"IfcThermodynamicTemperatureMeasure",
"IfcSolidAngleMeasure",
"IfcPositiveRatioMeasure",
"IfcRatioMeasure",
"IfcPositivePlaneAngleMeasure",
"IfcPlaneAngleMeasure",
"IfcParameterValue",
"IfcNumericMeasure",
"IfcMassMeasure",
"IfcPositiveLengthMeasure",
"IfcLengthMeasure",
"IfcElectricCurrentMeasure",
"IfcDescriptiveMeasure",
"IfcCountMeasure",
"IfcContextDependentMeasure",
"IfcAreaMeasure",
"IfcAmountOfSubstanceMeasure",
"IfcLuminousIntensityMeasure",
"IfcNormalisedRatioMeasure",
"IfcComplexNumber",
"IfcNonNegativeLengthMeasure",
"IfcAbsorbedDoseMeasure",
"IfcAccelerationMeasure",
"IfcAngularVelocityMeasure",
"IfcAreaDensityMeasure",
"IfcCompoundPlaneAngleMeasure",
"IfcCurvatureMeasure",
"IfcDoseEquivalentMeasure",
"IfcDynamicViscosityMeasure",
"IfcElectricCapacitanceMeasure",
"IfcElectricChargeMeasure",
"IfcElectricConductanceMeasure",
"IfcElectricResistanceMeasure",
"IfcElectricVoltageMeasure",
"IfcEnergyMeasure",
"IfcForceMeasure",
"IfcFrequencyMeasure",
"IfcHeatFluxDensityMeasure",
"IfcHeatingValueMeasure",
"IfcIlluminanceMeasure",
"IfcInductanceMeasure",
"IfcIntegerCountRateMeasure",
"IfcIonConcentrationMeasure",
"IfcIsothermalMoistureCapacityMeasure",
"IfcKinematicViscosityMeasure",
"IfcLinearForceMeasure",
"IfcLinearMomentMeasure",
"IfcLinearStiffnessMeasure",
"IfcLinearVelocityMeasure",
"IfcLuminousFluxMeasure",
"IfcLuminousIntensityDistributionMeasure",
"IfcMagneticFluxDensityMeasure",
"IfcMagneticFluxMeasure",
"IfcMassDensityMeasure",
"IfcMassFlowRateMeasure",
"IfcMassPerLengthMeasure",
"IfcModulusOfElasticityMeasure",
"IfcModulusOfLinearSubgradeReactionMeasure",
"IfcModulusOfRotationalSubgradeReactionMeasure",
"IfcModulusOfSubgradeReactionMeasure",
"IfcMoistureDiffusivityMeasure",
"IfcMolecularWeightMeasure",
"IfcMomentOfInertiaMeasure",
"IfcMonetaryMeasure",
"IfcPHMeasure",
"IfcPlanarForceMeasure",
"IfcPowerMeasure",
"IfcPressureMeasure",
"IfcRadioActivityMeasure",
"IfcRotationalFrequencyMeasure",
"IfcRotationalMassMeasure",
"IfcRotationalStiffnessMeasure",
"IfcSectionModulusMeasure",
"IfcSectionalAreaIntegralMeasure",
"IfcShearModulusMeasure",
"IfcSoundPowerLevelMeasure",
"IfcSoundPowerMeasure",
"IfcSoundPressureLevelMeasure",
"IfcSoundPressureMeasure",
"IfcSpecificHeatCapacityMeasure",
"IfcTemperatureGradientMeasure",
"IfcTemperatureRateOfChangeMeasure",
"IfcThermalAdmittanceMeasure",
"IfcThermalConductivityMeasure",
"IfcThermalExpansionCoefficientMeasure",
"IfcThermalResistanceMeasure",
"IfcThermalTransmittanceMeasure",
"IfcTorqueMeasure",
"IfcVaporPermeabilityMeasure",
"IfcVolumetricFlowRateMeasure",
"IfcWarpingConstantMeasure",
"IfcWarpingMomentMeasure",
]
def update_preset(self, context): def update_preset(self, context):
from blenderbim.bim.data.ui.presets import presets from blenderbim.bim.data.ui.presets import presets