mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
Now support custom queries for advanced users in the facet selector (similar to old selector). Also support types and count keys. (e.g. filter by objects with zero types, or zero materials, etc).
This commit is contained in:
@@ -324,6 +324,10 @@ def draw_filter(layout, props, data, module):
|
|||||||
elif ifc_filter.type == "location":
|
elif ifc_filter.type == "location":
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
row.prop(ifc_filter, "name", text="", icon="PACKAGE")
|
row.prop(ifc_filter, "name", text="", icon="PACKAGE")
|
||||||
|
elif ifc_filter.type == "query":
|
||||||
|
row = box.row(align=True)
|
||||||
|
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
|
||||||
|
row.prop(ifc_filter, "value", text="")
|
||||||
elif ifc_filter.type == "instance":
|
elif ifc_filter.type == "instance":
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
row.prop(ifc_filter, "value", text="", icon="GRIP")
|
row.prop(ifc_filter, "value", text="", icon="GRIP")
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ class SaveSearch(Operator, tool.Ifc.Operator):
|
|||||||
group = [g for g in tool.Ifc.get().by_type("IfcGroup") if g.Name == self.name]
|
group = [g for g in tool.Ifc.get().by_type("IfcGroup") if g.Name == self.name]
|
||||||
if group:
|
if group:
|
||||||
group = group[0]
|
group = group[0]
|
||||||
|
group.Description = description
|
||||||
else:
|
else:
|
||||||
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.name, Description=description)
|
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.name, Description=description)
|
||||||
if results:
|
if results:
|
||||||
|
|||||||
@@ -128,7 +128,8 @@ class BIMSearchProperties(PropertyGroup):
|
|||||||
("classification", "Classification", "", "OUTLINER", 4),
|
("classification", "Classification", "", "OUTLINER", 4),
|
||||||
("location", "Location", "", "PACKAGE", 5),
|
("location", "Location", "", "PACKAGE", 5),
|
||||||
("type", "Type", "", "FILE_VOLUME", 6),
|
("type", "Type", "", "FILE_VOLUME", 6),
|
||||||
("instance", "GlobalId", "", "GRIP", 7),
|
("query", "Query", "", "POINTCLOUD_DATA", 7),
|
||||||
|
("instance", "GlobalId", "", "GRIP", 8),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
saved_searches: EnumProperty(items=get_saved_searches, name="Saved Searches")
|
saved_searches: EnumProperty(items=get_saved_searches, name="Saved Searches")
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ class Search(blenderbim.core.tool.Search):
|
|||||||
elif ifc_filter.type == "location":
|
elif ifc_filter.type == "location":
|
||||||
comparison, value = cls.get_comparison_and_value(ifc_filter)
|
comparison, value = cls.get_comparison_and_value(ifc_filter)
|
||||||
filter_group_query.append(f"location{comparison}{value}")
|
filter_group_query.append(f"location{comparison}{value}")
|
||||||
|
elif ifc_filter.type == "query":
|
||||||
|
keys = cls.wrap_value(ifc_filter, ifc_filter.name)
|
||||||
|
comparison, value = cls.get_comparison_and_value(ifc_filter)
|
||||||
|
filter_group_query.append(f"query:{keys}{comparison}{value}")
|
||||||
if not has_instance_or_entity_filter:
|
if not has_instance_or_entity_filter:
|
||||||
filter_group_query.insert(0, "IfcProduct")
|
filter_group_query.insert(0, "IfcProduct")
|
||||||
filter_group_query.insert(0, "IfcTypeProduct")
|
filter_group_query.insert(0, "IfcTypeProduct")
|
||||||
@@ -158,9 +162,16 @@ class ImportFilterQueryTransformer(lark.Transformer):
|
|||||||
comparison, value = args
|
comparison, value = args
|
||||||
return {"type": "location", "value": f"{comparison}{value}"}
|
return {"type": "location", "value": f"{comparison}{value}"}
|
||||||
|
|
||||||
|
def query(self, args):
|
||||||
|
keys, comparison, value = args
|
||||||
|
return {"type": "query", "name": keys, "value": f"{comparison}{value}"}
|
||||||
|
|
||||||
def comparison(self, args):
|
def comparison(self, args):
|
||||||
return "" if args[0].data == "equals" else "!="
|
return "" if args[0].data == "equals" else "!="
|
||||||
|
|
||||||
|
def keys(self, args):
|
||||||
|
return self.value(args)
|
||||||
|
|
||||||
def pset(self, args):
|
def pset(self, args):
|
||||||
return self.value(args)
|
return self.value(args)
|
||||||
|
|
||||||
@@ -181,16 +192,3 @@ class ImportFilterQueryTransformer(lark.Transformer):
|
|||||||
return "TRUE"
|
return "TRUE"
|
||||||
elif args[0].children[0].data == "false":
|
elif args[0].children[0].data == "false":
|
||||||
return "FALSE"
|
return "FALSE"
|
||||||
|
|
||||||
def compare(self, element_value, comparison, value):
|
|
||||||
if isinstance(value, str):
|
|
||||||
if isinstance(element_value, int):
|
|
||||||
value = int(value)
|
|
||||||
elif isinstance(element_value, float):
|
|
||||||
value = float(value)
|
|
||||||
result = element_value == value
|
|
||||||
elif isinstance(value, re.Pattern):
|
|
||||||
result = bool(value.match(element_value))
|
|
||||||
elif value in (None, True, False):
|
|
||||||
result = element_value is value
|
|
||||||
return result if comparison == "=" else not result
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ filter_elements_grammar = lark.Lark(
|
|||||||
filter_group: facet_list ("+" facet_list)*
|
filter_group: facet_list ("+" facet_list)*
|
||||||
facet_list: facet ("," facet)*
|
facet_list: facet ("," facet)*
|
||||||
|
|
||||||
facet: instance | entity | attribute | type | material | property | classification | location
|
facet: instance | entity | attribute | type | material | query | classification | location | property
|
||||||
|
|
||||||
instance: not? globalid
|
instance: not? globalid
|
||||||
globalid: /[0-3][a-zA-Z0-9_$]{21}/
|
globalid: /[0-3][a-zA-Z0-9_$]{21}/
|
||||||
@@ -40,9 +40,11 @@ filter_elements_grammar = lark.Lark(
|
|||||||
property: pset "." prop comparison value
|
property: pset "." prop comparison value
|
||||||
classification: "classification" comparison value
|
classification: "classification" comparison value
|
||||||
location: "location" comparison value
|
location: "location" comparison value
|
||||||
|
query: "query:" keys comparison value
|
||||||
|
|
||||||
pset: quoted_string | unquoted_string | regex_string
|
pset: quoted_string | unquoted_string | regex_string
|
||||||
prop: quoted_string | unquoted_string | regex_string
|
prop: quoted_string | unquoted_string | regex_string
|
||||||
|
keys: quoted_string | unquoted_string
|
||||||
|
|
||||||
attribute_name: /[A-Z]\\w+/
|
attribute_name: /[A-Z]\\w+/
|
||||||
ifc_class: /Ifc\\w+/
|
ifc_class: /Ifc\\w+/
|
||||||
@@ -361,6 +363,14 @@ class FacetTransformer(lark.Transformer):
|
|||||||
|
|
||||||
self.elements = set(filter(filter_function, self.elements))
|
self.elements = set(filter(filter_function, self.elements))
|
||||||
|
|
||||||
|
def query(self, args):
|
||||||
|
keys, comparison, value = args
|
||||||
|
|
||||||
|
def filter_function(element):
|
||||||
|
return self.compare(get_element_value(element, keys), comparison, value)
|
||||||
|
|
||||||
|
self.elements = set(filter(filter_function, self.elements))
|
||||||
|
|
||||||
def get_container_tree(self, container):
|
def get_container_tree(self, container):
|
||||||
tree = self.container_trees.get(container, None)
|
tree = self.container_trees.get(container, None)
|
||||||
if tree:
|
if tree:
|
||||||
@@ -382,6 +392,9 @@ class FacetTransformer(lark.Transformer):
|
|||||||
def comparison(self, args):
|
def comparison(self, args):
|
||||||
return "=" if args[0].data == "equals" else "!="
|
return "=" if args[0].data == "equals" else "!="
|
||||||
|
|
||||||
|
def keys(self, args):
|
||||||
|
return self.value(args)
|
||||||
|
|
||||||
def pset(self, args):
|
def pset(self, args):
|
||||||
return self.value(args)
|
return self.value(args)
|
||||||
|
|
||||||
@@ -646,13 +659,20 @@ class Selector:
|
|||||||
elif key == "container":
|
elif key == "container":
|
||||||
value = ifcopenshell.util.element.get_container(value)
|
value = ifcopenshell.util.element.get_container(value)
|
||||||
elif key == "space":
|
elif key == "space":
|
||||||
element = ifcopenshell.util.element.get_container(element, ifc_class="IfcSpace")
|
value = ifcopenshell.util.element.get_container(element, ifc_class="IfcSpace")
|
||||||
elif key == "storey":
|
elif key == "storey":
|
||||||
element = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuildingStorey")
|
value = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuildingStorey")
|
||||||
elif key == "building":
|
elif key == "building":
|
||||||
element = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuilding")
|
value = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuilding")
|
||||||
elif key == "site":
|
elif key == "site":
|
||||||
element = ifcopenshell.util.element.get_container(element, ifc_class="IfcSite")
|
value = ifcopenshell.util.element.get_container(element, ifc_class="IfcSite")
|
||||||
|
elif key == "types":
|
||||||
|
value = ifcopenshell.util.element.get_types(element)
|
||||||
|
elif key == "count":
|
||||||
|
if isinstance(value, set):
|
||||||
|
value = len(list(value))
|
||||||
|
elif isinstance(value, (list, tuple)):
|
||||||
|
value = len(value)
|
||||||
elif key == "class":
|
elif key == "class":
|
||||||
value = value.is_a()
|
value = value.is_a()
|
||||||
elif key == "id":
|
elif key == "id":
|
||||||
|
|||||||
Reference in New Issue
Block a user