diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 40af36886b..8b6ffe2a6b 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -324,6 +324,10 @@ def draw_filter(layout, props, data, module): elif ifc_filter.type == "location": row = box.row(align=True) 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": row = box.row(align=True) row.prop(ifc_filter, "value", text="", icon="GRIP") diff --git a/src/blenderbim/blenderbim/bim/module/search/operator.py b/src/blenderbim/blenderbim/bim/module/search/operator.py index 62a5b496b6..c929938632 100644 --- a/src/blenderbim/blenderbim/bim/module/search/operator.py +++ b/src/blenderbim/blenderbim/bim/module/search/operator.py @@ -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] if group: group = group[0] + group.Description = description else: group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.name, Description=description) if results: diff --git a/src/blenderbim/blenderbim/bim/module/search/prop.py b/src/blenderbim/blenderbim/bim/module/search/prop.py index 8b51f58a74..bdcc3d223c 100644 --- a/src/blenderbim/blenderbim/bim/module/search/prop.py +++ b/src/blenderbim/blenderbim/bim/module/search/prop.py @@ -128,7 +128,8 @@ class BIMSearchProperties(PropertyGroup): ("classification", "Classification", "", "OUTLINER", 4), ("location", "Location", "", "PACKAGE", 5), ("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") diff --git a/src/blenderbim/blenderbim/tool/search.py b/src/blenderbim/blenderbim/tool/search.py index 892a49a3b4..49c5b978ef 100644 --- a/src/blenderbim/blenderbim/tool/search.py +++ b/src/blenderbim/blenderbim/tool/search.py @@ -61,6 +61,10 @@ class Search(blenderbim.core.tool.Search): elif ifc_filter.type == "location": comparison, value = cls.get_comparison_and_value(ifc_filter) 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: filter_group_query.insert(0, "IfcProduct") filter_group_query.insert(0, "IfcTypeProduct") @@ -158,9 +162,16 @@ class ImportFilterQueryTransformer(lark.Transformer): comparison, value = args 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): return "" if args[0].data == "equals" else "!=" + def keys(self, args): + return self.value(args) + def pset(self, args): return self.value(args) @@ -181,16 +192,3 @@ class ImportFilterQueryTransformer(lark.Transformer): return "TRUE" elif args[0].children[0].data == "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 diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 6929b69e05..a4a2ce4f0f 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -29,7 +29,7 @@ filter_elements_grammar = lark.Lark( filter_group: facet_list ("+" facet_list)* 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 globalid: /[0-3][a-zA-Z0-9_$]{21}/ @@ -40,9 +40,11 @@ filter_elements_grammar = lark.Lark( property: pset "." prop comparison value classification: "classification" comparison value location: "location" comparison value + query: "query:" keys comparison value pset: quoted_string | unquoted_string | regex_string prop: quoted_string | unquoted_string | regex_string + keys: quoted_string | unquoted_string attribute_name: /[A-Z]\\w+/ ifc_class: /Ifc\\w+/ @@ -361,6 +363,14 @@ class FacetTransformer(lark.Transformer): 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): tree = self.container_trees.get(container, None) if tree: @@ -382,6 +392,9 @@ class FacetTransformer(lark.Transformer): def comparison(self, args): return "=" if args[0].data == "equals" else "!=" + def keys(self, args): + return self.value(args) + def pset(self, args): return self.value(args) @@ -646,13 +659,20 @@ class Selector: elif key == "container": value = ifcopenshell.util.element.get_container(value) 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": - element = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuildingStorey") + value = ifcopenshell.util.element.get_container(element, ifc_class="IfcBuildingStorey") 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": - 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": value = value.is_a() elif key == "id":