move to tools methods for working with manual booleans #3709

Also fixed a bug adding boolean when pset is already added and representation type in add_boolean

```
  File "\addons\blenderbim\tool\ifc.py", line 201, in execute
    IfcStore.execute_ifc_operator(self, context)
  File "\addons\blenderbim\bim\ifc.py", line 336, in execute_ifc_operator
    result = getattr(operator, "_execute")(context)
  File "\addons\blenderbim\bim\module\model\opening.py", line 534, in _execute
    data = json.loads(pset["Data"])
  File "\addons\blenderbim\libs\site\packages\ifcopenshell\entity_instance.py", line 248, in __getitem__
    if key < 0 or key >= len(self):
TypeError: '<' not supported between instances of 'str' and 'int'
```
This commit is contained in:
Andrej730
2023-10-17 16:38:25 +05:00
parent 3f018a4195
commit 35d66f5d8c
4 changed files with 69 additions and 53 deletions
@@ -528,17 +528,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
"geometry.add_boolean", tool.Ifc.get(), representation=representation, operator="DIFFERENCE", **mesh_data
)
pset = ifcopenshell.util.element.get_pset(element1, "BBIM_Boolean")
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
data = json.loads(pset["Data"])
data.extend([b.id() for b in booleans])
data = list(set(data))
else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element1, name="BBIM_Boolean")
data = [b.id() for b in booleans]
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": json.dumps(data)})
tool.Model.mark_manual_booleans(element1, booleans)
tool.Model.clear_scene_openings()
blenderbim.core.geometry.switch_representation(
@@ -672,17 +662,17 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
except:
continue
boolean_id = None
boolean = None
for inverse in tool.Ifc.get().get_inverse(item):
if inverse.is_a("IfcBooleanResult"):
boolean_id = inverse.id()
boolean = inverse
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_id)
bbim_boolean_updates.setdefault(element, []).append(boolean)
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if body:
blenderbim.core.geometry.switch_representation(
@@ -696,18 +686,8 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
)
bpy.data.objects.remove(obj)
for element, boolean_ids in bbim_boolean_updates.items():
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
if not pset:
continue
data = set(json.loads(pset["Data"]))
data -= set(boolean_ids)
data = list(data)
pset = tool.Ifc.get().by_id(pset["id"])
if data:
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": json.dumps(data)})
else:
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
for element, booleans in bbim_boolean_updates.items():
tool.Model.unmark_manual_booleans(element, booleans)
tool.Blender.set_active_object(upstream_obj)
return {"FINISHED"}
+43 -7
View File
@@ -474,11 +474,7 @@ class Model(blenderbim.core.tool.Model):
return {"thickness": thickness, "offset": offset, "direction_sense": direction_sense}
@classmethod
def get_manual_booleans(cls, element):
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
if not pset:
return []
boolean_ids = json.loads(pset["Data"])
def get_booleans(cls, element):
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if not body:
return []
@@ -487,11 +483,51 @@ class Model(blenderbim.core.tool.Model):
while items:
item = items.pop()
if item.is_a("IfcBooleanResult"):
if item.id() in boolean_ids:
booleans.append(item)
booleans.append(item)
items.append(item.FirstOperand)
return booleans
@classmethod
def get_manual_booleans(cls, element):
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
if not pset:
return []
boolean_ids = json.loads(pset["Data"])
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if not body:
return []
booleans = [b for b in cls.get_booleans(element) if b.id() in boolean_ids]
return booleans
@classmethod
def mark_manual_booleans(cls, element, booleans):
pset_data = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
boolean_ids = [b.id() for b in booleans]
if pset_data:
pset = tool.Ifc.get().by_id(pset_data["id"])
data = json.loads(pset_data["Data"])
data.extend(boolean_ids)
data = list(set(data))
else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Boolean")
data = boolean_ids
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": json.dumps(data)})
@classmethod
def unmark_manual_booleans(cls, element, booleans):
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)
pset = tool.Ifc.get().by_id(pset["id"])
if data:
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": json.dumps(data)})
else:
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
@classmethod
def get_flow_segment_axis(cls, obj):
z_values = [v[2] for v in obj.bound_box]
+17 -19
View File
@@ -54,10 +54,20 @@ class TestGenerateOccurrenceName(NewFile):
class TestGetManualBooleans(NewFile):
def test_run(self):
assert isinstance(subject(), blenderbim.core.tool.Model)
def test_get_manual_booleans(self):
clippings = [
{
"type": "IfcBooleanClippingResult",
"operand_type": "IfcHalfSpaceSolid",
"matrix": np.eye(4).tolist(),
},
{
"type": "IfcBooleanResult",
"operand_type": "IfcHalfSpaceSolid",
"matrix": np.eye(4).tolist(),
},
]
def setup_profile_represntation(self, clippings=[]):
ifc = ifcopenshell.file()
self.ifc = ifc
tool.Ifc.set(ifc)
@@ -89,21 +99,9 @@ class TestGetManualBooleans(NewFile):
"geometry.add_profile_representation", ifc, context=body, profile=hea100, depth=5, clippings=clippings
)
ifcopenshell.api.run("geometry.assign_representation", ifc, product=element, representation=representation)
return element, representation
def test_manual_booleans(self):
element, representation = self.setup_profile_represntation()
matrix = np.eye(4)
ifcopenshell.api.run(
"geometry.add_boolean", self.ifc, representation=representation, type="IfcHalfSpaceSolid", matrix=matrix
)
assert len(subject.get_manual_booleans(element)) == 1
def test_automatic_booleans_ignored(self):
clipping = {
"type": "IfcBooleanClippingResult",
"operand_type": "IfcHalfSpaceSolid",
"matrix": np.eye(4).tolist(),
}
element, representation = self.setup_profile_represntation(clippings=[clipping])
booleans = subject.get_booleans(element)
assert len(booleans) == 2
assert len(subject.get_manual_booleans(element)) == 0
subject.mark_manual_booleans(element, booleans)
assert len(subject.get_manual_booleans(element)) == 2
@@ -57,9 +57,11 @@ class Usecase:
)
):
items.append(self.file.createIfcBooleanClippingResult(self.settings["operator"], item, result))
representation_type = "Clipping"
else:
items.append(self.file.createIfcBooleanResult(self.settings["operator"], item, result))
self.settings["representation"].RepresentationType = "CSG"
representation_type = "CSG"
self.settings["representation"].RepresentationType = representation_type
self.settings["representation"].Items = items
return items