diff --git a/cadquery/selectors.py b/cadquery/selectors.py index 246db30..81a7ba2 100644 --- a/cadquery/selectors.py +++ b/cadquery/selectors.py @@ -323,6 +323,64 @@ class DirectionMinMaxSelector(Selector): # return all objects at the max/min distance (within a tolerance) return filter(lambda o: abs(d - distance(o)) < self.TOLERANCE, objectList) +class DirectionNthSelector(Selector): + """ + Selects objects closest or farthest in the specified direction + Used for faces, points, and edges + + Applicability: + All object types. for a vertex, its point is used. for all other kinds + of objects, the center of mass of the object is used. + + You can use the string shortcuts >(X|Y|Z) or <(X|Y|Z) if you want to + select based on a cardinal direction. + + For example this:: + + CQ(aCube).faces ( DirectionMinMaxSelector((0,0,1),True ) + + Means to select the face having the center of mass farthest in the positive z direction, + and is the same as: + + CQ(aCube).faces( ">Z" ) + + Future Enhancements: + provide a nicer way to select in arbitrary directions. IE, a bit more code could + allow '>(0,0,1)' to work. + + """ + def __init__(self, vector, n, directionMax=True, tolerance=0.0001): + self.vector = vector + self.max = max + self.directionMax = directionMax + self.TOLERANCE = tolerance + if directionMax: + self.N = n + else: + self.N = -n + + def filter(self,objectList): + + def distance(tShape): + return tShape.Center().dot(self.vector) + #if tShape.ShapeType == 'Vertex': + # pnt = tShape.Point + #else: + # pnt = tShape.Center() + #return pnt.dot(self.vector) + + #make and distance to object dict + objectDict = {distance(el) : el for el in objectList} + #calculate how many digits of precision do we need + digits = int(1/self.TOLERANCE) + # create a rounded distance to original distance mapping (implicitly perfroms unique operation) + dist_round_dist = {round(d,digits) : d for d in objectDict.keys()} + # choose the Nth unique rounded distance + nth_d = dist_round_dist[sorted(dist_round_dist.keys())[self.N]] + + # map back to original objects and return + return [objectDict[d] for d in objectDict.keys() if abs(d-nth_d) < self.TOLERANCE] + class BinarySelector(Selector): """ Base class for selectors that operates with two other