Search code examples
lispautocadautocad-pluginautolisp

Set and Reset of System Variables - AutoCAD LISP


I'm trying to make drawing wiring diagrams extremely easy in AutoCAD with next to no button presses other than my pre-programmed ones.

One involves a LISP that is not playing nicely with setting system variables and then resetting them to what they were previously. The program seems to perform the intended function, but not with the intended results.

Once my PLINE command starts, the variables get reset. I need the PLINE to start, finish, and then the variables get reset.

I've tried setting OrthoMode and SnapMode within a command in the LISP, as well as through the (setvar (getvar ...)) commands.

(defun varget ()
    (setq lis '("orthomode" "snapmode"))
    (setq var (mapcar 'getvar lis))
    (setq var1 '(1 1))
    (setq no 0)
    (repeat (length lis)
        (setvar (nth no lis) (nth no var1))
        (setq no (1+ no))
    )
    (princ)
 )

(defun varset ()
    (setq no 0)
    (repeat (length lis)
        (setvar (nth no lis) (nth no var))
        (setq no (1+ no))
    )
(princ)
)

(princ)

(defun C:wire ()
(progn
(varget)
(setq prevlayer (getvar "clayer"))
(setq P (getstring "Audio(A)/Video(V)/Comm(CO)/Coax(R)/Control(C)/(N)etwork/(P)ower:"))
(IF (= P "V")(command "-LAYER" "M" "VIDEO" "C" "150" "" "" "PLINE" PAUSE))
(IF (= P "A")(command "-LAYER" "M" "AUDIO" "C" "94" "" "" "PLINE" PAUSE))
(IF (= P "CO")(command "-LAYER" "M" "COMM" "C" "206" "" "" "PLINE" PAUSE))
(IF (= P "R")(command "-LAYER" "M" "COAX" "C" "44" "" "" "PLINE" PAUSE))
(IF (= P "C")(command "-LAYER" "M" "CONTROL" "C" "10" "" "" "PLINE" PAUSE))
(IF (= P "N")(command "-LAYER" "M" "NETWORK" "C" "210" "" "" "PLINE" PAUSE))
(IF (= P "P")(command "-LAYER" "M" "POWER" "C" "7" "" "" "PLINE" PAUSE))
(setvar "clayer" prevlayer)
(varset)
(princ)
);Progn
);defun

No error messages.

I expect the variables to be reset after performing the PLINE command.


Solution

  • The issue with your code is that you are only pausing for a single user input before attempting to reset the system variables and complete evaluation of the program.

    Instead, you will need to use a loop to continuously pause for user input before continuing with program evaluation.

    For example:

    ;; Define function, declare local symbols
    (defun c:wire ( / col lay opt val var )
    
        ;; System variables to be modified within the program
        (setq var '(clayer orthomode snapmode cmdecho)
        ;; Retrieve current sys var values
              val  (mapcar 'getvar var)                
        ) ;; end setq
    
        ;; Predefine the getkword options
        (initget "Audio Video COmm R Control Network Power")
        ;; Prompt the user for input, default to "Audio" on null input
        (setq opt (cond ((getkword "\n[Audio/Video/COmm/Coax(R)/Control/Network/Power] <Audio>: ")) ("Audio")))
    
        ;; Define the layer & colour based on the option returned
        (cond
            (   (= opt "Audio")   (setq lay "AUDIO"    col  94))
            (   (= opt "Video")   (setq lay "VIDEO"    col 150))
            (   (= opt "COmm")    (setq lay "COMM"     col 206))
            (   (= opt "R")       (setq lay "COAX"     col  44))
            (   (= opt "Control") (setq lay "CONTROL"  col  10))
            (   (= opt "Network") (setq lay "NETWORK"  col 210))
            (   (= opt "Power")   (setq lay "POWER"    col   7))
        ) ;; end cond
    
        ;; Suppress command-line output for the -LAYER command
        (setvar 'cmdecho 0)
        ;; Create & set the layer & layer colour
        (command "_.-layer" "_M" lay "_C" col "" "")
    
        ;; Set everything except the first sys var
        (mapcar 'setvar (cdr var) '(1 1 1))
        ;; Initiate the PLINE command
        (command "_.pline")
        ;; Continuously pause for user input
        (while (= 1 (logand 1 (getvar 'cmdactive))) (command "\\"))
    
        ;; Reset system variables
        (mapcar 'setvar var val)
    
        ;; Suppress the value returned by the last evaluated expression
        (princ) 
    ) ;; end defun
    

    A few points to note:

    • Always declare your local variables to avoid clashing with identically named variables in the document namespace. See my tutorial here for more information on how & why you do this.

    • Use getkword in place of getstring to control & validate the user's input.

    • Use "\\" in place of the pause symbol, as the pause symbol is an unprotected global variable and can easily be inadvertently redefined outside of your program, causing your program to break. Since the pause symbol evaluates to "\\" you may as well use the literal backslash.

    As an extension, you may also want to consider implementing a local error handler to handle when the user inevitably presses Esc during evaluation of the program (the system variables would otherwise not be reset under such circumstances). I describe how to do this in my tutorial here.

    Here is a basic example demonstrating the inclusion of a local error handler:

    ;; Define function, declare local symbols
    (defun c:wire ( / *error* col lay opt val var )
    
        ;; Define local error handler
        (defun *error* ( msg )
            ;; Reset system variables
            (mapcar 'setvar var val)
            ;; Suppress the output of standard cancellation messages
            (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
                ;; Print critical errors
                (princ (strcat "\nError: " msg))
            ) ;; end if
            (princ) ;; Suppress the value returned by the last evaluated expression
        ) ;; end defun
    
        ;; System variables to be modified within the program
        (setq var '(clayer orthomode snapmode cmdecho)
        ;; Retrieve current sys var values
              val  (mapcar 'getvar var)                
        ) ;; end setq
    
        ;; Predefine the getkword options
        (initget "Audio Video COmm R Control Network Power")
        ;; Prompt the user for input, default to "Audio" on null input
        (setq opt (cond ((getkword "\n[Audio/Video/COmm/Coax(R)/Control/Network/Power] <Audio>: ")) ("Audio")))
    
        ;; Define the layer & colour based on the option returned
        (cond
            (   (= opt "Audio")   (setq lay "AUDIO"    col  94))
            (   (= opt "Video")   (setq lay "VIDEO"    col 150))
            (   (= opt "COmm")    (setq lay "COMM"     col 206))
            (   (= opt "R")       (setq lay "COAX"     col  44))
            (   (= opt "Control") (setq lay "CONTROL"  col  10))
            (   (= opt "Network") (setq lay "NETWORK"  col 210))
            (   (= opt "Power")   (setq lay "POWER"    col   7))
        ) ;; end cond
    
        ;; Suppress command-line output for the -LAYER command
        (setvar 'cmdecho 0)
        ;; Create & set the layer & layer colour
        (command "_.-layer" "_M" lay "_C" col "" "")
    
        ;; Set everything except the first sys var
        (mapcar 'setvar (cdr var) '(1 1 1))
        ;; Initiate the PLINE command
        (command "_.pline")
        ;; Continuously pause for user input
        (while (= 1 (logand 1 (getvar 'cmdactive))) (command "\\"))
    
        ;; Reset system variables
        (mapcar 'setvar var val)
    
        ;; Suppress the value returned by the last evaluated expression
        (princ) 
    ) ;; end defun