Lee Mac Posted November 21, 2008 Posted November 21, 2008 Ok, so I'm having an absolute nightmaire today - two thread in a matter of a few minutes! None of my LISPs seem to want to work today... Ok, so I've been trying to create a LISP to draw a centre line on a circle - simple as pi. But I keep returning an error and I can't work out why - no doubt its probably something so simple... Anyway, I would appreciate any help available, and, in the words of JONTHEPOPE, "Sorry for all the posts.." ;| Centre-Line by Lee McDonnell November 2008 |; (defun c:cl (/ oldlay oldsnap c1 c1ent c1cent c1rad crat) ; --- Error Trap --- (defun *error*(msg) (if oldVars (mapcar 'setvar varLst oldVars) ); end if (princ "\nError or Esc pressed... ") (princ) ); end of *error* (setq varLst (list "CMDECHO" "OSMODE" "CLAYER" "DIMSCALE") oldVars (mapcar 'getvar varLst) ); end setq ; --- Error Trap --- (setvar "cmdecho" 0) (setq oldlay (getvar "clayer")) (setq oldsnap (getvar "osmode")) (mapcar 'cllayer '("1" "2" "3" "4" "5")) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\nType \"CLSET\" to Change Base Variables. << Current Settings >> C/L Ratio: " (getvar "cl:ratio"))) (while (setq c1 (entsel "\nSelect Circle for Centre-line: ")) (setq c1ent (entget (car c1))) (if (= (cdr (assoc 0 c1ent)) "CIRCLE") (progn (setq c1cent (assoc 10 c1ent) c1rad (assoc 40 c1ent) crat (/ (atof (getenv "cl:ratio")) 100) ) ; end setq (setvar "osmode" 0) (setvar "clayer" "5") (command "-linetype" "S" "CENTER" "") (command "_line" (polar c1cent pi (* clrad crat) ) ; end polar (polar c1cent 0 (* clrad crat) ) ; end polar "" ) ;end line (command "_line" (polar c1cent (/ (* 3 pi) 2) (* clrad crat) ) ; end polar (polar c1cent (/ pi 2) (* clrad crat) ) end polar "" ) ; end line ) ; end progn (alert "\nEntity is not a Circle.") ) ; end if ) ; end while (setvar "clayer" oldlay) (setvar "osmode" oldsnap) (setvar "cmdecho" 1) (princ "\nFunction Complete.") (princ) ) ; end cl (defun cllayer (lay) (if (not (tblsearch "LAYER" lay)) (command "_.-layer" "_m" lay "_c" lay lay "") ) ; end if (princ) ) end cllayer (defun c:clset (/ cratio) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\n<< Current Settings >> C/L Ratio: " (getvar "cl:ratio") "%")) (if (setq cratio (getreal (strcat "\nSpecify C/L as % of Circle Radius <" (getenv "cl:ratio") "> : "))) (setenv "cl:ratio" (rtos cratio)) ) ; end if (princ "\nBase Variables Set.") (princ) ) ; end clset Thanks Guys Quote
paulmcz Posted November 22, 2008 Posted November 22, 2008 You can borrow mine for now... (defun c:cce (/ lt osn oucs ss b d d1 ename elist cp r pn ps pw pe r2) (command "cmdecho" (getvar "cmdecho")) (setq lt "center") (if (= (tblsearch "ltype" lt) nil) (command "-linetype" "l" lt "acad.lin" "")) (princ "\n Center cross: ") (cond ((setq ss (ssget '((-4 . "<OR") (0 . "CIRCLE,ARC,ELLIPSE") (-4 . "OR>") ) ) ) (setq b (sslength ss)) ; = number of circles in ss (setq d b) (repeat b (setq d1 (1- d) ename (ssname ss d1) ; = last entity in ss elist (entget ename) cp (cdr (assoc 10 elist)) r (cdr (assoc 40 elist)) d (* r 1.5) ; greater this number, greater overlap of center lines (%) pn (polar cp (* pi 0.5) d) ps (polar cp (* pi 1.5) d) pw (polar cp pi d) pe (polar cp 0 d) d d1 r2 (* r 0.25) ) ;(setvar "osmode" 0) (entmake (list (cons 0 "LINE") (cons 6 lt) (cons 62 3) (cons 10 pn) (cons 11 ps) (cons 48 r2) (cons 210 (list 0.0 0.0 1.0)) ) ) (entmake (list (cons 0 "LINE") (cons 6 lt) (cons 62 3) (cons 10 pw) (cons 11 pe) (cons 48 r2) (cons 210 (list 0.0 0.0 1.0)) ) ) ) ) (T (princ "\n No circle selected! ")) ) (if (not (tblsearch "ltype" lt)) (princ (strcat "\n Linetype \"" lt "\" was not loaded.")) ) (princ) ) (prompt "\n Type < cce > for circle or arc center lines") Quote
CALCAD Posted November 22, 2008 Posted November 22, 2008 Lee, I found a lot of small things : many instances of 'cl' where you needed 'c1' and several 'getvar' instead of 'getenv'. Several (assoc) calls needed to be (cdr (assoc)). Also found a couple of comments without leading semicolons. It may have been unnecessary but I moved the error trap and other defuns out of the main program because it made things easier for me to follow. I added some code to save and restore the system *error* handler. Maybe this is not strictly required, but it's how I learned to do it and I wanted to make sure it wasn't causing trouble. I had to rename the main program to CLDRAW because CL is an alias for COPYLINK on my system. The program does draw centerlines, but I am not sure that it's running fully as you intended. The 'WHILE' loop is endless - this may be intentional so you can draw centerlines on any number of circles, but it does mean that one must force the program to end with 'ESC'. Also, the prompt suggests that you can reset a value with CLSET, but there's no pause to allow it within the main program. The linetype is not reset when the program ends - it remains centerline. Five layers are created - layer 5 is set active and remains active at program end. I just don't know your intentions. I hope this program ends up doing what you want. When and if you finish it, please post the final version. I may want to use it myself! (defun c:clset (/ cratio) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\n<< Current Settings >> C/L Ratio: " (getenv "cl:ratio") "%")) ; chg getvar to getenv (if (setq cratio (getreal (strcat "\nSpecify C/L as % of Circle Radius <" (getenv "cl:ratio") "> : "))) (setenv "cl:ratio" (rtos cratio)) ) ; end if (princ "\nBase Variables Set.") (princ) ) ; end clset (defun cllayer (lay) ; moved from end (if (not (tblsearch "LAYER" lay)) (command "_.-layer" "_m" lay "_c" lay lay "") ) ; end if (princ) ) ; end cllayer - added semicolon ; --- Error Trap --- (defun cl_error (msg) (if oldVars (mapcar 'setvar varLst oldVars) ); end if (princ "\nError or Esc pressed... ") (setq *ERROR* sys_error) (princ) ); end of *error* ; --- Error Trap --- (defun c:cldraw (/ oldlay oldsnap c1 c1ent c1cent c1rad crat) (setq sys_error *ERROR*) (setq *ERROR* cl_error) (setq varLst (list "CMDECHO" "OSMODE" "CLAYER" "DIMSCALE") oldVars (mapcar 'getvar varLst) ); end setq (setvar "cmdecho" 0) (setq oldlay (getvar "clayer")) (setq oldsnap (getvar "osmode")) (mapcar 'cllayer '("1" "2" "3" "4" "5")) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\nType \"CLSET\" to Change Base Variables. << Current Settings >> C/L Ratio: " (getenv "cl:ratio"))) ; fix (while (setq c1 (entsel "\nSelect Circle for Centre-line: ")) (setq c1ent (entget (car c1))) (if (= (cdr (assoc 0 c1ent)) "CIRCLE") ; fixed c1rad & add cdr in progn (progn (setq c1cent (cdr (assoc 10 c1ent)) c1rad (cdr (assoc 40 c1ent)) crat (/ (atof (getenv "cl:ratio")) 100) ) ; end setq (princ "\nc1rad = ")(princ c1rad) (princ "\ncrat = ")(princ crat) (setvar "osmode" 0) (setvar "clayer" "5") (command "-linetype" "S" "CENTER" "") (command "_line" (polar c1cent pi (* c1rad crat) ) ; end polar (polar c1cent 0 (* c1rad crat) ) ; end polar "" ) ; end line (command "_line" (polar c1cent (/ (* 3 pi) 2) (* c1rad crat) ) ; end polar (polar c1cent (/ pi 2) (* c1rad crat) ) ; end polar "" ) ; end line ) ; end progn (alert "\nEntity is not a Circle.") ) ; end if ) ; end while (setvar "clayer" oldlay) (setvar "osmode" oldsnap) (setvar "cmdecho" 1) (setq *ERROR* sys_error) (princ "\nFunction Complete.") (princ) ) ; end cl Quote
Lee Mac Posted November 23, 2008 Author Posted November 23, 2008 You are a legend CALCAD - I am embarassed to see the amount of ridiculous mistakes I made in that LISP.... The LISP works well now thanks to you... - I have not used your version of the error trap - only because I do not completely understand it, but thanks for your help. But, I can't work out why the layer does not reset to the original current layer. I have included the: (setvar "clayer" oldlay) After the "While" function completes, however, layer "5" still remains active upon completion of the "while" function. Thanks once again LISP as it stands: ;| Centre-Line by Lee McDonnell November 2008 |; (defun c:cl (/ oldlay oldsnap c1 c1ent c1cent c1rad crat) ; --- Error Trap --- (defun *error*(msg) (if oldVars (mapcar 'setvar varLst oldVars) ); end if (princ "\nError or Esc pressed... ") (princ) ); end of *error* (setq varLst (list "CMDECHO" "OSMODE" "CLAYER" "DIMSCALE") oldVars (mapcar 'getvar varLst) ); end setq ; --- Error Trap --- (setvar "cmdecho" 0) (setq oldlay (getvar "clayer")) (setq oldsnap (getvar "osmode")) (mapcar 'cllayer '("1" "2" "3" "4" "5")) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\nType \"CLSET\" to Change Base Variables. << Current Settings >> C/L Ratio: " (getenv "cl:ratio"))) (while (/= (setq c1 (entsel "\nSelect Circle for Centre-line: ")) nil) (setq c1ent (entget (car c1))) (if (= (cdr (assoc 0 c1ent)) "CIRCLE") (progn (setq c1cent (cdr (assoc 10 c1ent)) c1rad (cdr (assoc 40 c1ent)) crat (/ (atof (getenv "cl:ratio")) 100) ) ; end setq (setvar "osmode" 0) (setvar "clayer" "5") (command "-linetype" "S" "CENTER" "") (command "_line" (polar c1cent pi (* c1rad crat) ) ; end polar (polar c1cent 0 (* c1rad crat) ) ; end polar "" ) ;end line (command "_line" (polar c1cent (/ (* 3 pi) 2) (* c1rad crat) ) ; end polar (polar c1cent (/ pi 2) (* c1rad crat) ) ; end polar "" ) ; end line ) ; end progn (alert "\nEntity is not a Circle.") ) ; end if (command "-linetype" "S" "Bylayer" "") ) ; end while (setvar "clayer" oldlay) (setvar "osmode" oldsnap) (setvar "cmdecho" 1) (princ "\nFunction Complete.") (princ) ) ; end cl (defun cllayer (lay) (if (not (tblsearch "LAYER" lay)) (command "_.-layer" "_m" lay "_c" lay lay "") ) ; end if (princ) ) ; end cllayer (defun c:clset (/ cratio) (if (not (getenv "cl:ratio")) (setenv "cl:ratio" "122") ) ; end if (princ (strcat "\n<< Current Settings >> C/L Ratio: " (getenv "cl:ratio") "%")) (if (setq cratio (getreal (strcat "\nSpecify C/L as % of Circle Radius <" (getenv "cl:ratio") "> : "))) (setenv "cl:ratio" (rtos cratio)) ) ; end if (princ "\nBase Variables Set.") (princ) ) ; end clset Quote
CALCAD Posted November 23, 2008 Posted November 23, 2008 Lee, Using your latest code, everything seems to work on my system. The active layer and the linetype revert to the originals. I can exit the program by ESC or Enter or just picking empty space on the screen. If I pick anything not a circle, the alert box appears and clicking OK returns to the loop. The CLSET program also works fine. Eveything is good here and I don't have a clue why the layer won't reset for you. As you say, the (setvar "clayer" oldlay) should handle it and your error trap also handles it by restoring oldVars. So, sorry to say, I'm out of ideas on the layer issue. About the *error* handler : It's mostly a 'good form' issue. When you write (defun *error* (msg) , you are redefining the system error handler. If you don't save and restore the default handler, the one you define becomes the new system handler and, in some cases, this is not what you want. When I first began learning Autolisp, I caused myself some grief because I would write a handler, something like yours, and then go on to write another program and become confused because when errors would occur in the program, the message displayed was not what I expected. And sometimes system variables would contain strange non-default values, and it took awhile to track down the cause. Because many well behaved programs rarely or never cause errors that invoke the system handler, you can go for a long time without realizing that the system handler has been inadvertently modified. So after a little study of other programmers' code I adopted my standard approach. At or near the beginning of the lisp, I save the default handler with (setq sys_error *error*), followed by the new definition (setq *error* my_error). I then write a separate function (defun my_error (msg) . . . (setq *error* sys_error) ) The last line restores the default handler whenever my handler is invoked. I also include the (setq *error* sys_error) at or near the end of the main progam, so the handler is restored in every normal exit. This method works reliably for me. If there is a better way, I would welcome being informed of it. Quote
Lee Mac Posted November 23, 2008 Author Posted November 23, 2008 Thanks for the info about the error handler - I will now use that in my code. I have some more info about my problem - when I exit the function by pressing enter or hitting empty space, the layer is not restored. But, if I hit Esc to end the function, the layer and linetype are restored, but only because my error handler runs. (error message appears) Quote
CALCAD Posted November 24, 2008 Posted November 24, 2008 Lee, You might try using the same method at the close of the WHILE that you use in the error trap, namely the mapcar : (if oldVars (mapcar 'setvar varLst oldVars) ); end if Might be worth a try, and it does simplify the code somewhat. Quote
Lee Mac Posted November 24, 2008 Author Posted November 24, 2008 Thanks CALCAD, will give that a try - thanks for all your help in this matter, as always, any advice is much appreciated. Quote
CAB Posted November 24, 2008 Posted November 24, 2008 I did a quick run through changing to my style in some cases and tweaking to my liking. ;| Centre-Line by Lee McDonnell November 2008 |; (defun c:cl (/ oldlay oldsnap c1 c1ent c1cent c1rad crat *error* ; always localize the error handler ) ; --- Error Trap --- (defun *error* (msg) ;;(if oldVars <--<< Not needed with Mapcar, if nil then mapcar will not execute (mapcar 'setvar varLst oldVars) ; end if (if (= msg "") (princ "\nUser Quit... ") (princ "\nError or Esc pressed... ") ) (princ) ) ; end of *error* (setq varLst (list "CMDECHO" "OSMODE" "CLAYER" "DIMSCALE") ; osmode could be removed oldVars (mapcar 'getvar varLst) ) ; end setq ; --- Error Trap --- (setvar "cmdecho" 0) ;;(setq oldlay (getvar "clayer")) Not needed ;;(setq oldsnap (getvar "osmode")) Not needed (mapcar 'cllayer '("1" "2" "3" "4" "5")) (or (getenv "cl:ratio") (setenv "cl:ratio" "122")) (princ (strcat "\nType \"CLSET\" to Change Base Variables. << Current Settings >> C/L Ratio: " (getenv "cl:ratio") ) ) (while (setq c1 (entsel "\nSelect Circle for Centre-line: ")) (setq c1ent (entget (car c1))) (if (= (cdr (assoc 0 c1ent)) "CIRCLE") (progn (setq c1cent (cdr (assoc 10 c1ent)) c1rad (cdr (assoc 40 c1ent)) crat (/ (atof (getenv "cl:ratio")) 100) ) ; end setq ;;(setvar "osmode" 0) (setvar "clayer" "5") (command "-linetype" "S" "CENTER" "") (command "_line" "_non" (polar c1cent pi (* c1rad crat)) "_non" (polar c1cent 0 (* c1rad crat)) "" ) ;end line (command "_line" "_non" (polar c1cent (* pi 1.5) (* c1rad crat)) "_non" (polar c1cent (/ pi 2) (* c1rad crat)) "" ) ; end line ) ; end progn (alert "\nEntity is not a Circle.") ) ; end if (command "-linetype" "S" "Bylayer" "") ) ; end while ;;(setvar "clayer" oldlay) Not needed ;;(setvar "osmode" oldsnap) Not needed ;;(setvar "cmdecho" 1) Not needed (*error* "") ; CAB reset the vars (princ "\nFunction Complete.") (princ) ) ; end cl (defun cllayer (lay) (if (not (tblsearch "LAYER" lay)) (command "_.-layer" "_m" lay "_c" lay lay "") ) ; end if ; (princ) not needed if you are not returning to the command line ) ; end cllayer (defun c:clset (/ cratio) (or (getenv "cl:ratio")(setenv "cl:ratio" "122")) (princ (strcat "\n<< Current Settings >> C/L Ratio: " (getenv "cl:ratio") "%")) (if (setq cratio (getreal (strcat "\nSpecify C/L as % of Circle Radius <" (getenv "cl:ratio") "> : " ) ) ) (setenv "cl:ratio" (rtos cratio)) ) ; end if (princ "\nBase Variables Set.") (princ) ) ; end clset Quote
CALCAD Posted November 26, 2008 Posted November 26, 2008 Hey Lee, did you get your program to reset the layer? I'm impressed with CAB's version. Simplifies the code nicely. Interesting how CAB's OR statement simply and completely replaces the IF (NOT ... In my earlier post I asked for a better approach to the *error* handler and CAB has provided it. Does everything that needs to be done and much more compactly than my method. Thanks CAB! Also want to recognize the program from paulmcz. It automatically draws green centerlines in all circles, arcs and ellipses and sets the linetype scale proportionally. I had to modify the ssget to work on my system, but then it worked beautifully. Thanks paulmcz! Quote
Lee Mac Posted November 26, 2008 Author Posted November 26, 2008 Hey CALCAD, CAB, I just tried your LISP CAB, and I must say, you have tidied up my LISP beautifully... I'm loving that (or) statement in place of the (if(not))... I don't know how you think of these things Your LISP functions well and my layer is successfully reset. I can only imagine that the Error Handler in my original code clashed with my lines that reset the current layer. But it works now and thanks to CAB and CALCAD for both your help - all is much appreciated - I just hope I can return the favour at some point Quote
JONTHEPOPE Posted November 26, 2008 Posted November 26, 2008 HEY LEE MAC IT'S ME 'JTP' I'm intersted in you program sounds cool . does the drawing have to be active to work ?? I Don't really have anything to add to this post . just thought is was cool we are, friends and your on the other side of the world . Quote
Lee Mac Posted November 26, 2008 Author Posted November 26, 2008 Hey JTP, Yeh it is pretty cool that people from all over the world share programs they have created. My program is just for adding Centre-lines to circles, after the user has set a base variable - namely the ratio of the line to the radius of the circle (preset at 122%). The drawing does have to be active, and the user selects the circles one by one, until hitting either "enter" or "esc" to exit the function. Here is the final version: ;| Centre-Line by Lee McDonnell November 2008 Credit to CALCAD & CAB for Help with Development |; (defun c:cl (/ oldlay oldsnap c1 c1ent c1cent c1rad crat *error* ; always localize the error handler ) ; --- Error Trap --- (defun *error* (msg) (mapcar 'setvar varLst oldVars) (if (= msg "") (princ "\nUser Quit... ") (princ "\nError or Esc pressed... ") ) (princ) ) ; end of *error* (setq varLst (list "CMDECHO" "CLAYER" "DIMSCALE") oldVars (mapcar 'getvar varLst) ) ; end setq ; --- Error Trap --- (setvar "cmdecho" 0) (mapcar 'cllayer '("1" "2" "3" "4" "5")) (or (getenv "cl:ratio") (setenv "cl:ratio" "122")) (princ (strcat "\nType \"CLSET\" to Change Base Variables. << Current Settings >> C/L Ratio: " (getenv "cl:ratio") ) ) (while (setq c1 (entsel "\nSelect Circle for Centre-line: ")) (setq c1ent (entget (car c1))) (if (= (cdr (assoc 0 c1ent)) "CIRCLE") (progn (setq c1cent (cdr (assoc 10 c1ent)) c1rad (cdr (assoc 40 c1ent)) crat (/ (atof (getenv "cl:ratio")) 100) ) ; end setq (setvar "clayer" "5") (command "-linetype" "S" "CENTER" "") (command "_line" "_non" (polar c1cent pi (* c1rad crat)) "_non" (polar c1cent 0 (* c1rad crat)) "" ) ;end line (command "_line" "_non" (polar c1cent (* pi 1.5) (* c1rad crat)) "_non" (polar c1cent (/ pi 2) (* c1rad crat)) "" ) ; end line ) ; end progn (alert "\nEntity is not a Circle.") ) ; end if (command "-linetype" "S" "Bylayer" "") ) ; end while (*error* "") ; Thanks CAB for this (princ "\nFunction Complete.") (princ) ) ; end cl (defun cllayer (lay) (if (not (tblsearch "LAYER" lay)) (command "_.-layer" "_m" lay "_c" lay lay "") ) ; end if ) ; end cllayer (defun c:clset (/ cratio) (or (getenv "cl:ratio")(setenv "cl:ratio" "122")) (princ (strcat "\n<< Current Settings >> C/L Ratio: " (getenv "cl:ratio") "%")) (if (setq cratio (getreal (strcat "\nSpecify C/L as % of Circle Radius <" (getenv "cl:ratio") "> : " ) ) ) (setenv "cl:ratio" (rtos cratio)) ) ; end if (princ "\nBase Variables Set.") (princ) ) ; end clset Quote
Recommended Posts
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.