Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

Commit

Permalink
Merge pull request #180 from adam-urbanczyk/master
Browse files Browse the repository at this point in the history
Fixing DirectionNthSelector
  • Loading branch information
jmwright committed Apr 18, 2017
2 parents 8bf31d0 + c2ce8fe commit 152da20
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 22 deletions.
36 changes: 14 additions & 22 deletions cadquery/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
import math
from cadquery import Vector,Edge,Vertex,Face,Solid,Shell,Compound
from collections import defaultdict
from pyparsing import Literal,Word,nums,Optional,Combine,oneOf,upcaseTokens,\
CaselessLiteral,Group,infixNotation,opAssoc,Forward,\
ZeroOrMore,Keyword
Expand Down Expand Up @@ -299,11 +300,6 @@ 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)

# import OrderedDict
from collections import OrderedDict
Expand Down Expand Up @@ -336,34 +332,30 @@ def __init__(self, vector, n, directionMax=True, tolerance=0.0001):
self.max = max
self.directionMax = directionMax
self.TOLERANCE = tolerance
if directionMax:
self.N = n #do we want indexing from 0 or from 1?
else:
self.N = -n

self.N = n

def filter(self,objectList):
#select first the objects that are normal/parallel to a given dir
objectList = super(DirectionNthSelector,self).filter(objectList)

def distance(tShape):
return tShape.Center().dot(self.direction)
#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()}

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

# choose the Nth unique rounded distance
nth_d = dist_round_dist[sorted(dist_round_dist.keys())[self.N]]
nth_distance = sorted(objectDict.keys(),
reverse=not self.directionMax)[self.N]

# map back to original objects and return
return [objectDict[d] for d in objectDict.keys() if abs(d-nth_d) < self.TOLERANCE]
return objectDict[nth_distance]

class BinarySelector(Selector):
"""
Expand Down
44 changes: 44 additions & 0 deletions tests/TestCQSelectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,14 @@ def testNthDistance(self):
#2nd face
val = c.faces('>(1,0,0)[1]').val()
self.assertAlmostEqual(val.Center().x,-1.5)
val = c.faces('>X[1]').val()
self.assertAlmostEqual(val.Center().x,-1.5)

#2nd face with inversed selection vector
val = c.faces('>(-1,0,0)[1]').val()
self.assertAlmostEqual(val.Center().x,1.5)
val = c.faces('<X[1]').val()
self.assertAlmostEqual(val.Center().x,1.5)

#2nd last face
val = c.faces('>X[-2]').val()
Expand All @@ -210,6 +214,46 @@ def testNthDistance(self):
#check if the selected face if normal to the specified Vector
self.assertAlmostEqual(val.normalAt().cross(Vector(1,0,0)).Length,0.0)

#test selection of multiple faces with the same distance
c = Workplane('XY')\
.box(1,4,1,centered=(False,True,False)).faces('<Z')\
.box(2,2,2,centered=(True,True,False)).faces('>Z')\
.box(1,1,1,centered=(True,True,False))

#select 2nd from the bottom (NB python indexing is 0-based)
vals = c.faces('>Z[1]').vals()
self.assertEqual(len(vals),2)

val = c.faces('>Z[1]').val()
self.assertAlmostEqual(val.Center().z,1)

#do the same but by selecting 3rd from the top
vals = c.faces('<Z[2]').vals()
self.assertEqual(len(vals),2)

val = c.faces('<Z[2]').val()
self.assertAlmostEqual(val.Center().z,1)

#do the same but by selecting 2nd last from the bottom
vals = c.faces('<Z[-2]').vals()
self.assertEqual(len(vals),2)

val = c.faces('<Z[-2]').val()
self.assertAlmostEqual(val.Center().z,1)

#verify that <Z[-1] is equivalent to <Z
val1 = c.faces('<Z[-1]').val()
val2 = c.faces('<Z').val()
self.assertTupleAlmostEquals(val1.Center().toTuple(),
val2.Center().toTuple(),
3)

#verify that >Z[-1] is equivalent to >Z
val1 = c.faces('>Z[-1]').val()
val2 = c.faces('>Z').val()
self.assertTupleAlmostEquals(val1.Center().toTuple(),
val2.Center().toTuple(),
3)

def testNearestTo(self):
c = CQ(makeUnitCube())
Expand Down

0 comments on commit 152da20

Please sign in to comment.