Fix #1313. Fix bug where you couldn't import two different IFC files in succession in the same Blender file.

This commit is contained in:
Dion Moult
2021-02-14 17:27:10 +11:00
parent 6966da3bdf
commit 595131e6e8
2 changed files with 39 additions and 39 deletions
@@ -21,6 +21,7 @@ import numpy as np
from pathlib import Path from pathlib import Path
from itertools import cycle from itertools import cycle
from datetime import datetime from datetime import datetime
from blenderbim.bim.module.context.data import Data as ContextData
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from . import schema from . import schema
@@ -284,7 +285,6 @@ class IfcImporter:
self.settings_native.set(self.settings_native.INCLUDE_CURVES, True) self.settings_native.set(self.settings_native.INCLUDE_CURVES, True)
self.settings_2d = ifcopenshell.geom.settings() self.settings_2d = ifcopenshell.geom.settings()
self.settings_2d.set(self.settings_2d.INCLUDE_CURVES, True) self.settings_2d.set(self.settings_2d.INCLUDE_CURVES, True)
self.existing_elements = {}
self.include_elements = [] self.include_elements = []
self.exclude_elements = [] self.exclude_elements = []
self.project = None self.project = None
@@ -297,6 +297,7 @@ class IfcImporter:
self.mesh_shapes = {} self.mesh_shapes = {}
self.time = 0 self.time = 0
self.unit_scale = 1 self.unit_scale = 1
self.added_data = {}
self.native_elements = {} self.native_elements = {}
self.native_data = {} self.native_data = {}
self.aggregates = {} self.aggregates = {}
@@ -318,8 +319,6 @@ class IfcImporter:
self.profile_code("Purge diffs") self.profile_code("Purge diffs")
self.load_file() self.load_file()
self.profile_code("Loading file") self.profile_code("Loading file")
self.load_existing_rooted_elements()
self.profile_code("Load existing rooted elements")
self.set_ifc_file() self.set_ifc_file()
self.profile_code("Setting file") self.profile_code("Setting file")
if self.ifc_import_settings.should_auto_set_workarounds: if self.ifc_import_settings.should_auto_set_workarounds:
@@ -628,9 +627,6 @@ class IfcImporter:
def create_type_product(self, element): def create_type_product(self, element):
self.ifc_import_settings.logger.info("Creating object %s", element) self.ifc_import_settings.logger.info("Creating object %s", element)
if element.GlobalId in self.existing_elements:
self.type_products[element.GlobalId] = self.existing_elements[element.GlobalId]
return
representation_map = self.get_type_product_body_representation_map(element) representation_map = self.get_type_product_body_representation_map(element)
mesh = None mesh = None
if representation_map: if representation_map:
@@ -645,7 +641,7 @@ class IfcImporter:
except: except:
self.ifc_import_settings.logger.error("Failed to generate shape for %s", element) self.ifc_import_settings.logger.error("Failed to generate shape for %s", element)
obj = bpy.data.objects.new(self.get_name(element), mesh) obj = bpy.data.objects.new(self.get_name(element), mesh)
IfcStore.link_element(element, obj) self.link_element(element, obj)
self.material_creator.create(element, obj, mesh) self.material_creator.create(element, obj, mesh)
self.type_products[element.GlobalId] = obj self.type_products[element.GlobalId] = obj
@@ -755,9 +751,6 @@ class IfcImporter:
if not self.ifc_import_settings.should_import_spaces and element.is_a("IfcSpace"): if not self.ifc_import_settings.should_import_spaces and element.is_a("IfcSpace"):
return return
if element.GlobalId in self.existing_elements:
return self.existing_elements[element.GlobalId]
self.ifc_import_settings.logger.info("Creating object %s", element) self.ifc_import_settings.logger.info("Creating object %s", element)
if shape: if shape:
@@ -777,7 +770,7 @@ class IfcImporter:
mesh = None mesh = None
obj = bpy.data.objects.new(self.get_name(element), mesh) obj = bpy.data.objects.new(self.get_name(element), mesh)
IfcStore.link_element(element, obj) self.link_element(element, obj)
if shape: if shape:
m = shape.transformation.matrix.data m = shape.transformation.matrix.data
@@ -1020,7 +1013,7 @@ class IfcImporter:
def merge_by_class(self): def merge_by_class(self):
merge_set = {} merge_set = {}
for obj in IfcStore.id_map.values(): for obj in self.added_data.values():
if "/" not in obj.name or "IfcRelAggregates" in obj.users_collection[0].name: if "/" not in obj.name or "IfcRelAggregates" in obj.users_collection[0].name:
continue continue
merge_set.setdefault(obj.name.split("/")[0], []).append(obj) merge_set.setdefault(obj.name.split("/")[0], []).append(obj)
@@ -1028,7 +1021,7 @@ class IfcImporter:
def merge_by_material(self): def merge_by_material(self):
merge_set = {} merge_set = {}
for obj in IfcStore.id_map.values(): for obj in self.added_data.values():
if "/" not in obj.name or "IfcRelAggregates" in obj.users_collection[0].name: if "/" not in obj.name or "IfcRelAggregates" in obj.users_collection[0].name:
continue continue
if not obj.material_slots: if not obj.material_slots:
@@ -1054,7 +1047,7 @@ class IfcImporter:
cleaned_material["material"] = bpy.data.materials.new("Merged Material") cleaned_material["material"] = bpy.data.materials.new("Merged Material")
cleaned_material["material"].diffuse_color = cleaned_material["diffuse_color"] cleaned_material["material"].diffuse_color = cleaned_material["diffuse_color"]
for obj in IfcStore.id_map.values(): for obj in self.added_data.values():
if not hasattr(obj, "material_slots") or not obj.material_slots: if not hasattr(obj, "material_slots") or not obj.material_slots:
continue continue
for slot in obj.material_slots: for slot in obj.material_slots:
@@ -1078,7 +1071,7 @@ class IfcImporter:
def clean_mesh(self): def clean_mesh(self):
obj = None obj = None
last_obj = None last_obj = None
for obj in IfcStore.id_map.values(): for obj in self.added_data.values():
if obj.type == "MESH": if obj.type == "MESH":
obj.select_set(True) obj.select_set(True)
last_obj = obj last_obj = obj
@@ -1097,12 +1090,6 @@ class IfcImporter:
return return
self.openings[element.GlobalId] = obj self.openings[element.GlobalId] = obj
def load_existing_rooted_elements(self):
# TODO: consider how this impacts file reloading, for now we assume you only ever load the same file again
for obj in bpy.data.objects:
if hasattr(obj, "BIMObjectProperties") and obj.BIMObjectProperties.ifc_definition_id:
self.existing_elements[self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId] = obj
def load_diff(self): def load_diff(self):
if not self.ifc_import_settings.diff_file: if not self.ifc_import_settings.diff_file:
return return
@@ -1173,9 +1160,6 @@ class IfcImporter:
def create_project(self): def create_project(self):
self.project = {"ifc": self.file.by_type("IfcProject")[0]} self.project = {"ifc": self.file.by_type("IfcProject")[0]}
if self.project["ifc"].GlobalId in self.existing_elements:
self.project["blender"] = self.existing_elements[self.project["ifc"].GlobalId].users_collection[0]
return
self.project["blender"] = bpy.data.collections.new("IfcProject/{}".format(self.project["ifc"].Name)) self.project["blender"] = bpy.data.collections.new("IfcProject/{}".format(self.project["ifc"].Name))
obj = self.create_product(self.project["ifc"]) obj = self.create_product(self.project["ifc"])
if obj: if obj:
@@ -1191,17 +1175,13 @@ class IfcImporter:
if element.is_a("IfcSpace"): if element.is_a("IfcSpace"):
continue continue
global_id = element.GlobalId global_id = element.GlobalId
if global_id in self.existing_elements: collection = bpy.data.collections.new(self.get_name(element))
collection = self.existing_elements[global_id].users_collection[0] self.spatial_structure_elements[global_id] = {"blender": collection}
self.spatial_structure_elements[global_id] = {"blender": collection} parent.children.link(collection)
else: obj = self.create_product(element)
collection = bpy.data.collections.new(self.get_name(element)) if obj:
self.spatial_structure_elements[global_id] = {"blender": collection} self.spatial_structure_elements[global_id]["blender_obj"] = obj
parent.children.link(collection) collection.objects.link(obj)
obj = self.create_product(element)
if obj:
self.spatial_structure_elements[global_id]["blender_obj"] = obj
collection.objects.link(obj)
if element.IsDecomposedBy: if element.IsDecomposedBy:
for rel_aggregate in element.IsDecomposedBy: for rel_aggregate in element.IsDecomposedBy:
self.add_related_objects(collection, rel_aggregate.RelatedObjects) self.add_related_objects(collection, rel_aggregate.RelatedObjects)
@@ -1227,7 +1207,7 @@ class IfcImporter:
element = rel_aggregate.RelatingObject element = rel_aggregate.RelatingObject
obj = bpy.data.objects.new("{}/{}".format(element.is_a(), element.Name), None) obj = bpy.data.objects.new("{}/{}".format(element.is_a(), element.Name), None)
IfcStore.link_element(element, obj) self.link_element(element, obj)
self.place_object_in_spatial_tree(element, obj) self.place_object_in_spatial_tree(element, obj)
collection = bpy.data.collections.new(obj.name) collection = bpy.data.collections.new(obj.name)
@@ -1258,8 +1238,8 @@ class IfcImporter:
bpy.ops.object.delete({"selected_objects": objects_to_purge}) bpy.ops.object.delete({"selected_objects": objects_to_purge})
def place_objects_in_spatial_tree(self): def place_objects_in_spatial_tree(self):
for ifc_definition_id, obj in IfcStore.id_map.items(): for global_id, obj in self.added_data.items():
self.place_object_in_spatial_tree(self.file.by_id(ifc_definition_id), obj) self.place_object_in_spatial_tree(self.file.by_guid(global_id), obj)
def place_object_in_spatial_tree(self, element, obj): def place_object_in_spatial_tree(self, element, obj):
if element.is_a("IfcProject"): if element.is_a("IfcProject"):
@@ -1567,11 +1547,16 @@ class IfcImporter:
return parent @ self.get_axis2placement(plc.RelativePlacement) return parent @ self.get_axis2placement(plc.RelativePlacement)
def set_default_context(self): def set_default_context(self):
ContextData.load()
for subcontext in self.file.by_type("IfcGeometricRepresentationSubContext"): for subcontext in self.file.by_type("IfcGeometricRepresentationSubContext"):
if subcontext.ContextIdentifier == "Body": if subcontext.ContextIdentifier == "Body":
bpy.context.scene.BIMProperties.contexts = str(subcontext.id()) bpy.context.scene.BIMProperties.contexts = str(subcontext.id())
break break
def link_element(self, element, obj):
self.added_data[element.GlobalId] = obj
IfcStore.link_element(element, obj)
class IfcImportSettings: class IfcImportSettings:
def __init__(self): def __init__(self):
+16 -1
View File
@@ -34,6 +34,21 @@ sheets_enum = []
vector_styles_enum = [] vector_styles_enum = []
def updateIfcFile(self, context):
if context.scene.BIMProperties.ifc_file:
IfcStore.file = None
IfcStore.schema = None
# Purge data cache
from blenderbim.bim import modules
for module in modules.values():
if not module:
continue
try:
getattr(getattr(module, 'data'), 'Data').purge()
except AttributeError:
pass
def getDiagramScales(self, context): def getDiagramScales(self, context):
global diagram_scales_enum global diagram_scales_enum
if ( if (
@@ -391,7 +406,7 @@ class BIMTextProperties(PropertyGroup):
class BIMProperties(PropertyGroup): class BIMProperties(PropertyGroup):
schema_dir: StringProperty(default=os.path.join(cwd, "schema") + os.path.sep, name="Schema Directory") schema_dir: StringProperty(default=os.path.join(cwd, "schema") + os.path.sep, name="Schema Directory")
data_dir: StringProperty(default=os.path.join(cwd, "data") + os.path.sep, name="Data Directory") data_dir: StringProperty(default=os.path.join(cwd, "data") + os.path.sep, name="Data Directory")
ifc_file: StringProperty(name="IFC File") ifc_file: StringProperty(name="IFC File", update=updateIfcFile)
id_map: StringProperty(name="ID Map") id_map: StringProperty(name="ID Map")
guid_map: StringProperty(name="GUID Map") guid_map: StringProperty(name="GUID Map")
export_schema: EnumProperty(items=[("IFC4", "IFC4", ""), ("IFC2X3", "IFC2X3", "")], name="IFC Schema") export_schema: EnumProperty(items=[("IFC4", "IFC4", ""), ("IFC2X3", "IFC2X3", "")], name="IFC Schema")