Jump to content

While Loop not exiting cleanly.


roveachine

Recommended Posts

Hi All 

 

Pretty new to AutoLISP and never posted on a forum before so bear with me.

 

I've written a lisp routine that creates a bunch of layers and then goes on to use these in other parts of the routine. the whole thing uses a list that contains various data and then runs through that list creating the layer .

I've chosen to do it this way so the list can be dynamic and its easier to change alter or add to the list further down the line. 

My issue is that when it runs through the list using a while loop it doesn't finish up cleanly and this creates issues with the rest of the routine, I have searched and cant seem to find anything specific to my issue. 

 

How can I exit the while loop cleanly when it receives a NIL entry?

 

I'm trying to do this without using VLISP or ideally not putting it into an if statement but that might be the only option. 

 

code is: 

 

 (setq listindex 0)
    (setq layerlist1 (list 
    '(0 "CNC 00 - Panel Outline - No Rout" 252 0.25)
    '(1 "CNC 01 - Engraving 45 deg - Depth 0.5" 7 0.25)
    '(2 "CNC 02 - Outside Rout" 30 0.25)
    '(3 "CNC 03 - Diam 4.0mm - Depth Through" 1 2.0)
    '(4 "CNC 03 - Diam 7.0mm - Depth Through" 1 3.5)
    '(5 "CNC 03 - Diam 8.2mm - Depth Through" 1 4.05)
    '(6 "CNC 03 - Through Rout Inside Correction" 1 0.25)
    '(7 "CNC 04 - Diam 2.0mm - Depth 0.5mm" 2 0.75)
    '(8 "CNC 04 - Diam 2.0mm - Depth 10mm" 2 1.0)
    '(9 "CNC 04 - Diam 5.0mm - Depth 10.0mm" 2 2.5)
    '(10 "CNC 04 - Diam 10.0mm - Depth 13.0mm" 2 5.0)
    '(11 "CNC 04 - Diam 15.0mm - Depth 14.5mm" 2 7.5)
    '(12 "CNC 04 - Diam 35.0mm - Depth 13.5mm" 2 17.5)
    '(13 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 6 3.75)
    '(14 "CNC 09 - Diam 8.2mm - Depth 10.0mm" 161 4.1)
    '(15 "CNC 10 - Diam 8.2mm - Depth 2.0mm" 13 4.15)
    '(16 "CNC 05 - Pocket - Diam 12.0mm - Depth 6.0mm" 4 0.25)
    '(17 "CNC 06 - Scribe - Diam 12.0mm - Depth LPZ - 9" 100 0.25)
    '(18 "CNC 07 - Pocket - Diam 12.0mm - Depth Custom" 241 0.25)
    '(19 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 7 3.75)
    '(20 "SET MANUALLY - CHECK" 221 0.25)
    '(21 "CRUMBLING - Diam 12.0mm - Depth LPZ - 0.5mm" 2 0.25)
    '(22 "no layer" 7 0.25)
                  ) ; end list
    ) ; end setq layerlist1
