bim.add_representation - update occurrences too if there were no representations

and new representation was just added to the type

Example - https://imgur.com/a/v6a5kg2
This commit is contained in:
Andrej730
2024-07-03 15:21:14 +05:00
parent f9aba58342
commit 5a0df870f5
3 changed files with 79 additions and 16 deletions
@@ -211,7 +211,7 @@ class AddRepresentation(bpy.types.Operator, Operator):
if original_data: if original_data:
tool.Geometry.change_object_data(obj, data, is_global=True) tool.Geometry.change_object_data(obj, data, is_global=True)
else: else:
obj = tool.Geometry.recreate_object_with_data(obj, data) obj = tool.Geometry.recreate_object_with_data(obj, data, is_global=True)
try: try:
core.add_representation( core.add_representation(
+10 -1
View File
@@ -690,7 +690,9 @@ class Geometry(blenderbim.core.tool.Geometry):
obj.name = name obj.name = name
@classmethod @classmethod
def recreate_object_with_data(cls, obj: bpy.types.Object, data: Union[bpy.types.ID, None]) -> bpy.types.Object: def recreate_object_with_data(
cls, obj: bpy.types.Object, data: Union[bpy.types.ID, None], is_global: bool = False
) -> bpy.types.Object:
"""Recreate a Blender object with the provided `data`. """Recreate a Blender object with the provided `data`.
This method is useful when an object should no longer have associated This method is useful when an object should no longer have associated
@@ -703,11 +705,18 @@ class Geometry(blenderbim.core.tool.Geometry):
Original `obj` is deleted and becomes invalid and should be replaced Original `obj` is deleted and becomes invalid and should be replaced
with an object returned by this method. with an object returned by this method.
:param is_global: Whether all `obj` occurrences should also be recreated
with the provided `data`. Works only if `obj` is an IfcTypeProduct.
:return: The newly recreated object. :return: The newly recreated object.
""" """
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
name = obj.name name = obj.name
if element: if element:
if is_global and element.is_a("IfcTypeProduct"):
ocurrences = ifcopenshell.util.element.get_types(element)
for occurrence in ocurrences:
cls.recreate_object_with_data(tool.Ifc.get_object(occurrence), data)
tool.Ifc.unlink(element=element) tool.Ifc.unlink(element=element)
obj.name = ifcopenshell.guid.new() obj.name = ifcopenshell.guid.new()
+68 -14
View File
@@ -20,11 +20,13 @@ import bpy
import math import math
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.api.type
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
from mathutils import Vector from mathutils import Vector
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
from blenderbim.tool.geometry import Geometry as subject from blenderbim.tool.geometry import Geometry as subject
from typing import Union
class TestImplementsTool(NewFile): class TestImplementsTool(NewFile):
@@ -375,23 +377,75 @@ class TestRenameObject(NewFile):
assert obj.name == "name" assert obj.name == "name"
# TODO: add a test
class TestReplaceObjectWithEmpty(NewFile): class TestReplaceObjectWithEmpty(NewFile):
def test_run(self): def validate(
self,
element: ifcopenshell.entity_instance,
obj: bpy.types.Object,
new_obj: bpy.types.Object,
new_data: Union[bpy.types.Mesh, None],
) -> None:
assert not tool.Blender.is_valid_data_block(obj)
assert new_obj.users_collection[0] == bpy.context.scene.collection
assert tool.Ifc.get_entity(new_obj) == element
assert tool.Ifc.get_object(element) == new_obj
assert new_obj.data is new_data
assert new_obj.matrix_world.translation.x == 1
def create_object(
self, name: str, data: Union[bpy.types.Mesh, None], ifc_class: str
) -> tuple[bpy.types.Object, ifcopenshell.entity_instance]:
ifc = tool.Ifc.get()
obj = bpy.data.objects.new(name, data)
obj.matrix_world.translation.x = 1
bpy.context.scene.collection.objects.link(obj)
element = ifc.create_entity(ifc_class)
tool.Ifc.link(element, obj)
return obj, element
def run_test_replace_non_global(
self, from_data: Union[bpy.types.Mesh, None], to_data: Union[bpy.types.Mesh, None]
) -> None:
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
obj.matrix_world[0][3] = 1 obj, element = self.create_object("Object", from_data, "IfcWall")
bpy.context.scene.collection.objects.link(obj) new_obj = subject.recreate_object_with_data(obj, to_data)
element = ifc.createIfcWall() if from_data:
tool.Ifc.link(element, obj) assert tool.Blender.is_valid_data_block(from_data)
subject.recreate_object_with_data(obj, None) self.validate(element, obj, new_obj, to_data)
obj = bpy.data.objects.get("Object")
assert obj.users_collection[0] == bpy.context.scene.collection def test_replace_mesh_with_empty(self) -> None:
assert tool.Ifc.get_entity(obj) == element self.run_test_replace_non_global(bpy.data.meshes.new("Mesh"), None)
assert tool.Ifc.get_object(element) == obj
assert obj.data is None def test_replace_empty_with_mesh(self) -> None:
assert obj.matrix_world[0][3] == 1 self.run_test_replace_non_global(None, bpy.data.meshes.new("New Mesh"))
def run_test_for_global_argument(
self, from_data: Union[bpy.types.Mesh, None], to_data: Union[bpy.types.Mesh, None]
) -> None:
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
type_obj, element_type = self.create_object("IfcWallType", from_data, "IfcWallType")
obj1, element1 = self.create_object("IfcWall1", from_data, "IfcWall")
obj2, element2 = self.create_object("IfcWall2", from_data, "IfcWall")
ifcopenshell.api.type.assign_type(ifc, related_objects=[element1, element2], relating_type=element_type)
to_data = to_data
new_obj = subject.recreate_object_with_data(type_obj, to_data, is_global=True)
if from_data:
assert tool.Blender.is_valid_data_block(from_data)
self.validate(element_type, type_obj, new_obj, to_data)
self.validate(element1, obj1, bpy.data.objects["IfcWall1"], to_data)
self.validate(element2, obj2, bpy.data.objects["IfcWall2"], to_data)
def test_replace_mesh_with_empty_global(self) -> None:
self.run_test_for_global_argument(bpy.data.meshes.new("Mesh"), None)
def test_replace_empty_with_mesh_global(self) -> None:
self.run_test_for_global_argument(None, bpy.data.meshes.new("New Mesh"))
class TestResolveMappedRepresentation(NewFile): class TestResolveMappedRepresentation(NewFile):