mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Add operators for saving and loading blend metadata files
This commit is contained in:
@@ -115,11 +115,13 @@ classes = [
|
|||||||
operator.EditBlenderCollection,
|
operator.EditBlenderCollection,
|
||||||
operator.FileAssociate,
|
operator.FileAssociate,
|
||||||
operator.FileUnassociate,
|
operator.FileUnassociate,
|
||||||
|
operator.LoadBlendMetadataAndIFC,
|
||||||
operator.OpenPath,
|
operator.OpenPath,
|
||||||
operator.OpenUpstream,
|
operator.OpenUpstream,
|
||||||
operator.OpenUri,
|
operator.OpenUri,
|
||||||
operator.ReloadIfcFile,
|
operator.ReloadIfcFile,
|
||||||
operator.RevertClippingPlaneCut,
|
operator.RevertClippingPlaneCut,
|
||||||
|
operator.SaveBlendMetadataFile,
|
||||||
operator.SelectDir,
|
operator.SelectDir,
|
||||||
operator.SelectIfcFile,
|
operator.SelectIfcFile,
|
||||||
operator.SelectURIAttribute,
|
operator.SelectURIAttribute,
|
||||||
|
|||||||
@@ -331,6 +331,19 @@ class BIM_PT_project(Panel):
|
|||||||
col.prop(props, "ifc_file", text="")
|
col.prop(props, "ifc_file", text="")
|
||||||
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
||||||
|
|
||||||
|
# Blend metadata file UI
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
col = row.column()
|
||||||
|
col.enabled = False
|
||||||
|
# Show blend metadata file as a label, not editable
|
||||||
|
blendmetadata_path = ""
|
||||||
|
if props.ifc_file:
|
||||||
|
blendmetadata_path = props.ifc_file + ".blendmetadata"
|
||||||
|
col.label(text=blendmetadata_path)
|
||||||
|
row.operator("bim.save_blend_metadata_file", icon="FILE_TICK", text="")
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.load_blend_metadata_and_ifc", icon="FILE_REFRESH", text="Load Metadata + IFC")
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_new_project_wizard(Panel):
|
class BIM_PT_new_project_wizard(Panel):
|
||||||
bl_label = "New Project Wizard"
|
bl_label = "New Project Wizard"
|
||||||
|
|||||||
@@ -236,6 +236,92 @@ class SelectIfcFile(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
|||||||
return res
|
return res
|
||||||
return ImportHelper.invoke(self, context, event)
|
return ImportHelper.invoke(self, context, event)
|
||||||
|
|
||||||
|
class SaveBlendMetadataFile(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.save_blend_metadata_file"
|
||||||
|
bl_label = "Save Blend Metadata File"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
"""
|
||||||
|
Save the current blend file as a metadata-only file (no geometry), preserving settings, window arrangement, geometry nodes, etc.
|
||||||
|
"""
|
||||||
|
props = tool.Blender.get_bim_props()
|
||||||
|
ifc_file = getattr(props, "ifc_file", None)
|
||||||
|
if not ifc_file:
|
||||||
|
self.report({"WARNING"}, "No IFC file path set.")
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
blendmetadata_path = ifc_file + ".metadata.blend"
|
||||||
|
|
||||||
|
# Save a temporary copy of the current blend file
|
||||||
|
temp_path = bpy.path.abspath('//__temp_blendmetadata.blend')
|
||||||
|
bpy.ops.wm.save_as_mainfile(filepath=temp_path, copy=True)
|
||||||
|
|
||||||
|
# Prepare Python script to run in background Blender to remove geometry
|
||||||
|
cleanup_script = f"""
|
||||||
|
import bpy
|
||||||
|
# Remove all mesh objects and mesh collections
|
||||||
|
for obj in bpy.data.objects:
|
||||||
|
if obj.type == 'MESH':
|
||||||
|
bpy.data.objects.remove(obj, do_unlink=True)
|
||||||
|
for collection in bpy.data.collections:
|
||||||
|
# Remove collections that only contain mesh objects
|
||||||
|
if all(o.type == 'MESH' for o in collection.objects):
|
||||||
|
bpy.data.collections.remove(collection)
|
||||||
|
bpy.ops.wm.save_as_mainfile(filepath=r'{blendmetadata_path}')
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Save cleanup script to temp file
|
||||||
|
import tempfile
|
||||||
|
with tempfile.NamedTemporaryFile('w', suffix='.py', delete=False) as script_file:
|
||||||
|
script_file.write(cleanup_script)
|
||||||
|
script_path = script_file.name
|
||||||
|
|
||||||
|
# Run Blender in background to clean and save metadata file
|
||||||
|
blender_exe = bpy.app.binary_path
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run([
|
||||||
|
blender_exe,
|
||||||
|
temp_path,
|
||||||
|
'--background',
|
||||||
|
'--python', script_path
|
||||||
|
], capture_output=True)
|
||||||
|
|
||||||
|
# Clean up temp files
|
||||||
|
try:
|
||||||
|
os.remove(temp_path)
|
||||||
|
os.remove(script_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
self.report({"INFO"}, f"Blend metadata file saved to: {blendmetadata_path}")
|
||||||
|
else:
|
||||||
|
self.report({"ERROR"}, f"Failed to save blend metadata file: {result.stderr.decode()}")
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
class LoadBlendMetadataAndIFC(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.load_blend_metadata_and_ifc"
|
||||||
|
bl_label = "Load Blend Metadata and IFC"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = tool.Blender.get_bim_props()
|
||||||
|
ifc_file = getattr(props, "ifc_file", None)
|
||||||
|
if not ifc_file:
|
||||||
|
self.report({"WARNING"}, "No IFC file path set.")
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
metadata_path = ifc_file + ".metadata.blend"
|
||||||
|
# Open the metadata blend file
|
||||||
|
bpy.ops.wm.open_mainfile(filepath=metadata_path)
|
||||||
|
# After loading metadata, clear blend warning (no geometry loaded yet)
|
||||||
|
props = tool.Blender.get_bim_props()
|
||||||
|
props.has_blend_warning = False
|
||||||
|
# Load the IFC file into the current session (preserve layout)
|
||||||
|
bpy.ops.bim.load_project(filepath=ifc_file, should_start_fresh_session=False)
|
||||||
|
self.report({"INFO"}, f"Loaded metadata and IFC: {metadata_path}, {ifc_file}")
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
# TODO: Unused operator.
|
# TODO: Unused operator.
|
||||||
# Is there a need for this or 'DIR_PATH' propety subtype does almost the same,
|
# Is there a need for this or 'DIR_PATH' propety subtype does almost the same,
|
||||||
|
|||||||
Reference in New Issue
Block a user