(setq LayerList2 (length layerlist1))    
  (setq LayerNme1(nth 1(assoc listindex layerlist1)))
  (setq CNClay1(nth 1(assoc listindex layerlist1)))
  (setq laycolour1 (nth 2(assoc listindex layerList1)))
  (setq circRAD1 (nth 3(assoc listindex layerList1)))
    (while (<= listindex LayerList2) ;enter while here can make this dynamic im sure maybe link to length of layerlist1 var
                (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1) '(70 . 0) ( cons 62 laycolour1)))
                (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
                    (prompt (strcat "\nCNC Layer created " CNClay1))
                    (setq listindex (1+ listindex))
                (setq LayerNme1(nth 1(assoc listindex layerlist1)))
                (setq CNCLay1(nth 1(assoc listindex layerlist1)))
                (setq laycolour1 (nth 2(assoc listindex layerlist1)))
                (setq circRAD1 (nth 3(assoc listindex layerList1)))
    ); end while

 

 

Thanks in advance 

Edited by SLW210
Added Code Tags!
Link to comment
Share on other sites

Hi roveachine, welcome in the forum!

At a first glance, I would say that you expect the first item in a list to be the no 1. But you should use (nth 0 layerlist1) to get the first element, not (nth 1...)

So this will prevent to generate the first layer. But this also will give you an error at the other end. If there are layerlist2 items in the layerlist1, then you can get the last one using (nth (1- layerlist2) layerlist1). The expression (nth layerlist2 layerlist1) will target after the end of the list.

I can't run lisps right now -but I think that that will solve your issue...

Link to comment
Share on other sites

As a general thing I would look at which values could give a nil result and force the end of the while loop if they are

 

for example:

(if (= <result> nil)

  set endloop marker

  continue

)

 

maybe something like this:

 

  (while (<= listindex LayerList2) ;enter while here can make this dynamic im sure maybe link to length of layerlist1 var
    (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1) '(70 . 0) ( cons 62 laycolour1)))
    (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
    (prompt (strcat "\nCNC Layer created " CNClay1))
    (setq listindex (1+ listindex))
(if ( = (setq LayerNme1 (nth 1 (assoc listindex layerlist1))) nil)
(progn
(setq listindex LayerList2) ; set while loop counter to ending value
) ; end progn
(progn
    (setq CNCLay1 (nth 1 (assoc listindex layerlist1)))
    (setq laycolour1 (nth 2 (assoc listindex layerlist1)))
    (setq circRAD1 (nth 3 (assoc listindex layerList1)))
) ; end progn
) ; end if
  ); end while

 

Link to comment
Share on other sites

Thanks for both of your replies.

 

I think I may have explained myself incorrectly.

 

I'm telling the while loop to carry on until list index and layerlist2 (23) are equal to each other and then I want it to finish looping through.

 

My understanding is that when a While loop receives a NIL it will exit, this does seem to be working but it returns an error and then stops the rest of the routine from working. 

 

Steven P I did try your code but couldn't get it to work so maybe I'm inserting it into the wrong place?

 

fucarro, thanks for forcing me to look at the code in more detail i had identified a few errors but even then it didn't seem to help with exiting the while loop. 

 

 

 

Link to comment
Share on other sites

My reply earlier was suggesting how to end a loop early by setting the counter value to the end loop value.

 

In your command line you have set a handy prompt of all the layers the LISP is creating, and in this case I think the last comment you should see when it runs is:

 

CNC Layer created no layer; error: bad argument type: consp nil

 

... so your loop is working until at least (setq listindex (1+ listindex)) - the line before, prompt works

 

You can use that as a subtle hint and fix the code with that, noting of course that if you have a list of 22 items and you try to return the 23rd item you will get an error..... A while loop will continue to the end and stop at the start of the next loop if the condition is met, I prefer to increment the counter as the last line in the loop.

 

 

This should fix it

 

(defun c:test ( / listindex layerlist1 LayerList2 LayerNme1 CNClay1 laycolour1 circRAD1)

  (setq listindex 0)
  (setq layerlist1 (list
      '(0 "CNC 00 - Panel Outline - No Rout" 252 0.25)
      '(1 "CNC 01 - Engraving 45 deg - Depth 0.5" 7 0.25)
      '(2 "CNC 02 - Outside Rout" 30 0.25)
      '(3 "CNC 03 - Diam 4.0mm - Depth Through" 1 2.0)
      '(4 "CNC 03 - Diam 7.0mm - Depth Through" 1 3.5)
      '(5 "CNC 03 - Diam 8.2mm - Depth Through" 1 4.05)
      '(6 "CNC 03 - Through Rout Inside Correction" 1 0.25)
      '(7 "CNC 04 - Diam 2.0mm - Depth 0.5mm" 2 0.75)
      '(8 "CNC 04 - Diam 2.0mm - Depth 10mm" 2 1.0)
      '(9 "CNC 04 - Diam 5.0mm - Depth 10.0mm" 2 2.5)
      '(10 "CNC 04 - Diam 10.0mm - Depth 13.0mm" 2 5.0)
      '(11 "CNC 04 - Diam 15.0mm - Depth 14.5mm" 2 7.5)
      '(12 "CNC 04 - Diam 35.0mm - Depth 13.5mm" 2 17.5)
      '(13 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 6 3.75)
      '(14 "CNC 09 - Diam 8.2mm - Depth 10.0mm" 161 4.1)
      '(15 "CNC 10 - Diam 8.2mm - Depth 2.0mm" 13 4.15)
      '(16 "CNC 05 - Pocket - Diam 12.0mm - Depth 6.0mm" 4 0.25)
      '(17 "CNC 06 - Scribe - Diam 12.0mm - Depth LPZ - 9" 100 0.25)
      '(18 "CNC 07 - Pocket - Diam 12.0mm - Depth Custom" 241 0.25)
      '(19 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 7 3.75)
      '(20 "SET MANUALLY - CHECK" 221 0.25)
      '(21 "CRUMBLING - Diam 12.0mm - Depth LPZ - 0.5mm" 2 0.25)
      '(22 "no layer" 7 0.25)
    ) ; end list
  ) ; end setq layerlist1
  (setq LayerList2 (length layerlist1))    
  (setq LayerNme1(nth 1(assoc listindex layerlist1)))
  (setq CNClay1(nth 1(assoc listindex layerlist1)))
  (setq laycolour1 (nth 2(assoc listindex layerList1)))
  (setq circRAD1 (nth 3(assoc listindex layerList1)))
    (while (<= listindex LayerList2) ;enter while here can make this dynamic im sure maybe link to length of layerlist1 var
      (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1) '(70 . 0) ( cons 62 laycolour1)))
      (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
      (prompt (strcat "\nCNC Layer created " CNClay1))
      (setq listindex (1+ listindex))
(if (< (+ listindex 1) (length layerlist1)) ;; If listindex is less than the list length, note +1 since index starts at 0
  (progn
          (setq LayerNme1 (nth 1 (assoc listindex layerlist1)))
          (setq CNCLay1 (nth 1 (assoc listindex layerlist1)))
          (setq laycolour1 (nth 2 (assoc listindex layerlist1)))
          (setq circRAD1 (nth 3 (assoc listindex layerList1)))
)) ; end if, end progn
    ); end while

  (princ)
)

 

Edited by Steven P
Link to comment
Share on other sites

but.... I think you have the while loop back to front and this might be better. It might not be better. Fewer lines, and removed the need for the error check above.

 

(defun c:test ( / listindex layerlist1 LayerList2 LayerNme1 CNClay1 laycolour1 circRAD1)

  (setq layerlist1 (list
      '(0 "CNC 00 - Panel Outline - No Rout" 252 0.25)
      '(1 "CNC 01 - Engraving 45 deg - Depth 0.5" 7 0.25)
      '(2 "CNC 02 - Outside Rout" 30 0.25)
      '(3 "CNC 03 - Diam 4.0mm - Depth Through" 1 2.0)
      '(4 "CNC 03 - Diam 7.0mm - Depth Through" 1 3.5)
      '(5 "CNC 03 - Diam 8.2mm - Depth Through" 1 4.05)
      '(6 "CNC 03 - Through Rout Inside Correction" 1 0.25)
      '(7 "CNC 04 - Diam 2.0mm - Depth 0.5mm" 2 0.75)
      '(8 "CNC 04 - Diam 2.0mm - Depth 10mm" 2 1.0)
      '(9 "CNC 04 - Diam 5.0mm - Depth 10.0mm" 2 2.5)
      '(10 "CNC 04 - Diam 10.0mm - Depth 13.0mm" 2 5.0)
      '(11 "CNC 04 - Diam 15.0mm - Depth 14.5mm" 2 7.5)
      '(12 "CNC 04 - Diam 35.0mm - Depth 13.5mm" 2 17.5)
      '(13 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 6 3.75)
      '(14 "CNC 09 - Diam 8.2mm - Depth 10.0mm" 161 4.1)
      '(15 "CNC 10 - Diam 8.2mm - Depth 2.0mm" 13 4.15)
      '(16 "CNC 05 - Pocket - Diam 12.0mm - Depth 6.0mm" 4 0.25)
      '(17 "CNC 06 - Scribe - Diam 12.0mm - Depth LPZ - 9" 100 0.25)
      '(18 "CNC 07 - Pocket - Diam 12.0mm - Depth Custom" 241 0.25)
      '(19 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 7 3.75)
      '(20 "SET MANUALLY - CHECK" 221 0.25)
      '(21 "CRUMBLING - Diam 12.0mm - Depth LPZ - 0.5mm" 2 0.25)
      '(22 "no layer" 7 0.25)
    ) ; end list
  ) ; end setq layerlist1

;;  (setq LayerList2 (length layerlist1))                ;; This is in the while command
;;  (setq LayerNme1(nth 1(assoc listindex layerlist1)))  ;; this is in the while loop
;;  (setq CNClay1(nth 1(assoc listindex layerlist1)))    ;; this is in the while loop
;;  (setq laycolour1 (nth 2(assoc listindex layerList1)));; this is in the while loop
;;  (setq circRAD1 (nth 3(assoc listindex layerList1)))  ;; this is in the while loop
  (setq listindex 0)
  (while (< listindex (length layerlist1))
    (setq LayerNme1  (nth 1 (assoc listindex layerlist1))) ;;DO YOU NEED THIS? IT IS THE SAME AS LINE BELOW
    (setq CNCLay1    (nth 1 (assoc listindex layerlist1)))
    (setq laycolour1 (nth 2 (assoc listindex layerlist1)))
    (setq circRAD1   (nth 3 (assoc listindex layerList1)))
    (entmake (list 
      '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord")
      '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1)
      '(70 . 0) ( cons 62 laycolour1)
    )) ; end entmake (split it like this so it doesn't run over lines, just my OCD.....)
    (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
    (prompt (strcat "\nCNC Layer created " CNClay1))
    (setq listindex (+ listindex 1))
  ); end while
  (princ)
)

 

Edited by Steven P
Link to comment
Share on other sites

@Steven P you hit the nail on the head with your second response I knew that was the issue just didn't know how to verbalise it so thanks. 

 

both your first and second bits of code works perfectly, although like you I prefer the second option its so much neater. 

 

in the below you mention the +1 on the listindex. I'm confused with this, when I run the parts individually in AutoCAD both of the layerlist1 and listindex end up at the same number (23) so why start with +1 on the list index? 

 

16 hours ago, Steven P said:
(defun c:test ( / listindex layerlist1 LayerList2 LayerNme1 CNClay1 laycolour1 circRAD1)

  (setq listindex 0)
  (setq layerlist1 (list
      '(0 "CNC 00 - Panel Outline - No Rout" 252 0.25)
      '(1 "CNC 01 - Engraving 45 deg - Depth 0.5" 7 0.25)
      '(2 "CNC 02 - Outside Rout" 30 0.25)
      '(3 "CNC 03 - Diam 4.0mm - Depth Through" 1 2.0)
      '(4 "CNC 03 - Diam 7.0mm - Depth Through" 1 3.5)
      '(5 "CNC 03 - Diam 8.2mm - Depth Through" 1 4.05)
      '(6 "CNC 03 - Through Rout Inside Correction" 1 0.25)
      '(7 "CNC 04 - Diam 2.0mm - Depth 0.5mm" 2 0.75)
      '(8 "CNC 04 - Diam 2.0mm - Depth 10mm" 2 1.0)
      '(9 "CNC 04 - Diam 5.0mm - Depth 10.0mm" 2 2.5)
      '(10 "CNC 04 - Diam 10.0mm - Depth 13.0mm" 2 5.0)
      '(11 "CNC 04 - Diam 15.0mm - Depth 14.5mm" 2 7.5)
      '(12 "CNC 04 - Diam 35.0mm - Depth 13.5mm" 2 17.5)
      '(13 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 6 3.75)
      '(14 "CNC 09 - Diam 8.2mm - Depth 10.0mm" 161 4.1)
      '(15 "CNC 10 - Diam 8.2mm - Depth 2.0mm" 13 4.15)
      '(16 "CNC 05 - Pocket - Diam 12.0mm - Depth 6.0mm" 4 0.25)
      '(17 "CNC 06 - Scribe - Diam 12.0mm - Depth LPZ - 9" 100 0.25)
      '(18 "CNC 07 - Pocket - Diam 12.0mm - Depth Custom" 241 0.25)
      '(19 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 7 3.75)
      '(20 "SET MANUALLY - CHECK" 221 0.25)
      '(21 "CRUMBLING - Diam 12.0mm - Depth LPZ - 0.5mm" 2 0.25)
      '(22 "no layer" 7 0.25)
    ) ; end list
  ) ; end setq layerlist1
  (setq LayerList2 (length layerlist1))    
  (setq LayerNme1(nth 1(assoc listindex layerlist1)))
  (setq CNClay1(nth 1(assoc listindex layerlist1)))
  (setq laycolour1 (nth 2(assoc listindex layerList1)))
  (setq circRAD1 (nth 3(assoc listindex layerList1)))
    (while (<= listindex LayerList2) ;enter while here can make this dynamic im sure maybe link to length of layerlist1 var
      (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1) '(70 . 0) ( cons 62 laycolour1)))
      (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
      (prompt (strcat "\nCNC Layer created " CNClay1))
      (setq listindex (1+ listindex))
(if (< (+ listindex 1) (length layerlist1)) ;; If listindex is less than the list length, note +1 since index starts at 0
  (progn
          (setq LayerNme1 (nth 1 (assoc listindex layerlist1)))
          (setq CNCLay1 (nth 1 (assoc listindex layerlist1)))
          (setq laycolour1 (nth 2 (assoc listindex layerlist1)))
          (setq circRAD1 (nth 3 (assoc listindex layerList1)))
)) ; end if, end progn
    ); end while

  (princ)
)

 

 

This second option looks so much neater.

Am I write in my understanding that you don't need to set the variables before the while loop because the loop will start at the first listindex number, set those variables, and then loop through. 

 

16 hours ago, Steven P said:
(defun c:test ( / listindex layerlist1 LayerList2 LayerNme1 CNClay1 laycolour1 circRAD1)

  (setq layerlist1 (list
      '(0 "CNC 00 - Panel Outline - No Rout" 252 0.25)
      '(1 "CNC 01 - Engraving 45 deg - Depth 0.5" 7 0.25)
      '(2 "CNC 02 - Outside Rout" 30 0.25)
      '(3 "CNC 03 - Diam 4.0mm - Depth Through" 1 2.0)
      '(4 "CNC 03 - Diam 7.0mm - Depth Through" 1 3.5)
      '(5 "CNC 03 - Diam 8.2mm - Depth Through" 1 4.05)
      '(6 "CNC 03 - Through Rout Inside Correction" 1 0.25)
      '(7 "CNC 04 - Diam 2.0mm - Depth 0.5mm" 2 0.75)
      '(8 "CNC 04 - Diam 2.0mm - Depth 10mm" 2 1.0)
      '(9 "CNC 04 - Diam 5.0mm - Depth 10.0mm" 2 2.5)
      '(10 "CNC 04 - Diam 10.0mm - Depth 13.0mm" 2 5.0)
      '(11 "CNC 04 - Diam 15.0mm - Depth 14.5mm" 2 7.5)
      '(12 "CNC 04 - Diam 35.0mm - Depth 13.5mm" 2 17.5)
      '(13 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 6 3.75)
      '(14 "CNC 09 - Diam 8.2mm - Depth 10.0mm" 161 4.1)
      '(15 "CNC 10 - Diam 8.2mm - Depth 2.0mm" 13 4.15)
      '(16 "CNC 05 - Pocket - Diam 12.0mm - Depth 6.0mm" 4 0.25)
      '(17 "CNC 06 - Scribe - Diam 12.0mm - Depth LPZ - 9" 100 0.25)
      '(18 "CNC 07 - Pocket - Diam 12.0mm - Depth Custom" 241 0.25)
      '(19 "CNC 08 - Diam 7.5mm - Depth 13.5mm" 7 3.75)
      '(20 "SET MANUALLY - CHECK" 221 0.25)
      '(21 "CRUMBLING - Diam 12.0mm - Depth LPZ - 0.5mm" 2 0.25)
      '(22 "no layer" 7 0.25)
    ) ; end list
  ) ; end setq layerlist1

;;  (setq LayerList2 (length layerlist1))                ;; This is in the while command
;;  (setq LayerNme1(nth 1(assoc listindex layerlist1)))  ;; this is in the while loop
;;  (setq CNClay1(nth 1(assoc listindex layerlist1)))    ;; this is in the while loop
;;  (setq laycolour1 (nth 2(assoc listindex layerList1)));; this is in the while loop
;;  (setq circRAD1 (nth 3(assoc listindex layerList1)))  ;; this is in the while loop
  (setq listindex 0)
  (while (< listindex (length layerlist1))
    (setq LayerNme1  (nth 1 (assoc listindex layerlist1))) ;;DO YOU NEED THIS? IT IS THE SAME AS LINE BELOW
    (setq CNCLay1    (nth 1 (assoc listindex layerlist1)))
    (setq laycolour1 (nth 2 (assoc listindex layerlist1)))
    (setq circRAD1   (nth 3 (assoc listindex layerList1)))
    (entmake (list 
      '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord")
      '(100 . "AcDbLayerTableRecord")  (cons 2 CNClay1)
      '(70 . 0) ( cons 62 laycolour1)
    )) ; end entmake (split it like this so it doesn't run over lines, just my OCD.....)
    (entmake (list '(0 . "CIRCLE") (cons 8 CNClay1) '(10  0.0 0.0 0.0) (cons 40 circRAD1)))
    (prompt (strcat "\nCNC Layer created " CNClay1))
    (setq listindex (+ listindex 1))
  ); end while
  (princ)
)

 

 

 

This is all so I know for future reference ( I prefer to learn and understand rather than just take and use the code).

 

Thanks.

  • Like 1
Link to comment
Share on other sites

No problem,

 

The +1 thing is all to do with how it counts. Lists start at item 0 and the length of a list starts at item 1. This list is 5 items long: (0 1 2 3 4), but to read the 5th item you want to use 4 as the reference , to read the first item you use 0. I think however I shouldn't have put that in there, should have been just a plain less then - good question and correction.

 

Yes, that's right, you don't need to set anything before the while loop if you get it all in the right order. Perhaps think in while loops "set values, process stuff, increase counter", set values in or out of the loop it will do the same. I'd set any fixed values outside of the loop (only needs processing once) and anything that depends on the loop inside it.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...