@@ -269,77 +269,74 @@ def execute(self, context):
269269 cleanup_script = f"""
270270import 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
331331bpy.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