Selector now uses classmethods to make it easier for scriptwriters to use

This commit is contained in:
Dion Moult
2022-03-21 17:28:16 +11:00
parent c478e5bf1b
commit 44afa0df5d
2 changed files with 83 additions and 26 deletions
@@ -23,8 +23,9 @@ import lark
class Selector:
def parse(self, ifc_file, query):
self.file = ifc_file
@classmethod
def parse(cls, ifc_file, query):
cls.file = ifc_file
l = lark.Lark(
"""start: query (lfunction query)*
@@ -82,13 +83,14 @@ class Selector:
)
start = l.parse(query)
return self.get_group(start)
return cls.get_group(start)
def get_group(self, group):
@classmethod
def get_group(cls, group):
lfunction = None
for child in group.children:
if child.data == "query":
new_results = self.get_query(child)
new_results = cls.get_query(child)
if not lfunction:
results = new_results
elif lfunction == "or":
@@ -100,14 +102,16 @@ class Selector:
lfunction = child.children[0].data
return results
def get_query(self, query):
@classmethod
def get_query(cls, query):
for child in query.children:
if child.data == "selector":
return self.get_selector(child)
return cls.get_selector(child)
elif child.data == "group":
return self.get_group(child)
return cls.get_group(child)
def get_selector(self, selector):
@classmethod
def get_selector(cls, selector):
if len(selector.children) == 1:
inverse_relationship = None
class_or_guid_selector = selector.children[0]
@@ -116,15 +120,16 @@ class Selector:
class_or_guid_selector = selector.children[1]
if class_or_guid_selector.data == "class_selector":
results = self.get_class_selector(class_or_guid_selector)
results = cls.get_class_selector(class_or_guid_selector)
elif class_or_guid_selector.data == "guid_selector":
results = self.get_guid_selector(class_or_guid_selector)
results = cls.get_guid_selector(class_or_guid_selector)
if not inverse_relationship:
return results
return self.parse_inverse_relationship(results, inverse_relationship.children[0].data)
return cls.parse_inverse_relationship(results, inverse_relationship.children[0].data)
def parse_inverse_relationship(self, elements, inverse_relationship):
@classmethod
def parse_inverse_relationship(cls, elements, inverse_relationship):
results = []
for element in elements:
if inverse_relationship == "types":
@@ -140,20 +145,22 @@ class Selector:
results.append(relationship.RelatedBuildingElement)
return results
def get_class_selector(self, class_selector):
@classmethod
def get_class_selector(cls, class_selector):
if class_selector.children[0] == "COBie":
elements = ifcopenshell.util.fm.get_cobie_components(self.file)
elements = ifcopenshell.util.fm.get_cobie_components(cls.file)
elif class_selector.children[0] == "COBieType":
elements = ifcopenshell.util.fm.get_cobie_types(self.file)
elements = ifcopenshell.util.fm.get_cobie_types(cls.file)
elif class_selector.children[0] == "FMHEM":
elements = ifcopenshell.util.fm.get_fmhem_types(self.file)
elements = ifcopenshell.util.fm.get_fmhem_types(cls.file)
else:
elements = self.file.by_type(class_selector.children[0])
elements = cls.file.by_type(class_selector.children[0])
if len(class_selector.children) > 1 and class_selector.children[1].data == "filter":
return self.filter_elements(elements, class_selector.children[1])
return cls.filter_elements(elements, class_selector.children[1])
return elements
def filter_elements(self, elements, filter_rule):
@classmethod
def filter_elements(cls, elements, filter_rule):
results = []
key = filter_rule.children[0].children[0]
if not isinstance(key, str):
@@ -163,14 +170,15 @@ class Selector:
comparison = filter_rule.children[1].children[0].data
value = filter_rule.children[2].children[0][1:-1]
for element in elements:
element_value = self.get_element_value(element, key)
element_value = cls.get_element_value(element, key)
if element_value is None:
continue
if not comparison or self.filter_element(element, element_value, comparison, value):
if not comparison or cls.filter_element(element, element_value, comparison, value):
results.append(element)
return results
def get_element_value(self, element, key):
@classmethod
def get_element_value(cls, element, key):
if "." in key and key.split(".")[0] == "type":
try:
element = ifcopenshell.util.element.get_type(element)
@@ -206,7 +214,8 @@ class Selector:
if pset_name in psets and prop in psets[pset_name]:
return psets[pset_name][prop]
def filter_element(self, element, element_value, comparison, value):
@classmethod
def filter_element(cls, element, element_value, comparison, value):
if comparison == "equal":
return str(element_value) == value
elif comparison == "contains":
@@ -221,5 +230,6 @@ class Selector:
return element_value <= float(value)
return False
def get_guid_selector(self, guid_selector):
return [self.file.by_id(guid_selector.children[0])]
@classmethod
def get_guid_selector(cls, guid_selector):
return [cls.file.by_id(guid_selector.children[0])]