diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index ee68518c7b..e9a2fbc331 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -83,14 +83,11 @@ classes = ( opening.EditOpenings, opening.FlipFill, opening.HideAllOpenings, - opening.HideBooleans, opening.HideOpenings, opening.PurgeUnusedOpenings, opening.RecalculateFill, opening.RemoveBoolean, - opening.RemoveBooleans, opening.SelectBoolean, - opening.ShowBooleans, opening.ShowOpenings, opening.UpdateOpeningsFocus, profile.ChangeCardinalPoint, diff --git a/src/bonsai/bonsai/bim/module/model/opening.py b/src/bonsai/bonsai/bim/module/model/opening.py index 23864df0ed..c1f380969a 100644 --- a/src/bonsai/bonsai/bim/module/model/opening.py +++ b/src/bonsai/bonsai/bim/module/model/opening.py @@ -558,260 +558,6 @@ class AddBoolean(Operator, tool.Ifc.Operator): tool.Root.reload_item_decorator() -class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper): - bl_idname = "bim.show_booleans" - bl_label = "Show Booleans" - bl_description = "Show booleans for the selected objects.\nCan be used to reset booleans positions" - bl_options = {"REGISTER", "UNDO"} - - @classmethod - def poll(cls, context): - obj = context.active_object - return ( - obj is not None - and obj.data - and hasattr(obj.data, "BIMMeshProperties") - and obj.data.BIMMeshProperties.ifc_definition_id - ) - - def _execute(self, context): - selected_objects = tool.Blender.get_selected_objects() - boolean_objs = [] - for obj in selected_objects: - if not isinstance(mesh := obj.data, bpy.types.Mesh) or not mesh.BIMMeshProperties.ifc_definition_id: - continue - boolean_objs.extend(self.show_booleans(obj)) - - if boolean_objs: - DecorationsHandler.install(context) - tool.Blender.set_objects_selection(context, boolean_objs[0], boolean_objs) - - return {"FINISHED"} - - def show_booleans(self, obj: bpy.types.Object) -> list[bpy.types.Object]: - unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - representation = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id) - booleans: list[ifcopenshell.entity_instance] = [] - for item in representation.Items: - booleans.extend(self.get_booleans(item)) - - props = bpy.context.scene.BIMModelProperties - tool.Model.purge_scene_openings() - - existing_booleans = { - boolean_obj.data.BIMMeshProperties.ifc_boolean_id: boolean_obj - for opening in props.openings - if (boolean_obj := opening.obj).data.BIMMeshProperties.obj == obj - } - objects_to_remove = set() - - booleans_objs: list[bpy.types.Object] = [] - for boolean in booleans: - boolean_obj = None - - if boolean.is_a() == "IfcHalfSpaceSolid": - surface = boolean.BaseSurface - if surface.is_a("IfcPlane"): - boolean_obj = self.create_half_space_solid() - position = surface.Position - position = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist()) - position.translation *= unit_scale - boolean_obj.matrix_world = obj.matrix_world @ position - else: - self.report( - {"INFO"}, - f"Showing boolean using non-IfcPlane IfcSurface ({surface.is_a()}) is not supported.", - ) - else: - settings = ifcopenshell.geom.settings() - logger = logging.getLogger("ImportIFC") - ifc_import_settings = import_ifc.IfcImportSettings.factory(bpy.context, IfcStore.path, logger) - shape = ifcopenshell.geom.create_shape(settings, boolean) - if shape: - ifc_importer = import_ifc.IfcImporter(ifc_import_settings) - ifc_importer.file = tool.Ifc.get() - mesh = ifc_importer.create_mesh(boolean, shape) - else: - mesh = None - boolean_obj = object_data_add(bpy.context, mesh, operator=self) - boolean_obj.name = "BooleanMesh" - boolean_obj.matrix_world = obj.matrix_world - - if boolean_obj: - boolean_id = boolean.id() - if boolean_id in existing_booleans: - # Remove existing boolean as it will be reloaded. - objects_to_remove.add(existing_booleans[boolean_id]) - boolean_obj.data.BIMMeshProperties.ifc_boolean_id = boolean_id - boolean_obj.data.BIMMeshProperties.obj = obj - tool.Root.add_tracked_opening(boolean_obj, "BOOLEAN") - booleans_objs.append(boolean_obj) - - tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True) - return booleans_objs - - def get_booleans(self, item: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: - results = [] - if item.is_a("IfcBooleanResult"): - results.extend(self.get_booleans(item.FirstOperand)) - results.append(item.SecondOperand) - return results - - def create_half_space_solid(self) -> bpy.types.Object: - bm = bmesh.new() - bmesh.ops.create_grid(bm, size=0.5) - bm.verts.ensure_lookup_table() - bm.edges.ensure_lookup_table() - bm.faces.ensure_lookup_table() - mesh = bpy.data.meshes.new(name="Dumb Opening") - bm.to_mesh(mesh) - bm.free() - obj = object_data_add(bpy.context, mesh, operator=self) - obj.name = "HalfSpaceSolid" - return obj - - -class HideBooleans(Operator, tool.Ifc.Operator): - bl_idname = "bim.hide_booleans" - bl_label = "Hide Booleans" - bl_description = ( - "Hide boolean objects and apply their changed transforms.\n" - "If boolean object is selected, hide it, otherwise hide all boolean objects" - ) - bl_options = {"REGISTER", "UNDO"} - - def _execute(self, context): - ifc_file = tool.Ifc.get() - unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) - builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc_file) - - set_active_obj, set_selected_objs = None, None - boolean_objs: list[bpy.types.Object] - selected_objects = tool.Blender.get_selected_objects() - 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: - boolean_objs = selected_booleans_objs - if (active_object := context.active_object) in selected_booleans_objs: - active_obj_source = active_object - else: - active_obj_source = selected_booleans_objs[0] - set_active_obj = tool.Model.get_booleaned_obj(active_obj_source) - 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: - props = bpy.context.scene.BIMModelProperties - 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) - - for obj in boolean_objs: - main_obj = tool.Model.get_booleaned_obj(obj) - if not main_obj: - continue - - # Update boolean transform. - if main_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"): - surface = boolean.BaseSurface - - # Only IfcPlane is supported currently. - position = surface.Position - m = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist()) - m.translation *= unit_scale - - # Only update if transform was changed. - if not np.allclose(m, obj.matrix_world): - new_m = main_obj.matrix_world.inverted() @ obj.matrix_world - new_m.normalize() - new_m.translation /= unit_scale - new_m = np.array(new_m) - ifcopenshell.util.element.remove_deep2(ifc_file, position) - surface.Position = builder.create_axis2_placement_3d_from_matrix(new_m) - tool.Geometry.reload_representation(main_obj) - - objects_to_remove.add(obj) - - tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True) - 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: - tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs) - return {"FINISHED"} - - -class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper): - bl_idname = "bim.remove_booleans" - bl_label = "Remove Booleans" - bl_options = {"REGISTER", "UNDO"} - - def _execute(self, context): - upstream_obj = None - bbim_boolean_updates = {} - objects_to_remove = set() - for obj in context.selected_objects: - if ( - not obj.data - or not hasattr(obj.data, "BIMMeshProperties") - or not obj.data.BIMMeshProperties.ifc_boolean_id - ): - continue - try: - item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_boolean_id) - except: - continue - - boolean_id = None - for inverse in tool.Ifc.get().get_inverse(item): - if inverse.is_a("IfcBooleanResult"): - 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_id) - body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") - if body: - bonsai.core.geometry.switch_representation( - tool.Ifc, - tool.Geometry, - obj=upstream_obj, - representation=body, - should_reload=True, - is_global=True, - should_sync_changes_first=False, - ) - objects_to_remove.add(obj) - - tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True) - - 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"} - - class ShowOpenings(Operator, tool.Ifc.Operator): bl_idname = "bim.show_openings" bl_label = "Show" diff --git a/src/bonsai/bonsai/bim/module/void/ui.py b/src/bonsai/bonsai/bim/module/void/ui.py index ae18d0cc72..d07266a56f 100644 --- a/src/bonsai/bonsai/bim/module/void/ui.py +++ b/src/bonsai/bonsai/bim/module/void/ui.py @@ -162,13 +162,6 @@ class BIM_PT_booleans(Panel): ) op.mark_as_manual = not booleans_are_manual - elif upsteam_obj := obj.data.BIMMeshProperties.obj: - upstream_obj_ifc_id = upsteam_obj.BIMObjectProperties.ifc_definition_id - - row = layout.row(align=True) - row.label(text=upsteam_obj.name) - row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = upstream_obj_ifc_id - if not props.is_editing: return