@@ -103,32 +103,58 @@ def testFaceTypesFilter(self):
103103 def testPerpendicularDirFilter (self ):
104104 c = CQ (makeUnitCube ())
105105
106- self .assertEqual (8 , c .edges ("#Z" ).size ()) # 8 edges are perp. to z
107- self .assertEqual (4 , c .faces ("#Z" ).size ()) # 4 faces are perp to z too!
106+ perp_edges = c .edges ("#Z" )
107+ self .assertEqual (8 , perp_edges .size ()) # 8 edges are perp. to z
108+ # dot product of perpendicular vectors is zero
109+ for e in perp_edges .vals ():
110+ self .assertAlmostEqual (e .tangentAt (0 ).dot (Vector (0 , 0 , 1 )), 0.0 )
111+ perp_faces = c .faces ("#Z" )
112+ self .assertEqual (4 , perp_faces .size ()) # 4 faces are perp to z too!
113+ for f in perp_faces .vals ():
114+ self .assertAlmostEqual (f .normalAt (None ).dot (Vector (0 , 0 , 1 )), 0.0 )
108115
109116 def testFaceDirFilter (self ):
110117 c = CQ (makeUnitCube ())
111118 # a cube has one face in each direction
112119 self .assertEqual (1 , c .faces ("+Z" ).size ())
120+ self .assertTupleAlmostEquals (
121+ (0 , 0 , 1 ), c .faces ("+Z" ).val ().Center ().toTuple (), 3
122+ )
113123 self .assertEqual (1 , c .faces ("-Z" ).size ())
124+ self .assertTupleAlmostEquals (
125+ (0 , 0 , 0 ), c .faces ("-Z" ).val ().Center ().toTuple (), 3
126+ )
114127 self .assertEqual (1 , c .faces ("+X" ).size ())
115- self .assertEqual (1 , c .faces ("X" ).size ()) # should be same as +X
128+ self .assertTupleAlmostEquals (
129+ (0.5 , 0 , 0.5 ), c .faces ("+X" ).val ().Center ().toTuple (), 3
130+ )
116131 self .assertEqual (1 , c .faces ("-X" ).size ())
132+ self .assertTupleAlmostEquals (
133+ (- 0.5 , 0 , 0.5 ), c .faces ("-X" ).val ().Center ().toTuple (), 3
134+ )
117135 self .assertEqual (1 , c .faces ("+Y" ).size ())
136+ self .assertTupleAlmostEquals (
137+ (0 , 0.5 , 0.5 ), c .faces ("+Y" ).val ().Center ().toTuple (), 3
138+ )
118139 self .assertEqual (1 , c .faces ("-Y" ).size ())
140+ self .assertTupleAlmostEquals (
141+ (0 , - 0.5 , 0.5 ), c .faces ("-Y" ).val ().Center ().toTuple (), 3
142+ )
119143 self .assertEqual (0 , c .faces ("XY" ).size ())
144+ self .assertEqual (1 , c .faces ("X" ).size ()) # should be same as +X
120145 self .assertEqual (c .faces ("+X" ).val ().Center (), c .faces ("X" ).val ().Center ())
121146 self .assertNotEqual (c .faces ("+X" ).val ().Center (), c .faces ("-X" ).val ().Center ())
122147
123148 def testParallelPlaneFaceFilter (self ):
124149 c = CQ (makeUnitCube ())
125150
126151 # faces parallel to Z axis
127- self .assertEqual (2 , c .faces ("|Z" ).size ())
128- # TODO: provide short names for ParallelDirSelector
129- self .assertEqual (
130- 2 , c .faces (selectors .ParallelDirSelector (Vector ((0 , 0 , 1 )))).size ()
131- ) # same thing as above
152+ # these two should produce the same behaviour:
153+ for s in ["|Z" , selectors .ParallelDirSelector (Vector (0 , 0 , 1 ))]:
154+ parallel_faces = c .faces (s )
155+ self .assertEqual (2 , parallel_faces .size ())
156+ for f in parallel_faces .vals ():
157+ self .assertAlmostEqual (abs (f .normalAt (None ).dot (Vector (0 , 0 , 1 ))), 1 )
132158 self .assertEqual (
133159 2 , c .faces (selectors .ParallelDirSelector (Vector ((0 , 0 , - 1 )))).size ()
134160 ) # same thing as above
@@ -138,9 +164,15 @@ def testParallelPlaneFaceFilter(self):
138164
139165 def testParallelEdgeFilter (self ):
140166 c = CQ (makeUnitCube ())
141- self .assertEqual (4 , c .edges ("|Z" ).size ())
142- self .assertEqual (4 , c .edges ("|X" ).size ())
143- self .assertEqual (4 , c .edges ("|Y" ).size ())
167+ for sel , vec in zip (
168+ ["|X" , "|Y" , "|Z" ], [Vector (1 , 0 , 0 ), Vector (0 , 1 , 0 ), Vector (0 , 0 , 1 )]
169+ ):
170+ edges = c .edges (sel )
171+ # each direction should have 4 edges
172+ self .assertEqual (4 , edges .size ())
173+ # each edge should be parallel with vec and have a cross product with a length of 0
174+ for e in edges .vals ():
175+ self .assertAlmostEqual (e .tangentAt (0 ).cross (vec ).Length , 0.0 )
144176
145177 def testMaxDistance (self ):
146178 c = CQ (makeUnitCube ())
@@ -155,24 +187,28 @@ def testMaxDistance(self):
155187 self .assertAlmostEqual (1.0 , v .Z , 3 )
156188
157189 # test the case of multiple objects at the same distance
158- el = c .edges ("< Z" ).vals ()
190+ el = c .edges ("> Z" ).vals ()
159191 self .assertEqual (4 , len (el ))
192+ for e in el :
193+ self .assertAlmostEqual (e .Center ().z , 1 )
160194
161195 def testMinDistance (self ):
162196 c = CQ (makeUnitCube ())
163197
164- # should select the topmost face
198+ # should select the bottom face
165199 self .assertEqual (1 , c .faces ("<Z" ).size ())
166200 self .assertEqual (4 , c .faces ("<Z" ).vertices ().size ())
167201
168- # vertices should all be at z=1 , if this is the top face
202+ # vertices should all be at z=0 , if this is the bottom face
169203 self .assertEqual (4 , len (c .faces ("<Z" ).vertices ().vals ()))
170204 for v in c .faces ("<Z" ).vertices ().vals ():
171205 self .assertAlmostEqual (0.0 , v .Z , 3 )
172206
173207 # test the case of multiple objects at the same distance
174208 el = c .edges ("<Z" ).vals ()
175209 self .assertEqual (4 , len (el ))
210+ for e in el :
211+ self .assertAlmostEqual (e .Center ().z , 0 )
176212
177213 def testNthDistance (self ):
178214 c = Workplane ("XY" ).pushPoints ([(- 2 , 0 ), (2 , 0 )]).box (1 , 1 , 1 )
@@ -252,20 +288,42 @@ def testNthDistance(self):
252288 val = c .faces ("<Z[-2]" ).val ()
253289 self .assertAlmostEqual (val .Center ().z , 1 )
254290
291+ # note that .val() will return the workplane center if the objects list
292+ # is empty, so to make sure this test fails with a selector that
293+ # selects nothing, use .vals()[0]
255294 # verify that <Z[-1] is equivalent to <Z
256- val1 = c .faces ("<Z[-1]" ).val ()
257- val2 = c .faces ("<Z" ).val ()
295+ val1 = c .faces ("<Z[-1]" ).vals ()[ 0 ]
296+ val2 = c .faces ("<Z" ).vals ()[ 0 ]
258297 self .assertTupleAlmostEquals (
259298 val1 .Center ().toTuple (), val2 .Center ().toTuple (), 3
260299 )
261300
262301 # verify that >Z[-1] is equivalent to >Z
263- val1 = c .faces (">Z[-1]" ).val ()
264- val2 = c .faces (">Z" ).val ()
302+ val1 = c .faces (">Z[-1]" ).vals ()[ 0 ]
303+ val2 = c .faces (">Z" ).vals ()[ 0 ]
265304 self .assertTupleAlmostEquals (
266305 val1 .Center ().toTuple (), val2 .Center ().toTuple (), 3
267306 )
268307
308+ # DirectionNthSelector should not select faces that are not perpendicular
309+ twisted_boxes = (
310+ Workplane ()
311+ .box (1 , 1 , 1 , centered = (True , True , False ))
312+ .transformed (rotate = (45 , 0 , 0 ), offset = (0 , 0 , 3 ))
313+ .box (1 , 1 , 1 )
314+ )
315+ self .assertTupleAlmostEquals (
316+ twisted_boxes .faces (">Z[-1]" ).val ().Center ().toTuple (), (0 , 0 , 1 ), 3
317+ )
318+ # this should select a face on the upper/rotated cube, not the lower/unrotated cube
319+ self .assertGreater (twisted_boxes .faces ("<(0, 1, 1)[-1]" ).val ().Center ().z , 1 )
320+ # verify that >Z[-1] is equivalent to >Z
321+ self .assertTupleAlmostEquals (
322+ twisted_boxes .faces (">(0, 1, 1)[0]" ).vals ()[0 ].Center ().toTuple (),
323+ twisted_boxes .faces ("<(0, 1, 1)[-1]" ).vals ()[0 ].Center ().toTuple (),
324+ 3 ,
325+ )
326+
269327 def testNearestTo (self ):
270328 c = CQ (makeUnitCube (centered = False ))
271329
@@ -453,22 +511,6 @@ def testRadiusNthSelector(self):
453511 wire_circles .wires (selectors .RadiusNthSelector (1 )).val ().radius (), 4
454512 )
455513
456- # a polygon with rounded corners has a radius, according to OCCT
457- loop_wire = Wire .makePolygon (
458- [Vector (- 10 , 0 , 0 ), Vector (0 , 10 , 0 ), Vector (10 , 0 , 0 ),]
459- )
460- loop_workplane = (
461- Workplane ().add (loop_wire .offset2D (1 )).add (loop_wire .offset2D (2 ))
462- )
463- self .assertAlmostEqual (
464- loop_workplane .wires (selectors .RadiusNthSelector (0 )).val ().radius (), 1.0
465- )
466- self .assertAlmostEqual (
467- loop_workplane .wires (selectors .RadiusNthSelector (1 )).val ().radius (), 2.0
468- )
469- with self .assertRaises (IndexError ):
470- loop_workplane .wires (selectors .RadiusNthSelector (2 ))
471-
472514 def testAndSelector (self ):
473515 c = CQ (makeUnitCube ())
474516
0 commit comments