Support adding duplicated existing boolean

Example - https://imgur.com/a/rRQz9dx
This commit is contained in:
Andrej730
2025-01-15 18:39:05 +05:00
parent 5d17554d04
commit 23b1a71cba
3 changed files with 41 additions and 17 deletions
+31 -9
View File
@@ -36,6 +36,7 @@ import ifcopenshell.util.unit
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.geometry import bonsai.core.geometry
import bonsai.bim.import_ifc as import_ifc import bonsai.bim.import_ifc as import_ifc
from collections import defaultdict
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from math import pi, radians from math import pi, radians
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
@@ -737,27 +738,43 @@ class HideBooleans(Operator, tool.Ifc.Operator):
set_active_obj, set_selected_objs = None, None set_active_obj, set_selected_objs = None, None
boolean_objs: list[bpy.types.Object] boolean_objs: list[bpy.types.Object]
selected_objects = tool.Blender.get_selected_objects() selected_objects = tool.Blender.get_selected_objects()
selected_booleans_objs = [obj for obj in selected_objects if tool.Model.is_boolean_obj(obj)] selected_booleans_objs = [
obj for obj in selected_objects if tool.Model.get_tracked_opening_type(obj) == "BOOLEAN"
]
# Hide currently selected booleans, otherwise hide all booleans.
if selected_booleans_objs: if selected_booleans_objs:
boolean_objs = selected_booleans_objs boolean_objs = selected_booleans_objs
if (active_object := context.active_object) in selected_booleans_objs: if (active_object := context.active_object) in selected_booleans_objs:
active_obj_source = active_object active_obj_source = active_object
else: else:
active_obj_source = selected_booleans_objs[0] active_obj_source = selected_booleans_objs[0]
set_active_obj = active_obj_source.data.BIMMeshProperties.obj set_active_obj = tool.Model.get_booleaned_obj(active_obj_source)
set_selected_objs = [tool.Model.get_booleaned_obj(obj) for obj in boolean_objs] assert set_active_obj
set_selected_objs = [
bool_obj for obj in selected_booleans_objs if (bool_obj := tool.Model.get_booleaned_obj(obj))
]
else: else:
props = bpy.context.scene.BIMModelProperties props = bpy.context.scene.BIMModelProperties
boolean_objs = [obj for o in props.openings if (obj := o.obj)] boolean_objs = [obj for o in props.openings if (obj := o.obj) and o.name == "BOOLEAN"]
objects_to_remove: set[bpy.types.Object] = set()
booleans_to_add: dict[bpy.types.Object, list[bpy.types.Object]] = defaultdict(list)
objects_to_remove = set()
for obj in boolean_objs: for obj in boolean_objs:
ifc_boolean_id = obj.data.BIMMeshProperties.ifc_boolean_id main_obj = tool.Model.get_booleaned_obj(obj)
boolean = tool.Ifc.get_entity_by_id(ifc_boolean_id) if not main_obj:
continue
# Update boolean transform. # Update boolean transform.
if boolean: if main_obj:
main_obj = cast(bpy.types.Object, obj.data.BIMMeshProperties.obj) ifc_boolean_id = obj.data.BIMMeshProperties.ifc_boolean_id
boolean = tool.Ifc.get_entity_by_id(ifc_boolean_id)
if boolean is None:
booleans_to_add[main_obj].append(obj)
continue
if boolean.is_a("IfcHalfSpaceSolid"): if boolean.is_a("IfcHalfSpaceSolid"):
surface = boolean.BaseSurface surface = boolean.BaseSurface
@@ -781,6 +798,11 @@ class HideBooleans(Operator, tool.Ifc.Operator):
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True) tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
tool.Model.purge_scene_openings() tool.Model.purge_scene_openings()
if booleans_to_add:
for obj, boolean_objs in booleans_to_add.items():
with context.temp_override(selected_objects=boolean_objs + [obj]):
bpy.ops.bim.add_boolean()
if set_active_obj and set_selected_objs is not None: if set_active_obj and set_selected_objs is not None:
tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs) tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs)
return {"FINISHED"} return {"FINISHED"}
+4 -2
View File
@@ -104,6 +104,9 @@ class BIM_PT_booleans(Panel):
if not BooleansData.is_loaded: if not BooleansData.is_loaded:
BooleansData.load() BooleansData.load()
obj = context.active_object
assert obj
if not context.active_object.data: if not context.active_object.data:
return return
layout = self.layout layout = self.layout
@@ -126,8 +129,7 @@ class BIM_PT_booleans(Panel):
) )
op.mark_as_manual = not booleans_are_manual op.mark_as_manual = not booleans_are_manual
elif context.active_object.data.BIMMeshProperties.ifc_boolean_id: elif upsteam_obj := obj.data.BIMMeshProperties.obj:
upsteam_obj = context.active_object.data.BIMMeshProperties.obj
upstream_obj_ifc_id = upsteam_obj.BIMObjectProperties.ifc_definition_id upstream_obj_ifc_id = upsteam_obj.BIMObjectProperties.ifc_definition_id
row = layout.row(align=True) row = layout.row(align=True)
+6 -6
View File
@@ -2007,12 +2007,12 @@ class Model(bonsai.core.tool.Model):
return {"ifc_file": tmp, "curves": curves} return {"ifc_file": tmp, "curves": curves}
@classmethod @classmethod
def is_boolean_obj(cls, obj: bpy.types.Object) -> bool: def get_booleaned_obj(cls, obj: bpy.types.Object) -> Union[bpy.types.Object, None]:
return obj.type == "MESH" and obj.data.BIMMeshProperties.ifc_boolean_id """Get boolean obj, return `None` if either it's not a tracked boolean
or it's not referring to an object (e.g. potential boolean object)."""
@classmethod if obj.type != "MESH":
def get_booleaned_obj(cls, boolean_obj: bpy.types.Object) -> bpy.types.Object: return
return boolean_obj.data.BIMMeshProperties.obj return obj.data.BIMMeshProperties.obj
@classmethod @classmethod
def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]: def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]: