mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Fix regression in speed in collection assignment
As hinted in the TODO note for linking collections safely, try-catch is actually much faster. This brings it to 10% faster than 0.7 speeds. Previously the regression made it 10x slower.
This commit is contained in:
@@ -39,74 +39,88 @@ class Collector(bonsai.core.tool.Collector):
|
||||
users_collection.objects.unlink(obj)
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
# Note that tool.Geometry.is_locked is only checked within the if
|
||||
# statements for efficiency as it is a slow check.
|
||||
|
||||
if element.is_a("IfcGridAxis"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
element = (element.PartOfU or element.PartOfV or element.PartOfW)[0]
|
||||
elif element.is_a("IfcGrid"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
|
||||
if element.is_a("IfcProject"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_to_collection_safe(collection, bpy.context.scene.collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
cls.link_collection_child_safe(bpy.context.scene.collection, collection)
|
||||
elif element.is_a("IfcTypeProduct"):
|
||||
collection = cls._create_project_child_collection("IfcTypeProduct")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
elif element.is_a("IfcOpeningElement"):
|
||||
collection = cls._create_project_child_collection("IfcOpeningElement")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
elif element.is_a("IfcStructuralItem"):
|
||||
collection = cls._create_project_child_collection("IfcStructuralItem")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
elif element.is_a("IfcLinearPositioningElement"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
collection = cls._create_project_child_collection("IfcLinearPositioningElement")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
elif element.is_a("IfcReferent"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
collection = cls._create_project_child_collection("IfcReferent")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
elif tool.Ifc.get_schema() == "IFC2X3" and element.is_a("IfcSpatialStructureElement"):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_to_collection_safe(collection, project_obj.BIMObjectProperties.collection)
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
elif (
|
||||
tool.Ifc.get_schema() != "IFC2X3"
|
||||
and element.is_a("IfcSpatialElement")
|
||||
and not element.is_a("IfcSpatialZone")
|
||||
):
|
||||
if tool.Geometry.is_locked(element):
|
||||
tool.Geometry.lock_object(obj)
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_to_collection_safe(collection, project_obj.BIMObjectProperties.collection)
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
elif element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_to_collection_safe(collection, project_obj.BIMObjectProperties.collection)
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
elif element.is_a("IfcAnnotation") and (drawing_obj := cls.get_annotation_drawing_obj(element)):
|
||||
cls.link_to_collection_safe(obj, drawing_obj.BIMObjectProperties.collection)
|
||||
cls.link_collection_object_safe(drawing_obj.BIMObjectProperties.collection, obj)
|
||||
elif container := ifcopenshell.util.element.get_container(element):
|
||||
container_obj = tool.Ifc.get_object(container)
|
||||
if not (collection := container_obj.BIMObjectProperties.collection):
|
||||
cls.assign(container_obj)
|
||||
collection = container_obj.BIMObjectProperties.collection
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
else:
|
||||
collection = cls._create_project_child_collection("Unsorted")
|
||||
cls.link_to_collection_safe(obj, collection)
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
|
||||
@classmethod
|
||||
def _create_project_child_collection(cls, name: str) -> bpy.types.Collection:
|
||||
"""get or create new collection inside project"""
|
||||
collection = bpy.data.collections.get(name)
|
||||
if not collection:
|
||||
collection = bpy.data.collections.new(name)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_obj.BIMObjectProperties.collection.children.link(collection)
|
||||
if layer_collection := tool.Blender.get_layer_collection(collection):
|
||||
cls.set_layer_collection_visibility(layer_collection)
|
||||
if collection := bpy.data.collections.get(name):
|
||||
return collection
|
||||
collection = bpy.data.collections.new(name)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_obj.BIMObjectProperties.collection.children.link(collection)
|
||||
if layer_collection := tool.Blender.get_layer_collection(collection):
|
||||
cls.set_layer_collection_visibility(layer_collection)
|
||||
return collection
|
||||
|
||||
@classmethod
|
||||
@@ -129,26 +143,19 @@ class Collector(bonsai.core.tool.Collector):
|
||||
return tool.Ifc.get_object(related_object)
|
||||
|
||||
@classmethod
|
||||
def link_to_collection_safe(
|
||||
cls, obj_or_col: Union[bpy.types.Object, bpy.types.Collection], collection: bpy.types.Collection
|
||||
) -> None:
|
||||
"""Link `obj_or_col` (an object or a collection) to the `collection`
|
||||
if `obj_or_col` is not part of that collection already.
|
||||
def link_collection_object_safe(cls, collection: bpy.types.Collection, obj: bpy.types.Object) -> None:
|
||||
# Catching an exception is 10x faster than doing collection.objects.find
|
||||
try:
|
||||
collection.objects.link(obj)
|
||||
except:
|
||||
pass
|
||||
|
||||
Method is needed to avoid RuntimeErrors like below that occur if you link object/collection
|
||||
to the collection directly and they are already part of that collection.
|
||||
RuntimeError: Error: Object 'xxx' already in collection 'xxx'.
|
||||
"""
|
||||
# TODO: Maybe just catching RuntimeError is faster?
|
||||
if isinstance(obj_or_col, bpy.types.Object):
|
||||
if collection.objects.find(obj_or_col.name) != -1:
|
||||
return
|
||||
collection.objects.link(obj_or_col)
|
||||
return
|
||||
|
||||
if collection.children.find(obj_or_col.name) != -1:
|
||||
return
|
||||
collection.children.link(obj_or_col)
|
||||
@classmethod
|
||||
def link_collection_child_safe(cls, collection: bpy.types.Collection, child: bpy.types.Collection) -> None:
|
||||
try:
|
||||
collection.children.link(child)
|
||||
except:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def set_layer_collection_visibility(cls, layer_collection):
|
||||
|
||||
Reference in New Issue
Block a user