Implement filtered selection in new spatial decomposition panel

This commit is contained in:
Dion Moult
2024-07-29 18:09:08 +10:00
parent 74141bec73
commit 8ca2a55616
5 changed files with 90 additions and 33 deletions
@@ -237,15 +237,36 @@ class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.select_decomposed_elements"
bl_label = "Select Children"
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):
return f"Select all elements contained in this {operator.ifc_class}"
return "Select all contained elements filtered by this type" + "\nALT+CLICK to select all contained elements"
def invoke(self, context, event):
if event.type == "LEFTMOUSE" and event.alt:
self.should_filter = False
return self.execute(context)
def _execute(self, context):
core.select_decomposed_elements(tool.Spatial, container=tool.Ifc.get().by_id(self.container))
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
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,
)
class SetDefaultContainer(bpy.types.Operator, tool.Ifc.Operator):
@@ -123,6 +123,7 @@ class Element(PropertyGroup):
name: 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")
total: IntProperty(name="Total")
@@ -144,3 +145,8 @@ class BIMSpatialDecompositionProperties(PropertyGroup):
def active_container(self):
if self.containers and self.active_container_index < len(self.containers):
return self.containers[self.active_container_index]
@property
def active_element(self):
if self.elements and self.active_element_index < len(self.elements):
return self.elements[self.active_element_index]
@@ -161,15 +161,20 @@ class BIM_PT_spatial_decomposition(Panel):
if not self.props.total_elements:
row = self.layout.row(align=True)
row.label(text="No Contained Elements", icon="FILE_3D")
row.label(text=f"{self.props.active_container.ifc_class} > No Contained Elements", icon="FILE_3D")
row.prop(self.props, "should_include_children", text="", icon="OUTLINER")
return
row = self.layout.row(align=True)
row.label(text=f"{self.props.total_elements} Contained Elements", icon="FILE_3D")
row.label(text=f"{self.props.active_container.ifc_class} > {self.props.total_elements} Contained Elements", icon="FILE_3D")
row.prop(self.props, "should_include_children", text="", icon="OUTLINER")
op = row.operator("bim.select_decomposed_elements", icon="RESTRICT_SELECT_OFF", text="")
op.ifc_class = self.props.active_container.ifc_class
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(
@@ -187,7 +192,20 @@ class BIM_UL_containers_manager(UIList):
if item:
row = layout.row(align=True)
self.draw_hierarchy(row, item)
row.prop(item, "name", emboss=False, text="")
icon = {
"IfcProject": "FILE",
"IfcSite": "WORLD",
"IfcBuilding": "HOME",
"IfcBuildingStorey": "LINENUMBERS_OFF",
"IfcSpace": "ANTIALIASED",
"IfcFacilityPart": "MOD_FLUID",
"IfcBridgePart": "MOD_FLUID",
"IfcFacilityPartCommon": "MOD_FLUID",
"IfcMarinePart": "MOD_FLUID",
"IfcRailwayPart": "MOD_FLUID",
"IfcRoadPart": "MOD_FLUID",
}.get(item.ifc_class, "META_PLANE")
row.prop(item, "name", emboss=False, text="", icon=icon)
if item.long_name:
row.prop(item, "long_name", emboss=False, text="")
col = row.column()
@@ -208,24 +226,6 @@ class BIM_UL_containers_manager(UIList):
)
else:
row.label(text="", icon="BLANK1")
if item.ifc_class == "IfcProject":
row.label(text="", icon="FILE")
else:
icon = {
"IfcSite": "WORLD",
"IfcBuilding": "HOME",
"IfcBuildingStorey": "LINENUMBERS_OFF",
"IfcSpace": "ANTIALIASED",
"IfcFacilityPart": "MOD_FLUID",
"IfcBridgePart": "MOD_FLUID",
"IfcFacilityPartCommon": "MOD_FLUID",
"IfcMarinePart": "MOD_FLUID",
"IfcRailwayPart": "MOD_FLUID",
"IfcRoadPart": "MOD_FLUID",
}.get(item.ifc_class, "META_PLANE")
op = row.operator("bim.select_decomposed_elements", icon=icon, text="", emboss=False)
op.ifc_class = item.ifc_class
op.container = item.ifc_definition_id
class BIM_UL_elements(UIList):
@@ -240,7 +240,6 @@ class BIM_UL_elements(UIList):
col.label(text=str(item.total))
elif item.is_type:
row.label(text="", icon="BLANK1")
row.label(text="", icon="DISCLOSURE_TRI_DOWN")
row.label(text=item.name)
col = row.column()
col.alignment = "RIGHT"
+15 -2
View File
@@ -149,8 +149,21 @@ def delete_container(
spatial.import_spatial_decomposition()
def select_decomposed_elements(spatial: tool.Spatial, container: ifcopenshell.entity_instance) -> None:
spatial.select_products(spatial.get_decomposed_elements(container))
def select_decomposed_elements(
spatial: tool.Spatial,
container: ifcopenshell.entity_instance,
ifc_class: str | None = None,
relating_type: ifcopenshell.entity_instance | None = None,
is_untyped: bool = False,
) -> 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)
spatial.select_products(elements)
def generate_space(ifc: tool.Ifc, model: tool.Model, root: tool.Root, spatial: tool.Spatial, type: tool.Type) -> None:
+24 -6
View File
@@ -39,7 +39,7 @@ import json
from math import pi
from mathutils import Vector, Matrix
from shapely import Polygon
from typing import Generator, Optional, Union, Literal, Any
from typing import Generator, Optional, Union, Literal, Any, List
class Spatial(blenderbim.core.tool.Spatial):
@@ -244,9 +244,10 @@ class Spatial(blenderbim.core.tool.Spatial):
continue
element_type = ifcopenshell.util.element.get_type(element)
ifc_class = element.is_a()
ifc_definition_id = element_type.id() if element_type else 0
type_name = element_type.Name or "Unnamed" if element_type else "Untyped"
results.setdefault(ifc_class, {}).setdefault(type_name, 0)
results[ifc_class][type_name] += 1
results.setdefault(ifc_class, {}).setdefault(ifc_definition_id, {"total": 0, "type_name": type_name})
results[ifc_class][ifc_definition_id]["total"] += 1
total_elements = 0
for ifc_class in sorted(results.keys()):
@@ -254,17 +255,34 @@ class Spatial(blenderbim.core.tool.Spatial):
new.name = ifc_class
new.is_class = True
total = 0
for type_name in sorted(results[ifc_class].keys()):
for ifc_definition_id in sorted(
results[ifc_class].keys(), key=lambda x: results[ifc_class][x]["type_name"]
):
new2 = props.elements.add()
new2.name = type_name
new2.is_type = True
new2.total = results[ifc_class][type_name]
new2.name = results[ifc_class][ifc_definition_id]["type_name"]
new2.total = results[ifc_class][ifc_definition_id]["total"]
new2.ifc_definition_id = ifc_definition_id
total += new2.total
new.total = total
total_elements += total
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)]
@classmethod
def import_spatial_decomposition(cls) -> None:
props = bpy.context.scene.BIMSpatialDecompositionProperties