MarcoW Posted June 25, 2009 Posted June 25, 2009 I would like to have a lisp routine that does something that looks quite simple allthough I can't manage to programm it myself . This is what it should do. After command ie. "draw" I should be able to draw a pline or spline, promt (initget Pline Spline) with as many points as I need. When giving enter, "the pointing" stops. Until here it is all just a pline / spline. Then there should be prompted for the side of the second pline, ie. (initget L R). Or prompt to click for the desired side in offset to the first line, that might be even better. When giving L or R (or clickin the side) the second pline / spline should be created. Because the first and the second pline / spline are of a different layer and color it cannot be done with offset. It looks a lot like offset so maybe offset might come in handy...? This is what I have so far (clearly not working): ;;errorhandling when the lisp is ready, do not bother yet (defun c:draw (); make variables local when lisp ready (setq pt1 (getpoint "\nGive the first point: ") pt2 (getpoint "\nGive second point: ") pt3 (getpoint "\nGive third point: ") pt4 (getpoint "\nGive fourth point: ") ss (ssadd) ; Creating an empty selection set );end of setq How would I get to click as many points as needed? Now only 4 points are available - and those 4 points must be given !! An "enter" should go to the next step. BTW, "getpoint" I do not like, for the line is not visible when clicking. So I figured "getdist" would help but then I get strange way of drawing / selecting the points. (command "_.pline" pt1 pt2 pt3 pt4 "") (ssadd (entlast) ss) ; Add the polyline to the selection set I think ss get would be better instead of using "last". (command "offset" 50 ss) this would work but I don't wanna use the offset function for I want to create a new line on other layer. Selecting the side of wich the second pline should appear (initget "L R") (setq side (getkword "\nSecond line left or right of first line? (L/R) <R>: ")) Only L or R can be given while is same as R (cond ((= side "L") (then do this) ;; when given R or <Enter> ;; ------------ (t (do this ) (princ) );end of defun And how to put it all together? Quote
Lee Mac Posted June 25, 2009 Posted June 25, 2009 You made a good attempt at it Marco, you had some good ideas. Well Done. Here is how I would approach it, please read the comments: [b][color=RED]([/color][/b][b][color=BLUE]defun[/color][/b] c:draw [b][color=RED]([/color][/b][b][color=BLUE]/[/color][/b] *error* vl ov tmp cEnt pt[color=black] dEnt[/color][color=black] dObj[/color][b][color=RED])[/color][/b] [i][color=#990099];; Define Function and Localise Variables[/color][/i] [i][color=#990099];; Don't localise Curv:def, as it remains Global.[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]vl-load-com[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Load Visual LISP functions - for use later.[/color][/i] [i][color=#990099];; I find it easier to change object properties[/color][/i] [i][color=#990099];; using Visual LISP - it can be done in many ways,[/color][/i] [i][color=#990099];; but this is just my preference.[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]or[/color][/b] Curv:def [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] Curv:def [b][color=#ff00ff]"Spline"[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; First time default, as Curv:def will be nil otherwise.[/color][/i] [i][color=#990099];; Error Handler - as we are tampering with Sys Vars[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]defun[/color][/b] *error* [b][color=RED]([/color][/b]msg[b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]if[/color][/b] ov [b][color=RED]([/color][/b][b][color=BLUE]mapcar[/color][/b] [b][color=DARKRED]'[/color][/b][b][color=BLUE]setvar[/color][/b] vl ov[b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Reset Sys Vars[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]if[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]not[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]wcmatch[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]strcase[/color][/b] msg[b][color=RED])[/color][/b] [b][color=#ff00ff]"*BREAK,*CANCEL*,*EXIT*"[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]princ[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]strcat[/color][/b] [b][color=#ff00ff]"\n<< Error: "[/color][/b] msg [b][color=#ff00ff]" >>"[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]princ[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] vl [b][color=DARKRED]'[/color][/b][b][color=RED]([/color][/b][b][color=#ff00ff]"CMDECHO"[/color][/b] [b][color=#ff00ff]"OSMODE"[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Define a list of Sys Vars[/color][/i] ov [b][color=RED]([/color][/b][b][color=BLUE]mapcar[/color][/b] [b][color=DARKRED]'[/color][/b][b][color=BLUE]getvar[/color][/b] vl[b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Retrieve their Settings[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]initget[/color][/b] [b][color=#ff00ff]"Spline Pline"[/color][/b][b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]or[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]not[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] tmp [b][color=RED]([/color][/b][b][color=BLUE]getkword[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]strcat[/color][/b] [b][color=#ff00ff]"\nSpline or Pline? <"[/color][/b] Curv:def [b][color=#ff00ff]">: "[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] Curv:def tmp[b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Either the user has hit Enter, in which case we don't need to[/color][/i] [i][color=#990099];; change the value of Curv:def, else, the user has typed something[/color][/i] [i][color=#990099];; other than that of Curv:def, so we set it as the new default.[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]command[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]if[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]eq[/color][/b] Curv:def [b][color=#ff00ff]"Spline"[/color][/b][b][color=RED])[/color][/b] [b][color=#ff00ff]"_.Spline"[/color][/b] [b][color=#ff00ff]"_.Pline"[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Invoke Command[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]while[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]>[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]getvar[/color][/b] [b][color=#ff00ff]"CMDACTIVE"[/color][/b][b][color=RED])[/color][/b] [b][color=#009900]0[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Whilst the Command is active[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]command[/color][/b] pause[b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; pause for user input[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] cEnt [b][color=RED]([/color][/b][b][color=BLUE]entlast[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; Retrieve newly created Curve[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]if[/color][/b] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] pt [b][color=RED]([/color][/b][b][color=BLUE]getpoint[/color][/b] [b][color=#ff00ff]"\nSelect Side of Curve to Offset: "[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; If the user selects a point to offset[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]progn[/color][/b] [i][color=#990099]; Wrap the following[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]mapcar[/color][/b] [b][color=DARKRED]'[/color][/b][b][color=BLUE]setvar[/color][/b] vl [b][color=DARKRED]'[/color][/b][b][color=RED]([/color][/b][b][color=#009900]0[/color][/b] [b][color=#009900]0[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Turn off OSMODE, as we don't want it to affect the Offset.[/color][/i] [i][color=#990099];; Turn off CMDECHO, as we don't want to see the returns of[/color][/i] [i][color=#990099];; the offset at the command line.[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]command[/color][/b] [b][color=#ff00ff]"_.offset"[/color][/b] [b][color=#009900]50[/color][/b] cEnt pt [b][color=#ff00ff]""[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Perform Offset[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] dEnt [b][color=RED]([/color][/b][b][color=BLUE]entlast[/color][/b][b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Collect Offset Object[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]setq[/color][/b] dObj [b][color=RED]([/color][/b][b][color=BLUE]vlax-ename->vla-object[/color][/b] dEnt[b][color=RED])[/color][/b][b][color=RED])[/color][/b] [i][color=#990099];; Convert it to a VLA-OBJECT[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]vla-put-layer[/color][/b] dObj [b][color=#ff00ff]"0"[/color][/b][b][color=RED])[/color][/b] [i][color=#990099]; <<---- Change this to your layer[/color][/i] [i][color=#990099];; Set Object Layer[/color][/i] [b][color=RED])[/color][/b] [i][color=#990099]; End Progn[/color][/i] [b][color=RED])[/color][/b] [i][color=#990099]; End IF[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]mapcar[/color][/b] [b][color=DARKRED]'[/color][/b][b][color=BLUE]setvar[/color][/b] vl ov[b][color=RED])[/color][/b] [i][color=#990099]; Reset Sys Vars[/color][/i] [b][color=RED]([/color][/b][b][color=BLUE]princ[/color][/b][b][color=RED])[/color][/b] [b][color=RED])[/color][/b] [i][color=#990099]; End Draw[/color][/i] Quote
Lee Mac Posted June 25, 2009 Posted June 25, 2009 Also, you could use: (command "_.offset" "_L" ...) To change the layer of the offset object. Quote
MarcoW Posted June 25, 2009 Author Posted June 25, 2009 Lee, It is amazing, again how you fix it. I have printed out the routine to study it at home. Thank you again, you must have got your house full of thank you's ... Before I have read in to the routine I wanna ask you if you would enhance it if I would ask you politely. There are several things that would make it even better for my use. But before getting in to this, would you try to fix it? One of the thing ie. is to fillet the corners of the pline in a certain radius. Cheers mate. Quote
Lee Mac Posted June 25, 2009 Posted June 25, 2009 I'm happy to help you change the LISP in any way that you want, as long as you learn from it. Quote
Commandobill Posted June 25, 2009 Posted June 25, 2009 29 may 09 Yes, mine will not work for Attributed blocks, but will be quicker making the block than using the "command-call-cop-out" like yours... f3 ! Quote
Lee Mac Posted June 25, 2009 Posted June 25, 2009 f3 ! I know, I know, but I wanted Marco to learn from the LISP, and so wanted to keep it close to what he already had... btw, f3? Quote
Commandobill Posted June 25, 2009 Posted June 25, 2009 f3? lol it's to turn your osnaps on and off... "oh snap" Quote
Commandobill Posted June 25, 2009 Posted June 25, 2009 just in case it didnt catch on in england "Oh snap was a line used in the rap parody "Just a Friend" by Biz Markie. It became somewhat of a slang term for use following insult or surprise." http://wiki.ytmnd.com/Oh_Snap! Quote
MarcoW Posted June 26, 2009 Author Posted June 26, 2009 On topic again Hi Lee, After a little study...For you insisted; me getting to learn something! I guess that learning to read routines in the end wil provide me enough knowledge to write some routines myself. So I must READ. (defun c:draw (/ *error* vl ov tmp cEnt pt dEnt dObj) ;; Define Function and Localise Variables ;; Don't localise Curv:def, as it remains Global. By keeping the variable Curv;def global, the routine is set to use the chosen line (pline or spline) again when invoking it later in a session. Allrighty then. (vl-load-com) ;; Load Visual LISP functions - for use later. ;; I find it easier to change object properties ;; using Visual LISP - it can be done in many ways, ;; but this is just my preference. Visual Lisp is total new to me, so I thought "hey why don't download some tutorials". So I did that and now I have loads of information to go through. Ooff... Lucky me! From afralisp.net: Before you can use the VLisp functions with AutoLisp, you need to load the supporting code that enables these functions. The (vl-load-com) function first checks if the VLisp support is already loaded; if so, the function does nothing. If the functions are not loaded, (vl-load-com) loads them. (or Curv:def (setq Curv:def "Spline")) ;; First time default, as Curv:def will be nil otherwise. That one, I don't get. Am I correct when I say that the line (or Curv:def (setq Curv:def "Spline")) means: "This is an or function, when the variable curv:def is NIL then set it to "spline". If it is not NIL then leave it as it is, ie. when during previous use of this routine there is given pline." ;; Error Handler - as we are tampering with Sys Vars (defun *error* (msg) (if ov (mapcar 'setvar vl ov)) ; Reset Sys Vars (if (not (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")) (princ (strcat "\n<< Error: " msg " >>"))) (princ)) Error handling is necessary, I know, but I find it somewhat complicated. Starting with (defun *error* (msg) is standard. The used varible is msg, and then ...uh.. Especially the wcmatch I never saw before. (setq vl '("CMDECHO" "OSMODE") ; Define a list of Sys Vars ov (mapcar 'getvar vl)) ; Retrieve their Settings Create a list of system variables we want to read out in a sort of main variable vl. Set the variable ov (old variables) to the values as read out in vl. THe way it exactly works I do not know but I get whats going on... I guess... (initget "Spline Pline") (or (not (setq tmp (getkword (strcat "\nSpline or Pline? <" Curv:def ">: ")))) (setq Curv:def tmp)) ;; Either the user has hit Enter, in which case we don't need to ;; change the value of Curv:def, else, the user has typed something ;; other than that of Curv:def, so we set it as the new default. Let's give the user a choise, whether to choose for spline or pline. Note that the variable Curv:def was read out in the beginning of this routine. When first using the routine in a session it returns "spline" and else it returns which of both is chosen. The variable tmp will be set to whatever is chosen, next Curv:def is set to the value of tmp. Only thing I do not get is the part (or (not. Question, is or used to force a choise between the initget options? And then again, is not used to get the proper error message? (command (if (eq Curv:def "Spline") "_.Spline" "_.Pline")) ; Invoke Command When curv:def is equal to "spline" then command "_.spline" else command "_.pline". Right? Note the missing "" for ending the command. (while (> (getvar "CMDACTIVE") 0) ; Whilst the Command is active (command pause)) ; pause for user input It's a loop, as long as the command is active (until the "" or enter occurs) it loops back. (setq cEnt (entlast)) ; Retrieve newly created Curve Put the last created curve (pline or spline) in to the variable cEnt. (if (setq pt (getpoint "\nSelect Side of Curve to Offset: ")) ; If the user selects a point to offset Prompt for a side to offset. When pt is given then got to the prgn part. If pt is not given, ie. pressed escape button then go to the next part, called (mapcar 'setvar vl ov). So reset the system variables. (progn ; Wrap the following Why progn? I mean, why wrap? When not using progn, wouldn't it do the same? (mapcar 'setvar vl '(0 0)) ;; Turn off OSMODE, as we don't want it to affect the Offset. ;; Turn off CMDECHO, as we don't want to see the returns of ;; the offset at the command line. (command "_.offset" 50 cEnt pt "") ;; Perform Offset (setq dEnt (entlast)) ;; Collect Offset Object This makes sense to me. (setq dObj (vlax-ename->vla-object dEnt)) ;; Convert it to a VLA-OBJECT (vla-put-layer dObj "0") ; <<---- Change this to your layer ;; Set Object Layer That does not make sense to me, as said: I have to dig in to the vlisp tutorial. ) ; End Progn ) ; End IF (mapcar 'setvar vl ov) ; Reset Sys Vars (princ) ; exit cleanly ) ; End Draw Got the message. To be hounest: I am a bit unsure if I will be able to create such routines from scratch. 10 hours a day I am working, parts of it with autocad. And whenever my schedule allows me I can spend some time on programming. Maybe I should give it more time befor concluding the worst. Thanks in advance again for your reply. Quote
Lee Mac Posted June 26, 2009 Posted June 26, 2009 (or Curv:def (setq Curv:def "Spline")) ;; First time default, as Curv:def will be nil otherwise. That one, I don't get. Am I correct when I say that the line (or Curv:def (setq Curv:def "Spline")) means: "This is an or function, when the variable curv:def is NIL then set it to "spline". If it is not NIL then leave it as it is, ie. when during previous use of this routine there is given pline." Ok, some people are against using the or function in this way, and would rather use: (if (not Curv:def) (setq Curv:def "Spline")) If that makes things simpler. - However I like the use of or as it makes the code more concise. The way to think about it is that or keeps evaluating statements until a statement returns T, at which point it stops evaluating. Hence, if Curv:def has a value, then it is non-nil (remember that T is anything non-nil), and hence the (setq... will not be evaluated. And vice-versa. ;; Error Handler - as we are tampering with Sys Vars (defun *error* (msg) (if ov (mapcar 'setvar vl ov)) ; Reset Sys Vars (if (not (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")) (princ (strcat "\n<< Error: " msg " >>"))) (princ)) Error handling is necessary, I know, but I find it somewhat complicated. Starting with (defun *error* (msg) is standard. The used varible is msg, and then ...uh.. Especially the wcmatch I never saw before. If you look at the Visual LISP Editor help file on the wcmatch function, it is used to match a pattern within a string - hence I am using it to suppress the "cancelled" messages. If the error message does not contain the phrases listed, then it will be printed, else not. (setq vl '("CMDECHO" "OSMODE") ; Define a list of Sys Vars ov (mapcar 'getvar vl)) ; Retrieve their Settings Create a list of system variables we want to read out in a sort of main variable vl. Set the variable ov (old variables) to the values as read out in vl. THe way it exactly works I do not know but I get whats going on... I guess... vl is just a list of Strings. in this case the strings are the names of our System Variables. mapcar will execute the provided function (in this case getvar) on every item in the list, and return a list of the results. Hence, if the CMDECHO was 1, an OSMODE was 55, ov would be set to something like: (1 55) Depending on the values of the System Variables listed. (initget "Spline Pline") (or (not (setq tmp (getkword (strcat "\nSpline or Pline? <" Curv:def ">: ")))) (setq Curv:def tmp)) ;; Either the user has hit Enter, in which case we don't need to ;; change the value of Curv:def, else, the user has typed something ;; other than that of Curv:def, so we set it as the new default. Let's give the user a choise, whether to choose for spline or pline. Note that the variable Curv:def was read out in the beginning of this routine. When first using the routine in a session it returns "spline" and else it returns which of both is chosen. The variable tmp will be set to whatever is chosen, next Curv:def is set to the value of tmp. Only thing I do not get is the part (or (not. Question, is or used to force a choise between the initget options? And then again, is not used to get the proper error message? Ok, the or has nothing to do with the initget function. The initget function is set to allow the keywords listed, and also allows the user to hit enter - which would make the getkword return nil. Hence, using the logic described above: Either: 1) the getkword returns nil, hence the not getkword returns T - and so the second statement is not evaluated, so the Current value of Curv:def is used in the following statements. Or: 2) The getkword returns a non-nil value - and so the user has typed something, so the second statement will be evaluated, and so the value of curv:def will be set to this new input. (progn ; Wrap the following Why progn? I mean, why wrap? When not using progn, wouldn't it do the same? progn is used to "wrap" expressions so that they are treated as a single expression. IF would normally require three (or fewer) expressions: - a test expression - "then" expression - "else" expression And so, we use progn to wrap all the expressions that we want evaluated if the test expression returns t. So that the if statement treats them all as one expression. If the progn was not used, only the next expression would be evaluated, and then an error would ensue saying too many arguments. (setq dObj (vlax-ename->vla-object dEnt)) ;; Convert it to a VLA-OBJECT (vla-put-layer dObj "0") ; <<---- Change this to your layer ;; Set Object Layer That does not make sense to me, as said: I have to dig in to the vlisp tutorial. This, as I said, could be done differently, using the "layer" option in the "offset" command. Hope this helps, If you still don't understand something that I have written, just ask. Lee Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.