See the top rated post in this thread. Click here

Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Anatomy of an AUTOLISP file

  1. #1
    AUGI Addict kennet.sjoberg's Avatar
    Join Date
    2002-05
    Posts
    1,707
    Login to Give a bone
    3

    Question Anatomy of an AUTOLISP file

    Ok, share my beer and lisp code (defun c: ( / ) )

    The first line in a lisp program is the "defun" line, I think it comes from "define function"
    a function is a piece of code that you can call in different ways, the code can be very simple but usefull in many other programs.

    Example, a function that convert Degrees to Radians and send a message the user
    Code:
    (defun Deg2Rad ( Input1 Input2   / LocalVar1 LocalVar2 AndSoOnVar ) ; *GlobalVar1*
      (setq LocalVar1 (* (/ Input1 180.0 ) pi ) )
      (princ LocalVar1 )
      (if (= LocalVar1 pi ) (setq *GlobalVar1* T ) (setq *GlobalVar1* nil ) ) ; See later on
      (princ Input2 )
      (princ)
    )
    Deg2Rad is the name of the function

    Input1 and Input2 is the argumen ( x / ) that you send to the function that treate them.
    sometimes you can se errormessages like "too many arguments" or "too few arguments" or "bad argument type"
    they occur when you send wrong amount of arguments or wrong argument type to the function
    Examples :
    (Deg2Rad 90 " Happy Computing !" ) ; => 1.5708 Happy Computing !
    (Deg2Rad " Happy Computing !" ) ; => Error: too few arguments
    (Deg2Rad 1 0 " Happy Computing !" ) ; => Error: too many arguments
    (Deg2Rad "90" " Happy Computing !" ) ; => Error: bad argument type: numberp: "90"

    LocalVar1, AndSoOnVar is local variables ( / x ) inside the function that is treated, cleared and forgotten by AutoCAD when the function is done,
    To save memory and to not fake up with other functions and program it is very important to take care of those local variables,
    many programmers are careless and do not take care of the local variables and then they are not local variables anymore but global.

    *GlobalVar1* is a global variable, it can be used inside a function but is not declared as a local in the first line.
    it means that it stay resident untill the AutoCAD task is shut down. The *asterisk* is a good way to mark and separate global variables from local.
    Example :
    (Deg2Rad 90 " Happy Computing !" ) ; 1.57080 Happy Computing !
    Command: !*GlobalVar1* <--- test variables at command line with a preceding exclamation mark
    nil empty or not true
    (Deg2Rad 180 " Happy Computing !" ) ; 3.14159 Happy Computing !
    Command: !*GlobalVar1*
    T value is present or true
    as you can see the *GlobalVar1* is set to nil or T depending on what you feed the function Deg2Rad with
    later on you can use the *GlobalVar1* in an other function or program.

    Well two more things in the function, the first is very important
    (/ Input1 180.0 ) ; <- this is a real division (/ 70 180.0 ) = 0.388889
    (/ Input1 180 ) ; <- this is an integer division (/ 70 180 ) = 0
    the second is hairstyle
    (princ) ; second last line do a silent end, otherwise you will see a "nil" at the prompt when the function is done
    if you assign a variable to LocalVar2 and replace (princ) with LocalVar2 you will see that variable instead.

    Ok, to run a function like (vl-load-com) { that is a lisp extender for vla- and vlax- commands } you just type
    Command: (vl-load-com) at the command prompt, or inside a lisp it is good as it is.

    If you want be able to use the function as a command in the AutoCAD command window, just put the c: befor the function name. { maybe command function }
    Lets make a new command function and use the *GlobalVar1* that we used in the other function.
    Code:
    (defun c:Check½Circle (/ )
      (if *GlobalVar1* (alert "½Circle is found" ) (princ "\ohhh no. . . .  I failed again" ) )
      (princ)
    )
    if you type Check½Circle in the Command window you will have different results depending on how the *GlobalVar1* is set from the "other" program
    Command: Check½Circle
    ohhh no. . . . I failed again

    Well let us run the other program that left the *GlobalVar1*
    Command: (Deg2Rad 180 " Happy Computing !" )
    3.14159 Happy Computing !

    and once again
    Command: Check½Circle
    Now you got the alert message "½Circle is found"

    . . .recognize that it is important to treat local variables as local and global variables as shared global.

    Ok, what else ?? . . .beer and code, that make sense for me . . .or

    : ) Happy Computing !

    kennet
    Last edited by kennet.sjoberg; 2006-06-29 at 10:20 PM. Reason: Sorry for my gramatic and spelling

  2. #2
    AUGI Addict kennet.sjoberg's Avatar
    Join Date
    2002-05
    Posts
    1,707
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    When Opie was so kind to me and stick up the first :beer in a new thread I feel guilty to take one more.

    Ok, share my beer2 and lisp code (defun c: ( / ) )

    I suppose that you now can the difference between local and global variables, but what is UserVariables ?

    A UserVariable is a setting that the user have set in his AutoCAD environment and is pleased with,
    for example OSMODE snap modes.
    If a user have set the snapmode to end, mid and center and you want to change it in the program to only accept near,
    you will easy do it in the program. But when the program is done it must reset it to the previous setting !

    Example:
    Code:
    (defun c:MyLine (/ Pt1 Pt2 )
      (setq Pt1 (getpoint "First Point" ) )
      (setq Pt2 (getpoint "Second Point" ) )
      (setvar "OSMODE" 512 ) ; accept only snap to near - or nothing
      (command "._line" Pt1 Pt2 "" )
      (princ)
    )
    Now you have a new command MyLine that draws a line between Pt1 and Pt2 on existing objects if present.
    And a new command that fake up the users OSMODE settings ! !


    How to avoid that ?
    It is easy with the suck-change-reset method

    First let us check that the osmode is faked up by the previous command
    Command: osmode
    Enter new value for OSMODE <512>: <--- Yes, bad 512 is left from the program
    Let us now turn it in to my favourite snap setting 111 ( easy to remember and good to use )
    (setvar "OSMODE" 111 )

    let us check the new settings
    Command: osmode
    Enter new value for OSMODE <111>: <--- Yes, my favourite osmode setting is present

    and then rewrite the program

    Example:
    Code:
    (defun c:MyLine (/ OldOsm Pt1 Pt2 )
      (setq OldOsm (getvar "OSMODE" ) ) ; suck the user variable
      (setvar "OSMODE" 512 ) ; change the variable, accept only snap to near - or nothing
      (setq Pt1 (getpoint "Pick the start point" ))
      (setq Pt2 (getpoint "Pick the end point" ))
      (command "._line" Pt1 Pt2 "" )
      (setvar "OSMODE" OldOsm ) ; reset the user variable
      (princ)
    )
    Let us check the setting again
    Command: osmode
    Enter new value for OSMODE <111>: <--- Yes, Yes my favourite osmode setting is still there.

    Now you have a new command MyLine that draws a line between Pt1 and Pt2 on existing objects if present.
    AND a new command that left the user OSMODE settings UNCHANGED.


    Ok, what else ?? . . .beer and code, that make sense for me . . .or

    : ) Happy Computing !

    kennet
    Last edited by kennet.sjoberg; 2006-06-29 at 10:20 PM. Reason: Sorry for my gramatic and spelling

  3. #3
    I could stop if I wanted to
    Join Date
    2003-11
    Posts
    277
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    Quote Originally Posted by kennet.sjoberg
    When Opie was so kind to me and stick up the first :beer in a new thread I feel guilty to take one more.

    ...

    : ) Happy Computing !

    kennet
    Hi kennet,
    in your code,if user stop in the middle that the program,user should to resetting system variable,why not use with error trapping,look like this.
    Code:
    (defun c:MyLine (/ Pt1 Pt2 )
      (setq *error* myer)                                  
      (setq om (getvar "osmode"))                   ; get osmode setting  
      (setvar "osmode" 512)                         ; osmode set to 512
      (setq Pt1 (getpoint "First Point" ) )
      (setq Pt2 (getpoint "Second Point" ) )
      ;(setvar "OSMODE" 512 ) ; accept only snap to near - or nothing
      (command "._line" Pt1 Pt2 "" )
      (setvar "osmode" om)                            ; return setting
      (setq *error* nil)   
      (princ)
      )
    
    (defun myer (msg)                                          
      (setvar "osmode" om)
      (setq att "***Resetting system variable was done***")
      (princ att)
      )
    Last edited by Opie; 2006-06-30 at 01:22 PM. Reason: Removed bulk of original quote

  4. #4
    AUGI Addict kennet.sjoberg's Avatar
    Join Date
    2002-05
    Posts
    1,707
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    Quote Originally Posted by Adesu
    Hi kennet,
    in your code,if user stop in the middle that the program. . .
    Yes, that is true. The simple code is written with awareness
    and errorhandling was planed to be my next

    : ) Happy Computing !

    kennet

    Please do not resend all my text in your reply, just a <snip> if necessary.
    It will turn in to much text. . .

    BTW in your code
    What happens to AutoCAD default errorhandler when doing (setq *error* nil) ? = DESTROYED
    Is function "myer" unnecessary left staying resident when done ? = YES
    and is variable "om" unnecessary left staying resident when done ? = YES

    Think about that for a while, in the meantime I will take a or two . .
    Last edited by kennet.sjoberg; 2006-08-08 at 09:26 PM. Reason: BTW

  5. #5
    AUGI Addict kennet.sjoberg's Avatar
    Join Date
    2002-05
    Posts
    1,707
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    Ok, share my beer3 and lisp code (defun c: ( / ) )

    Errorhandling, is that necessary?
    Yes if you want to work in a correct AutoCAD environment.

    The main thing an error handler has to do is to reset the user environment if the program crash caused by the user or by the program itself. The error handler can be written very advanced or very simple, global or local, and I will not prescribe any of them because they all have there own purpose in the right program.

    I will continue with a simple code with a simple local named error handler and a undo flag,
    just to make lines that is easy to follow and probably easy to understand.
    Code:
    (defun c:MyLine (/ MyLine_err OldErr OldOsm Pt1 Pt2 ) ;; The new command with local variables
      ;;; Subroutines
      (defun MyLine_err (msg / ) ;; Errorhandler designed for this program
        (princ (strcat "\nUser [Esc], " (strcase msg T ) " ! " ) ) ;; Print the error message
        (setvar "OSMODE" OldOsm ) ;; Reset OSMODE from 512 to previous state
        (command "._UNDO" "End" ) ;; Close the undo flag
        (setq *error* OldErr ) ;; Reset the errorhandler to the previous errorhandler
        (command "._U" ) ;; If this line is commented out all inserted lines will NOT be removed when Esc or error.
        (princ)
      )
      ;;; Settings
      (setq OldErr *error* ) ;; Save current (may be AutoCADs default) errorhandler
      (setq *error* MyLine_err ) ;; Replace the current errorhandler function with MyLine_err function
      (setq OldOsm (getvar "OSMODE" ) ) ;; Save current (User) OSMODE settings
      (command "_.UNDO" "BEgin") ;; Create a undo start flag
      ;;; Main Program
      (setvar "OSMODE" 512 ) ;; Change the OSMODE to fit the program
      (setq Pt1 (getpoint "Start point: ") )
      (alert "Press the [OK] button, and later on after a few lines the [Esc] button\nthe error handler will trap you and reset OSMODE to previous state.\n\nThen it also will go back to the undo begin mark where no line is inserted. " )
      (while (setq Pt2 (getpoint Pt1 " next: ") ) ;; Create H/V lines until [Enter] or [Spacebar] is pressed
        (command "._line" Pt1 (list (car Pt2 ) (cadr Pt1 )) Pt2 )
        (command )
        (setq Pt1 Pt2 Pt2 nil )
      )
      ;;; Resetting
      (setvar "OSMODE" OldOsm ) ;; Reset OSMODE from 512 to previous state
      (command "_.UNDO" "End") ;; Close the undo flag, it means that you can Command: _U away all inserted lines in one time, and not one by one
      (setq *error* OldErr ) ;; Reset the errorhandler to the previous errorhandler
      (alert "When a Happy End is done, you can\nCommand: U away all inserted lines all in one time\nand not Command: U one by one. . ." )
      (princ) ;; Silent and Happy End
    )
    Take the note that all the user or system variables that you change in the ;; Settings or in the ;; Main Program must be resetted in the ;; Resetting part when a Happy End is done, or in the ;; Subroutines part in the Errorhandler designed for this program
    see the suck-change-reset method earlier in this thread.

    Ok, what else ?? . . .beer and code, that make sense for me . . .or

    : ) Happy Computing !

    kennet

  6. #6
    I could stop if I wanted to pnorman's Avatar
    Join Date
    2005-02
    Location
    Calgary
    Posts
    203
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    What about this method. Combines error and variable handling into one easy to use function and also includes undo method.

    Code:
    ;|
    Written by Phillip Norman
    nospam.cadd@phillipnorman.com ;remove "nospam."
    Permission to copy, modify, and distribute this software
    for any purpose is freely granted.
    THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
    WARRANTY. ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR
    PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
    March 2006
    Functions
    ppn_error
    ppn_sysvar
    ppn_slisp
    ppn_elisp
    ppn_get:edata
    c:AS
    Global Vars
    *PPN_UNDO_#*
    *SYSVAR_LIST*
    |;
    (defun ppn_error (MSG)	 ; global error function
    (princ (strcat "\n" MSG)) ; return the error message
    (ppn_sysvar nil)		 ; reset the system variables
    (if *PPN_UNDO_#*		 ; reset the undo mark counter
    	(progn
    	 (repeat *PPN_UNDO_#*
    		(vla-EndUndoMark (vla-get-activedocument (vlax-get-acad-object)))
    	 )
    	 (setq *PPN_UNDO_#* nil)
    	)
    )
    )
    ;| function to store and reset system variables
    has three conditions
    1. if the given argument is list then store the current value
    	 of each system variable in the list and then set the new
    	 value to the value given by the second item in each pair
    	 eg.
    	 (ppn_sysvar '(("texteval" . 1)("cmdecho" . 0)))
    	 (ppn_sysvar (list (cons "clayer" (getvar "clayer"))))
    	 (ppn_sysvar (list (cons "clayer" (getvar "clayer"))'("osmode" . 0)))
    2. if the given argument is an integer then reset that number of system
    	 variables from the list of variables in *SYSVAR_LIST*
    	 eg.
    	 (ppn_sysvar 2)
    3. if the given argument is nil then reset all sysvars
    	 in the list of variables in *SYSVAR_LIST*
    |;
    (defun ppn_sysvar (SYSVARLST / SYSVAR)
    (cond
    	((= (type SYSVARLST) 'LIST)
    	 (foreach SYSVAR SYSVARLST
    	 (setq *SYSVAR_LIST* (cons (cons (car SYSVAR) (getvar (car SYSVAR))) *SYSVAR_LIST*))
    	 (vla-setvariable (vla-get-activedocument (vlax-get-acad-object)) (car SYSVAR) (cdr SYSVAR))
    	 )
    	)
    	((= (type SYSVARLST) 'INT)
    	 (if *SYSVAR_LIST*
    	 (repeat SYSVARLST
    		 (setq SYSVAR (car *SYSVAR_LIST*))
    		 (setq *SYSVAR_LIST* (cdr *SYSVAR_LIST*))
    		 (vla-setvariable (vla-get-activedocument (vlax-get-acad-object)) (car SYSVAR) (cdr SYSVAR))
    	 )
    	 )
    	)
    	((= SYSVARLST nil)
    	 (repeat (length *SYSVAR_LIST*)
    	 (setq SYSVAR (car *SYSVAR_LIST*))
    	 (setq *SYSVAR_LIST* (cdr *SYSVAR_LIST*))
    	 (vla-setvariable (vla-get-activedocument (vlax-get-acad-object)) (car SYSVAR) (cdr SYSVAR))
    	 )
    	)
    )
    (princ)
    )
    ; function used at start of every macro to initialise undo
    (defun ppn_slisp ()
    (vla-StartUndoMark (vla-get-activedocument (vlax-get-acad-object)))
    (if *PPN_UNDO_#*
    	(setq *PPN_UNDO_#* (1+ *PPN_UNDO_#*))
    	(setq *PPN_UNDO_#* 1)
    )
    )
    ; function used at end of every macro to close undo
    (defun ppn_elisp ()
    (repeat *PPN_UNDO_#*
    	(vla-EndUndoMark (vla-get-activedocument (vlax-get-acad-object)))
    )
    (setq *PPN_UNDO_#* nil)
    )
    ; function to get dxf code ITEM# from entity E1 and store in symbol ITEM
    (defun ppn_get:edata (E1 ITEM ITEM# / E1DATA)
    	 (if E1
    		(progn
    		 (setq E1DATA (entget (car E1)))
    		 (set (read ITEM) (cdr (assoc ITEM# E1DATA)))
    		)
    	 )
    )
    ; example function - match properties macro for layer, color, linetype, object ltscale
    (defun c:as (/ E1 LYR COL LT LTSC *error*)
    (defun *error* (MSG) ; local error handler to reset entity redraw
    	(if E1 (redraw (car E1) 4))
    	(ppn_error MSG)	; call main error handler
    )
    (ppn_slisp)
    (ppn_sysvar '(("cmdecho" . 0)))
    (setq E1 (entsel "Select source object: "))
    	(if (not E1)
    		(progn
    		 (setq LYR (getvar "clayer"))
    		 (setq COL "bylayer")
    		 (setq LT "bylayer")
    		 (setq LTSC 1)
    		)
    		(progn
    		 (redraw (car E1) 3)
    		 (ppn_get:edata E1 "LYR" 8)
    		 (ppn_get:edata E1 "COL" 62)
    		 (if (not COL) (setq COL "bylayer"))
    		 (ppn_get:edata E1 "LT" 6)
    		 (if (not LT) (setq LT "bylayer"))
    		 (ppn_get:edata E1 "LTSC" 48)
    		 (if (not LTSC) (setq LTSC 1))
    		)
    	)
    (princ (strcat LYR "\n"))
    (while (setq E2 (ssget ":S"))
    	(progn
    	 (ppn_sysvar '(("highlight" . 0)))
    	 (command "_.change" E2 "" "_p" "_c" COL "_lt" LT "_s" LTSC "_layer" LYR "")
    	 (ppn_sysvar 1)
    	)
    )
    (setvar "clayer" LYR)
    (if E1 (redraw (car E1) 4))
    (ppn_sysvar 1)
    (ppn_elisp)
    (princ)
    )
    Regards
    Phill
    Attached Files Attached Files
    Last edited by pnorman; 2006-08-14 at 06:45 PM.

  7. #7
    Member
    Join Date
    2005-05
    Posts
    2
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    Code:
    ;;a new way of  error function
    (defun c:myline	(/ edoc oldos)
      (setq	edoc  (vla-get-activedocument (vlax-get-acad-object))
    	oldos (getvar "osmode")
      )
      (vla-startundomark edoc)
      (setvar "osmode" 0)
      (vl-catch-all-apply
        '(lambda (/ pt1 pt2)
           (setq Pt1 (getpoint "\nStart point: "))
           (while (setq Pt2 (getpoint Pt1 " \nNext: "))
    	 (command "._line" Pt1 (list (car Pt2) (cadr Pt1)) Pt2)
    	 (command)
    	 (setq Pt1 Pt2
    	       Pt2 nil
    	 )
           )
         )
      )
      (setvar "osmode" oldos)
      (vla-endundomark edoc)
      (princ)
    )

  8. #8
    Administrator Opie's Avatar
    Join Date
    2002-01
    Location
    jUSt Here (a lot)
    Posts
    9,106
    Login to Give a bone
    0

    Default Re: Anatomy of an AUTOLISP file

    This thread was not created for any one individual. It is for anyone that can explain the anatomy of an AUTOLISP file / routine so other programmers can learn and understand AutoLISP.

    If you would like to discuss posts within or ask questions about this thread, please do so in
    the "Discussion of "Anatomy of an AUTOLISP file"" thread.

    Thanks,
    Richard
    Forum Moderator
    If you have a technical question, please find the appropriate forum and ask it there.
    You will get a quicker response from your fellow AUGI members than if you sent it to me via a PM or email.
    jUSt

  9. #9
    AUGI Addict kennet.sjoberg's Avatar
    Join Date
    2002-05
    Posts
    1,707
    Login to Give a bone
    2

    Default Re: Anatomy of an AUTOLISP file

    Uggh, very crowded on the bar desk, there is almost no room for my next beer.
    Anyway, share my beer4 and lisp reactor code (defun c: ( / ) )

    Well, I made a "Inser Xref on layer _XREF" reactor that I have numbered, commented and colored
    so it may be easy to follow, it is built of 4 main parts
    an edit commandwillstart ( 2b ) reactor + the lisp function ( 2a ) it triggers
    { here between will the xref command run that you already have started }
    an edit commandEnded ( 3b ) reactor + the lisp function ( 3a ) it triggers

    I hope the code will help you to further on make your own reactors,
    in the meantime you can use this CODE and press
    <------------------------- the reputation button ; )

    Code:
    ;;; ( 1 )
    ;;; Load the extended AutoLISP functions, that support vlr-
    (vl-load-com)
    
    ;;; ( 2a )
    ;;; My lispfunction "Xref_Start_Function" check if the argument "Command-In" sent from the "Xref_Start_Reactor" is "XREF"
    ;;; because the vlr-commandwillstart reactor do send all commands used, ( not only from the command xref ).
    (defun Xref_Start_Function   (ObjReactor Command-In / ) ;; Global variable is *OldXrefLay*
      (if (= (car Command-In ) "XREF" ) ;; If the started command is Xref, do the things in progn
        (progn
          (setq *OldXrefLay* (getvar "CLAYER" ) ) ;; Save current layer to the global variable *OldXrefLay*
          (alert "Do not Bind an Xref with the ( ) Bind option, use the (o) Insert option  " ) ;; You can remove this demo line
          (if (not (tblsearch "LAYER" "_XREF" )) ;; If the layer "_XREF" dot not exist, create it
            (entmake '((0 . "LAYER") (100 . "AcDbSymbolTableRecord") (100 . "AcDbLayerTableRecord") (2 . "_XREF" ) (70 . 0) (62 . 7) (6 . "Continuous" )) )
            ( ) ;; Must use entmake, Command not allowed or just do not work for me in a  function trigged by a reactor
          )
          (setvar "CLAYER" "_XREF" ) ;; Set current layer to "_XREF"
        )
        ( ) ;; Command_in was something else than "XREF"
      )
    ) ;; When this function is ended the Xref command will continue.
    
    
    ;;; ( 2b )
    ;;; A commandwillstart reactor starts at all commands, not only by the xref command
    ;;; and this reactor trigger my lisp function "Xref_Start_Function" that must already been loaded.
    ;;; Note that I assign the reactor to the variable "Xref_Start_Reactor", it is not a must but see later on in ( 4 )
    (setq Xref_Start_Reactor   (vlr-editor-reactor nil '((:vlr-commandwillstart . Xref_Start_Function ))) )
    
    ;;; ( 3a )
    ;;; This lisp function act in symbiosis with the lispfunction in ( 2a ), it use the value in the global variable *OldXrefLay*
    ;;; and reset the layer to previous after the "XREF" command is done
    ;;; it will be started by the vlr-commandEnded reactor in ( 3b )
    (defun Xref_End_Function (ObjReactor Command-In / )
      (if (and (= (car Command-In ) "XREF" ) *OldXrefLay* )
        (setvar "CLAYER" *OldXrefLay* ) ;; Reset layer to previous
        ( ) ;; Command_in was something else than "XREF"
      )
    )
    
    ;;; ( 3b )
    ;;; A commandEnded reactor starts after all commands, not only by the xref command
    ;;; and this reactor trigger my lispfunction "Xref_End_Function" that must already been loaded.
    ;;; Note that I assign the reactor to the variable "Xref_End_Reactor", it is not a must but see later on in ( 4 )
    (setq Xref_End_Reactor   (vlr-editor-reactor nil '((:vlr-commandEnded . Xref_End_Function ))) )
    
    ;;; ( 4 )
    ;;; It is also good to have the possibility to remove a reactor and clear it and its function
    ;;; because of that I assigned my reactors to variables that I easy can catch.
    ; (vlr-remove Xref_Start_Reactor   )                       ;; Removes the reactor assigned to variable named Xref_Start_Reactor
    ; (setq Xref_Start_Function nil Xref_Start_Reactor   nil ) ;; Clear\assign nil to the function and the reactor
    ; (vlr-remove Xref_End_Reactor   )                         ;; Removes the reactor assigned to variable named Xref_End_Reactor
    ; (setq Xref_End_Function nil Xref_End_Reactor   nil )     ;; Clear\assign nil to the function and the reactor
    ; (setq *OldXrefLay* nil ) ;; Clear the global variable, for take care
    ;;; . . . and do not load a reactor more than once, otherwise it will repeat itself x number of times.
    ;;;
    Ok, what else ?? . . .beer and code, that make sense for me . . .or confused ?

    : ) Happy Computing !

    kennet
    Last edited by kennet.sjoberg; 2006-10-30 at 10:42 AM. Reason: removed one if statement

  10. #10
    All AUGI, all the time CAB2k's Avatar
    Join Date
    2016-01
    Location
    Brandon, Florida
    Posts
    687
    Login to Give a bone
    1

    Default Re: Anatomy of an AUTOLISP file

    I recently added to this so I thought I would put it here.

    Here is my take on the subject of Logic function & there use:

    The if statement works like this
    Code:
    (if (this is true) 
      (then do this)
    )
    Code:
    (if (this is true) 
      (then do this)
      (else do this when false)
    )


    The (cond) stmt on the other hand executes the all of code following
    a true condition and then exits the condition stmt.

    Code:
    (cond
      ((= 1 0)
        none of this will get executed
        because the conditions is false
      ) ; end cond 1
    
      ((= 1 1)
         do all of this because it is true
         and this
         and this
       ) ; end cond 2
    
       ((= 2 2)
         none of this will get
         executed even if it is true
         because the prior stmt was true
       ) ; end cond 3
    
       (T
         This is often placed at the last position
         in a condition statement and will be executed
         if all the prior conditions are false
         if any one of the above conditions are true
          this will not be executed
       ) ; end cond 4
    ) ; end cond stmt
    More on the condition statement in a minute.


    The OR will process each line as long as they are false, it will quit when true is returned
    Code:
    (or (a. is true) ; stop here
         (b. does not get this far)
    )
    Code:
    (or (a. is false) ; keep going
         (b. do this & if false keep going)
         (c. do this if b was false)
    )
    The AND will process each line as long as they are true, it will quit when false is returned
    Code:
    (and (a. is true) ; keep going
          (b. do this & if true keep going)
          (c. do this if b was true)
    )
    Note that AND & OR themselves only return true or nil,
    whereas IF and COND will return the value of the expression.
    Code:
    (setq rtn
           (or (+ 3 7) ; returns 10 which is not nil so it passes the test for true
                (+ 2 4 6) ; return 12
           )
    )
    While the value in rtn is t
    Code:
    (setq rtn
           (if (+ 3 7) ; returns 10 which is not nil so it passes the test for true
                (+ 2 4 6) ; return 12
           )
    )
    The value in rtn is 12
    Code:
    (setq rtn
           (if (> 3 7) ; 3 is not > 7 so this returns nil
                (+ 2 4 6) ; return 12
           )
    )
    The value in rtn is nil because there was no else line to consider
    Code:
    (setq rtn
           (if (> 3 7) ; 3 is not > 7 so this returns nil
                (+ 2 4 6) 
                (- 10 2)
           )
    )
    No supprise here, the rtn value is 8

    The cond statement works simular to the if
    Here is an example I like
    Code:
    (initget 0 "Yes No")
    (setq ans 
              (cond 
              	((getkword "\nGive your answer.  [Yes/No] <Yes>: "))
                    ("Yes")
              )
    )
    If the user hits the enter key nil is returned and the cond returns "Yes"
    If the user enters text the text is returned




    Some examples of (progn
    Note that progn returns the value of the LAST evaluated expression.
    Code:
    (if (this is true)
       (progn
            do all of this
            and this
            and this
        )
       (don't do this)
    ); endif
    
    (if (this is false)
       (don't do this)
       (progn
            do all of this
            and this
            and this
        )
    )
    So you see the progn is a way to group code together.
    The (if) stmt will execute the group of code when true and
    will execute the second group of code when false,
    if there is a second group of code. If you forget the (progn) only the first
    line of code will be executed if true and the rest skipped.
    There are other ways to group code together and you will learn them in time.




    The (cond) stmt on the other hand executes all of the code following
    a true condition and then exits the condition stmt. Remember true is anything not nil.

    Code:
    (cond
      ((= 1 0)
        none of this will get executed
        because the conditions is false
      ) ; end cond 1
    
      ((= 1 1)
         do all of this because it is true
         and this
         and this
       ) ; end cond 2
    
       ((= 2 2)
         none of this will get
         executed even if it is true
         because the prior stmt was true
       ) ; end cond 3
    
       (T
         This is often placed at the last position
         in a condition statement and will be executed
         if all the prior conditions are false
         if any one of the above conditions are true
          this will not be executed
       ) ; end cond 4
    ) ; end cond stmt


    Here is a trick for the cond statement when you want to conditionally execute the cond.
    Often we see it like this:
    Code:
    (if (something is true) ; reminder, 'true' here is really anything (not nil)
      (cond
        ((= 1 1) ...)
        ((= 2 2) ...)
      ) ; end cond stmt
    ) ; endif
    It can be written like this so that if something is not true the first condition is true &
    nothing is done but the cond statement is satisfied that it found a true condition.
    The processing skips the remaining conditions.
    Code:
    (cond
      ((not (something is true))) ; if something is not true stop here
      ((= 1 1) ...)
      ((= 2 2) ...)
    ) ; end cond stmt


    The WHILE function as a conditional loop and continues the loop until the next
    expression returns nil. Here we test the value in cnt looking for it to become 0
    so that we can exit the while loop. The code within the loop is executed 5 times,
    while the cnt value is 0 through 4.
    Code:
    (setq cnt 0)
    (while (< cnt 5)
      ;;  do some stuff
      (setq cnt (1+ cnt))
    )
    It can also be written like this and the cnt value is 0 through 4.
    Code:
    (setq cnt -1)
    (while (< (setq cnt (1+ cnt)) 5)
      ;;  do some stuff
    )
    Sometimes the condition you want to test is set at the end of the code within
    the loop. The code may look like this.
    Code:
    (setq continue_loop t)
    (while continue_loop
      ;;  do some stuff
      (if (I want to leave the loop is true)
        (setq continue_loop nil) ; flag to exit the loop
      )
    )
    This can also be written like this:
    Code:
    (setq continue_loop t)
    (while 
      (progn
      ;;  do some stuff
       (not (I want to leave the loop is true)) ; flag to exit the loop
      ) ; progn
    )
    So you see that when (I want to leave the loop is true) returns true, the not will
    return nil and because it is the last expression in the progn, that is the value the
    while sees. It then exits the loop.


    Here is a real world example.
    This is my solution for entering numbers like key words
    The simulated key words would be "90 180 270 -90"
    Code:
    (while
      (progn
        (setq rang
               (cond ((getint "\nEnter the rotation angle [90/180/270] <90>"))
                     (90)))
        (if (not (vl-position rang '(90 180 270 -90)))
          (not (prompt "\nError  Angle must be 90 180 270, please re-enter.")))
      )
    )

    That's all for now.
    See ya.
    Last edited by CAB2k; 2007-09-27 at 02:47 PM.

Page 1 of 2 12 LastLast

Similar Threads

  1. Protected AutoLISP File
    By vipin_nair in forum AutoLISP
    Replies: 4
    Last Post: 2011-06-06, 02:04 PM
  2. AutoLisp File Size
    By BeKirra in forum AutoLISP
    Replies: 10
    Last Post: 2008-06-05, 06:41 PM
  3. Replies: 14
    Last Post: 2006-11-03, 10:44 AM
  4. Autolisp file viewer
    By rscudetto.61523 in forum AutoLISP
    Replies: 9
    Last Post: 2005-04-05, 03:31 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •