TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: daron on August 06, 2004, 04:27:44 PM
-
Can this be done?
First I tried this:
(defun c:aet (/ lpnt pmpt)
(setq lpnt (getvar "lastpoint"))
(defun cont ()
(initget "Undo")
(setq pmpt (getpoint lpnt "\nSelect end point Undo or [Enter] to exit: "))
)
(while pmpt ;;;I even tried cont here.
(cond ((or (/= pmpt nil) (/= pmpt "Undo"))
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
((= pmpt "Undo")
(command ".erase" "l" "")
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
)
)
(princ)
)
but I can't get the defun to repeat or something. I've also tried it as a lambda instead of defun.
This was a last resort.
(defun c:aet (/ lpnt pmpt)
(setq lpnt (getvar "lastpoint"))
(while (initget "Undo")
(setq pmpt (getpoint lpnt "\nSelect end point Undo or [Enter] to exit: "))
(cond ((or (/= pmpt nil) (/= pmpt "Undo"))
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
((= pmpt "Undo")
(command ".erase" "l" "")
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
)
)
(princ)
)
What do I need to do to use initget before getpoint and use getpoint as a while condition?
-
Try This...
(defun c:aet (/ lpnt pmpt)
(setq lpnt (getvar "lastpoint"))
(initget "Undo")
(while (setq pmpt (getpoint lpnt "\nSelect end point Undo or [Enter] to exit: "))
(cond ((or (/= pmpt nil) (/= pmpt "Undo"))
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
((= pmpt "Undo")
(command ".erase" "l" "")
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
)
(initget "Undo")
)
(princ)
)
-
Or This...
(defun c:aet (/ lpnt pmpt)
(setq lpnt (getvar "lastpoint"))
(while
(progn
(initget "Undo")
(setq pmpt (getpoint lpnt "\nSelect end point Undo or [Enter] to exit: "))
)
(cond ((or (/= pmpt nil) (/= pmpt "Undo"))
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
((= pmpt "Undo")
(command ".erase" "l" "")
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
)
)
(princ)
)
The (progn ...) can be extended with as many functions as desired.
-
...
(while (or (initget "Undo")(setq pmpt (getpoint ...)))
...
)
.. is yet another
-
Personally, I don't like using OR when I mean PROGN. It's confusing.
Sometimes, I might use OR or AND that way, because it works like a short-circuit operator (functions in the statement are evaluated until one of them is false for an AND or true for an OR, at which point the AND/OR terminates without executing any remaining instructions). But because of the syntax of Lisp, using AND or OR in this way also greatly reduces code readability, so I still don't really like it. It's probably better to use COND in this case - it makes intent clearer, even though it means extra parentheses (another Lisp syntax-decision that decreases readability).
YMMV.
-
Modualr programing my friend. Think on the conceptual level, not the level of process'.
How do functions like OR and AND take away from the readability of code when they are bacic logical functions of the language?
-
In Stig's example, the OR works exactly like a PROGN, but only because the initget always returns nil. You have to know that initget always returns nil for the intent of the code to be clear. The intent of PROGN, on the other hand, is obvious. The difference may not mean much to experienced programmers, but it can mean a world of difference to a less-experienced programmer trying to read the code, or even to an experienced programmer new to the environment.
-
I have to agree with sinc's basic premise -- clear intent is preferable to "clever" code.
-
Well, I think they are all interesting in the sense that it was a road I hadn't considered. Neither the OR nor the PROGN had I ever used for WHILE nor did I think it were possible. Both examples have broadened my horizons. Thanks.
CAB, (initget...) before the while would work the first time, but with each successive run through while will not call initget. That is why I was hoping to use the defun to make the successive calls. Thanks, though.
-
Daron, Take another look at CAB's code. Its very good; The last thing in the while loop is an initget. *Wink* His code is the reason why i didnt post mine. (His was better then mine. )
-
Thanks Se7en. I missed that. Sorry CAB. It's too early in the morning to catch all that.
I have another question related to the same code. I can't think of a good way to get the undo portion working. I'll repost what improvements I've come up with on this code. I'm thinking something recursive to append all the points selected to be able to undo and move the lastpoint to the correct point, but I don't want this to get bogged down or out of hand. Recursive or not, I think append is the direction I want to go, but I'm sure many of you guys have dealt with creating undo functions in this manner, I thought I'd just throw it out at you and see what more I can learn from you.
(defun c:aet (/ ptpnt endpnt lpnt pmpt)
(setq cmde (getvar "cmdecho")
omod (getvar "orthomode")
)
(setvar "cmdecho" 0)
(setvar "orthomode" 0)
(initget "Continue")
(setq stpnt (getpoint "\nSelect start point of arc or [<C>ontinue]: "))
(cond ((or (= stpnt "Continue") (= stpnt nil))
(setq lpnt (getvar "lastpoint"))
)
((or (/= stpnt "Continue") (/= stpnt nil))
(setq endpnt (getpoint stpnt "\nSelect end point of arc: "))
(command ".arc" stpnt "e" endpnt "d" pause)
(setq lpnt endpnt)
)
)
(while
(progn (initget "Undo")
(setq pmpt (getpoint lpnt "\nSelect end point, Undo or [Enter] to exit: "))
)
(cond ((or (/= pmpt nil) (/= pmpt "Undo"))
(command ".arc" "@" "e" pmpt "d" pause)
(setq lpnt pmpt)
)
((= pmpt "Undo")
(command ".erase" "l" "")
)
)
)
(setvar "cmdecho" cmde)
(setvar "orthomode" omod)
(princ)
)
Regardless of the undo portion not working correctly here, I get an error message that doesn't make sense.
Select end point, Undo or [Enter] to exit:
Select end point, Undo or [Enter] to exit: u
Invalid 2D point.
; error: Function cancelled
u should be a valid point with the initget call, but it's acting like it's not. I don't understand what's going on there. I tried or as well.
-
Daron, use AND instead of OR in the not-equal-to-Undo condition
-
Two suggestions:
(Fast solution) Look into bit 7 (value 128) for initget calls; trap non coordinate input and branch accordingly.
(Better solution) Consider a different approach than wrapping calls to command, .i.e. a function that gathers points etc. then calling entmake or vla-add-lwpolyline / arc / whatever as appropriate given a succesful selection of points / instructions.
My 2¢ :)
-
I'll look into all suggestions. The only problem I have with using entmake or vla-... is that I don't remember being able to have the arc visible when drawing it. I need to use pause to achieve that and command is the only way I'm aware to get that. Prove me wrong please!!! I'd love to not use command.
-
I'll look into all suggestions. The only problem I have with using entmake or vla-... is that I don't remember being able to have the arc visible when drawing it. I need to use pause to achieve that and command is the only way I'm aware to get that. Prove me wrong please!!! I'd love to not use command.
Without resorting to kludges (grdraw etc.) or 3rd party tools, the dynamic drawing (or ghosting) of the "budding" arc is not a practical avenue (imo) to mimic the arc command given the effort required. You're basically on the right track given your requirements (now that I better understand it), all you need to do is idiot (oops, bullet) proof the wrapper so it anticipates all potential inut and branches (sometimes ignoring) input accordingly. If I had time, and I apologise for participating here when I really don't, I'd push some bits for you. I'll try to help out here and there though. Cheers, M.
-
Daron, I would use the ARC command as you do it, also. About the undo option, I would build a list of points as the command progresses and use those points to backtrace during undo sessions.
Below is my suggestion for implementing the undo mechanism. I'll let the comments take over further explanation:
(defun c:aet (/ ptpnt endpnt lpnt stpnt pmpt undolst cmde init omod pmp)
(setq cmde (getvar "cmdecho")
omod (getvar "orthomode")
)
(setvar "cmdecho" 0)
(setvar "orthomode" 0)
;; instead of LASTPOINT (which can be set by numerous actions), I'd
;; suggest that you use a dedicated global point to continue from.
;; first, check if the global holds a point list
(cond ((vl-consp *aet_pt*)
;; ok, global point exists (highly probable at least)
;; go set up the prompt and initget option .. also set
;; lpnt to the global point
(setq pmp "\nSelect start point of arc or [<C>ontinue]: "
init "Continue"
lpnt *aet_pt*
)
)
;; no global exists .. just ask for initial point with no
;; initget options
((setq pmp "\nSelect start point of arc: "
init 0
)
)
)
;; go ask for point or option
(initget init)
(setq stpnt (getpoint pmp))
;; check result
;; if "Continue" or nothing then simply jump right into the loop
(cond ((or (not stpnt) (= stpnt "Continue")))
;; if not the above, get endpoint and start to build the
;; undo data list. Because CMDECHO is off, help the user
;; by issuing the standard prompt at the user input
((setq endpnt (getpoint stpnt "\nSelect end point of arc: "))
(princ
"\nSpecify tangent direction for the start point of arc: "
)
(command ".arc" stpnt "e" endpnt "d" pause)
(setq lpnt endpnt
undolst (list stpnt)
)
)
)
;; initialize the loop prompt
(setq pmp "\nSelect end point or [Undo]: ")
(while
(progn (initget "Undo")
(setq pmpt (getpoint lpnt pmp))
)
;; if Undo, then first check the undo data and see if it's
;; even possible to undo (otherwise do nothing but tell there
;; is nothing to undo)
(cond ((= pmpt "Undo")
(cond ((not undolst) (princ "Nothing to undo"))
;; if undo data exists: go erase the last arc,
;; reset lpnt to first occurence in the undo list
;; and chop off the "undid" point from the undo list
(T
(command ".ERASE" "Last" "")
(setq lpnt (car undolst)
undolst (cdr undolst)
)
)
)
)
;; if point is received: go draw the arc, append point
;; to the undo list and set lpnt to the new point.
;; again, help the user by issuing the standard prompt
(pmpt
(princ
"\nSpecify tangent direction for the start point of arc: "
)
(command ".ARC" lpnt "E" pmpt "D" pause)
(setq undolst (cons lpnt undolst)
lpnt pmpt
)
)
)
;; adjust prompt to reflect the status of the undo data
(setq pmp (if undolst
"\nSelect end point or [Undo]: "
"\nSelect end point: "
)
)
)
;; put last point up for later continuance
(setq *aet_pt* lpnt)
(setvar "cmdecho" cmde)
(setvar "orthomode" omod)
(princ)
)
-
Thank you Stig. I'll go test it and learn to better understand it.
-
You're welcome. Now to the home assignment: Implement a redo mechanism :)
-
Now that's something I hadn't even considered, but I'm not sure I see the need. I'll see what I can do though.
-
Who needs a need?
I was just trying to be amusing. Hope you can use the code I posted, Daron.
-
The code you posted is awesome. I've been using it all day. As far as a need goes, I'm going to try and improve on it by adding a line function and better than a redo function, I'd like to add a close function to it. I hope others find it useful, too.
Thanks again, Stig.
-
A possible refinement maybe???
Build a selection set as you go, then PEDIT the whole thing into a single pline when you're done?
-
Good idea. I'd like to get the line portion worked out before attempting that though. If you want to write a module for doing that, it might be a good exercise.
-
Good idea. I'd like to get the line portion worked out before attempting that though. If you want to write a module for doing that, it might be a good exercise.
umm... remember who yer talking to?? ...the thief/hack/cad-slug?? ...the only reason I kin rite my name is mom has it stenciled on my boxers.
-
Mmm. I thought you knew a little. No activeX here. All unleaded lisp. We're even using command.