mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Save loaded paths to linked IFC models in IFC #5899
Short demo - https://imgur.com/a/3LIt9Sr
This commit is contained in:
@@ -49,6 +49,7 @@ class IfcExporter:
|
||||
IfcStore.update_cache()
|
||||
self.sync_all_objects()
|
||||
self.sync_edited_objects()
|
||||
tool.Project.save_linked_models_to_ifc()
|
||||
extension = self.ifc_export_settings.output_file.split(".")[-1].lower()
|
||||
if extension == "ifczip":
|
||||
with tempfile.TemporaryDirectory() as unzipped_path:
|
||||
|
||||
@@ -258,6 +258,8 @@ class IfcImporter:
|
||||
self.profile_code("Place objects in collections")
|
||||
self.setup_arrays()
|
||||
self.profile_code("Setup arrays")
|
||||
tool.Project.load_linked_models_from_ifc()
|
||||
self.profile_code("Load linked models")
|
||||
self.lock_scales()
|
||||
self.profile_code("Lock objects scales")
|
||||
self.add_project_to_scene()
|
||||
|
||||
@@ -21,7 +21,7 @@ import ifcopenshell.util.system
|
||||
import bonsai.bim.helper
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from typing import Any, Union
|
||||
from typing import Any, Union, Sequence
|
||||
|
||||
|
||||
class Document(bonsai.core.tool.Document):
|
||||
@@ -102,7 +102,7 @@ class Document(bonsai.core.tool.Document):
|
||||
def import_references(cls, document: ifcopenshell.entity_instance) -> None:
|
||||
props = bpy.context.scene.BIMDocumentProperties
|
||||
is_ifc2x3 = tool.Ifc.get_schema() == "IFC2X3"
|
||||
references = (document.DocumentReferences or []) if is_ifc2x3 else document.HasDocumentReferences
|
||||
references = cls.get_document_references(document)
|
||||
for element in references:
|
||||
new = props.documents.add()
|
||||
new.ifc_definition_id = element.id()
|
||||
@@ -157,3 +157,12 @@ class Document(bonsai.core.tool.Document):
|
||||
def set_external_reference_id(cls, reference: ifcopenshell.entity_instance, value: Union[str, None]) -> None:
|
||||
"""Set IfcExternalReference.ItemReference/Identification, compatible with IFC2X3."""
|
||||
reference[1] = value
|
||||
|
||||
@classmethod
|
||||
def get_document_references(
|
||||
cls, document: ifcopenshell.entity_instance
|
||||
) -> tuple[ifcopenshell.entity_instance, ...]:
|
||||
"""Get IfcDocumentReference.ReferencedDocuments, compatible with IFC2X3."""
|
||||
if document.file.schema == "IFC2X3":
|
||||
return document.DocumentReferences or ()
|
||||
return document.HasDocumentReferences
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import os
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.document
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import bonsai.core.aggregate
|
||||
@@ -32,7 +33,7 @@ import bonsai.tool as tool
|
||||
from bonsai.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.project.append_asset import APPENDABLE_ASSET_TYPES
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class Project(bonsai.core.tool.Project):
|
||||
@@ -214,3 +215,74 @@ class Project(bonsai.core.tool.Project):
|
||||
@classmethod
|
||||
def run_root_reload_grid_decorator(cls) -> None:
|
||||
tool.Root.reload_grid_decorator()
|
||||
|
||||
@classmethod
|
||||
def get_linked_models_document(cls) -> Union[ifcopenshell.entity_instance, None]:
|
||||
for document in tool.Ifc.get().by_type("IfcDocumentInformation"):
|
||||
if document.Name == "BBIM_Linked_Models":
|
||||
return document
|
||||
|
||||
@classmethod
|
||||
def load_linked_models_from_ifc(cls) -> None:
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
links.clear()
|
||||
links_document = cls.get_linked_models_document()
|
||||
if not links_document:
|
||||
return
|
||||
|
||||
references = tool.Document.get_document_references(links_document)
|
||||
if not references:
|
||||
return
|
||||
|
||||
for reference in references:
|
||||
link = links.add()
|
||||
link.name = reference.Location
|
||||
|
||||
@classmethod
|
||||
def save_linked_models_to_ifc(cls) -> None:
|
||||
ifc_file = tool.Ifc.get()
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
filepaths: set[Path] = set()
|
||||
for link in links:
|
||||
filepaths.add(Path(link.name))
|
||||
|
||||
links_document = next(
|
||||
(
|
||||
document
|
||||
for document in ifc_file.by_type("IfcDocumentInformation")
|
||||
if document.Name == "BBIM_Linked_Models"
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
if not filepaths and links_document is None:
|
||||
return
|
||||
|
||||
paths_to_add = filepaths.copy()
|
||||
references_to_remove: list[ifcopenshell.entity_instance] = []
|
||||
if links_document:
|
||||
references = tool.Document.get_document_references(links_document)
|
||||
for reference in references:
|
||||
# I guess got corrupted by the user.
|
||||
if not (location := reference.Location):
|
||||
references_to_remove.remove(reference)
|
||||
continue
|
||||
path = Path(location)
|
||||
if path in paths_to_add:
|
||||
paths_to_add.remove(path)
|
||||
else:
|
||||
references_to_remove.append(reference)
|
||||
|
||||
if paths_to_add:
|
||||
if links_document is None:
|
||||
links_document = ifcopenshell.api.document.add_information(ifc_file)
|
||||
links_document.Name = "BBIM_Linked_Models"
|
||||
links_document.Description = "Bonsai internal document containing references to currently linked models"
|
||||
|
||||
for path in paths_to_add:
|
||||
reference = ifcopenshell.api.document.add_reference(ifc_file, links_document)
|
||||
reference.Location = path.as_posix()
|
||||
|
||||
if references_to_remove:
|
||||
for reference in references_to_remove:
|
||||
ifcopenshell.api.document.remove_reference(ifc_file, reference)
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.document
|
||||
import ifcopenshell.api.root
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
import tempfile
|
||||
@@ -238,3 +240,108 @@ class TestLoadProject(NewFile):
|
||||
assert not tool.Ifc.get()
|
||||
assert bpy.data.objects["IfcWall/Wall"]
|
||||
assert tool.Blender.is_valid_data_block(monkey)
|
||||
|
||||
|
||||
class TestLoadLinkedModels(NewFile):
|
||||
def test_load_linked_models_no_document(self):
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
subject.load_linked_models_from_ifc()
|
||||
assert len(links) == 0
|
||||
|
||||
def test_load_linked_models_document_no_references(self):
|
||||
ifc = ifcopenshell.file()
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
ifcopenshell.api.root.create_entity(ifc, "IfcProject")
|
||||
document = ifcopenshell.api.document.add_information(ifc)
|
||||
document.Name = "BBIM_Linked_Models"
|
||||
tool.Ifc.set(ifc)
|
||||
subject.load_linked_models_from_ifc()
|
||||
assert len(links) == 0
|
||||
|
||||
def test_load_linked_models_document_with_references(self):
|
||||
ifc = ifcopenshell.file()
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
ifcopenshell.api.root.create_entity(ifc, "IfcProject")
|
||||
document = ifcopenshell.api.document.add_information(ifc)
|
||||
document.Name = "BBIM_Linked_Models"
|
||||
reference = ifcopenshell.api.document.add_reference(ifc, document)
|
||||
linked_model_path = "test.ifc"
|
||||
reference.Location = linked_model_path
|
||||
tool.Ifc.set(ifc)
|
||||
subject.load_linked_models_from_ifc()
|
||||
assert len(links) == 1
|
||||
assert links[0].name == linked_model_path
|
||||
|
||||
|
||||
class TestSaveLinkedModelsToIfc(NewFile):
|
||||
def test_save_linked_models_to_ifc_no_links(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
subject.save_linked_models_to_ifc()
|
||||
assert len(ifc.by_type("IfcDocumentInformation")) == 0
|
||||
assert len(ifc.by_type("IfcDocumentReference")) == 0
|
||||
|
||||
def test_save_linked_models_to_ifc_paths_to_add(self):
|
||||
ifc = ifcopenshell.file()
|
||||
ifcopenshell.api.root.create_entity(ifc, "IfcProject")
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
link = links.add()
|
||||
linked_model_path = "test.ifc"
|
||||
link.name = linked_model_path
|
||||
tool.Ifc.set(ifc)
|
||||
subject.save_linked_models_to_ifc()
|
||||
assert len(documents := ifc.by_type("IfcDocumentInformation")) == 1
|
||||
assert documents[0].Name == "BBIM_Linked_Models"
|
||||
assert len(references := ifc.by_type("IfcDocumentReference")) == 1
|
||||
assert references[0].Location == linked_model_path
|
||||
|
||||
def test_save_linked_models_to_ifc_already_created_references(self):
|
||||
ifc = ifcopenshell.file()
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
ifcopenshell.api.root.create_entity(ifc, "IfcProject")
|
||||
|
||||
document = ifcopenshell.api.document.add_information(ifc)
|
||||
document.Name = "BBIM_Linked_Models"
|
||||
document_id = document.id()
|
||||
reference = ifcopenshell.api.document.add_reference(ifc, document)
|
||||
linked_model_path = "test.ifc"
|
||||
reference.Location = linked_model_path
|
||||
reference_id = reference.id()
|
||||
|
||||
link = links.add()
|
||||
linked_model_path = "test.ifc"
|
||||
link.name = linked_model_path
|
||||
tool.Ifc.set(ifc)
|
||||
subject.save_linked_models_to_ifc()
|
||||
|
||||
# Information and references to stay intact.
|
||||
assert len(documents := ifc.by_type("IfcDocumentInformation")) == 1
|
||||
assert documents[0].id() == document_id
|
||||
assert documents[0].Name == "BBIM_Linked_Models"
|
||||
assert len(references := ifc.by_type("IfcDocumentReference")) == 1
|
||||
assert references[0].id() == reference_id
|
||||
assert references[0].Location == linked_model_path
|
||||
|
||||
def test_save_linked_models_to_ifc_references_to_remove(self):
|
||||
ifc = ifcopenshell.file()
|
||||
links = bpy.context.scene.BIMProjectProperties.links
|
||||
ifcopenshell.api.root.create_entity(ifc, "IfcProject")
|
||||
|
||||
document = ifcopenshell.api.document.add_information(ifc)
|
||||
document.Name = "BBIM_Linked_Models"
|
||||
document_id = document.id()
|
||||
reference = ifcopenshell.api.document.add_reference(ifc, document)
|
||||
linked_model_path = "test.ifc"
|
||||
reference.Location = linked_model_path
|
||||
|
||||
tool.Ifc.set(ifc)
|
||||
subject.save_linked_models_to_ifc()
|
||||
links.clear()
|
||||
|
||||
# Remove reference for removed link.
|
||||
assert len(documents := ifc.by_type("IfcDocumentInformation")) == 1
|
||||
assert documents[0].id() == document_id
|
||||
assert documents[0].Name == "BBIM_Linked_Models"
|
||||
assert len(ifc.by_type("IfcDocumentReference")) == 0
|
||||
|
||||
Reference in New Issue
Block a user