mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +00:00
Fix issues with accessing invalid entities in bim.reassign_class #4371
bim.reassign_class wasn't considering that root.reassign_class will also reassign class for occurrences of the same type and was reaccessing invalid elements
This commit is contained in:
@@ -21,6 +21,7 @@ import ifcopenshell
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.type
|
||||||
import blenderbim.bim.handler
|
import blenderbim.bim.handler
|
||||||
import blenderbim.core.geometry
|
import blenderbim.core.geometry
|
||||||
import blenderbim.core.material
|
import blenderbim.core.material
|
||||||
@@ -103,33 +104,68 @@ class ReassignClass(bpy.types.Operator):
|
|||||||
predefined_type = context.scene.BIMRootProperties.ifc_predefined_type
|
predefined_type = context.scene.BIMRootProperties.ifc_predefined_type
|
||||||
if predefined_type == "USERDEFINED":
|
if predefined_type == "USERDEFINED":
|
||||||
predefined_type = context.scene.BIMRootProperties.ifc_userdefined_type
|
predefined_type = context.scene.BIMRootProperties.ifc_userdefined_type
|
||||||
reassigned_elements = set()
|
|
||||||
|
# NOTE: root.reassign_class
|
||||||
|
# automatically will reassign class for other occurrences of the type
|
||||||
|
# so we need to run it only for the types or non-typed elements
|
||||||
|
elements_to_reassign = set()
|
||||||
|
# need to update blender object name
|
||||||
|
# for all elements that were changed in the process
|
||||||
|
elements_to_update = set()
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
product = ifcopenshell.api.run(
|
obj.BIMObjectProperties.is_reassigning_class = False
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if element.is_a("IfcTypeObject"):
|
||||||
|
elements_to_reassign.add(element)
|
||||||
|
elements_to_update.update(ifcopenshell.util.element.get_types(element))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check if element is typed
|
||||||
|
element_type = ifcopenshell.util.element.get_type(element)
|
||||||
|
if element_type:
|
||||||
|
elements_to_reassign.add(element_type)
|
||||||
|
elements_to_update.update(ifcopenshell.util.element.get_types(element_type))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# non-typed element
|
||||||
|
elements_to_reassign.add(element)
|
||||||
|
|
||||||
|
# store elements to objects to update later as elements will get invalid
|
||||||
|
# after class reassignment
|
||||||
|
elements_to_update = elements_to_update | elements_to_reassign
|
||||||
|
objects_to_update = set(o for e in elements_to_update if (o := tool.Ifc.get_object(e)))
|
||||||
|
|
||||||
|
base_class = context.scene.BIMRootProperties.ifc_class
|
||||||
|
if context.scene.BIMRootProperties.ifc_product == "IfcElementType":
|
||||||
|
type_class = base_class
|
||||||
|
occurrence_classes = ifcopenshell.util.type.get_applicable_entities(type_class)
|
||||||
|
occurrence_class = None if len(occurrence_classes) == 0 else occurrence_classes[0]
|
||||||
|
else:
|
||||||
|
occurrence_class = base_class
|
||||||
|
type_classes = ifcopenshell.util.type.get_applicable_types(occurrence_class)
|
||||||
|
type_class = None if len(type_classes) == 0 else type_classes[0]
|
||||||
|
|
||||||
|
reassigned_elements = set()
|
||||||
|
for element in elements_to_reassign:
|
||||||
|
ifc_class = type_class if element.is_a("IfcTypeObject") else occurrence_class
|
||||||
|
if ifc_class is None:
|
||||||
|
self.report(
|
||||||
|
{"ERROR"},
|
||||||
|
f"Couldn't find valid class for reassigning element of class {element.is_a()} based on class {base_class}",
|
||||||
|
)
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
element = ifcopenshell.api.run(
|
||||||
"root.reassign_class",
|
"root.reassign_class",
|
||||||
self.file,
|
self.file,
|
||||||
product=tool.Ifc.get_entity(obj),
|
product=element,
|
||||||
ifc_class=context.scene.BIMRootProperties.ifc_class,
|
ifc_class=ifc_class,
|
||||||
predefined_type=predefined_type,
|
predefined_type=predefined_type,
|
||||||
)
|
)
|
||||||
reassigned_elements.add(product)
|
reassigned_elements.add(element)
|
||||||
obj.name = tool.Loader.get_name(product)
|
|
||||||
obj.BIMObjectProperties.is_reassigning_class = False
|
|
||||||
|
|
||||||
dependent_elements = set()
|
for obj in objects_to_update:
|
||||||
for reassigned_element in reassigned_elements:
|
obj.name = tool.Loader.get_name(tool.Ifc.get_entity(obj))
|
||||||
if reassigned_element.is_a("IfcTypeObject"):
|
|
||||||
dependent_elements.update(ifcopenshell.util.element.get_types(product))
|
|
||||||
else:
|
|
||||||
element_type = ifcopenshell.util.element.get_type(product)
|
|
||||||
if element_type:
|
|
||||||
dependent_elements.add(element_type)
|
|
||||||
dependent_elements.update(ifcopenshell.util.element.get_types(element_type))
|
|
||||||
|
|
||||||
for dependent_element in dependent_elements:
|
|
||||||
obj = tool.Ifc.get_object(dependent_element)
|
|
||||||
if obj:
|
|
||||||
obj.name = tool.Loader.get_name(dependent_element)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -169,3 +169,31 @@ class TestSetObjectName(NewFile):
|
|||||||
element.Name = "Foobar"
|
element.Name = "Foobar"
|
||||||
subject.set_object_name(obj, element)
|
subject.set_object_name(obj, element)
|
||||||
assert obj.name == "IfcWall/Foobar"
|
assert obj.name == "IfcWall/Foobar"
|
||||||
|
|
||||||
|
|
||||||
|
class TestReassignClass(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.BIMProjectProperties.template_file = "IFC4 Demo Library.ifc"
|
||||||
|
bpy.ops.bim.create_project()
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
context = bpy.context
|
||||||
|
relating_type_id = ifc_file.by_type("IfcSlabType")[0].id()
|
||||||
|
n_wall_types = len(ifc_file.by_type("IfcWallType"))
|
||||||
|
n_slab_types = len(ifc_file.by_type("IfcSlabType"))
|
||||||
|
|
||||||
|
# create 3 slabs
|
||||||
|
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||||
|
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||||
|
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||||
|
|
||||||
|
slabs = [tool.Ifc.get_object(e) for e in ifc_file.by_type("IfcSlab")]
|
||||||
|
assert len(slabs) == 3
|
||||||
|
tool.Blender.set_objects_selection(context, slabs[0], (slabs[1],))
|
||||||
|
context.scene.BIMRootProperties.ifc_product = "IfcElement"
|
||||||
|
context.scene.BIMRootProperties.ifc_class = "IfcWall"
|
||||||
|
bpy.ops.bim.reassign_class()
|
||||||
|
|
||||||
|
assert len(ifc_file.by_type("IfcWall")) == 3
|
||||||
|
assert len(ifc_file.by_type("IfcSlab")) == 0
|
||||||
|
assert len(ifc_file.by_type("IfcWallType")) == n_wall_types + 1
|
||||||
|
assert len(ifc_file.by_type("IfcSlabType")) == n_slab_types - 1
|
||||||
|
|||||||
Reference in New Issue
Block a user