Bonsai - extract elements from selection #4316

Demo - https://imgchest.com/p/xny8qvox5yb
You can also now reuse 'bpy.data.texts['globalid-filter-3UvnD5Ml95zBDEcwAkAUIp']' kind of queries from Search in ExtractElements query.
This commit is contained in:
Andrej730
2024-12-06 18:57:44 +05:00
parent 2a713846ce
commit c4ffc06a88
7 changed files with 81 additions and 14 deletions
+3
View File
@@ -52,6 +52,7 @@ def draw_attributes(
layout: bpy.types.UILayout,
copy_operator: Optional[str] = None,
popup_active_attribute: Optional[bonsai.bim.prop.Attribute] = None,
callback: Optional[Callable[[bonsai.bim.prop.Attribute, bpy.types.UILayout], None]] = None,
) -> None:
"""you can set attribute active in popup with `active_attribute`
meaning you will be able to type into attribute's field without having to click
@@ -62,6 +63,8 @@ def draw_attributes(
if attribute == popup_active_attribute:
row.activate_init = True
draw_attribute(attribute, row, copy_operator)
if callback:
callback(attribute, row)
def draw_attribute(
@@ -21,6 +21,7 @@ from . import ui, prop, operator
classes = (
operator.ExecuteIfcPatch,
operator.ExtractSelectedElements,
operator.RunMigratePatch,
operator.SelectIfcPatchInput,
operator.SelectIfcPatchOutput,
@@ -89,6 +89,7 @@ class ExecuteIfcPatch(bpy.types.Operator):
value = value[0]
arguments.append(value)
arguments = tool.Patch.post_process_patch_arguments(recipe_name, arguments)
args = ifcpatch.ArgumentsDict(
recipe=props.ifc_patch_recipes,
arguments=arguments,
@@ -208,3 +209,21 @@ class RunMigratePatch(bpy.types.Operator):
pass # Probably running in headless mode
bonsai.bim.handler.refresh_ui_data()
return {"FINISHED"}
class ExtractSelectedElements(bpy.types.Operator):
bl_idname = "bim.patch_query_from_selected"
bl_label = "Fill patch query based on the selected elements"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMPatchProperties
recipe_name = props.ifc_patch_recipes
if recipe_name != "ExtractElements":
self.report({"ERROR"}, "Only supported for the 'ExtractElements' recipe.")
return {"CANCELLED"}
query = tool.Search.get_query_for_selected_elements()
props.ifc_patch_args_attr[0].string_value = query
return {"FINISHED"}
+7 -1
View File
@@ -55,6 +55,12 @@ class BIM_PT_patch(bpy.types.Panel):
row.prop(props, "ifc_patch_output")
row.operator("bim.select_ifc_patch_output", icon="FILE_FOLDER", text="")
def draw_callback_(_, row: bpy.types.UILayout) -> None:
if props.ifc_patch_recipes == "ExtractElements":
row.operator("bim.patch_query_from_selected", text="", icon="EYEDROPPER")
if props.ifc_patch_args_attr:
draw_attributes(props.ifc_patch_args_attr, layout)
draw_callback = draw_callback_ if props.ifc_patch_recipes == "ExtractElements" else None
draw_attributes(props.ifc_patch_args_attr, layout, callback=draw_callback)
op = layout.operator("bim.execute_ifc_patch")
@@ -101,20 +101,10 @@ class SelectFilterElements(bpy.types.Operator):
def execute(self, context):
filter_groups = tool.Search.get_filter_groups(self.module)
global_ids = []
for obj in context.selected_objects:
if element := tool.Ifc.get_entity(obj):
if global_id := getattr(element, "GlobalId", None):
global_ids.append(global_id)
if len(global_ids) > 50:
# Too much to store in a string property
name = f"globalid-filter-{ifcopenshell.guid.new()}"
text_data = bpy.data.texts.new(name)
text_data.from_string(",".join(global_ids))
filter_groups[self.group_index].filters[self.index].value = f"bpy.data.texts['{name}']"
query = tool.Search.get_query_for_selected_elements()
filter_groups[self.group_index].filters[self.index].value = query
if query.startswith("bpy.data.texts['"):
self.report({"INFO"}, f'List of Global Ids was saved to the text file "{name}" in the current .blend file')
else:
filter_groups[self.group_index].filters[self.index].value = ",".join(global_ids)
return {"FINISHED"}
+11
View File
@@ -20,6 +20,7 @@ import bpy
import ifcopenshell
import ifcpatch
import bonsai.core.tool
from typing import Any
class Patch(bonsai.core.tool.Patch):
@@ -40,3 +41,13 @@ class Patch(bonsai.core.tool.Patch):
@classmethod
def does_patch_has_output(cls, recipe: str) -> bool:
return recipe != "SplitByBuildingStorey"
@classmethod
def post_process_patch_arguments(cls, recipe: str, args: list[Any]) -> list[Any]:
if recipe == "ExtractElements":
query = args[0]
assert isinstance(query, str)
if "bpy.data.texts" in query:
text_name = query.split("bpy.data.texts")[1][2:-2]
args[0] = bpy.data.texts[text_name].as_string()
return args
+37
View File
@@ -1,6 +1,26 @@
# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import lark
import bonsai.tool as tool
import bonsai.core.tool
import ifcopenshell.guid
import ifcopenshell.util.selector
@@ -267,6 +287,23 @@ class Search(bonsai.core.tool.Search):
return palette[-1]
return cls.interpolate_color(palette[index], palette[index + 1], fraction)
@classmethod
def get_query_for_selected_elements(cls) -> str:
global_ids = []
for obj in tool.Blender.get_selected_objects():
if element := tool.Ifc.get_entity(obj):
if global_id := getattr(element, "GlobalId", None):
global_ids.append(global_id)
query = ",".join(global_ids)
if len(global_ids) > 50:
# Too much to store in a string property.
name = f"globalid-filter-{ifcopenshell.guid.new()}"
text_data = bpy.data.texts.new(name)
text_data.from_string(query)
query = f"bpy.data.texts['{name}']"
return query
class ImportFilterQueryTransformer(lark.Transformer):
def __init__(self, filter_groups):