/ nc_files / ngcgui_lib / qpocket.ngc
qpocket.ngc
  1  (info: Quadrilateral pocketing using cutter radius compensation)
  2  
  3  ; Use with care, test in simulator first.
  4  
  5  ; Notes:
  6  ;   Defaults herein are inch based
  7  ;   Uses tool diameter from tool table for cutter radius compensation
  8  ;   Supports conventional or climb milling
  9  ;   Ramps to depth for each z increment
 10  ;   Mirror about x axis for negative scale
 11  
 12  ;   too small diameter tools and/or small stepovers may exceed outlinepasslimit
 13  ;   too large diameter tools may case gouging errors
 14  
 15  ; Works for most rectangles and parallelograms but may require some care
 16  ; for specifying:
 17  ;      point ordering (see entry move notes below)
 18  ;      tool diameter (in tool table)
 19  ;      stepover
 20  
 21  ; Entry moves:
 22  ;   Input point ordering  Requested Direction       Entry line
 23  ;   --------------------  ------------------------  ------------------
 24  ;   1234 == CW            2 == CW  == Conventional  point1 --> point2
 25  ;   1234 == CW            3 == CCW == Climb         point1 --> point4
 26  
 27  ;   1234 == CCW           2 == CW  == Conventional  point1 --> point4
 28  ;   1234 == CCW           3 == CCW == Climb         point1 --> point2
 29  
 30  ; To accomodate the widest range of tool diameters, order the point sequence
 31  ; (1234) so that the entry move is not directed towards an acute angle.
 32  
 33  ; Scaling, rotations, and offsets are supported.
 34  ;   Scaling is applied first.
 35  ;   Rotation is then applied (with respect to origin). It is often simplest
 36  ;   to specify the feature so that it is centered at the origin.
 37  ;   Offsets are applied last.
 38  
 39  ;----------------------------------------------------------------------
 40  ; Copyright: 2012,2014
 41  ; Author:    Dewey Garrett <dgarrett@panix.com>
 42  ;
 43  ; This program is free software; you can redistribute it and/or modify
 44  ; it under the terms of the GNU General Public License as published by
 45  ; the Free Software Foundation; either version 2 of the License, or
 46  ; (at your option) any later version.
 47  ;
 48  ; This program is distributed in the hope that it will be useful,
 49  ; but WITHOUT ANY WARRANTY; without even the implied warranty of
 50  ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 51  ; GNU General Public License for more details.
 52  ;
 53  ; You should have received a copy of the GNU General Public License
 54  ; along with this program; if not, write to the Free Software
 55  ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 56  ;----------------------------------------------------------------------
 57  
 58  o<qpocket>  sub
 59  
 60       #<toolno> =  #1 (=1)
 61          #<rpm> =  #2 (=1000)
 62          #<dir> =  #3 (=2 2conv|3climb) ; conventional=cw, climb=ccw
 63     #<feedrate> =  #4 (=10)
 64     #<cutdepth> =  #5 (=0.1)
 65        #<zincr> =  #6 (=0.02)
 66        #<zsafe> =  #7 (=0.2)
 67       #<zstart> =  #8 (=0)
 68  
 69           #<x1> =  #9
 70           #<y1> = #10
 71           #<x2> = #11
 72           #<y2> = #12
 73           #<x3> = #13
 74           #<y3> = #14
 75           #<x4> = #15
 76           #<y4> = #16
 77  
 78        #<scale> = #17 (=1)     ; use neg value for mirroring
 79       #<rotate> = #18 (=0)     ; angle in degrees
 80         #<xoff> = #19 (=0)
 81         #<yoff> = #20 (=0)
 82     #<stepover> = #21 (=0.5)   ; tooldiameter fraction
 83       #<g64tol> = #22 (=0.002)
 84  #<spin_notify> = #23 (=1)     ; 1 == prompt user
 85      #<use_g43> = #24 (=1)
 86    #<h_for_g43> = #25 (=0)
 87      #<verbose> = #26 (=0)
 88  
 89    #<depthpasslimit> = 100    ; outer loop
 90  #<outlinepasslimit> = 100    ; inner loop
 91            #<tdelta> = 0.01  ; small increment to tool diameter
 92          #<cutdepth> = [0 - #<cutdepth>]
 93             #<zincr> = [0 - #<zincr>]
 94  
 95  g40             ; make sure cutter radius compensation off at start
 96  g64 p #<g64tol> ; path tolerance
 97  
 98  o<if10> if [#<scale> EQ 0]
 99            (print, qpocket: zero scale #<scale> - EXITING)
100            (debug, qpocket: zero scale #<scale> - EXITING)
101            (AXIS,notify, qpocket: zero scale - EXITING)
102            m2
103  o<if10> endif
104  
105  o<if11> if [#<scale> LT 0]
106            (print, qpocket: MIRROR about x axis for negative scale #<scale>)
107            (debug, qpocket: MIRROR about x axis for negative scale #<scale>)
108            (AXIS,notify, qpocket: MIRROR about x axis for negative scale)
109  o<if11> endif
110          #<x1>    = [#<scale> * #<x1>]
111          #<x2>    = [#<scale> * #<x2>]
112          #<x3>    = [#<scale> * #<x3>]
113          #<x4>    = [#<scale> * #<x4>]
114  
115          #<scale> = [ABS[#<scale>]]
116          #<y1>    = [#<scale> * #<y1>]
117          #<y2>    = [#<scale> * #<y2>]
118          #<y3>    = [#<scale> * #<y3>]
119          #<y4>    = [#<scale> * #<y4>]
120  
121          #<scale> = 1
122  
123  o<if20> if [[#<stepover> GT 1] OR [#<stepover> LE 0]]
124            (print, qpocket: invalid stepover=#<stepover> - EXITING)
125            (debug, qpocket: invalid stepover=#<stepover> - EXITING)
126            (AXIS,notify, qpocket: invalid stepover - EXITING)
127            m2
128  o<if20> endif
129  
130  o<if30> if [[#<dir> NE 2] AND [#<dir> NE 3]]
131            (print, qpocket:bad dir=#<dir> - EXITING)
132            (debug, qpocket:bad dir=#<dir> - EXITING)
133            (AXIS,notify, qpocket:bad dir - EXITING)
134            m2
135  o<if30> endif
136  
137            ;compute direction eg 2==cw,3==ccw for points as ordered:
138  o<dir>    call [4][#<x1>][#<y1>][#<x2>][#<y2>][#<x3>][#<y3>][#<x4>][#<y4>]
139            #<pointsdir> = #<_dir:> ; direction of input points 2==cw
140            #<xctr> = #<_dir:cx>    ; centroid
141            #<yctr> = #<_dir:cy>    ; centroid
142  
143  o<ifdir1> if [#<pointsdir> LE 0]
144              ; failed to get direction -- pathological case
145              (print, failed to compute direction - EXITING)
146              (debug, failed to compute direction - EXITING)
147              (AXIS,notify, failed to compute direction - EXITING)
148              m2
149  o<ifdir1> endif
150  
151  ; Get data for x,y points
152  #<npoints> = 4
153  o<pointsdata> call [#<npoints>] [#<x1>][#<x2>][#<x3>][#<x4>]
154    #<xc> = #<_pointsdata:ctr>
155  #<xmin> = [#<_pointsdata:min> - #<xctr>]
156  #<xmax> = [#<_pointsdata:max> - #<xctr>]
157  o<pointsdata> call [#<npoints>] [#<y1>][#<y2>][#<y3>][#<y4>]
158    #<yc> = #<_pointsdata:ctr>
159  #<ymin> = [#<_pointsdata:min> - #<yctr>]
160  #<ymax> = [#<_pointsdata:max> - #<yctr>]
161  
162  ; Respecify input points about the x,y centroid
163  o<ifv0>   if [#<verbose> GT 0]
164              (debug, centroid: #<xctr> #<yctr>)
165  o<ifv0>   endif
166  
167    #<x1> = [#<x1> - #<xctr>]
168    #<x2> = [#<x2> - #<xctr>]
169    #<x3> = [#<x3> - #<xctr>]
170    #<x4> = [#<x4> - #<xctr>]
171  
172    #<y1> = [#<y1> - #<yctr>]
173    #<y2> = [#<y2> - #<yctr>]
174    #<y3> = [#<y3> - #<yctr>]
175    #<y4> = [#<y4> - #<yctr>]
176  
177  ; make order of points agree with input direction request
178  o<if40> if [#<pointsdir> NE #<dir>]
179  o<ifv1>   if [#<verbose> GT 0]
180              (debug, reversing input point sequence: 1-4-3-2)
181  o<ifv1>   endif
182            ; swap points ordering: 1234 --> 1432
183            #<xt> = #<x2>
184            #<yt> = #<y2>
185            #<x2> = #<x4>
186            #<y2> = #<y4>
187            #<x4> = #<xt>
188            #<y4> = #<yt>
189  o<if40> endif
190  
191  ; determine min size for first outline pass
192  o<if50> if [[#<xmax>-#<xmin>] GT [#<ymax>-#<ymin>]]
193             #<minor> = [ABS[#<ymax>-#<ymin>]/2]
194  o<if50> else
195             #<minor> = [ABS[#<xmax>-#<xmin>]/2]
196  o<if50> endif
197  
198  ; load tool and establish scaling for first outline pass
199  o<loadtool> call [#<toolno>][#<use_g43>][#<h_for_g43>][#<verbose>]
200       #<thetooldiam> = #5410
201          #<tooldiam> = [#5410 + #<tdelta>]
202                 #<r> = [#<tooldiam> / 2]
203             #<sizei> = [#<tooldiam> / #<minor>]
204           #<qscalei> = [#<scale> * #<sizei>]
205  
206  o<ifsc> if [#<qscalei> GE #<scale>]
207            (print, qpocket: tooldiam is too big #<thetooldiam> - EXITING)
208            (debug, qpocket: tooldiam is too big #<thetooldiam> - EXITING)
209            (AXIS,notify, qpocket: tooldiam is too big - EXITING)
210            m2
211  o<ifsc> endif
212  
213  ; scale the centered feature and translate to original position
214  o<move> call [#<x1>][#<y1>][0][#<qscalei>][#<xctr>][#<yctr>]
215          #<x1i> = #<_move:x>
216          #<y1i> = #<_move:y>
217  o<move> call [#<x2>][#<y2>][0][#<qscalei>][#<xctr>][#<yctr>]
218          #<x2i> = #<_move:x>
219          #<y2i> = #<_move:y>
220  o<move> call [#<x3>][#<y3>][0][#<qscalei>][#<xctr>][#<yctr>]
221          #<x3i> = #<_move:x>
222          #<y3i> = #<_move:y>
223  o<move> call [#<x4>][#<y4>][0][#<qscalei>][#<xctr>][#<yctr>]
224          #<x4i> = #<_move:x>
225          #<y4i> = #<_move:y>
226  ; xni,yni are the initial points at the smallest scaling
227  
228  ; apply input rotation and offset
229  o<move> call [#<x1i>][#<y1i>][#<rotate>][1][#<xoff>][#<yoff>]
230          #<x1i> = #<_move:x>
231          #<y1i> = #<_move:y>
232  o<move> call [#<x2i>][#<y2i>][#<rotate>][1][#<xoff>][#<yoff>]
233          #<x2i> = #<_move:x>
234          #<y2i> = #<_move:y>
235  o<move> call [#<x3i>][#<y3i>][#<rotate>][1][#<xoff>][#<yoff>]
236          #<x3i> = #<_move:x>
237          #<y3i> = #<_move:y>
238  o<move> call [#<x4i>][#<y4i>][#<rotate>][1][#<xoff>][#<yoff>]
239          #<x4i> = #<_move:x>
240          #<y4i> = #<_move:y>
241  
242           ;get angles for connecting lines
243  o<line>  call [#<x1i>][#<y1i>][#<x2i>][#<y2i>]
244           #<cos12> = #<_line:cos>
245           #<sin12> = #<_line:sin>
246  o<line>  call [#<x2i>][#<y2i>][#<x3i>][#<y3i>]
247           #<cos23> = #<_line:cos>
248           #<sin23> = #<_line:sin>
249  o<line>  call [#<x3i>][#<y3i>][#<x4i>][#<y4i>]
250           #<cos34> = #<_line:cos>
251           #<sin34> = #<_line:sin>
252  o<line>  call [#<x4i>][#<y4i>][#<x1i>][#<y1i>]
253           #<cos41> = #<_line:cos>
254           #<sin41> = #<_line:sin>
255  
256           ;compute angles at line interesctions:
257  o<dot>   call [#<x1i>][#<y1i>][#<x2i>][#<y2i>][#<x3i>][#<y3i>]
258           #<ang123> = #<_dot:ang>
259  o<dot>   call [#<x2i>][#<y2i>][#<x3i>][#<y3i>][#<x4i>][#<y4i>]
260           #<ang234> = #<_dot:ang>
261  o<dot>   call [#<x3i>][#<y3i>][#<x4i>][#<y4i>][#<x1i>][#<y1i>]
262           #<ang341> = #<_dot:ang>
263  o<dot>   call [#<x4i>][#<y4i>][#<x1i>][#<y1i>][#<x2i>][#<y2i>]
264           #<ang412> = #<_dot:ang>
265  
266           f #<feedrate>
267           s #<rpm> m3 ;spindle cw
268  o<if60>  if [#<spin_notify> GT 0]
269  o<spin>    call [#<rpm>] ; optionally prompt user
270  o<if60>  endif
271           g0 z#<zsafe>
272  
273           ; depth loop (outer)
274           #<zcurrent>  = #<zstart>
275           #<depthpass> = 1
276  o<wh10>  while [#<zcurrent> GT #<cutdepth>]
277             #<zlast>    = #<zcurrent>
278             #<zcurrent> = [#<zcurrent> + #<zincr>]
279  o<wh11>    if [#<zcurrent> LT #<cutdepth>]
280               #<zcurrent> = #<cutdepth>
281  o<wh11>    endif
282  o<wh12>    if [#<depthpass> GT #<depthpasslimit>]
283               (print, qpocket: depthpasslimit exceeded #<depthpasslimit> - EXITING)
284               (debug, qpocket: depthpasslimit exceeded #<depthpasslimit> - EXITING)
285               (AXIS,notify, qpocket: depthpasslimit exceeded - EXITING)
286               m2
287  o<wh12>    endif
288  
289  o<pas1>    if [#<depthpass> EQ 1]
290               ;entry point:
291               ;go along the 1-->2 line to enter at a point where tool will fit
292  
293               #<elen12>  = [     #<r> / [TAN[#<ang412>/2]]]
294               #<k12>     = [#<elen12> / #<r>]
295               ;(print, entry 12 k=#<k12> elen12=#<elen12> angle=#<angle>)
296               #<xentry>      = [#<x1i> + #<elen12> * #<cos12>]
297               #<yentry>      = [#<y1i> + #<elen12> * #<sin12>]
298               ;compute pre-entry points:
299  o<dir00>     if [#<dir> EQ 2] ; dir EQ 2 CW (conventional)
300                 #<prex2>  = [#<xentry> + #<r> * #<sin12> - #<r> * #<cos12>]
301                 #<prey2>  = [#<yentry> - #<r> * #<cos12> - #<r> * #<sin12>]
302                 #<prex1>  = [#<prex2>  + #<r> * #<cos12>]
303                 #<prey1>  = [#<prey2>  + #<r> * #<sin12>]
304                 #<vx>     = [            #<r> * #<cos12>]
305                 #<vy>     = [            #<r> * #<sin12>]
306  o<dir00>     else ;dir EQ 3 CCW (climb)
307                 #<prex2>  = [#<xentry> - #<r> * #<sin12> - #<r> * #<cos12>]
308                 #<prey2>  = [#<yentry> + #<r> * #<cos12> - #<r> * #<sin12>]
309                 #<prex1>  = [#<prex2>  + #<r> * #<cos12>]
310                 #<prey1>  = [#<prey2>  + #<r> * #<sin12>]
311                 #<vx>     = [            #<r> * #<cos12>]
312                 #<vy>     = [            #<r> * #<sin12>]
313  o<dir00>     endif
314               g0  x #<prex1> y #<prey1> ;preentry 1
315               g0  x #<prex2> y #<prey2> ;preentry 2
316  o<dir10>     if [#<dir> EQ 2] ; CW
317  /              g42 ;cutter radius comp right of path
318                 g2  x #<xentry> y #<yentry> i #<vx> j #<vy> ;arc entry
319  o<dir10>     else ;dir EQ 3 CCW
320  /              g41 ;cutter radius comp left of path
321                 g3  x #<xentry> y #<yentry> i #<vx> j #<vy> ;arc entry
322  o<dir10>     endif
323               g1 z #<zstart> ;plunge to start height from zsafe
324  o<pas1>    else
325               ; depthpass GT 1: return to interior entry point
326               g1 x #<xentry> y #<yentry> z#<zlast> ; use zlast
327  o<pas1>    endif
328  
329             ; outline loop (inner)
330             #<outlinepass> = 1
331             #<qscale>      = #<qscalei>
332             #<size>        = #<sizei>
333  o<wh20>    do
334  o<wh22>      if [#<outlinepass> GT #<outlinepasslimit>]
335                 (print, qpocket: outlinepasslimit exceeded #<outlinepasslimit> - EXITING)
336                 (debug, qpocket: outlinepasslimit exceeded #<outlinepasslimit> - EXITING)
337                 (AXIS,notify,qpocket: outlinepasslimit exceeded - EXITING)
338                 m2
339  o<wh22>      endif
340  
341               #<seq> = [#<outlinepass> mod 4]
342  o<wh23>      if [#<outlinepass> EQ 1]
343                 ; move through smallest interior outline
344  
345  o<ramp1>     if [#<seq> EQ 1]
346                 g1 x #<x2i> y #<y2i> z#<zcurrent> ;ramp down to zcurrent
347                 g1 x #<x3i> y #<y3i>
348                 g1 x #<x4i> y #<y4i>
349                 g1 x #<x1i> y #<y1i>
350                 g1 x #<x2i> y #<y2i>
351  o<ramp1>     endif
352  o<ramp2>     if [#<seq> EQ 2]
353                 g1 x #<x3i> y #<y3i> z#<zcurrent> ;ramp down to zcurrent
354                 g1 x #<x4i> y #<y4i>
355                 g1 x #<x1i> y #<y1i>
356                 g1 x #<x2i> y #<y2i>
357                 g1 x #<x3i> y #<y3i>
358  o<ramp2>     endif
359  o<ramp3>     if [#<seq> EQ 3]
360                 g1 x #<x4i> y #<y4i> z#<zcurrent> ;ramp down to zcurrent
361                 g1 x #<x1i> y #<y1i>
362                 g1 x #<x2i> y #<y2i>
363                 g1 x #<x3i> y #<y3i>
364                 g1 x #<x4i> y #<y4i>
365  o<ramp3>     endif
366  o<ramp0>     if [#<seq> EQ 0]
367                 g1 x #<x1i> y #<y1i> z#<zcurrent> ;ramp down to zcurrent
368                 g1 x #<x2i> y #<y2i>
369                 g1 x #<x3i> y #<y3i>
370                 g1 x #<x4i> y #<y4i>
371                 g1 x #<x1i> y #<y1i>
372  o<ramp0>     endif
373  
374                 #<outlinepass> = [#<outlinepass> + 1]
375  o<wh23>      else
376                 ; increasingly larger outlines
377                 #<size>        = [#<size> + #<stepover> * #<sizei>]
378                 #<qscale>      = [#<scale> * #<size>]
379                 #<outlinepass> = [#<outlinepass> + 1]
380  o<wh24>        if [#<qscale> GE #<scale>]
381                   #<qscale> = #<scale>
382                   #<outlinepass> = 0 ;terminate after this pass
383  o<wh24>        endif
384                 ; scale the centered feature and translate to original position
385                 o<move> call [#<x1>][#<y1>][0][#<qscale>][#<xctr>][#<yctr>]
386                 #<x1t>  = #<_move:x>
387                 #<y1t>  = #<_move:y>
388                 o<move> call [#<x2>][#<y2>][0][#<qscale>][#<xctr>][#<yctr>]
389                 #<x2t>  = #<_move:x>
390                 #<y2t>  = #<_move:y>
391                 o<move> call [#<x3>][#<y3>][0][#<qscale>][#<xctr>][#<yctr>]
392                 #<x3t>  = #<_move:x>
393                 #<y3t>  = #<_move:y>
394                 o<move> call [#<x4>][#<y4>][0][#<qscale>][#<xctr>][#<yctr>]
395                 #<x4t>  = #<_move:x>
396                 #<y4t>  = #<_move:y>
397  
398                 ; apply input rotation and offset
399                 o<move> call [#<x1t>][#<y1t>][#<rotate>][1][#<xoff>][#<yoff>]
400                 #<x1s>  = #<_move:x>
401                 #<y1s>  = #<_move:y>
402                 o<move> call [#<x2t>][#<y2t>][#<rotate>][1][#<xoff>][#<yoff>]
403                 #<x2s>  = #<_move:x>
404                 #<y2s>  = #<_move:y>
405                 o<move> call [#<x3t>][#<y3t>][#<rotate>][1][#<xoff>][#<yoff>]
406                 #<x3s>  = #<_move:x>
407                 #<y3s>  = #<_move:y>
408                 o<move> call [#<x4t>][#<y4t>][#<rotate>][1][#<xoff>][#<yoff>]
409                 #<x4s>  = #<_move:x>
410                 #<y4s>  = #<_move:y>
411  
412                 ; move through scaled interior outline
413  o<seq0>        if [#<seq> EQ 0]
414                   g1 x #<x1s> y #<y1s> z #<zcurrent>
415                      x #<x2s> y #<y2s>
416                      x #<x3s> y #<y3s>
417                      x #<x4s> y #<y4s>
418                      x #<x1s> y #<y1s>
419  o<seq0>        endif
420  o<seq1>        if [#<seq> EQ 1]
421                   g1 x #<x2s> y #<y2s> z #<zcurrent>
422                      x #<x3s> y #<y3s>
423                      x #<x4s> y #<y4s>
424                      x #<x1s> y #<y1s>
425                      x #<x2s> y #<y2s>
426  o<seq1>        endif
427  o<seq2>        if [#<seq> EQ 2]
428                   g1 x #<x3s> y #<y3s> z #<zcurrent>
429                      x #<x4s> y #<y4s>
430                      x #<x1s> y #<y1s>
431                      x #<x2s> y #<y2s>
432                      x #<x3s> y #<y3s>
433  o<seq2>        endif
434  o<seq3>        if [#<seq> EQ 3]
435                   g1 x #<x4s> y #<y4s> z #<zcurrent>
436                      x #<x1s> y #<y1s>
437                      x #<x2s> y #<y2s>
438                      x #<x3s> y #<y3s>
439                      x #<x4s> y #<y4s>
440  o<seq3>        endif
441  
442  o<wh23>      endif
443  
444  o<wh20>    while [#<outlinepass> GT 0]
445             #<depthpass> = [#<depthpass> + 1]
446  o<wh10>  endwhile
447  
448           ; after finishing at input scale, need to turn corner
449           ; and go along the next line enough to turn off compensation
450  o<fin0>  if [#<seq> EQ 0] ;end at pt 1
451             #<xfinal_a> = #<x1s>
452             #<yfinal_a> = #<y1s>
453             #<elen12>   = [#<r> / [TAN[#<ang412>/2]]]
454             #<xfinal_b> = [#<x1s> + #<elen12> * #<cos12>]
455             #<yfinal_b> = [#<y1s> + #<elen12> * #<sin12>]
456  o<fin0>  endif
457  o<fin1>  if [#<seq> EQ 1] ;end at pt 2
458             #<xfinal_a> = #<x2s>
459             #<yfinal_a> = #<y2s>
460             #<elen23>   = [#<r> / [TAN[#<ang123>/2]]]
461             #<xfinal_b> = [#<x2s> + #<elen23> * #<cos23>]
462             #<yfinal_b> = [#<y2s> + #<elen23> * #<sin23>]
463  o<fin1>  endif
464  o<fin2>  if [#<seq> EQ 2] ;end at pt 3
465             #<xfinal_a> = #<x3s>
466             #<yfinal_a> = #<y3s>
467             #<elen34>   = [#<r> / [TAN[#<ang234>/2]]]
468             #<xfinal_b> = [#<x3s> + #<elen34> * #<cos34>]
469             #<yfinal_b> = [#<y3s> + #<elen34> * #<sin34>]
470  o<fin2>  endif
471  o<fin3>  if [#<seq> EQ 3] ;end at pt 4
472             #<xfinal_a> = #<x4s>
473             #<yfinal_a> = #<y4s>
474             #<elen41>   = [#<r> / [TAN[#<ang341>/2]]]
475             #<xfinal_b> = [#<x4s> + #<elen41> * #<cos41>]
476             #<yfinal_b> = [#<y4s> + #<elen41> * #<sin41>]
477  o<fin3>  endif
478  
479           g1 x #<xfinal_a> y #<yfinal_a>
480           g1 x #<xfinal_b> y #<yfinal_b>
481  
482           g0 z #<zsafe>
483           g40 ;cutter radius compensation off
484  
485  o<qpocket> endsub