mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 08:02:29 +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
|
from . import ui, prop, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.ActivateIfcClassFilter,
|
|
||||||
operator.ActivateIfcBuildingStoreyFilter,
|
operator.ActivateIfcBuildingStoreyFilter,
|
||||||
|
operator.ActivateIfcClassFilter,
|
||||||
|
operator.AddFilter,
|
||||||
|
operator.AddFilterGroup,
|
||||||
|
operator.AddToIfcGroup,
|
||||||
operator.ColourByAttribute,
|
operator.ColourByAttribute,
|
||||||
operator.ColourByClass,
|
operator.ColourByClass,
|
||||||
operator.ColourByPset,
|
operator.ColourByPset,
|
||||||
operator.ToggleFilterSelection,
|
operator.FilterModelElements,
|
||||||
|
operator.IfcSelector,
|
||||||
|
operator.LoadQuery,
|
||||||
|
operator.OpenQueryLibrary,
|
||||||
|
operator.RemoveFilter,
|
||||||
|
operator.RemoveFilterGroup,
|
||||||
operator.ResetObjectColours,
|
operator.ResetObjectColours,
|
||||||
|
operator.SaveSelectorQuery,
|
||||||
|
operator.Search,
|
||||||
operator.SelectAttribute,
|
operator.SelectAttribute,
|
||||||
operator.SelectGlobalId,
|
operator.SelectGlobalId,
|
||||||
operator.SelectIfcClass,
|
operator.SelectIfcClass,
|
||||||
operator.SelectPset,
|
operator.SelectPset,
|
||||||
operator.ShowAllElements,
|
operator.ShowAllElements,
|
||||||
operator.FilterModelElements,
|
operator.ToggleFilterSelection,
|
||||||
operator.IfcSelector,
|
prop.BIMFacet,
|
||||||
operator.SaveSelectorQuery,
|
prop.BIMFilterGroup,
|
||||||
operator.OpenQueryLibrary,
|
|
||||||
operator.LoadQuery,
|
|
||||||
operator.AddToIfcGroup,
|
|
||||||
prop.BIMFilterClasses,
|
prop.BIMFilterClasses,
|
||||||
prop.BIMFilterBuildingStoreys,
|
prop.BIMFilterBuildingStoreys,
|
||||||
prop.BIMSearchProperties,
|
prop.BIMSearchProperties,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import re
|
|||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.selector
|
||||||
from ifcopenshell.util.selector import Selector
|
from ifcopenshell.util.selector import Selector
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
@@ -69,6 +70,120 @@ def does_keyword_exist(pattern, string, context):
|
|||||||
return True
|
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):
|
class SelectGlobalId(Operator):
|
||||||
"""Click to select the objects that match with the given Global ID"""
|
"""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")
|
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):
|
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_use_regex: BoolProperty(name="Search With Regex", default=False)
|
||||||
should_ignorecase: BoolProperty(name="Search Ignoring Case", default=True)
|
should_ignorecase: BoolProperty(name="Search Ignoring Case", default=True)
|
||||||
global_id: StringProperty(name="GlobalId")
|
global_id: StringProperty(name="GlobalId")
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from blenderbim.bim.ifc import IfcStore
|
|||||||
class BIM_PT_search(Panel):
|
class BIM_PT_search(Panel):
|
||||||
bl_label = "Search"
|
bl_label = "Search"
|
||||||
bl_idname = "BIM_PT_search"
|
bl_idname = "BIM_PT_search"
|
||||||
# bl_options = {"DEFAULT_CLOSED"}
|
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "PROPERTIES"
|
||||||
bl_region_type = "WINDOW"
|
bl_region_type = "WINDOW"
|
||||||
bl_context = "scene"
|
bl_context = "scene"
|
||||||
@@ -33,6 +32,59 @@ class BIM_PT_search(Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
props = context.scene.BIMSearchProperties
|
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 = self.layout.row()
|
||||||
row.prop(props, "should_use_regex")
|
row.prop(props, "should_use_regex")
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
|
|||||||
Reference in New Issue
Block a user