diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 59e47c7c02..8414c6d018 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -637,6 +637,11 @@ class OverrideDuplicateMove(bpy.types.Operator): element = tool.Ifc.get_entity(obj) if element and element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING": continue # For now, don't copy drawings until we stabilise a bit more. It's tricky. + + # Prior to duplicating, sync the object placement to make decomposition recreation more stable. + if tool.Ifc.is_moved(obj): + blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) + new_obj = obj.copy() if obj.data: new_obj.data = obj.data.copy() @@ -705,6 +710,10 @@ class OverrideDuplicateMoveLinked(bpy.types.Operator): relationships = tool.Root.get_decomposition_relationships(context.selected_objects) old_to_new = {} for obj in context.selected_objects: + # Prior to duplicating, sync the object placement to make decomposition recreation more stable. + if tool.Ifc.is_moved(obj): + blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) + new_obj = obj.copy() if obj.data: new_obj.data = obj.data.copy() diff --git a/src/blenderbim/blenderbim/tool/root.py b/src/blenderbim/blenderbim/tool/root.py index b7424ff3bc..ce198c9f00 100644 --- a/src/blenderbim/blenderbim/tool/root.py +++ b/src/blenderbim/blenderbim/tool/root.py @@ -23,6 +23,7 @@ import blenderbim.core.tool import blenderbim.core.geometry import blenderbim.tool as tool from mathutils import Vector +from blenderbim.bim.module.model.opening import FilledOpeningGenerator class Root(blenderbim.core.tool.Root): @@ -57,7 +58,10 @@ class Root(blenderbim.core.tool.Root): if not source.Representation: return dest.Representation = ifcopenshell.util.element.copy_deep( - tool.Ifc.get(), source.Representation, exclude=["IfcGeometricRepresentationContext"], exclude_callback=exclude_callback + tool.Ifc.get(), + source.Representation, + exclude=["IfcGeometricRepresentationContext"], + exclude_callback=exclude_callback, ) elif dest.is_a("IfcTypeProduct"): if not source.RepresentationMaps: @@ -140,9 +144,58 @@ class Root(blenderbim.core.tool.Root): for i, new_subelement in enumerate(new_subelements): new_element = new_elements[i] if data["type"] == "fill": - obj1 = tool.Ifc.get_object(new_element) - obj2 = tool.Ifc.get_object(new_subelement) - bpy.ops.bim.add_filled_opening(voided_obj=obj1.name, filling_obj=obj2.name) + element = new_element + filling = new_subelement + voided_obj = tool.Ifc.get_object(new_element) + filling_obj = tool.Ifc.get_object(new_subelement) + + existing_opening_occurrence = subelement.FillsVoids[0].RelatingOpeningElement + opening = ifcopenshell.api.run( + "root.copy_class", tool.Ifc.get(), product=existing_opening_occurrence + ) + ifcopenshell.api.run( + "geometry.edit_object_placement", + tool.Ifc.get(), + product=opening, + matrix=ifcopenshell.util.placement.get_local_placement(opening.ObjectPlacement), + is_si=False, + ) + + representation = ifcopenshell.util.representation.get_representation( + existing_opening_occurrence, "Model", "Body", "MODEL_VIEW" + ) + representation = ifcopenshell.util.representation.resolve_representation(representation) + mapped_representation = ifcopenshell.api.run( + "geometry.map_representation", tool.Ifc.get(), representation=representation + ) + ifcopenshell.api.run( + "geometry.assign_representation", + tool.Ifc.get(), + product=opening, + representation=mapped_representation, + ) + ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=opening, element=element) + ifcopenshell.api.run("void.add_filling", tool.Ifc.get(), opening=opening, element=filling) + + voided_objs = [voided_obj] + # Openings affect all subelements of an aggregate + for subelement in ifcopenshell.util.element.get_decomposition(element): + subobj = tool.Ifc.get_object(subelement) + if subobj: + voided_objs.append(subobj) + + for voided_obj in voided_objs: + if voided_obj.data: + representation = tool.Ifc.get().by_id(voided_obj.data.BIMMeshProperties.ifc_definition_id) + blenderbim.core.geometry.switch_representation( + tool.Ifc, + tool.Geometry, + obj=voided_obj, + representation=representation, + should_reload=True, + is_global=True, + should_sync_changes_first=False, + ) @classmethod def run_geometry_add_representation(