WIP move the IFC Debug code into its own module. See #1222.

This commit is contained in:
Dion Moult
2021-01-08 13:49:31 +11:00
parent 0dcdfcf46c
commit 53de93e582
8 changed files with 266 additions and 228 deletions
@@ -11,6 +11,7 @@ if bpy is not None:
import blenderbim.bim.module.bcf as module_bcf
import blenderbim.bim.module.context as module_context
import blenderbim.bim.module.covetool as module_covetool
import blenderbim.bim.module.debug as module_debug
import blenderbim.bim.module.geometry as module_geometry
import blenderbim.bim.module.model as module_model
import blenderbim.bim.module.project as module_project
@@ -35,7 +36,6 @@ if bpy is not None:
operator.ValidateIfcFile,
operator.ExportIFC,
operator.ImportIFC,
operator.ProfileImportIFC,
operator.ColourByClass,
operator.ColourByAttribute,
operator.ColourByPset,
@@ -200,11 +200,6 @@ if bpy is not None:
operator.RemoveDrawingStyleAttribute,
operator.CopyPropertyToSelection,
operator.CopyAttributeToSelection,
operator.CreateShapeFromStepId,
operator.SelectHighPolygonMeshes,
operator.InspectFromStepId,
operator.InspectFromObject,
operator.RewindInspector,
operator.RefreshDrawingList,
operator.SetBlenderClashSetA,
operator.SetBlenderClashSetB,
@@ -241,7 +236,6 @@ if bpy is not None:
prop.Sheet,
prop.PresentationLayer,
prop.BIMProperties,
prop.BIMDebugProperties,
prop.DocProperties,
prop.BIMLibrary,
prop.MapConversion,
@@ -281,7 +275,6 @@ if bpy is not None:
ui.BIM_PT_cobie,
ui.BIM_PT_patch,
ui.BIM_PT_mvd,
ui.BIM_PT_debug,
ui.BIM_PT_material,
ui.BIM_PT_presentation_layer_data,
ui.BIM_PT_object_material,
@@ -315,6 +308,7 @@ if bpy is not None:
classes.extend(module_bcf.classes)
classes.extend(module_context.classes)
classes.extend(module_covetool.classes)
classes.extend(module_debug.classes)
classes.extend(module_geometry.classes)
classes.extend(module_model.classes)
classes.extend(module_project.classes)
@@ -342,7 +336,6 @@ if bpy is not None:
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Scene.BIMDebugProperties = bpy.props.PointerProperty(type=prop.BIMDebugProperties)
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
bpy.types.Scene.BIMLibrary = bpy.props.PointerProperty(type=prop.BIMLibrary)
bpy.types.Scene.MapConversion = bpy.props.PointerProperty(type=prop.MapConversion)
@@ -360,6 +353,7 @@ if bpy is not None:
module_bcf.register()
module_context.register()
module_covetool.register()
module_debug.register()
module_geometry.register()
module_model.register()
module_project.register()
@@ -378,7 +372,6 @@ if bpy is not None:
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
del bpy.types.Scene.BIMProperties
del bpy.types.Scene.BIMDebugProperties
del bpy.types.Scene.DocProperties
del bpy.types.Scene.MapConversion
del bpy.types.Scene.TargetCRS
@@ -397,6 +390,7 @@ if bpy is not None:
module_project.unregister()
module_model.unregister()
module_geometry.unregister()
module_debug.unregister()
module_covetool.unregister()
module_context.unregister()
module_bcf.unregister()
@@ -0,0 +1,21 @@
import bpy
from . import ui, prop, operator
classes = (
operator.ProfileImportIFC,
operator.CreateShapeFromStepId,
operator.SelectHighPolygonMeshes,
operator.InspectFromStepId,
operator.InspectFromObject,
operator.RewindInspector,
prop.BIMDebugProperties,
ui.BIM_PT_debug,
)
def register():
bpy.types.Scene.BIMDebugProperties = bpy.props.PointerProperty(type=prop.BIMDebugProperties)
def unregister():
del bpy.types.Scene.BIMDebugProperties
@@ -0,0 +1,133 @@
import bpy
import logging
import ifcopenshell
import blenderbim.bim.import_ifc as import_ifc
from blenderbim.bim.ifc import IfcStore
class ProfileImportIFC(bpy.types.Operator):
bl_idname = "bim.profile_import_ifc"
bl_label = "Profile Import IFC"
def execute(self, context):
import cProfile
import pstats
cProfile.run(
f"import bpy; bpy.ops.import_ifc.bim(filepath='{bpy.context.scene.BIMProperties.ifc_file}')", "blender.prof"
)
p = pstats.Stats("blender.prof")
p.sort_stats("cumulative").print_stats(50)
return {"FINISHED"}
class CreateShapeFromStepId(bpy.types.Operator):
bl_idname = "bim.create_shape_from_step_id"
bl_label = "Create Shape From STEP ID"
def execute(self, context):
logger = logging.getLogger("ImportIFC")
self.ifc_import_settings = import_ifc.IfcImportSettings.factory(bpy.context, IfcStore.path, logger)
self.file = IfcStore.get_file()
element = self.file.by_id(int(bpy.context.scene.BIMDebugProperties.step_id))
settings = ifcopenshell.geom.settings()
# settings.set(settings.INCLUDE_CURVES, True)
shape = ifcopenshell.geom.create_shape(settings, element)
ifc_importer = import_ifc.IfcImporter(self.ifc_import_settings)
ifc_importer.file = self.file
mesh = ifc_importer.create_mesh(element, shape)
obj = bpy.data.objects.new("Debug", mesh)
bpy.context.scene.collection.objects.link(obj)
return {"FINISHED"}
class SelectHighPolygonMeshes(bpy.types.Operator):
bl_idname = "bim.select_high_polygon_meshes"
bl_label = "Select High Polygon Meshes"
def execute(self, context):
results = {}
for obj in bpy.data.objects:
if not isinstance(obj.data, bpy.types.Mesh) or len(obj.data.polygons) < int(
bpy.context.scene.BIMDebugProperties.number_of_polygons
):
continue
try:
obj.select_set(True)
except:
# If it is not in the view layer
pass
relating_type = obj.BIMObjectProperties.relating_type
if relating_type:
relating_type.select_set(True)
return {"FINISHED"}
class RewindInspector(bpy.types.Operator):
bl_idname = "bim.rewind_inspector"
bl_label = "Rewind Inspector"
def execute(self, context):
props = bpy.context.scene.BIMDebugProperties
total_breadcrumbs = len(props.step_id_breadcrumb)
if total_breadcrumbs < 2:
return {"FINISHED"}
previous_step_id = int(props.step_id_breadcrumb[total_breadcrumbs - 2].name)
props.step_id_breadcrumb.remove(total_breadcrumbs - 1)
props.step_id_breadcrumb.remove(total_breadcrumbs - 2)
bpy.ops.bim.inspect_from_step_id(step_id=previous_step_id)
return {"FINISHED"}
class InspectFromStepId(bpy.types.Operator):
bl_idname = "bim.inspect_from_step_id"
bl_label = "Inspect From STEP ID"
step_id: bpy.props.IntProperty()
def execute(self, context):
self.file = IfcStore.get_file()
bpy.context.scene.BIMDebugProperties.active_step_id = self.step_id
crumb = bpy.context.scene.BIMDebugProperties.step_id_breadcrumb.add()
crumb.name = str(self.step_id)
element = self.file.by_id(self.step_id)
while len(bpy.context.scene.BIMDebugProperties.attributes) > 0:
bpy.context.scene.BIMDebugProperties.attributes.remove(0)
while len(bpy.context.scene.BIMDebugProperties.inverse_attributes) > 0:
bpy.context.scene.BIMDebugProperties.inverse_attributes.remove(0)
for key, value in element.get_info().items():
self.add_attribute(bpy.context.scene.BIMDebugProperties.attributes, key, value)
for key in dir(element):
if (
not key[0].isalpha()
or key[0] != key[0].upper()
or key in element.get_info()
or not getattr(element, key)
):
continue
self.add_attribute(bpy.context.scene.BIMDebugProperties.inverse_attributes, key, getattr(element, key))
return {"FINISHED"}
def add_attribute(self, prop, key, value):
if isinstance(value, tuple) and len(value) < 10:
for i, item in enumerate(value):
self.add_attribute(prop, key + f"[{i}]", item)
return
elif isinstance(value, tuple) and len(value) >= 10:
key = key + "({})".format(len(value))
new = prop.add()
new.name = key
new.string_value = str(value)
if isinstance(value, ifcopenshell.entity_instance):
new.int_value = int(value.id())
class InspectFromObject(bpy.types.Operator):
bl_idname = "bim.inspect_from_object"
bl_label = "Inspect From Object"
def execute(self, context):
ifc_definition_id = bpy.context.active_object.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
return {"FINISHED"}
bpy.ops.bim.inspect_from_step_id(step_id=ifc_definition_id)
return {"FINISHED"}
@@ -0,0 +1,21 @@
from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
class BIMDebugProperties(PropertyGroup):
step_id: IntProperty(name="STEP ID")
number_of_polygons: IntProperty(name="Number of Polygons")
active_step_id: IntProperty(name="STEP ID")
step_id_breadcrumb: CollectionProperty(name="STEP ID Breadcrumb", type=StrProperty)
attributes: CollectionProperty(name="Attributes", type=Attribute)
inverse_attributes: CollectionProperty(name="Inverse Attributes", type=Attribute)
@@ -0,0 +1,64 @@
import bpy
from bpy.types import Panel
class BIM_PT_debug(Panel):
bl_label = "IFC Debug"
bl_idname = "BIM_PT_debug"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
props = scene.BIMDebugProperties
row = layout.row()
row.operator("bim.profile_import_ifc")
row = layout.row()
row.prop(props, "step_id", text="")
row = layout.row()
row.operator("bim.create_shape_from_step_id")
row = layout.row()
row.prop(props, "number_of_polygons", text="")
row = layout.row()
row.operator("bim.select_high_polygon_meshes")
layout.label(text="Inspector:")
row = layout.row(align=True)
if len(props.step_id_breadcrumb) >= 2:
row.operator("bim.rewind_inspector", icon="FRAME_PREV", text="")
row.prop(props, "active_step_id", text="")
row = layout.row(align=True)
row.operator("bim.inspect_from_step_id").step_id = bpy.context.scene.BIMDebugProperties.active_step_id
row.operator("bim.inspect_from_object")
if props.attributes:
layout.label(text="Direct attributes:")
for index, attribute in enumerate(props.attributes):
row = layout.row(align=True)
row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
if props.inverse_attributes:
layout.label(text="Inverse attributes:")
for index, attribute in enumerate(props.inverse_attributes):
row = layout.row(align=True)
row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
+23 -147
View File
@@ -140,19 +140,6 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
return {"FINISHED"}
class ProfileImportIFC(bpy.types.Operator):
bl_idname = "bim.profile_import_ifc"
bl_label = "Profile Import IFC"
def execute(self, context):
import cProfile
import pstats
cProfile.run(f"import bpy; bpy.ops.import_ifc.bim(filepath='{bpy.context.scene.BIMProperties.ifc_file}')", "blender.prof")
p = pstats.Stats("blender.prof")
p.sort_stats("cumulative").print_stats(50)
return {"FINISHED"}
class SelectGlobalId(bpy.types.Operator):
bl_idname = "bim.select_global_id"
bl_label = "Select GlobalId"
@@ -1380,8 +1367,9 @@ class ExecuteIfcClash(bpy.types.Operator):
ifc_clasher = ifcclash.IfcClasher(settings)
if bpy.context.scene.BIMProperties.should_create_clash_snapshots:
def get_viewpoint_snapshot(self, viewpoint, mat):
camera = bpy.data.objects.get('IFC Clash Camera')
camera = bpy.data.objects.get("IFC Clash Camera")
if not camera:
camera = bpy.data.objects.new("IFC Clash Camera", bpy.data.cameras.new("IFC Clash Camera"))
bpy.context.scene.collection.objects.link(camera)
@@ -1394,7 +1382,9 @@ class ExecuteIfcClash(bpy.types.Operator):
bpy.context.scene.render.resolution_x = 480
bpy.context.scene.render.resolution_y = 270
bpy.context.scene.render.image_settings.file_format = "PNG"
bpy.context.scene.render.filepath = os.path.join(bpy.context.scene.BIMProperties.data_dir, "snapshot.png")
bpy.context.scene.render.filepath = os.path.join(
bpy.context.scene.BIMProperties.data_dir, "snapshot.png"
)
bpy.ops.render.opengl(write_still=True)
return bpy.context.scene.render.filepath
@@ -2095,7 +2085,9 @@ class CutSection(bpy.types.Operator):
def does_obj_have_target_view_representation(self, obj, camera):
for representation in obj.BIMObjectProperties.representations:
element = self.file.by_id(representation.ifc_definition_id)
if ifcopenshell.util.element.is_representation_of_context(element, "Plan", "Annotation", camera.data.BIMCameraProperties.target_view):
if ifcopenshell.util.element.is_representation_of_context(
element, "Plan", "Annotation", camera.data.BIMCameraProperties.target_view
):
return True
def is_landscape(self):
@@ -2844,7 +2836,7 @@ class AddAnnotation(bpy.types.Operator):
obj = annotation.Annotator.add_text()
else:
obj = annotation.Annotator.get_annotation_obj(self.obj_name, self.data_type)
if self.obj_name == 'Break':
if self.obj_name == "Break":
obj = annotation.Annotator.add_plane_to_annotation(obj)
else:
obj = annotation.Annotator.add_line_to_annotation(obj)
@@ -3785,118 +3777,6 @@ class RemoveDrawingStyleAttribute(bpy.types.Operator):
return {"FINISHED"}
class CreateShapeFromStepId(bpy.types.Operator):
bl_idname = "bim.create_shape_from_step_id"
bl_label = "Create Shape From STEP ID"
def execute(self, context):
logger = logging.getLogger("ImportIFC")
self.ifc_import_settings = import_ifc.IfcImportSettings.factory(bpy.context, ifc.IfcStore.path, logger)
self.file = ifc.IfcStore.get_file()
element = self.file.by_id(int(bpy.context.scene.BIMDebugProperties.step_id))
settings = ifcopenshell.geom.settings()
# settings.set(settings.INCLUDE_CURVES, True)
shape = ifcopenshell.geom.create_shape(settings, element)
ifc_importer = import_ifc.IfcImporter(self.ifc_import_settings)
ifc_importer.file = self.file
mesh = ifc_importer.create_mesh(element, shape)
obj = bpy.data.objects.new("Debug", mesh)
bpy.context.scene.collection.objects.link(obj)
return {"FINISHED"}
class SelectHighPolygonMeshes(bpy.types.Operator):
bl_idname = "bim.select_high_polygon_meshes"
bl_label = "Select High Polygon Meshes"
def execute(self, context):
results = {}
for obj in bpy.data.objects:
if not isinstance(obj.data, bpy.types.Mesh) or len(obj.data.polygons) < int(
bpy.context.scene.BIMDebugProperties.number_of_polygons
):
continue
try:
obj.select_set(True)
except:
# If it is not in the view layer
pass
relating_type = obj.BIMObjectProperties.relating_type
if relating_type:
relating_type.select_set(True)
return {"FINISHED"}
class InspectFromStepId(bpy.types.Operator):
bl_idname = "bim.inspect_from_step_id"
bl_label = "Inspect From STEP ID"
step_id: bpy.props.IntProperty()
def execute(self, context):
self.file = ifc.IfcStore.get_file()
bpy.context.scene.BIMDebugProperties.active_step_id = self.step_id
crumb = bpy.context.scene.BIMDebugProperties.step_id_breadcrumb.add()
crumb.name = str(self.step_id)
element = self.file.by_id(self.step_id)
while len(bpy.context.scene.BIMDebugProperties.attributes) > 0:
bpy.context.scene.BIMDebugProperties.attributes.remove(0)
while len(bpy.context.scene.BIMDebugProperties.inverse_attributes) > 0:
bpy.context.scene.BIMDebugProperties.inverse_attributes.remove(0)
for key, value in element.get_info().items():
self.add_attribute(bpy.context.scene.BIMDebugProperties.attributes, key, value)
for key in dir(element):
if (
not key[0].isalpha()
or key[0] != key[0].upper()
or key in element.get_info()
or not getattr(element, key)
):
continue
self.add_attribute(bpy.context.scene.BIMDebugProperties.inverse_attributes, key, getattr(element, key))
return {"FINISHED"}
def add_attribute(self, prop, key, value):
if isinstance(value, tuple) and len(value) < 10:
for i, item in enumerate(value):
self.add_attribute(prop, key + f"[{i}]", item)
return
elif isinstance(value, tuple) and len(value) >= 10:
key = key + "({})".format(len(value))
new = prop.add()
new.name = key
new.string_value = str(value)
if isinstance(value, ifcopenshell.entity_instance):
new.int_value = int(value.id())
class InspectFromObject(bpy.types.Operator):
bl_idname = "bim.inspect_from_object"
bl_label = "Inspect From Object"
def execute(self, context):
ifc_definition_id = bpy.context.active_object.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
return {"FINISHED"}
bpy.ops.bim.inspect_from_step_id(step_id=ifc_definition_id)
return {"FINISHED"}
class RewindInspector(bpy.types.Operator):
bl_idname = "bim.rewind_inspector"
bl_label = "Rewind Inspector"
def execute(self, context):
props = bpy.context.scene.BIMDebugProperties
total_breadcrumbs = len(props.step_id_breadcrumb)
if total_breadcrumbs < 2:
return {"FINISHED"}
previous_step_id = int(props.step_id_breadcrumb[total_breadcrumbs - 2].name)
props.step_id_breadcrumb.remove(total_breadcrumbs - 1)
props.step_id_breadcrumb.remove(total_breadcrumbs - 2)
bpy.ops.bim.inspect_from_step_id(step_id=previous_step_id)
return {"FINISHED"}
class RefreshDrawingList(bpy.types.Operator):
bl_idname = "bim.refresh_drawing_list"
bl_label = "Refresh Drawing List"
@@ -4019,8 +3899,8 @@ class LinkIfc(bpy.types.Operator):
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
#bpy.context.active_object.active_material.BIMMaterialProperties.location = self.filepath
#coll_name = "MyCollection"
# bpy.context.active_object.active_material.BIMMaterialProperties.location = self.filepath
# coll_name = "MyCollection"
with bpy.data.libraries.load(self.filepath, link=True) as (data_from, data_to):
data_to.scenes = data_from.scenes
@@ -4056,11 +3936,7 @@ class SnapSpacesTogether(bpy.types.Operator):
for obj2 in bpy.context.selected_objects:
if obj2 == obj or obj.type != "MESH":
continue
result = obj2.ray_cast(
obj2.matrix_world.inverted() @ center,
polygon.normal,
distance=threshold
)
result = obj2.ray_cast(obj2.matrix_world.inverted() @ center, polygon.normal, distance=threshold)
if not result[0]:
continue
hit = obj2.matrix_world @ result[1]
@@ -4089,7 +3965,7 @@ class SnapSpacesTogether(bpy.types.Operator):
class CopyGrid(bpy.types.Operator):
bl_idname = "bim.add_grid"
bl_label = "Add Grid"
bl_options = {'UNDO'}
bl_options = {"UNDO"}
def execute(self, context):
props = context.scene.DocProperties
@@ -4098,20 +3974,20 @@ class CopyGrid(bpy.types.Operator):
drawing = props.drawings[props.active_drawing_index]
collection = bpy.data.collections.get("IfcGroup/" + drawing.name)
existing = [obj for obj in collection.objects if obj.name.startswith('IfcGridAxis')]
existing = [obj for obj in collection.objects if obj.name.startswith("IfcGridAxis")]
for obj in existing:
collection.objects.unlink(obj)
source = [obj
for coll in bpy.data.collections
if coll.name.startswith("IfcGrid")
for obj in coll.all_objects
if obj.name.startswith("IfcGridAxis")]
camera = [obj
for obj in collection.all_objects
if obj.type == 'CAMERA'][0]
source = [
obj
for coll in bpy.data.collections
if coll.name.startswith("IfcGrid")
for obj in coll.all_objects
if obj.name.startswith("IfcGridAxis")
]
camera = [obj for obj in collection.all_objects if obj.type == "CAMERA"][0]
clipping = camera.data.type == 'ORTHO'
clipping = camera.data.type == "ORTHO"
bounds = helper.ortho_view_frame(camera.data) if clipping else None
for src in source:
@@ -1510,15 +1510,6 @@ class BIMObjectProperties(PropertyGroup):
address: PointerProperty(name="Address", type=Address)
class BIMDebugProperties(PropertyGroup):
step_id: IntProperty(name="STEP ID")
number_of_polygons: IntProperty(name="Number of Polygons")
active_step_id: IntProperty(name="STEP ID")
step_id_breadcrumb: CollectionProperty(name="STEP ID Breadcrumb", type=StrProperty)
attributes: CollectionProperty(name="Attributes", type=Attribute)
inverse_attributes: CollectionProperty(name="Inverse Attributes", type=Attribute)
class BIMMaterialProperties(PropertyGroup):
is_external: BoolProperty(name="Has External Definition")
location: StringProperty(name="Location")
-62
View File
@@ -2033,68 +2033,6 @@ class BIM_PT_misc_utilities(Panel):
row.operator("bim.snap_spaces_together")
class BIM_PT_debug(Panel):
bl_label = "IFC Debug"
bl_idname = "BIM_PT_debug"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
props = scene.BIMDebugProperties
row = layout.row()
row.operator("bim.profile_import_ifc")
row = layout.row()
row.prop(props, "step_id", text="")
row = layout.row()
row.operator("bim.create_shape_from_step_id")
row = layout.row()
row.prop(props, "number_of_polygons", text="")
row = layout.row()
row.operator("bim.select_high_polygon_meshes")
layout.label(text="Inspector:")
row = layout.row(align=True)
if len(props.step_id_breadcrumb) >= 2:
row.operator("bim.rewind_inspector", icon="FRAME_PREV", text="")
row.prop(props, "active_step_id", text="")
row = layout.row(align=True)
row.operator("bim.inspect_from_step_id").step_id = bpy.context.scene.BIMDebugProperties.active_step_id
row.operator("bim.inspect_from_object")
if props.attributes:
layout.label(text="Direct attributes:")
for index, attribute in enumerate(props.attributes):
row = layout.row(align=True)
row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
if props.inverse_attributes:
layout.label(text="Inverse attributes:")
for index, attribute in enumerate(props.inverse_attributes):
row = layout.row(align=True)
row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
def ifc_units(self, context):
scene = context.scene
props = context.scene.BIMProperties