From 316b9554d4930991b655dd83d6c6e188209051b7 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 13 Jan 2025 12:46:39 +1100 Subject: [PATCH] Fix #5959. Bug where default selection basket in selector query was not added per facet list. Previously the code looked for additive facets (entity, instance) anywhere in the query, and then only added the default basket once at the beginning of the query. This change makes it look for additive facets in order (that way you could start with a default selection, and then later use an additive facet) and does it per facet list (so you can omit the additive facet at the beginning of each list). --- .../ifcopenshell/util/selector.py | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 1ac8809d11..37919b9408 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -763,37 +763,33 @@ class FacetTransformer(lark.Transformer): else: self.base_elements = elements.copy() self.elements = set() + self.has_additive_facet_in_current_list = False self.container_trees = {} + def add_default_elements(self): + if self.has_additive_facet_in_current_list: + return + self.has_additive_facet_in_current_list = True + if self.base_elements: + self.elements.update(self.base_elements) + else: + self.elements.update(self.file.by_type("IfcProduct")) + self.elements.update(self.file.by_type("IfcTypeProduct")) + def get_results(self) -> set[ifcopenshell.entity_instance]: results: set[ifcopenshell.entity_instance] = set() for r in self.results: results |= r return results - def transform(self, tree: lark.ParseTree): - def has_elements_token(tree: lark.tree.ParseTree) -> bool: - for child in tree.iter_subtrees_topdown(): - data = child.data - # Tokens that add elements to filter. - if data in ("entity", "instance"): - return True - return False - - # Only elements tokens can add elements to the filter. - # Fallback to default elements if they are not provided. - if self.base_elements is None and not has_elements_token(tree): - self.elements.update(self.file.by_type("IfcProduct")) - self.elements.update(self.file.by_type("IfcTypeProduct")) - - return super().transform(tree) - def facet_list(self, args): if self.elements: self.results.append(self.elements) self.elements = set() + self.has_additive_facet_in_current_list = False def instance(self, args): + self.has_additive_facet_in_current_list = True if self.base_elements is None: if args[0].data == "globalid": try: @@ -816,6 +812,7 @@ class FacetTransformer(lark.Transformer): } def entity(self, args): + self.has_additive_facet_in_current_list = True if self.base_elements is None: if args[0].data == "ifc_class": try: @@ -844,6 +841,7 @@ class FacetTransformer(lark.Transformer): element_value = getattr(element, name, None) return self.compare(element_value, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def type(self, args): @@ -853,6 +851,7 @@ class FacetTransformer(lark.Transformer): element_value = getattr(ifcopenshell.util.element.get_type(element), "Name", None) return self.compare(element_value, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def material(self, args): @@ -870,6 +869,7 @@ class FacetTransformer(lark.Transformer): return result if comparison == "=" else not result return self.compare(None, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def property(self, args): @@ -899,6 +899,7 @@ class FacetTransformer(lark.Transformer): return self.compare(element_value, comparison, value) return self.compare(None, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def classification(self, args): @@ -918,6 +919,7 @@ class FacetTransformer(lark.Transformer): return result if comparison == "=" else not result return self.compare(None, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def location(self, args): @@ -936,6 +938,7 @@ class FacetTransformer(lark.Transformer): return result if comparison == "=" else not result return self.compare(None, comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def group(self, args): @@ -949,6 +952,7 @@ class FacetTransformer(lark.Transformer): result = True return result if comparison == "=" else not result + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def parent(self, args): @@ -989,6 +993,7 @@ class FacetTransformer(lark.Transformer): for parent in parents: children |= set(ifcopenshell.util.element.get_decomposition(parent)) + self.add_default_elements() if comparison == "=": self.elements = self.elements & children else: @@ -1000,6 +1005,7 @@ class FacetTransformer(lark.Transformer): def filter_function(element: ifcopenshell.entity_instance) -> bool: return self.compare(get_element_value(element, keys), comparison, value) + self.add_default_elements() self.elements = set(filter(filter_function, self.elements)) def get_container_tree(self, container: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: