Non dynamically voided objects now auto update when their opening is removed

This commit is contained in:
Dion Moult
2021-09-09 12:54:43 +10:00
parent 3004d5424c
commit 33bc0be5ff
4 changed files with 148 additions and 5 deletions
@@ -21,7 +21,6 @@ import ifcopenshell.api
import ifcopenshell.util.representation
from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.void.data import Data
from ifcopenshell.api.context.data import Data as ContextData
class AddOpening(bpy.types.Operator):
@@ -87,6 +86,7 @@ class RemoveOpening(bpy.types.Operator):
def _execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
self.file = IfcStore.get_file()
is_modifier_removed = False
for modifier in obj.modifiers:
if modifier.type != "BOOLEAN":
continue
@@ -94,10 +94,19 @@ class RemoveOpening(bpy.types.Operator):
IfcStore.unlink_element(obj=modifier.object)
if "/" in modifier.object.name and modifier.object.name[0:3] == "Ifc":
modifier.object.name = "/".join(modifier.object.name.split("/")[1:])
is_modifier_removed = True
obj.modifiers.remove(modifier)
break
ifcopenshell.api.run("void.remove_opening", self.file, **{"opening": self.file.by_id(self.opening_id)})
if not is_modifier_removed:
bpy.ops.bim.switch_representation(
ifc_definition_id=obj.data.BIMMeshProperties.ifc_definition_id,
should_reload=True,
should_switch_all_meshes=True,
)
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
return {"FINISHED"}
+62 -4
View File
@@ -60,11 +60,19 @@ def i_add_a_cube():
bpy.ops.mesh.primitive_cube_add()
def i_add_a_cube_of_size_size_at_location(size, location):
bpy.ops.mesh.primitive_cube_add(size=float(size), location=[float(co) for co in location.split(",")])
def the_object_name_is_selected(name):
bpy.ops.object.select_all(action="DESELECT")
additionally_the_object_name_is_selected(name)
def additionally_the_object_name_is_selected(name):
obj = bpy.context.scene.objects.get(name)
if not obj:
assert False, 'The object "{name}" could not be selected'
bpy.ops.object.select_all(action="DESELECT")
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
@@ -81,7 +89,10 @@ def i_enable_prop(prop):
def i_press_operator(operator):
exec(f"bpy.ops.{operator}()")
if "(" in operator:
exec(f"bpy.ops.{operator}")
else:
exec(f"bpy.ops.{operator}()")
def the_object_name_exists(name):
@@ -153,14 +164,53 @@ def the_file_name_should_contain_value(name, value):
assert value in f.read()
def the_object_name1_has_a_boolean_difference_by_name2(name1, name2):
obj = the_object_name_exists(name1)
for modifier in obj.modifiers:
if modifier.type == "BOOLEAN" and modifier.object.name == name2:
return True
assert False, "No boolean found"
def the_object_name1_has_no_boolean_difference_by_name2(name1, name2):
obj = the_object_name_exists(name1)
for modifier in obj.modifiers:
if modifier.type == "BOOLEAN" and modifier.object.name == name2:
assert False, "A boolean was found"
def the_object_name_is_voided_by_void(name, void):
ifc = IfcStore.get_file()
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
for rel in element.HasOpenings:
if rel.RelatedOpeningElement.Name == void:
return True
assert False, "No void found"
def the_object_name_is_not_voided_by_void(name, void):
ifc = IfcStore.get_file()
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
for rel in element.HasOpenings:
if rel.RelatedOpeningElement.Name == void:
assert False, "A void was found"
def the_object_name_should_display_as_mode(name, mode):
assert the_object_name_exists(name).display_type == mode
def the_object_name_has_number_vertices(name, number):
total = len(the_object_name_exists(name).data.vertices)
assert total == int(number), f"We found {total} vertices"
definitions = {
"an empty IFC project": an_empty_ifc_project,
"I add a cube": i_add_a_cube,
'I add a cube of size "([0-9]+)" at "(.*)"': i_add_a_cube_of_size_size_at_location,
'the object "(.*)" is selected': the_object_name_is_selected,
'additionally the object "(.*)" is selected': additionally_the_object_name_is_selected,
'I set "(.*)" to "(.*)"': i_set_prop_to_value,
'I enable "(.*)"': i_enable_prop,
'I press "(.*)"': i_press_operator,
@@ -174,20 +224,28 @@ definitions = {
"I duplicate the selected objects": i_duplicate_the_selected_objects,
'the object "(.*)" and "(.*)" are different elements': the_object_name1_and_name2_are_different_elements,
'the file "(.*)" should contain "(.*)"': the_file_name_should_contain_value,
'the object "(.*)" has a boolean difference by "(.*)"': the_object_name1_has_a_boolean_difference_by_name2,
'the object "(.*)" has no boolean difference by "(.*)"': the_object_name1_has_no_boolean_difference_by_name2,
'the object "(.*)" is voided by "(.*)"': the_object_name_is_voided_by_void,
'the object "(.*)" is not voided by "(.*)"': the_object_name_is_not_voided_by_void,
'the object "(.*)" should display as "(.*)"': the_object_name_should_display_as_mode,
'the object "(.*)" has "([0-9]+)" vertices': the_object_name_has_number_vertices,
}
# Super lightweight Gherkin implementation
def run(scenario):
keywords = ["Given", "When", "Then", "And", "But"]
for line in scenario.split("\n"):
line = line.strip()
line = line.replace("{cwd}", os.getcwd())
for keyword in keywords:
line = line.replace(keyword, "")
line = line.strip()
if not line:
continue
match = None
for definition, callback in definitions.items():
match = re.search(definition, line)
match = re.search("^" + definition + "$", line)
if match:
try:
callback(*match.groups())
@@ -0,0 +1,76 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import test.bim.bootstrap
class TestAddOpening(test.bim.bootstrap.NewFile):
@test.bim.bootstrap.scenario
def test_adding_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 "IfcWall/Cube" is selected
And additionally the object "Cube" is selected
And I press "bim.add_opening(opening='Cube', obj='IfcWall/Cube')"
Then the object "IfcOpeningElement/Cube" is an "IfcOpeningElement"
And the object "IfcOpeningElement/Cube" should display as "WIRE"
And the object "IfcWall/Cube" has a boolean difference by "IfcOpeningElement/Cube"
And the object "IfcWall/Cube" is voided by "Cube"
"""
class TestRemoveOpening(test.bim.bootstrap.NewFile):
@test.bim.bootstrap.scenario
def test_removing_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 of size "1" at "1,0,0"
And the object "IfcWall/Cube" is selected
And additionally the object "Cube" is selected
And I press "bim.add_opening(opening='Cube', obj='IfcWall/Cube')"
And I press "bim.remove_opening(opening_id=97, obj='IfcWall/Cube')"
Then the object "IfcWall/Cube" has no boolean difference by "IfcOpeningElement/Cube"
And the object "IfcWall/Cube" is not voided by "Cube"
"""
@test.bim.bootstrap.scenario
def test_removing_a_non_dynamic_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 of size "1" at "1,0,0"
And the object "IfcWall/Cube" is selected
And additionally the object "Cube" is selected
And I press "bim.add_opening(opening='Cube', obj='IfcWall/Cube')"
And the object "IfcWall/Cube" is selected
And I press "bim.print_ifc_file"
And I press "bim.switch_representation(ifc_definition_id=86, should_reload=True)"
Then the object "IfcWall/Cube" has no boolean difference by "IfcOpeningElement/Cube"
And the object "IfcWall/Cube" has "16" vertices
When I press "bim.remove_opening(opening_id=97, obj='IfcWall/Cube')"
Then the object "IfcWall/Cube" has "8" vertices
"""