You can now filter and search in the spatial decomposition panel

This commit is contained in:
Dion Moult
2024-08-23 13:49:45 +10:00
parent 1ef2fb89af
commit a4a2497f33
5 changed files with 61 additions and 33 deletions
@@ -249,8 +249,6 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
should_filter: bpy.props.BoolProperty(name="Should Filter", default=True, options={"SKIP_SAVE"})
container: bpy.props.IntProperty()
ifc_class: bpy.props.StringProperty()
relating_type: bpy.props.IntProperty()
@classmethod
def description(cls, context, operator):
@@ -262,20 +260,25 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
return self.execute(context)
def _execute(self, context):
ifc_class = relating_type = is_untyped = None
if self.should_filter:
ifc_class = self.ifc_class
relating_type = tool.Ifc.get().by_id(self.relating_type) if self.relating_type else None
is_untyped = self.relating_type == 0
else:
ifc_class = ""
relating_type = None
is_untyped = False
active_element = context.scene.BIMSpatialDecompositionProperties.active_element
if active_element.is_class:
ifc_class = active_element.name
elif relating_type := active_element.ifc_definition_id:
ifc_class = active_element.ifc_class
relating_type = tool.Ifc.get().by_id(relating_type)
else:
ifc_class = active_element.ifc_class
is_untyped = True
element_filter = context.scene.BIMSpatialDecompositionProperties.element_filter
core.select_decomposed_elements(
tool.Spatial,
container=tool.Ifc.get().by_id(self.container),
ifc_class=ifc_class,
relating_type=relating_type,
is_untyped=is_untyped,
element_filter = element_filter
)
@@ -107,6 +107,7 @@ class BIMContainer(PropertyGroup):
class Element(PropertyGroup):
name: StringProperty(name="Name")
ifc_class: StringProperty(name="Name")
is_class: BoolProperty(name="Is Class", default=False)
is_type: BoolProperty(name="Is Type", default=False)
ifc_definition_id: IntProperty(name="IFC Definition ID")
@@ -118,6 +119,7 @@ class BIMSpatialDecompositionProperties(PropertyGroup):
contracted_containers: StringProperty(name="Contracted containers", default="[]")
expanded_containers: StringProperty(name="Expanded containers", default="[]")
active_container_index: IntProperty(name="Active Container Index", update=update_active_container_index)
element_filter: StringProperty(name="Element Filter", default="", options={"TEXTEDIT_UPDATE"})
elements: CollectionProperty(name="Elements", type=Element)
active_element_index: IntProperty(name="Active Element Index")
total_elements: IntProperty(name="Total Elements")
+18 -6
View File
@@ -16,6 +16,7 @@
# 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
from bpy.types import Panel, UIList
from bonsai.bim.module.spatial.data import SpatialData, SpatialDecompositionData
import bonsai.tool as tool
@@ -169,12 +170,6 @@ class BIM_PT_spatial_decomposition(Panel):
)
row.prop(self.props, "should_include_children", text="", icon="OUTLINER")
op = row.operator("bim.select_decomposed_elements", icon="RESTRICT_SELECT_OFF", text="")
if self.props.active_element.is_class:
op.ifc_class = self.props.active_element.name
op.relating_type = 0
elif self.props.active_element.is_type:
op.ifc_class = ""
op.relating_type = self.props.active_element.ifc_definition_id
op.container = ifc_definition_id
self.layout.template_list(
@@ -184,6 +179,7 @@ class BIM_PT_spatial_decomposition(Panel):
"elements",
self.props,
"active_element_index",
sort_lock=True,
)
@@ -229,6 +225,9 @@ class BIM_UL_containers_manager(UIList):
class BIM_UL_elements(UIList):
def __init__(self):
self.use_filter_show = True
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
@@ -244,3 +243,16 @@ class BIM_UL_elements(UIList):
col = row.column()
col.alignment = "RIGHT"
col.label(text=str(item.total))
def draw_filter(self, context, layout):
row = layout.row()
row.prop(context.scene.BIMSpatialDecompositionProperties, "element_filter", text="", icon="VIEWZOOM")
def filter_items(self, context, data, propname):
items = getattr(data, propname)
filter_name = context.scene.BIMSpatialDecompositionProperties.element_filter
filtered = bpy.types.UI_UL_list.filter_items_by_name(filter_name, self.bitflag_filter_item, items, "name")
return filtered, []
def get_filter_name(self):
return self.filter_name
+2 -6
View File
@@ -147,14 +147,10 @@ def select_decomposed_elements(
ifc_class: str | None = None,
relating_type: ifcopenshell.entity_instance | None = None,
is_untyped: bool = False,
element_filter: str | None = None,
) -> None:
elements = spatial.get_decomposed_elements(container)
if ifc_class:
elements = spatial.filter_elements_by_class(elements, ifc_class)
elif relating_type:
elements = spatial.filter_elements_by_relating_type(elements, relating_type)
elif is_untyped:
elements = spatial.filter_elements_by_untyped(elements)
elements = spatial.filter_elements(elements, ifc_class, relating_type, is_untyped, element_filter)
spatial.select_products(elements)
+27 -12
View File
@@ -233,6 +233,7 @@ class Spatial(bonsai.core.tool.Spatial):
new2 = props.elements.add()
new2.is_type = True
new2.name = results[ifc_class][ifc_definition_id]["type_name"]
new2.ifc_class = ifc_class
new2.total = results[ifc_class][ifc_definition_id]["total"]
new2.ifc_definition_id = ifc_definition_id
total += new2.total
@@ -242,18 +243,32 @@ class Spatial(bonsai.core.tool.Spatial):
props.total_elements = total_elements
@classmethod
def filter_elements_by_class(cls, elements: List[ifcopenshell.entity_instance], ifc_class: str):
return [e for e in elements if e.is_a(ifc_class)]
@classmethod
def filter_elements_by_relating_type(
cls, elements: List[ifcopenshell.entity_instance], relating_type: ifcopenshell.entity_instance
):
return [e for e in elements if ifcopenshell.util.element.get_type(e) == relating_type]
@classmethod
def filter_elements_by_untyped(cls, elements: List[ifcopenshell.entity_instance]):
return [e for e in elements if not ifcopenshell.util.element.get_type(e)]
def filter_elements(
cls,
elements: List[ifcopenshell.entity_instance],
ifc_class: str | None,
relating_type: ifcopenshell.entity_instance | None,
is_untyped: bool | None,
keyword: str | None,
) -> filter[ifcopenshell.entity_instance]:
keyword = keyword.lower() if keyword else keyword
def filter_element(element):
if ifc_class:
if not element.is_a(ifc_class):
return False
element_type = ifcopenshell.util.element.get_type(element)
if relating_type:
if relating_type != element_type:
return False
if is_untyped:
if element_type is not None:
return False
if keyword:
type_name = getattr(element_type, "Name", "") or ""
if keyword not in f"{element.is_a()} {type_name}".lower():
return False
return True
return filter(filter_element, elements)
@classmethod
def import_spatial_decomposition(cls) -> None: