Merge pull request #7509 from falken10vdl/Improve-saving-metadata.blend-file

Refactor SaveBlendMetadataFile to improve speed and IFC data cleanup
This commit is contained in:
falken10vdl
2025-12-20 04:16:55 +01:00
committed by GitHub
+53 -56
View File
@@ -269,77 +269,74 @@ class SaveBlendMetadataFile(bpy.types.Operator):
cleanup_script = f"""
import bpy
def remove_ifc_collections():
\"\"\"Remove all collections that start with 'IfcProject' and their contents.\"\"\"
collections_to_remove = []
# Find all IfcProject collections
for collection in bpy.data.collections:
if collection.name.startswith('IfcProject'):
collections_to_remove.append(collection)
# First, use bim.override_outliner_delete to properly remove IFC data
for collection in collections_to_remove:
# Collect all objects in the collection and its children
objects_to_delete = []
def collect_objects(col):
for obj in col.objects:
if obj not in objects_to_delete:
objects_to_delete.append(obj)
for child in col.children:
collect_objects(child)
collect_objects(collection)
# Use bim.override_outliner_delete for each object to clean up IFC data
for obj in objects_to_delete:
# Select only this object
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
# Try to use Bonsai's delete operator which cleans up IFC data
try:
bpy.ops.bim.override_outliner_delete()
except:
# If that fails, use standard delete
bpy.data.objects.remove(obj, do_unlink=True)
# Remove any remaining child collections
for child in list(collection.children):
try:
bpy.data.collections.remove(child, do_unlink=True)
except:
pass
# Remove the IfcProject collections themselves
for collection in collections_to_remove:
# Ensure all styles are loaded before attempting to remove them
try:
bpy.ops.bim.load_styles()
except Exception:
pass
# 1. Collect all IfcStyle material names
ifcstyle_material_names = []
try:
styles_props = getattr(bpy.context.scene, "BIMStylesProperties", None)
if styles_props is None and bpy.data.scenes:
styles_props = getattr(bpy.data.scenes[0], "BIMStylesProperties", None)
if styles_props:
for style in list(styles_props.styles):
material = getattr(style, "blender_material", None)
if material and material.name:
ifcstyle_material_names.append(material.name)
except Exception:
pass
# 2. Purge IfcStore
try:
from bonsai.bim.ifc import IfcStore
except ImportError:
IfcStore = None
if IfcStore:
try:
IfcStore.purge()
except Exception:
pass
# 3. Remove all collections named IfcProject*
for collection in list(bpy.data.collections):
if collection.name.startswith('IfcProject'):
try:
bpy.data.collections.remove(collection, do_unlink=True)
except:
except Exception:
pass
# Remove IFC-related data
remove_ifc_collections()
# 4. Purge orphaned data blocks after removing IfcProject collections
try:
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
except Exception:
pass
# Note: Scene-level BIM properties are saved with the metadata.blend file but will be
# overwritten when the IFC is loaded. Screen-level properties (BIMTabProperties,
# BIMPanelProperties, BIMAreaProperties) preserve UI customization settings.
# 5. Remove all materials corresponding to the IfcStyles we collected
materials_removed = 0
try:
for mat_name in ifcstyle_material_names:
if mat_name in bpy.data.materials:
try:
bpy.data.materials.remove(bpy.data.materials[mat_name], do_unlink=True)
materials_removed += 1
except Exception:
pass
except Exception:
pass
# Save the metadata file
bpy.ops.wm.save_as_mainfile(filepath=r'{blendmetadata_path}')
"""
import tempfile
with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as script_file:
script_file.write(cleanup_script)
script_path = script_file.name
blender_exe = bpy.app.binary_path
import subprocess
result = subprocess.run(
[blender_exe, temp_path, "--background", "--python", script_path], capture_output=True, text=True
)