Fix #3069. WARNING: dangerous change. Objects that have their own collection now have a pointer to that collection. This fixes a variety of subtle sync bugs.

This commit is contained in:
Dion Moult
2023-06-01 16:58:01 +10:00
parent 4bb46fa607
commit 586707dd28
5 changed files with 48 additions and 22 deletions
@@ -111,6 +111,7 @@ classes = [
prop.PsetQto, prop.PsetQto,
prop.GlobalId, prop.GlobalId,
prop.BIMObjectProperties, prop.BIMObjectProperties,
prop.BIMCollectionProperties,
prop.BIMMaterialProperties, prop.BIMMaterialProperties,
prop.BIMMeshProperties, prop.BIMMeshProperties,
ui.BIM_PT_section_plane, ui.BIM_PT_section_plane,
@@ -158,6 +159,7 @@ def register():
bpy.app.handlers.load_post.append(handler.loadIfcStore) bpy.app.handlers.load_post.append(handler.loadIfcStore)
bpy.app.handlers.save_post.append(handler.ensureIfcExported) bpy.app.handlers.save_post.append(handler.ensureIfcExported)
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties) bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Collection.BIMCollectionProperties = bpy.props.PointerProperty(type=prop.BIMCollectionProperties)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties) bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties) bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties) bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
@@ -184,6 +186,7 @@ def unregister():
bpy.app.handlers.load_post.remove(handler.loadIfcStore) bpy.app.handlers.load_post.remove(handler.loadIfcStore)
bpy.app.handlers.save_post.remove(handler.ensureIfcExported) bpy.app.handlers.save_post.remove(handler.ensureIfcExported)
del bpy.types.Scene.BIMProperties del bpy.types.Scene.BIMProperties
del bpy.types.Collection.BIMCollectionProperties
del bpy.types.Object.BIMObjectProperties del bpy.types.Object.BIMObjectProperties
del bpy.types.Material.BIMObjectProperties del bpy.types.Material.BIMObjectProperties
del bpy.types.Material.BIMMaterialProperties del bpy.types.Material.BIMMaterialProperties
+9 -3
View File
@@ -1337,8 +1337,9 @@ class IfcImporter:
"{}/{}".format(self.project["ifc"].is_a(), self.project["ifc"].Name) "{}/{}".format(self.project["ifc"].is_a(), self.project["ifc"].Name)
) )
obj = self.create_product(self.project["ifc"]) obj = self.create_product(self.project["ifc"])
if obj: self.project["blender"].objects.link(obj)
self.project["blender"].objects.link(obj) self.project["blender"].BIMCollectionProperties.obj = obj
obj.BIMObjectProperties.collection = self.project["blender"]
def create_collections(self): def create_collections(self):
if self.ifc_import_settings.collection_mode == "DECOMPOSITION": if self.ifc_import_settings.collection_mode == "DECOMPOSITION":
@@ -1673,6 +1674,8 @@ class IfcImporter:
return return
elif element.GlobalId in self.collections: elif element.GlobalId in self.collections:
collection = self.collections[element.GlobalId] collection = self.collections[element.GlobalId]
collection.BIMCollectionProperties.obj = obj
obj.BIMObjectProperties.collection = collection
collection.name = obj.name collection.name = obj.name
return collection.objects.link(obj) return collection.objects.link(obj)
elif getattr(element, "Decomposes", None): elif getattr(element, "Decomposes", None):
@@ -1687,7 +1690,10 @@ class IfcImporter:
elif element.is_a("IfcGridAxis"): elif element.is_a("IfcGridAxis"):
return return
elif element.GlobalId in self.collections: elif element.GlobalId in self.collections:
return self.collections[element.GlobalId].objects.link(obj) collection = self.collections[element.GlobalId]
collection.BIMCollectionProperties.obj = obj
obj.BIMObjectProperties.collection = collection
return collection.objects.link(obj)
elif element.is_a("IfcTypeObject"): elif element.is_a("IfcTypeObject"):
return self.type_collection.objects.link(obj) return self.type_collection.objects.link(obj)
elif element.is_a("IfcStructuralMember"): elif element.is_a("IfcStructuralMember"):
+5
View File
@@ -409,7 +409,12 @@ class GlobalId(PropertyGroup):
name: StringProperty(name="Name") name: StringProperty(name="Name")
class BIMCollectionProperties(PropertyGroup):
obj: PointerProperty(type=bpy.types.Object)
class BIMObjectProperties(PropertyGroup): class BIMObjectProperties(PropertyGroup):
collection: PointerProperty(type=bpy.types.Collection)
ifc_definition_id: IntProperty(name="IFC Definition ID") ifc_definition_id: IntProperty(name="IFC Definition ID")
blender_offset_type: EnumProperty( blender_offset_type: EnumProperty(
items=[(o, o, "") for o in ["NONE", "OBJECT_PLACEMENT", "CARTESIAN_POINT"]], items=[(o, o, "") for o in ["NONE", "OBJECT_PLACEMENT", "CARTESIAN_POINT"]],
+30 -19
View File
@@ -59,17 +59,18 @@ class Collector(blenderbim.core.tool.Collector):
parent_collection = collection parent_collection = collection
break break
if parent_collection: if not parent_collection:
parent_obj = bpy.data.objects.get(parent_collection.name) return
parent = tool.Ifc.get_entity(parent_obj)
if parent: parent = tool.Ifc.get_entity(parent_collection.BIMCollectionProperties.obj)
# This is lazy, but works. One of these will succeed, the other will fail silently. if parent:
blenderbim.core.spatial.assign_container( # This is lazy, but works. One of these will succeed, the other will fail silently.
tool.Ifc, tool.Collector, tool.Spatial, structure_obj=parent_obj, element_obj=obj blenderbim.core.spatial.assign_container(
) tool.Ifc, tool.Collector, tool.Spatial, structure_obj=parent_obj, element_obj=obj
blenderbim.core.aggregate.assign_object( )
tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=parent_obj, related_obj=obj blenderbim.core.aggregate.assign_object(
) tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=parent_obj, related_obj=obj
)
@classmethod @classmethod
def assign(cls, obj): def assign(cls, obj):
@@ -100,18 +101,21 @@ class Collector(blenderbim.core.tool.Collector):
@classmethod @classmethod
def _get_own_collection(cls, element, obj): def _get_own_collection(cls, element, obj):
if obj.BIMObjectProperties.collection:
return obj.BIMObjectProperties.collection
if element.is_a("IfcProject"): if element.is_a("IfcProject"):
return bpy.data.collections.get(obj.name) or bpy.data.collections.new(obj.name) return cls._create_own_collection(obj)
if tool.Ifc.get_schema() == "IFC2X3": if tool.Ifc.get_schema() == "IFC2X3":
if element.is_a("IfcSpatialStructureElement"): if element.is_a("IfcSpatialStructureElement"):
return bpy.data.collections.get(obj.name) or bpy.data.collections.new(obj.name) return cls._create_own_collection(obj)
else: else:
if element.is_a("IfcSpatialStructureElement") or element.is_a("IfcExternalSpatialStructureElement"): if element.is_a("IfcSpatialStructureElement") or element.is_a("IfcExternalSpatialStructureElement"):
return bpy.data.collections.get(obj.name) or bpy.data.collections.new(obj.name) return cls._create_own_collection(obj)
if element.is_a("IfcGrid"): if element.is_a("IfcGrid"):
return bpy.data.collections.get(obj.name) or bpy.data.collections.new(obj.name) return cls._create_own_collection(obj)
if element.is_a("IfcGridAxis"): if element.is_a("IfcGridAxis"):
if element.PartOfU: if element.PartOfU:
@@ -125,7 +129,7 @@ class Collector(blenderbim.core.tool.Collector):
axes = "WAxes" axes = "WAxes"
grid_obj = tool.Ifc.get_object(grid) grid_obj = tool.Ifc.get_object(grid)
if grid_obj: if grid_obj:
grid_col = bpy.data.collections.get(grid_obj.name) grid_col = cls._get_own_collection(grid, grid_obj)
axes_col = [c for c in grid_col.children if axes in c.name] axes_col = [c for c in grid_col.children if axes in c.name]
if axes_col: if axes_col:
return axes_col[0] return axes_col[0]
@@ -144,7 +148,7 @@ class Collector(blenderbim.core.tool.Collector):
return bpy.data.collections.get("Connections") or bpy.data.collections.new("Connections") return bpy.data.collections.get("Connections") or bpy.data.collections.new("Connections")
if getattr(element, "IsDecomposedBy", None): if getattr(element, "IsDecomposedBy", None):
return bpy.data.collections.get(obj.name) or bpy.data.collections.new(obj.name) return cls._create_own_collection(obj)
@classmethod @classmethod
def _get_collection(cls, element, obj): def _get_collection(cls, element, obj):
@@ -180,14 +184,14 @@ class Collector(blenderbim.core.tool.Collector):
if aggregate: if aggregate:
aggregate_obj = tool.Ifc.get_object(aggregate) aggregate_obj = tool.Ifc.get_object(aggregate)
if aggregate_obj: if aggregate_obj:
collection = bpy.data.collections.get(aggregate_obj.name) collection = aggregate_obj.BIMObjectProperties.collection
if collection: if collection:
return collection return collection
container = ifcopenshell.util.element.get_container(element) container = ifcopenshell.util.element.get_container(element)
if container: if container:
container_obj = tool.Ifc.get_object(container) container_obj = tool.Ifc.get_object(container)
collection = bpy.data.collections.get(container_obj.name) collection = container_obj.BIMObjectProperties.collection
if collection: if collection:
return collection return collection
@@ -208,3 +212,10 @@ class Collector(blenderbim.core.tool.Collector):
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0]) project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
project_obj.users_collection[0].children.link(collection) project_obj.users_collection[0].children.link(collection)
return collection return collection
@classmethod
def _create_own_collection(cls, obj):
collection = bpy.data.collections.new(obj.name)
obj.BIMObjectProperties.collection = collection
collection.BIMCollectionProperties.obj = obj
return collection
@@ -153,6 +153,7 @@ class TestAssign(NewFile):
tool.Ifc.link(space_element, space_obj) tool.Ifc.link(space_element, space_obj)
space_collection = bpy.data.collections.new("IfcSpace/Name") space_collection = bpy.data.collections.new("IfcSpace/Name")
bpy.context.scene.collection.children.link(space_collection) bpy.context.scene.collection.children.link(space_collection)
space_obj.BIMObjectProperties.collection = space_collection
space_collection.objects.link(space_obj) space_collection.objects.link(space_obj)
ifcopenshell.api.run( ifcopenshell.api.run(
"aggregate.assign_object", "aggregate.assign_object",