Fix #4267 and add tests

Crash was caused by unmark_manual_booleans accessing boolean element after they were deleted from IFC
This commit is contained in:
Andrej730
2024-01-30 14:05:35 +05:00
parent af593b6663
commit 5d020f36d3
4 changed files with 44 additions and 9 deletions
@@ -668,17 +668,17 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
except:
continue
boolean = None
boolean_id = None
for inverse in tool.Ifc.get().get_inverse(item):
if inverse.is_a("IfcBooleanResult"):
boolean = inverse
boolean_id = inverse.id()
break
ifcopenshell.api.run("geometry.remove_boolean", tool.Ifc.get(), item=item)
if obj.data.BIMMeshProperties.obj:
upstream_obj = obj.data.BIMMeshProperties.obj
element = tool.Ifc.get_entity(upstream_obj)
bbim_boolean_updates.setdefault(element, []).append(boolean)
bbim_boolean_updates.setdefault(element, []).append(boolean_id)
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if body:
blenderbim.core.geometry.switch_representation(
@@ -692,8 +692,8 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
)
bpy.data.objects.remove(obj)
for element, booleans in bbim_boolean_updates.items():
tool.Model.unmark_manual_booleans(element, booleans)
for element, boolean_ids in bbim_boolean_updates.items():
tool.Model.unmark_manual_booleans(element, boolean_ids)
tool.Blender.set_active_object(upstream_obj)
return {"FINISHED"}
@@ -259,8 +259,10 @@ class BooleansMarkAsManual(bpy.types.Operator):
if self.mark_as_manual:
tool.Model.mark_manual_booleans(element, booleans)
else:
tool.Model.unmark_manual_booleans(element, booleans)
tool.Model.unmark_manual_booleans(element, [b.id() for b in booleans])
self.report({"INFO"}, f"{len(booleans)} were marked as {'manual' if self.mark_as_manual else 'automatic'}")
self.report(
{"INFO"}, f"{len(booleans)} booleans were marked as {'manual' if self.mark_as_manual else 'automatic'}"
)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
+3 -2
View File
@@ -521,11 +521,12 @@ class Model(blenderbim.core.tool.Model):
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data})
@classmethod
def unmark_manual_booleans(cls, element, booleans):
def unmark_manual_booleans(cls, element, boolean_ids):
# NOTE: we use use boolean_ids instead of boolean entities
# so it will be possible to unmark manual booleans after they already was deleted
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
if not pset:
return
boolean_ids = [b.id() for b in booleans]
data = set(json.loads(pset["Data"]))
data -= set(boolean_ids)
data = list(data)
+32
View File
@@ -21,6 +21,7 @@ import ifcopenshell
import blenderbim.core.tool
import blenderbim.tool as tool
import numpy as np
import json
from test.bim.bootstrap import NewFile
from blenderbim.tool.model import Model as subject
from ifcopenshell.util.shape_builder import V
@@ -108,6 +109,37 @@ class TestGetManualBooleans(NewFile):
assert len(subject.get_manual_booleans(element)) == 2
class TestMarkManualBooleans(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcWall()
boolean = ifc.createIfcBooleanClippingResult()
subject.mark_manual_booleans(element, [boolean])
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
assert pset
value = json.loads(pset["Data"])
assert set(value) == {boolean.id()}
class TestUnmarkManualBooleans(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcWall()
boolean = ifc.createIfcBooleanClippingResult()
boolean2 = ifc.createIfcBooleanClippingResult()
subject.mark_manual_booleans(element, [boolean, boolean2])
subject.unmark_manual_booleans(element, [boolean.id()])
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
assert pset
value = json.loads(pset["Data"])
assert set(value) == {boolean2.id()}
class TestStairCalculatedParams(NewFile):
def compare_data(self, pset_data, expected_calculated_data):
calculated_data = subject.get_active_stair_calculated_params(pset_data)