Merge pull request #879 from snoyer/filter_by-property

allow to filter and group by property
This commit is contained in:
Roger Maitland 2025-01-28 19:02:09 -05:00 committed by GitHub
commit 9268f31a8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 3 deletions

View file

@ -2351,7 +2351,7 @@ class ShapeList(list[T]):
def filter_by(
self,
filter_by: ShapePredicate | Axis | Plane | GeomType,
filter_by: ShapePredicate | Axis | Plane | GeomType | property,
reverse: bool = False,
tolerance: float = 1e-5,
) -> ShapeList[T]:
@ -2446,6 +2446,11 @@ class ShapeList(list[T]):
# convert input to callable predicate
if callable(filter_by):
predicate = filter_by
elif isinstance(filter_by, property):
def predicate(obj):
return filter_by.__get__(obj)
elif isinstance(filter_by, Axis):
predicate = axis_parallel_predicate(filter_by, tolerance=tolerance)
elif isinstance(filter_by, Plane):
@ -2524,7 +2529,9 @@ class ShapeList(list[T]):
def group_by(
self,
group_by: Callable[[Shape], K] | Axis | Edge | Wire | SortBy = Axis.Z,
group_by: (
Callable[[Shape], K] | Axis | Edge | Wire | SortBy | property
) = Axis.Z,
reverse=False,
tol_digits=6,
) -> GroupBy[T, K]:
@ -2594,6 +2601,9 @@ class ShapeList(list[T]):
elif callable(group_by):
key_f = group_by
elif isinstance(group_by, property):
key_f = group_by.__get__
else:
raise ValueError(f"Unsupported group_by function: {group_by}")
@ -2625,7 +2635,7 @@ class ShapeList(list[T]):
def sort_by(
self,
sort_by: Axis | Callable[[T], K] | Edge | Wire | SortBy = Axis.Z,
sort_by: Axis | Callable[[T], K] | Edge | Wire | SortBy | property = Axis.Z,
reverse: bool = False,
) -> ShapeList[T]:
"""sort by
@ -2651,6 +2661,9 @@ class ShapeList(list[T]):
# If a callable is provided, use it directly as the key
objects = sorted(self, key=sort_by, reverse=reverse)
elif isinstance(sort_by, property):
objects = sorted(self, key=sort_by.__get__, reverse=reverse)
elif isinstance(sort_by, Axis):
if sort_by.wrapped is None:
raise ValueError("Cannot sort by an empty axis")

View file

@ -89,6 +89,14 @@ class TestShapeList(unittest.TestCase):
self.assertAlmostEqual(smallest.area, math.pi * 1**2, 5)
self.assertAlmostEqual(largest.area, math.pi * 2**2, 5)
def test_sort_by_property(self):
box1 = Box(1, 1, 1)
box2 = Box(2, 2, 2)
box3 = Box(3, 3, 3)
unsorted_boxes = ShapeList([box2, box3, box1])
assert unsorted_boxes.sort_by(Solid.volume) == [box1, box2, box3]
assert unsorted_boxes.sort_by(Solid.volume, reverse=True) == [box3, box2, box1]
def test_sort_by_invalid(self):
with self.assertRaises(ValueError):
Solid.make_box(1, 1, 1).faces().sort_by(">Z")
@ -119,6 +127,12 @@ class TestShapeList(unittest.TestCase):
self.assertEqual(len(shapelist.filter_by(lambda s: s.label == "A")), 2)
self.assertEqual(len(shapelist.filter_by(lambda s: s.label == "B")), 1)
def test_filter_by_property(self):
box1 = Box(2, 2, 2)
box2 = Box(2, 2, 2).translate((1, 1, 1))
assert len((box1 + box2).edges().filter_by(Edge.is_interior)) == 6
assert len((box1 - box2).edges().filter_by(Edge.is_interior)) == 3
def test_first_last(self):
vertices = (
Solid.make_box(1, 1, 1).vertices().sort_by(Axis((0, 0, 0), (1, 1, 1)))
@ -187,6 +201,17 @@ class TestShapeList(unittest.TestCase):
self.assertEqual([len(group) for group in result], [1, 3, 2])
def test_group_by_property(self):
box1 = Box(2, 2, 2)
box2 = Box(2, 2, 2).translate((1, 1, 1))
g1 = (box1 + box2).edges().group_by(Edge.is_interior)
assert len(g1.group(True)) == 6
assert len(g1.group(False)) == 24
g2 = (box1 - box2).edges().group_by(Edge.is_interior)
assert len(g2.group(True)) == 3
assert len(g2.group(False)) == 18
def test_group_by_retrieve_groups(self):
boxesA = [Solid.make_box(1, 1, 1) for _ in range(3)]
boxesB = [Solid.make_box(1, 1, 1) for _ in range(2)]