Skip to content

Commit

Permalink
Added RadiusNthSelector
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus7070 committed Nov 18, 2020
1 parent 3136ede commit 255b464
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
45 changes: 45 additions & 0 deletions cadquery/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,51 @@ def filter(self, objectList):
return r


class RadiusNthSelector(Selector):
"""
Select the object with the Nth radius.
Applicability:
All Edge and Wires.
Will ignore any shape that can not be represented as a circle or an arc of
a circle.
"""

def __init__(self, n, directionMax=True, tolerance=0.0001):
self.N = n
self.directionMax = directionMax
self.TOLERANCE = tolerance

def filter(self, objectList):
# calculate how many digits of precision do we need
digits = -math.floor(math.log10(self.TOLERANCE))

# make a radius dict
# this is one to many mapping so I am using a default dict with list
objectDict = defaultdict(list)
for el in objectList:
try:
rad = el.radius()
except ValueError:
continue
objectDict[round(rad, digits)].append(el)

# choose the Nth unique rounded distance
sortedObjectList = sorted(
list(objectDict.keys()), reverse=not self.directionMax
)
try:
nth_distance = sortedObjectList[self.N]
except IndexError:
raise IndexError(
f"Attempted to access the {self.N}-th radius in a list {len(sortedObjectList)} long"
)

# map back to original objects and return
return objectDict[nth_distance]


class DirectionMinMaxSelector(Selector):
"""
Selects objects closest or farthest in the specified direction
Expand Down
1 change: 1 addition & 0 deletions doc/apireference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ as a basis for futher operations.
ParallelDirSelector
DirectionSelector
DirectionNthSelector
RadiusNthSelector
PerpendicularDirSelector
TypeSelector
DirectionMinMaxSelector
Expand Down
1 change: 1 addition & 0 deletions doc/classreference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Selector Classes
ParallelDirSelector
DirectionSelector
DirectionNthSelector
RadiusNthSelector
PerpendicularDirSelector
TypeSelector
DirectionMinMaxSelector
Expand Down
78 changes: 78 additions & 0 deletions tests/test_selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,84 @@ def testBox(self):
).vals()
self.assertEqual(1, len(fl))

def testRadiusNthSelector(self):
part = (
Workplane()
.box(10, 10, 1)
.edges(">(1, 1, 0) and |Z")
.fillet(1)
.edges(">(-1, 1, 0) and |Z")
.fillet(1)
.edges(">(-1, -1, 0) and |Z")
.fillet(2)
.edges(">(1, -1, 0) and |Z")
.fillet(3)
.faces(">Z")
)
# smallest radius is 1.0
self.assertAlmostEqual(
part.edges(selectors.RadiusNthSelector(0)).val().radius(), 1.0
)
# there are two edges with the smallest radius
self.assertEqual(len(part.edges(selectors.RadiusNthSelector(0)).vals()), 2)
# next radius is 2.0
self.assertAlmostEqual(
part.edges(selectors.RadiusNthSelector(1)).val().radius(), 2.0
)
# largest radius is 3.0
self.assertAlmostEqual(
part.edges(selectors.RadiusNthSelector(-1)).val().radius(), 3.0
)
# accessing index 3 should be an IndexError
with self.assertRaises(IndexError):
part.edges(selectors.RadiusNthSelector(3))
# reversed
self.assertAlmostEqual(
part.edges(selectors.RadiusNthSelector(0, directionMax=False))
.val()
.radius(),
3.0,
)

# test the selector on wires
wire_circles = (
Workplane()
.circle(2)
.moveTo(10, 0)
.circle(2)
.moveTo(20, 0)
.circle(4)
.consolidateWires()
)
self.assertEqual(
len(wire_circles.wires(selectors.RadiusNthSelector(0)).vals()), 2
)
self.assertEqual(
len(wire_circles.wires(selectors.RadiusNthSelector(1)).vals()), 1
)
self.assertAlmostEqual(
wire_circles.wires(selectors.RadiusNthSelector(0)).val().radius(), 2
)
self.assertAlmostEqual(
wire_circles.wires(selectors.RadiusNthSelector(1)).val().radius(), 4
)

# a polygon with rounded corners has a radius, according to OCCT
loop_wire = Wire.makePolygon(
[Vector(-10, 0, 0), Vector(0, 10, 0), Vector(10, 0, 0),]
)
loop_workplane = (
Workplane().add(loop_wire.offset2D(1)).add(loop_wire.offset2D(2))
)
self.assertAlmostEqual(
loop_workplane.wires(selectors.RadiusNthSelector(0)).val().radius(), 1.0
)
self.assertAlmostEqual(
loop_workplane.wires(selectors.RadiusNthSelector(1)).val().radius(), 2.0
)
with self.assertRaises(IndexError):
loop_workplane.wires(selectors.RadiusNthSelector(2))

def testAndSelector(self):
c = CQ(makeUnitCube())

Expand Down

0 comments on commit 255b464

Please sign in to comment.