mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 09:32:37 +00:00
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:
@@ -668,17 +668,17 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
boolean = None
|
boolean_id = None
|
||||||
for inverse in tool.Ifc.get().get_inverse(item):
|
for inverse in tool.Ifc.get().get_inverse(item):
|
||||||
if inverse.is_a("IfcBooleanResult"):
|
if inverse.is_a("IfcBooleanResult"):
|
||||||
boolean = inverse
|
boolean_id = inverse.id()
|
||||||
break
|
break
|
||||||
ifcopenshell.api.run("geometry.remove_boolean", tool.Ifc.get(), item=item)
|
ifcopenshell.api.run("geometry.remove_boolean", tool.Ifc.get(), item=item)
|
||||||
|
|
||||||
if obj.data.BIMMeshProperties.obj:
|
if obj.data.BIMMeshProperties.obj:
|
||||||
upstream_obj = obj.data.BIMMeshProperties.obj
|
upstream_obj = obj.data.BIMMeshProperties.obj
|
||||||
element = tool.Ifc.get_entity(upstream_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")
|
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if body:
|
if body:
|
||||||
blenderbim.core.geometry.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
@@ -692,8 +692,8 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|||||||
)
|
)
|
||||||
bpy.data.objects.remove(obj)
|
bpy.data.objects.remove(obj)
|
||||||
|
|
||||||
for element, booleans in bbim_boolean_updates.items():
|
for element, boolean_ids in bbim_boolean_updates.items():
|
||||||
tool.Model.unmark_manual_booleans(element, booleans)
|
tool.Model.unmark_manual_booleans(element, boolean_ids)
|
||||||
|
|
||||||
tool.Blender.set_active_object(upstream_obj)
|
tool.Blender.set_active_object(upstream_obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -259,8 +259,10 @@ class BooleansMarkAsManual(bpy.types.Operator):
|
|||||||
if self.mark_as_manual:
|
if self.mark_as_manual:
|
||||||
tool.Model.mark_manual_booleans(element, booleans)
|
tool.Model.mark_manual_booleans(element, booleans)
|
||||||
else:
|
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()
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -521,11 +521,12 @@ class Model(blenderbim.core.tool.Model):
|
|||||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data})
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data})
|
||||||
|
|
||||||
@classmethod
|
@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")
|
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
||||||
if not pset:
|
if not pset:
|
||||||
return
|
return
|
||||||
boolean_ids = [b.id() for b in booleans]
|
|
||||||
data = set(json.loads(pset["Data"]))
|
data = set(json.loads(pset["Data"]))
|
||||||
data -= set(boolean_ids)
|
data -= set(boolean_ids)
|
||||||
data = list(data)
|
data = list(data)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import ifcopenshell
|
|||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import json
|
||||||
from test.bim.bootstrap import NewFile
|
from test.bim.bootstrap import NewFile
|
||||||
from blenderbim.tool.model import Model as subject
|
from blenderbim.tool.model import Model as subject
|
||||||
from ifcopenshell.util.shape_builder import V
|
from ifcopenshell.util.shape_builder import V
|
||||||
@@ -108,6 +109,37 @@ class TestGetManualBooleans(NewFile):
|
|||||||
assert len(subject.get_manual_booleans(element)) == 2
|
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):
|
class TestStairCalculatedParams(NewFile):
|
||||||
def compare_data(self, pset_data, expected_calculated_data):
|
def compare_data(self, pset_data, expected_calculated_data):
|
||||||
calculated_data = subject.get_active_stair_calculated_params(pset_data)
|
calculated_data = subject.get_active_stair_calculated_params(pset_data)
|
||||||
|
|||||||
Reference in New Issue
Block a user