mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
More powerful search interface that uses the new facet selector syntax
This commit is contained in:
@@ -20,24 +20,31 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.ActivateIfcClassFilter,
|
||||
operator.ActivateIfcBuildingStoreyFilter,
|
||||
operator.ActivateIfcClassFilter,
|
||||
operator.AddFilter,
|
||||
operator.AddFilterGroup,
|
||||
operator.AddToIfcGroup,
|
||||
operator.ColourByAttribute,
|
||||
operator.ColourByClass,
|
||||
operator.ColourByPset,
|
||||
operator.ToggleFilterSelection,
|
||||
operator.FilterModelElements,
|
||||
operator.IfcSelector,
|
||||
operator.LoadQuery,
|
||||
operator.OpenQueryLibrary,
|
||||
operator.RemoveFilter,
|
||||
operator.RemoveFilterGroup,
|
||||
operator.ResetObjectColours,
|
||||
operator.SaveSelectorQuery,
|
||||
operator.Search,
|
||||
operator.SelectAttribute,
|
||||
operator.SelectGlobalId,
|
||||
operator.SelectIfcClass,
|
||||
operator.SelectPset,
|
||||
operator.ShowAllElements,
|
||||
operator.FilterModelElements,
|
||||
operator.IfcSelector,
|
||||
operator.SaveSelectorQuery,
|
||||
operator.OpenQueryLibrary,
|
||||
operator.LoadQuery,
|
||||
operator.AddToIfcGroup,
|
||||
operator.ToggleFilterSelection,
|
||||
prop.BIMFacet,
|
||||
prop.BIMFilterGroup,
|
||||
prop.BIMFilterClasses,
|
||||
prop.BIMFilterBuildingStoreys,
|
||||
prop.BIMSearchProperties,
|
||||
|
||||
@@ -20,6 +20,7 @@ import re
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.selector
|
||||
from ifcopenshell.util.selector import Selector
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
@@ -69,6 +70,120 @@ def does_keyword_exist(pattern, string, context):
|
||||
return True
|
||||
|
||||
|
||||
class AddFilterGroup(Operator):
|
||||
bl_idname = "bim.add_filter_group"
|
||||
bl_label = "Add Filter Group"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMSearchProperties.filter_groups.add()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveFilterGroup(Operator):
|
||||
bl_idname = "bim.remove_filter_group"
|
||||
bl_label = "Remove Filter Group"
|
||||
index: IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props.filter_groups.remove(self.index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveFilter(Operator):
|
||||
bl_idname = "bim.remove_filter"
|
||||
bl_label = "Remove Filter Group"
|
||||
group_index: IntProperty()
|
||||
index: IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
props.filter_groups[self.group_index].filters.remove(self.index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddFilter(Operator):
|
||||
bl_idname = "bim.add_filter"
|
||||
bl_label = "Add Filter"
|
||||
index: IntProperty()
|
||||
type: StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
new = context.scene.BIMSearchProperties.filter_groups[self.index].filters.add()
|
||||
new.type = self.type
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class Search(Operator):
|
||||
bl_idname = "bim.search"
|
||||
bl_label = "Search"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
query = []
|
||||
for filter_group in props.filter_groups:
|
||||
filter_group_query = []
|
||||
has_instance_or_entity_filter = False
|
||||
for ifc_filter in filter_group.filters:
|
||||
if not ifc_filter.value:
|
||||
continue
|
||||
if ifc_filter.type == "instance":
|
||||
has_instance_or_entity_filter = True
|
||||
filter_group_query.append(ifc_filter.value)
|
||||
elif ifc_filter.type == "entity":
|
||||
has_instance_or_entity_filter = True
|
||||
filter_group_query.append(ifc_filter.value)
|
||||
elif ifc_filter.type == "attribute":
|
||||
if not ifc_filter.name:
|
||||
continue
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"{ifc_filter.name}{comparison}{value}")
|
||||
elif ifc_filter.type == "type":
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"type{comparison}{value}")
|
||||
elif ifc_filter.type == "material":
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"material{comparison}{value}")
|
||||
elif ifc_filter.type == "property":
|
||||
if not ifc_filter.pset or not ifc_filter.name:
|
||||
continue
|
||||
pset = self.wrap_value(ifc_filter, ifc_filter.pset)
|
||||
name = self.wrap_value(ifc_filter, ifc_filter.name)
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"{pset}.{name}{comparison}{value}")
|
||||
elif ifc_filter.type == "classification":
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"classification{comparison}{value}")
|
||||
elif ifc_filter.type == "location":
|
||||
comparison, value = self.get_comparison_and_value(ifc_filter)
|
||||
filter_group_query.append(f"location{comparison}{value}")
|
||||
if not has_instance_or_entity_filter:
|
||||
filter_group_query.insert(0, "IfcElement")
|
||||
query.append(", ".join(filter_group_query))
|
||||
query = " + ".join(query)
|
||||
results = ifcopenshell.util.selector.filter_elements(tool.Ifc.get(), query)
|
||||
|
||||
total_selected = 0
|
||||
for element in results:
|
||||
obj = tool.Ifc.get_object(element)
|
||||
if obj:
|
||||
obj.select_set(True)
|
||||
self.report({"INFO"}, f"{len(results)} Results")
|
||||
return {"FINISHED"}
|
||||
|
||||
def get_comparison_and_value(self, ifc_filter):
|
||||
if ifc_filter.value.startswith("!="):
|
||||
return ("!=", self.wrap_value(ifc_filter, ifc_filter.value[2:].strip()))
|
||||
return ("=", self.wrap_value(ifc_filter, ifc_filter.value.strip()))
|
||||
|
||||
def wrap_value(self, ifc_filter, value):
|
||||
if value.startswith("/") and value.endswith("/"):
|
||||
return value
|
||||
elif value in ("NULL", "TRUE", "FALSE"):
|
||||
return value
|
||||
return '"' + value + '"'
|
||||
|
||||
|
||||
class SelectGlobalId(Operator):
|
||||
"""Click to select the objects that match with the given Global ID"""
|
||||
|
||||
|
||||
@@ -79,7 +79,33 @@ class BIMFilterBuildingStoreys(PropertyGroup):
|
||||
unselected_objects: CollectionProperty(type=ObjProperty, name="Unfiltered Objects")
|
||||
|
||||
|
||||
class BIMFacet(PropertyGroup):
|
||||
name: StringProperty(name="Type")
|
||||
pset: StringProperty(name="Type")
|
||||
value: StringProperty(name="Type")
|
||||
type: StringProperty(name="Type")
|
||||
comparison: StringProperty(name="Comparison")
|
||||
|
||||
|
||||
class BIMFilterGroup(PropertyGroup):
|
||||
filters: CollectionProperty(type=BIMFacet, name="filters")
|
||||
|
||||
|
||||
class BIMSearchProperties(PropertyGroup):
|
||||
filter_query: StringProperty(name="Filter Query")
|
||||
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
|
||||
facet: EnumProperty(
|
||||
items=[
|
||||
("entity", "Class", "", "FILE_3D", 0),
|
||||
("attribute", "Attribute", "", "COPY_ID", 1),
|
||||
("property", "Property", "", "PROPERTIES", 2),
|
||||
("material", "Material", "", "MATERIAL", 3),
|
||||
("classification", "Classification", "", "OUTLINER", 4),
|
||||
("location", "Location", "", "PACKAGE", 5),
|
||||
("type", "Type", "", "FILE_VOLUME", 6),
|
||||
("instance", "GlobalId", "", "GRIP", 7),
|
||||
],
|
||||
)
|
||||
should_use_regex: BoolProperty(name="Search With Regex", default=False)
|
||||
should_ignorecase: BoolProperty(name="Search Ignoring Case", default=True)
|
||||
global_id: StringProperty(name="GlobalId")
|
||||
@@ -133,7 +159,7 @@ def load_selection_options(self, context):
|
||||
elif self.selector == "Attribute":
|
||||
attributes = ["GlobalId", "Name", "Description", "ObjectType", "Tag", "PredefinedType"]
|
||||
for a in attributes:
|
||||
options.append((a, a, ""))
|
||||
options.append((a, a, ""))
|
||||
|
||||
elif load_option == "sub_options":
|
||||
if self.selector in ["IfcSpatialElement", "IfcElementType"]:
|
||||
|
||||
@@ -24,7 +24,6 @@ from blenderbim.bim.ifc import IfcStore
|
||||
class BIM_PT_search(Panel):
|
||||
bl_label = "Search"
|
||||
bl_idname = "BIM_PT_search"
|
||||
# bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
@@ -33,6 +32,59 @@ class BIM_PT_search(Panel):
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMSearchProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD")
|
||||
|
||||
for i, filter_group in enumerate(props.filter_groups):
|
||||
box = self.layout.box()
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(props, "facet", text="")
|
||||
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
|
||||
op.type = props.facet
|
||||
op.index = i
|
||||
|
||||
for j, ifc_filter in enumerate(filter_group.filters):
|
||||
if ifc_filter.type == "entity":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="FILE_3D")
|
||||
elif ifc_filter.type == "attribute":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="COPY_ID")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "type":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="FILE_VOLUME")
|
||||
elif ifc_filter.type == "material":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="MATERIAL")
|
||||
elif ifc_filter.type == "property":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
|
||||
row.prop(ifc_filter, "name", text="")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "classification":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="OUTLINER")
|
||||
elif ifc_filter.type == "location":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="PACKAGE")
|
||||
elif ifc_filter.type == "instance":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="GRIP")
|
||||
op = row.operator("bim.remove_filter", text="", icon="X")
|
||||
op.group_index = i
|
||||
op.index = j
|
||||
|
||||
row = box.row()
|
||||
row.operator("bim.remove_filter_group", icon="X").index = i
|
||||
|
||||
if len(props.filter_groups):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.search", text="Search", icon="VIEWZOOM")
|
||||
|
||||
return # Temporary for now whilst searching is being upgraded.
|
||||
|
||||
row = self.layout.row()
|
||||
row.prop(props, "should_use_regex")
|
||||
row = self.layout.row()
|
||||
|
||||
Reference in New Issue
Block a user