mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
Adjust selector's behaviour to use the elements argument as a filtering subset
This was always the original intention, but never worked as designed. This is so that you don't need to filter the entire file (which can be huge).
This commit is contained in:
@@ -291,9 +291,10 @@ def filter_elements(
|
|||||||
:type ifc_file: ifcopenshell.file
|
:type ifc_file: ifcopenshell.file
|
||||||
:param query: Query to execute
|
:param query: Query to execute
|
||||||
:type query: str
|
:type query: str
|
||||||
:param elements: Base set of IFC elements for the query.
|
:param elements: Base set of IFC elements for the query. If not provided,
|
||||||
If provided, new elements found for the current query will be added to `elements`.
|
all elements in the IFC are queried. If provided, the query will be
|
||||||
Elements explicitly excluded in the `query` will also be excluded from `elements`
|
applied to this set of elements, so the result will be a subset of
|
||||||
|
elements.
|
||||||
:type elements: set[ifcopenshell.entity_instance], optional
|
:type elements: set[ifcopenshell.entity_instance], optional
|
||||||
:param edit_in_place: If `True`, mutate the provided `elements` in place. Defaults to `False`
|
:param edit_in_place: If `True`, mutate the provided `elements` in place. Defaults to `False`
|
||||||
:type edit_in_place: bool
|
:type edit_in_place: bool
|
||||||
@@ -497,11 +498,17 @@ def set_element_value(
|
|||||||
f"Failed to set value for element '{original_element}' with query '{query}' (invalid or unsupported query)."
|
f"Failed to set value for element '{original_element}' with query '{query}' (invalid or unsupported query)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FacetTransformer(lark.Transformer):
|
class FacetTransformer(lark.Transformer):
|
||||||
def __init__(self, ifc_file: ifcopenshell.file, elements: Optional[set[ifcopenshell.entity_instance]] = None):
|
def __init__(self, ifc_file: ifcopenshell.file, elements: Optional[set[ifcopenshell.entity_instance]] = None):
|
||||||
self.file = ifc_file
|
self.file = ifc_file
|
||||||
self.results = []
|
self.results = []
|
||||||
self.elements = set() if elements is None else elements
|
if elements is None:
|
||||||
|
self.base_elements = None
|
||||||
|
self.elements = set()
|
||||||
|
else:
|
||||||
|
self.base_elements = elements.copy()
|
||||||
|
self.elements = set()
|
||||||
self.container_parents = {}
|
self.container_parents = {}
|
||||||
self.container_trees = {}
|
self.container_trees = {}
|
||||||
|
|
||||||
@@ -517,28 +524,44 @@ class FacetTransformer(lark.Transformer):
|
|||||||
self.elements = set()
|
self.elements = set()
|
||||||
|
|
||||||
def instance(self, args):
|
def instance(self, args):
|
||||||
if args[0].data == "globalid":
|
if self.base_elements is None:
|
||||||
try:
|
if args[0].data == "globalid":
|
||||||
self.elements.add(self.file.by_guid(args[0].children[0].value))
|
try:
|
||||||
except:
|
self.elements.add(self.file.by_guid(args[0].children[0].value))
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.elements.remove(self.file.by_guid(args[1].children[0].value))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
if args[0].data == "globalid":
|
||||||
self.elements.remove(self.file.by_guid(args[1].children[0].value))
|
self.elements |= {
|
||||||
except:
|
e for e in self.base_elements if getattr(e, "GlobalId", None) == args[0].children[0].value
|
||||||
pass
|
}
|
||||||
|
else:
|
||||||
|
self.elements -= {
|
||||||
|
e for e in self.base_elements if getattr(e, "GlobalId", None) == args[1].children[0].value
|
||||||
|
}
|
||||||
|
|
||||||
def entity(self, args):
|
def entity(self, args):
|
||||||
if args[0].data == "ifc_class":
|
if self.base_elements is None:
|
||||||
try:
|
if args[0].data == "ifc_class":
|
||||||
self.elements |= set(self.file.by_type(args[0].children[0].value))
|
try:
|
||||||
except:
|
self.elements |= set(self.file.by_type(args[0].children[0].value))
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.elements -= set(self.file.by_type(args[1].children[0].value))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
if args[0].data == "ifc_class":
|
||||||
self.elements -= set(self.file.by_type(args[1].children[0].value))
|
self.elements |= {e for e in self.base_elements if e.is_a(args[0].children[0].value)}
|
||||||
except:
|
else:
|
||||||
pass
|
self.elements -= {e for e in self.base_elements if e.is_a(args[1].children[0].value)}
|
||||||
|
|
||||||
def attribute(self, args):
|
def attribute(self, args):
|
||||||
name, comparison, value = args
|
name, comparison, value = args
|
||||||
|
|||||||
@@ -25,41 +25,41 @@ import ifcopenshell.util.pset
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class TestFormat():
|
class TestFormat:
|
||||||
def test_no_formatting(self):
|
def test_no_formatting(self):
|
||||||
assert subject.format("123") == "123"
|
assert subject.format("123") == "123"
|
||||||
assert subject.format('\"123\"') == "123"
|
assert subject.format('"123"') == "123"
|
||||||
assert subject.format('\"foo\"') == "foo"
|
assert subject.format('"foo"') == "foo"
|
||||||
|
|
||||||
def test_string_formatting(self):
|
def test_string_formatting(self):
|
||||||
assert subject.format('upper(\"fOo\")') == "FOO"
|
assert subject.format('upper("fOo")') == "FOO"
|
||||||
assert subject.format('lower(\"fOo\")') == "foo"
|
assert subject.format('lower("fOo")') == "foo"
|
||||||
assert subject.format('title(\"fOo\")') == "Foo"
|
assert subject.format('title("fOo")') == "Foo"
|
||||||
assert subject.format('concat(\"fOo\", \"bar\")') == "fOobar"
|
assert subject.format('concat("fOo", "bar")') == "fOobar"
|
||||||
assert subject.format('upper(concat(\"fOo\", \"bar\"))') == "FOOBAR"
|
assert subject.format('upper(concat("fOo", "bar"))') == "FOOBAR"
|
||||||
assert subject.format('substr(\"foobar\", 3)') == "bar"
|
assert subject.format('substr("foobar", 3)') == "bar"
|
||||||
assert subject.format('substr(\"foobar\", 1, 2)') == "o"
|
assert subject.format('substr("foobar", 1, 2)') == "o"
|
||||||
assert subject.format('substr(\"foobar\", 1, -1)') == "ooba"
|
assert subject.format('substr("foobar", 1, -1)') == "ooba"
|
||||||
|
|
||||||
def test_number_formatting(self):
|
def test_number_formatting(self):
|
||||||
assert subject.format("round(123, 5)") == "125"
|
assert subject.format("round(123, 5)") == "125"
|
||||||
assert subject.format('round(\"123\", 5)') == "125"
|
assert subject.format('round("123", 5)') == "125"
|
||||||
assert subject.format('number(123)') == "123"
|
assert subject.format("number(123)") == "123"
|
||||||
assert subject.format('number(1234.56)') == "1,234.56"
|
assert subject.format("number(1234.56)") == "1,234.56"
|
||||||
assert subject.format('number(123, ".")') == "123"
|
assert subject.format('number(123, ".")') == "123"
|
||||||
assert subject.format('number(\"123\", ".")') == "123"
|
assert subject.format('number("123", ".")') == "123"
|
||||||
assert subject.format('number(123.12, ".")') == "123.12"
|
assert subject.format('number(123.12, ".")') == "123.12"
|
||||||
assert subject.format('number(123.12, ",")') == "123,12"
|
assert subject.format('number(123.12, ",")') == "123,12"
|
||||||
assert subject.format('number(1234.12, ",", ".")') == "1.234,12"
|
assert subject.format('number(1234.12, ",", ".")') == "1.234,12"
|
||||||
assert subject.format('metric_length(123, 5, 2)') == "125.00"
|
assert subject.format("metric_length(123, 5, 2)") == "125.00"
|
||||||
assert subject.format('metric_length(123.123, 0.1, 2)') == "123.10"
|
assert subject.format("metric_length(123.123, 0.1, 2)") == "123.10"
|
||||||
assert subject.format('metric_length(\"123\", 5, 2)') == "125.00"
|
assert subject.format('metric_length("123", 5, 2)') == "125.00"
|
||||||
assert subject.format('imperial_length(1, 1)') == "1'"
|
assert subject.format("imperial_length(1, 1)") == "1'"
|
||||||
assert subject.format('imperial_length(3.123, 1)') == "3' - 1\""
|
assert subject.format("imperial_length(3.123, 1)") == "3' - 1\""
|
||||||
assert subject.format('imperial_length(3.123, 2)') == "3' - 1 1/2\""
|
assert subject.format("imperial_length(3.123, 2)") == "3' - 1 1/2\""
|
||||||
assert subject.format('imperial_length(\"3.123\", 2)') == "3' - 1 1/2\""
|
assert subject.format('imperial_length("3.123", 2)') == "3' - 1 1/2\""
|
||||||
assert subject.format('imperial_length(\"123.123\", 2, \"inch\", \"foot\")') == "10' - 3\""
|
assert subject.format('imperial_length("123.123", 2, "inch", "foot")') == "10' - 3\""
|
||||||
assert subject.format('imperial_length(\"123.123\", 2, \"inch\", \"inch\")') == "123\""
|
assert subject.format('imperial_length("123.123", 2, "inch", "inch")') == '123"'
|
||||||
|
|
||||||
|
|
||||||
class TestGetElementValue(test.bootstrap.IFC4):
|
class TestGetElementValue(test.bootstrap.IFC4):
|
||||||
@@ -269,17 +269,19 @@ class TestFilterElements(test.bootstrap.IFC4):
|
|||||||
def test_using_elements_argument(self):
|
def test_using_elements_argument(self):
|
||||||
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
slab = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
|
slab = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
|
||||||
|
door = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDoor")
|
||||||
|
elements = {wall, slab}
|
||||||
|
results = subject.filter_elements(self.file, "IfcWall", {wall, slab})
|
||||||
|
assert results != elements
|
||||||
|
assert results == {wall}
|
||||||
|
elements = {wall, slab, door}
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall, IfcSlab", elements) == {wall, slab}
|
||||||
|
|
||||||
# keep elements unaffected by expression
|
def test_editing_in_place(self):
|
||||||
assert subject.filter_elements(self.file, "IfcWall", {slab}) == {wall, slab}
|
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
original_set = {wall}
|
||||||
# filter out excluded elements
|
|
||||||
assert subject.filter_elements(self.file, "IfcWall, ! IfcSlab", {slab}) == {wall}
|
|
||||||
|
|
||||||
# edit_in_place to update original set
|
|
||||||
original_set = set()
|
|
||||||
new_set = subject.filter_elements(self.file, "IfcWall", original_set, edit_in_place=True)
|
new_set = subject.filter_elements(self.file, "IfcWall", original_set, edit_in_place=True)
|
||||||
assert new_set == original_set
|
assert new_set == original_set == {wall}
|
||||||
|
|
||||||
|
|
||||||
class TestSetElementValue(test.bootstrap.IFC4):
|
class TestSetElementValue(test.bootstrap.IFC4):
|
||||||
|
|||||||
Reference in New Issue
Block a user