Originally Posted by
richards.64879
I've just started messing around with LISP programming, and came up with the following routine. I put this code together by browsing through the online developer documentation, and it illustrates several questions that arose along the way...
The code works, but a bunch of what I did seems really clunky to me, mostly because I seemed to be having typing issues. Having the getdist function return either a real or a string seemed to cause issues. It seemed like there should be an easier way of going about things...
I used a global variable to remember the offset distance between successive executions of the function, but is that how I should have done it? The routine also does no error-checking or handling. How should it handle a failure of the offset command (for example, if the selected item cannot be offset)? What else should I have done different?
Wow. I'm pretty impressed by this effort. You obviously have some programming background.
A global variable is easiest, so that is ok for this type of function. Alternatives would include Dictionaries/XRecords, one of the User?? system variables, or (a poor choice IMHO) the registry.
There isn't much error handling required in this case. The conditional branching took care of most of it, and AutoCAD's command pipeline takes care of the selected object cannot be offset error.
As you surmised, most of the improvements can be made in handling the default and input data types.
Here is my take on the function:
Code:
(defun C:OFS (/ prev prm ePick ptPick eNew)
(setvar "cmdecho" 0)
;;; there was no need to use a variable to store the CLayer
;;; initialize variable on 1 of 3 conditions:
;;; #1 if global is a string, it must be "Through"
;;; #2 if it is bound (but wasn't a string) it must be a number
;;; #3 if it wasn't bound at all, initialize global to "Through"
(setq prev (cond ((= 'STR (type *ZYZ_OFF*)) *ZYZ_OFF*)
(*ZYZ_OFF* (rtos *ZYZ_OFF*))
((setq *ZYZ_OFF* "Through"))))
;;; I prefer to explicitly show the bits used in (initget)
;;; Also, you may have forgot about 0 (why permit an offset of 0?)
(initget (+ 2 4 64) "Through")
;;; Might as well set the global to the user's input
;;; I also prefer to use (cond) since it allows for future conditions
;;; as opposed to nesting ifs
(setq *ZYZ_OFF* (cond ((getdist (strcat "Distance to offset or [Through] <" prev ">: ")))
(*ZYZ_OFF*))
prm (cond ((= 'REAL (type *ZYZ_OFF*)) "\nSelect side to offset: ")
("\nSelect through point: ")))
;;; Use clearer variable names; it costs nothing, and improves readabilty
(while (setq ePick (entsel "\nSelect entity to offset:"))
(redraw (car ePick) 3)
(cond ((setq ptPick (getpoint prm))
(command "_.offset" *ZYZ_OFF* ePick ptPick "")
(setq eNew (entget (entlast)))
;;; This is all you need to change the layer
(entmod (subst (cons 8 (getvar "CLayer")) (assoc 8 eNew) eNew))))
;;; Turn off highlight in cases where no ePick point is selected
(redraw (car ePick) 4))
(princ))