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.api
import ifcopenshell.util.schema import ifcopenshell.util.schema
import ifcopenshell.util.element import ifcopenshell.util.element
import blenderbim.bim.handler
from ifcopenshell.api.void.data import Data as VoidData from ifcopenshell.api.void.data import Data as VoidData
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -310,11 +311,14 @@ class CopyClass(bpy.types.Operator):
else: else:
bpy.ops.bim.add_representation(obj=obj.name) bpy.ops.bim.add_representation(obj=obj.name)
if result.is_a("IfcSpatialElement") or result.is_a("IfcSpatialStructureElement"): 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"} return {"FINISHED"}
def place_in_spatial_collection(self, old_element, obj): def place_in_spatial_collection(self, element, obj):
aggregate = ifcopenshell.util.element.get_aggregate(old_element) aggregate = ifcopenshell.util.element.get_aggregate(element)
if not aggregate: if not aggregate:
return return
container_obj = IfcStore.get_element(aggregate.id()) container_obj = IfcStore.get_element(aggregate.id())
@@ -327,3 +331,17 @@ class CopyClass(bpy.types.Operator):
new = bpy.data.collections.new(obj.name) new = bpy.data.collections.new(obj.name)
new.objects.link(obj) new.objects.link(obj)
collection.children.link(new) 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 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" 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 element.IsDecomposedBy
assert not new.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): def test_not_copying_any_representations_because_life_is_hard(self):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
element.Representation = self.file.createIfcProductDefinitionShape() 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) ifcopenshell.api.run("void.add_filling", self.file, opening=opening, element=door)
new = ifcopenshell.api.run("root.copy_class", self.file, product=opening) new = ifcopenshell.api.run("root.copy_class", self.file, product=opening)
assert not new.HasFillings 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