View Full Version : Anatomy of an AUTOLISP file
kennet.sjoberg
2006-06-28, 09:17 PM
Ok, share my beer and lisp code (defun c: :beer: ( / ) )
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
(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.
(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 :confused:
: ) Happy Computing !
kennet
kennet.sjoberg
2006-06-30, 12:00 AM
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: :beer: :beer: ( / ) )
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:
(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:
(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 :confused:
: ) Happy Computing !
kennet
Adesu
2006-06-30, 03:12 AM
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.
(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)
)
kennet.sjoberg
2006-06-30, 12:24 PM
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 :beer:
: ) 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 :beer: or two . .
kennet.sjoberg
2006-08-08, 11:12 PM
Ok, share my beer3 and lisp code (defun c: :beer: :beer: :beer: ( / ) )
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.
(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 :confused:
: ) Happy Computing !
kennet
pnorman
2006-08-11, 01:10 AM
What about this method. Combines error and variable handling into one easy to use function and also includes undo method.
;|
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
eachy
2006-08-12, 01:33 AM
;;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)
)
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
kennet.sjoberg
2006-10-28, 11:34 PM
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: :beer: :beer: :beer: :beer: ( / ) )
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 ; )
;;; ( 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
CAB2k
2006-11-17, 11:53 PM
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
(if (this is true)
(then do this)
)
(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.
(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
(or (a. is true) ; stop here
(b. does not get this far)
)
(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
(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.
(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
(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
(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
(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
(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.
(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.
(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:
(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.
(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.
(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.
(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.
(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:
(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"
(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.
kennet.sjoberg
2006-12-16, 12:09 PM
Well I have made some lisp code on my own, and gather some from around. . . .
So share my beer5 and how to load lisp code and use the functions
(defun c: :beer: : beer: : beer: : beer: :beer: ( / ) ) ; <-- ** Opie, please increase the icon limit level * *
Hmm.. there is a lot of different ways to load and use lisp code, and I will now try to enlighten a few of the ways.
If you are curious in just "code lines", and temporary want to test the code in the AutoCAD session you are in right now
to find out if it the code is useful for you, you can do like this:
1a.)
I will call this "Temporary AutoRun code"
Mark the code you are interested in from a starting parenthesis "(" to a ending parenthesis ")" like this
v--- mark from the starting parenthesis
(setq Counter 0 )
(repeat 10
(princ (setq Counter (1+ Counter )))
)
^--- to the ending parenthesis
copy it ( mouse button stupid ) and then paste it to the Command: line in the Command window in AutoCAD ( Yes ! )
you may need to press the [Enter] button after the paste function to execute the code, but then it will in this case run and show 1234567891010.
1b.)
Paste the code in to Vlide and investigate it with the tools in Vlide.
Start Vlide from inside AutoCAD, Command: vlide [Enter]
The second one is also temporary in the AutoCAD session and
2.)
I will call this "Temporary Run code at request."
Mark the code you are interested in from a starting defun parenthesis "(" to a ending code parenthesis ")" like this
v--- mark from the starting parenthesis
(defun c:test (/ Counter )
(setq Counter 0 )
(repeat 10
(princ (setq Counter (1+ Counter )))
)
(princ)
)
^--- to the ending parenthesis
And once again use the mouse button and copy and paste the code to the Command: line ( and press [Enter] if necessary )
(_> )
C:TEST
? ? ? What happened ? ? ?
Well, you have got a new temporary command in AutoCAD called "test" or in lisp terms (C:TEST ). Try it:
Command: test [Enter] ( for humans )
12345678910
or
Command: (C:TEST) [Enter] ( for programs )
12345678910
That was a CommandFunction = C:Function = C:TEST ( for humans )
Let us try the function for programs, no big difference just skip the c: and all hair style like the (princ)
(defun test (/ Counter )
(setq Counter 0 )
(repeat 10
(princ (setq Counter (1+ Counter )))
)
)
Try again to copy and paste the code to the Command: line
TEST
? ? ? What's happened now ? ? ?
I have got a new temporary program function loaded in AutoCAD called "test"
Try it:
Command: (test) [Enter] ( surrounding parenthesis, not for humans only for programs )
1234567891010
OK, now you can test part of a code cut'n paste (AutoRun)
Command functions for humans (defun c:test…Command: test
and functions for programs (defun test… Command: (test)
but all of those temporary in the AutoCAD session.
I have got a lisp file named test.lsp how do I load and use it ?
3.)
I will call this
"Temporary load a lisp file and run a function at request"
Save this code (copy and paste ) to a file named test.lsp, you can use Notepad.
v--- from the starting parenthesis
(defun c:test (/ Counter )
(setq Counter 0 )
(repeat 10
(princ (setq Counter (1+ Counter )))
)
(princ)
)
^--- to the ending parenthesis
Locate the newly created file test.lsp (or any other *.lsp file ) from Explorer, mark the file then drag and drop it in the AutoCAD drawing area ( YES ! ), the command window will response Command: (LOAD "MyDrive:/MyPath/test.lsp") C:TEST ( or similar )
Now you have a new temporary command named TEST ( or similar ) loaded.
Try it:
Command: test [Enter]
12345678910
4.)
But how do I do if I want the lisp command permanent in all AutoCAD's sessions ?
Load the lisp file in the start-up suit, I recommend the AcadDoc.lsp ( or acad.lsp ), I know there is a couple of other files in the start up suit "there it works to load lisp files", but please leave them alone they have their own particular purpose to fill.
Here is two ways to load/call the lisp file in AcadDoc.lsp,
you have to edit and add lines in AcadDoc.lsp and save it.
(load "test") ; use this line if the command always is used in the AutoCAD session
(autoload "test" '("test")) ; use this line if the command may be used in the AutoCAD session,
it will not load the function until the command is typed ( to save memory and avoid conflicts caused by bad programming. )
or this line give you a message if something is wrong
(princ (load "test" "** Error test.lsp not loaded **" ) )
If the file test.lsp is not in the AutoCAD search path you must include the path in the load line
(load"MyDrive:/MyPath/test.lsp") or
(load"MyDrive:\\MyPath\\test.lsp")
Next time you open a drawing, AutoCAD load the file AcadDoc.lsp that load your file test.lsp
and your command function is ready to be use as
Command: test
5.)
Beside this you can at least load lisp files from the CUI interface and also with appload,
but I prefer the fast and easy temporary way that drag'n drop from Explorer offer
and the fast and easy permanent way that AcadDoc.lsp offer.
Ok, what else ?? . . .beer and code, that make sense for me . . .or :confused: ?
: ) Happy Computing !
kennet
(defun c: :beer: : beer: : beer: : beer: :beer: ( / ) ) ; <-- ** Opie, please increase the icon limit level * *
kennet
Psst! you may have to show some ID and verify you have a DD before you get any more ;)
Good stuff, Kennet. Thanks.
kennet.sjoberg
2007-03-30, 02:07 PM
MAPCAR and LAMBDA . . is a long story to read from this LINK (http://forums.augi.com/showthread.php?p=680072#post680072)
: ) Happy Computing !
kennet
No beer is brought to you this time, jungsters.
vBulletin® v3.6.7, Copyright ©2000-2009, Jelsoft Enterprises Ltd.