Skip to content

Commit

Permalink
AreaNthSelector ignores "bad" Wires
Browse files Browse the repository at this point in the history
AreaNthSelector.key raises ValueError if temporary face creation fails for a wire for any reason (non-planar, non-closed). That causes _NthSelector that it inherits to ignore such wires. Done so for consistency with RadiusNthSelector that ignores anything it can not get radius from.
  • Loading branch information
fedorkotov committed Mar 16, 2021
1 parent 0fe9abd commit 93fceff
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
17 changes: 12 additions & 5 deletions cadquery/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,12 @@ class AreaNthSelector(_NthSelector):
Applicability:
Faces, Shells, Solids - Shape.Area() is used to compute area
planar Wires - a temporary face is created to compute area
closed planar Wires - a temporary face is created to compute area
Among other things can be used to select one of
the nested coplanar wires or faces.
Will ignore non-planar or non-closed wires.
Among other things can be used to select one of
the nested coplanar wires or faces.
For example to create a fillet on a shank:
Expand All @@ -507,7 +509,7 @@ class AreaNthSelector(_NthSelector):
)
Or to create a lip on a case seam:
result = (
cq.Workplane("XY")
.rect(20, 20)
Expand All @@ -534,7 +536,12 @@ def key(self, obj: Shape) -> float:
if isinstance(obj, (Face, Shell, Solid)):
return obj.Area()
elif isinstance(obj, Wire):
return Face.makeFromWires(obj).Area()
try:
return Face.makeFromWires(obj).Area()
except Exception as ex:
raise ValueError(
f"Can not compute area of the Wire: {ex}. AreaNthSelector supports only closed planar Wires."
)
else:
raise ValueError(
f"AreaNthSelector supports only Wires, Faces, Shells and Solids, not {type(obj).__name__}"
Expand Down
29 changes: 28 additions & 1 deletion tests/test_selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ def testAreaNthSelector_Edges(self):
with self.assertRaises(IndexError):
Workplane("XY").box(10, 10, 10).edges(selectors.AreaNthSelector(0))

def testAreaNthSelector_Wires(self):
def testAreaNthSelector_NestedWires(self):
"""
Tests key parts of case seam leap creation algorithm
(see example 26)
Expand Down Expand Up @@ -899,6 +899,33 @@ def testAreaNthSelector_Wires(self):
msg="Failed to select inner wire of 2 faces: wrong area",
)

def testAreaNthSelector_NonplanarWire(self):
"""
AreaNthSelector should raise ValueError when
used on non-planar wires so that they are ignored by
_NthSelector.
Non-planar wires in stack should not prevent selection of
planar wires.
"""
wp = Workplane("XY").circle(10).extrude(50)

with self.assertRaises(IndexError):
wp.wires(selectors.AreaNthSelector(1))

cylinder_flat_ends = wp.wires(selectors.AreaNthSelector(0))
self.assertEqual(
len(cylinder_flat_ends.vals()),
2,
msg="Failed to select cylinder flat end wires: wrong N wires",
)
self.assertTupleAlmostEquals(
[math.pi * 10 ** 2] * 2,
[Face.makeFromWires(wire).Area() for wire in cylinder_flat_ends.vals()],
5,
msg="Failed to select cylinder flat end wires: wrong area",
)

def testAreaNthSelector_Faces(self):
"""
Selecting two faces of 10x20x30 box with intermediate area.
Expand Down

0 comments on commit 93fceff

Please sign in to comment.