Skip to content

Commit 276a488

Browse files
authored
Merge pull request #7509 from falken10vdl/Improve-saving-metadata.blend-file
Refactor SaveBlendMetadataFile to improve speed and IFC data cleanup
2 parents 45de750 + 9a1b0ce commit 276a488

1 file changed

Lines changed: 54 additions & 57 deletions

File tree

src/bonsai/bonsai/bim/operator.py

Lines changed: 54 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -269,77 +269,74 @@ def execute(self, context):
269269
cleanup_script = f"""
270270
import bpy
271271
272-
def remove_ifc_collections():
273-
\"\"\"Remove all collections that start with 'IfcProject' and their contents.\"\"\"
274-
collections_to_remove = []
275-
276-
# Find all IfcProject collections
277-
for collection in bpy.data.collections:
278-
if collection.name.startswith('IfcProject'):
279-
collections_to_remove.append(collection)
280-
281-
# First, use bim.override_outliner_delete to properly remove IFC data
282-
for collection in collections_to_remove:
283-
# Collect all objects in the collection and its children
284-
objects_to_delete = []
285-
286-
def collect_objects(col):
287-
for obj in col.objects:
288-
if obj not in objects_to_delete:
289-
objects_to_delete.append(obj)
290-
for child in col.children:
291-
collect_objects(child)
292-
293-
collect_objects(collection)
294-
295-
# Use bim.override_outliner_delete for each object to clean up IFC data
296-
for obj in objects_to_delete:
297-
# Select only this object
298-
bpy.ops.object.select_all(action='DESELECT')
299-
obj.select_set(True)
300-
bpy.context.view_layer.objects.active = obj
301-
302-
# Try to use Bonsai's delete operator which cleans up IFC data
303-
try:
304-
bpy.ops.bim.override_outliner_delete()
305-
except:
306-
# If that fails, use standard delete
307-
bpy.data.objects.remove(obj, do_unlink=True)
308-
309-
# Remove any remaining child collections
310-
for child in list(collection.children):
311-
try:
312-
bpy.data.collections.remove(child, do_unlink=True)
313-
except:
314-
pass
315-
316-
# Remove the IfcProject collections themselves
317-
for collection in collections_to_remove:
272+
# Ensure all styles are loaded before attempting to remove them
273+
try:
274+
bpy.ops.bim.load_styles()
275+
except Exception:
276+
pass
277+
278+
# 1. Collect all IfcStyle material names
279+
ifcstyle_material_names = []
280+
try:
281+
styles_props = getattr(bpy.context.scene, "BIMStylesProperties", None)
282+
if styles_props is None and bpy.data.scenes:
283+
styles_props = getattr(bpy.data.scenes[0], "BIMStylesProperties", None)
284+
if styles_props:
285+
for style in list(styles_props.styles):
286+
material = getattr(style, "blender_material", None)
287+
if material and material.name:
288+
ifcstyle_material_names.append(material.name)
289+
except Exception:
290+
pass
291+
292+
# 2. Purge IfcStore
293+
try:
294+
from bonsai.bim.ifc import IfcStore
295+
except ImportError:
296+
IfcStore = None
297+
298+
if IfcStore:
299+
try:
300+
IfcStore.purge()
301+
except Exception:
302+
pass
303+
304+
# 3. Remove all collections named IfcProject*
305+
for collection in list(bpy.data.collections):
306+
if collection.name.startswith('IfcProject'):
318307
try:
319308
bpy.data.collections.remove(collection, do_unlink=True)
320-
except:
309+
except Exception:
321310
pass
322311
323-
# Remove IFC-related data
324-
remove_ifc_collections()
325-
326-
# Note: Scene-level BIM properties are saved with the metadata.blend file but will be
327-
# overwritten when the IFC is loaded. Screen-level properties (BIMTabProperties,
328-
# BIMPanelProperties, BIMAreaProperties) preserve UI customization settings.
312+
# 4. Purge orphaned data blocks after removing IfcProject collections
313+
try:
314+
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
315+
except Exception:
316+
pass
317+
318+
# 5. Remove all materials corresponding to the IfcStyles we collected
319+
materials_removed = 0
320+
try:
321+
for mat_name in ifcstyle_material_names:
322+
if mat_name in bpy.data.materials:
323+
try:
324+
bpy.data.materials.remove(bpy.data.materials[mat_name], do_unlink=True)
325+
materials_removed += 1
326+
except Exception:
327+
pass
328+
except Exception:
329+
pass
329330
330-
# Save the metadata file
331331
bpy.ops.wm.save_as_mainfile(filepath=r'{blendmetadata_path}')
332332
"""
333-
334333
import tempfile
335-
336334
with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as script_file:
337335
script_file.write(cleanup_script)
338336
script_path = script_file.name
339337

340338
blender_exe = bpy.app.binary_path
341339
import subprocess
342-
343340
result = subprocess.run(
344341
[blender_exe, temp_path, "--background", "--python", script_path], capture_output=True, text=True
345342
)

0 commit comments

Comments
 (0)