Fix #1737. Bug where copying an opening didn't copy relevant boolean modifiers too.

This commit is contained in:
Dion Moult
2021-09-21 15:19:18 +10:00
parent 1abca2681e
commit a29d691944
3 changed files with 53 additions and 3 deletions
@@ -21,6 +21,7 @@ import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.schema
import ifcopenshell.util.element
import blenderbim.bim.handler
from ifcopenshell.api.void.data import Data as VoidData
from blenderbim.bim.ifc import IfcStore
@@ -310,11 +311,14 @@ class CopyClass(bpy.types.Operator):
else:
bpy.ops.bim.add_representation(obj=obj.name)
if result.is_a("IfcSpatialElement") or result.is_a("IfcSpatialStructureElement"):
self.place_in_spatial_collection(old_element, obj)
self.place_in_spatial_collection(result, obj)
elif result.is_a("IfcOpeningElement"):
self.add_opening_modifiers(result, obj)
blenderbim.bim.handler.purge_module_data()
return {"FINISHED"}
def place_in_spatial_collection(self, old_element, obj):
aggregate = ifcopenshell.util.element.get_aggregate(old_element)
def place_in_spatial_collection(self, element, obj):
aggregate = ifcopenshell.util.element.get_aggregate(element)
if not aggregate:
return
container_obj = IfcStore.get_element(aggregate.id())
@@ -327,3 +331,17 @@ class CopyClass(bpy.types.Operator):
new = bpy.data.collections.new(obj.name)
new.objects.link(obj)
collection.children.link(new)
def add_opening_modifiers(self, result, obj):
for rel in result.VoidsElements:
building_obj = IfcStore.get_element(rel.RelatingBuildingElement.id())
try:
modifier = next(m for m in obj.modifiers if m.type == "BOOLEAN" and m.object == obj)
except StopIteration:
modifier = building_obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
modifier.object = obj
finally:
modifier.operation = "DIFFERENCE"
modifier.solver = "EXACT"
modifier.use_self = True
modifier.operand_type = "OBJECT"
@@ -107,3 +107,21 @@ class TestCopyClass(test.bim.bootstrap.NewFile):
And the object "IfcBuildingStorey/My Storey.001" is in the collection "IfcBuildingStorey/My Storey.001"
And the collection "IfcBuildingStorey/My Storey.001" is in the collection "IfcBuilding/My Building"
"""
@test.bim.bootstrap.scenario
def test_copying_an_opening(self):
return """
Given an empty IFC project
When the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add a cube
And the object "Cube" is selected
And additionally the object "IfcWall/Cube" is selected
And I press "bim.add_opening(opening='Cube', obj='IfcWall/Cube')"
And the object "IfcOpeningElement/Cube" is selected
And I duplicate the selected objects
Then the object "IfcOpeningElement/Cube" and "IfcOpeningElement/Cube.001" are different elements
And the object "IfcWall/Cube" has a boolean difference by "IfcOpeningElement/Cube"
And the object "IfcWall/Cube" has a boolean difference by "IfcOpeningElement/Cube.001"
"""
@@ -32,6 +32,13 @@ class TestCopyClass(test.bootstrap.IFC4):
assert element.IsDecomposedBy
assert not new.IsDecomposedBy
def test_copying_an_aggregate_decomposition(self):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcElementAssembly")
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
ifcopenshell.api.run("aggregate.assign_object", self.file, product=subelement, relating_object=element)
new = ifcopenshell.api.run("root.copy_class", self.file, product=subelement)
assert new.Decomposes[0].RelatingObject == element
def test_not_copying_any_representations_because_life_is_hard(self):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
element.Representation = self.file.createIfcProductDefinitionShape()
@@ -56,3 +63,10 @@ class TestCopyClass(test.bootstrap.IFC4):
ifcopenshell.api.run("void.add_filling", self.file, opening=opening, element=door)
new = ifcopenshell.api.run("root.copy_class", self.file, product=opening)
assert not new.HasFillings
def test_copying_a_filling(self):
door = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDoor")
opening = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcOpeningElement")
ifcopenshell.api.run("void.add_filling", self.file, opening=opening, element=door)
new = ifcopenshell.api.run("root.copy_class", self.file, product=door)
assert not new.FillsVoids