Lisp help, explanations welcome.

Lisp help, explanations welcome.

annoisscary
Advocate Advocate
1,435 Views
20 Replies
Message 1 of 21

Lisp help, explanations welcome.

annoisscary
Advocate
Advocate

Okay, its been about a week since I started dipping my toes into learning/applying lisp and I feel like I'm starting to be able to understand what's written but I'm still not confident in coding something like this to do what I want it to.

To get to the point, I found a lisp on these forums written by BTK back in 2017 that I made some changes to that draws what we call muntin bars (mullion? mullions?) it doesn't *really* draw the bars per say but the lite pattern that results from whatever configuration you are going for. So far, so good. However, I find myself wondering if I can add an IF function that will draw the offset for a profile or stops with 45 degree miters in the corners of each lite, and at the same time ditch the "frame offset" that gets called up first completely.. Or in the name of possible functionality at least make it so I can enter a value of 0 for no offset.

 

I have attached a sample drawing and the lisp file in question showing what it is I'm trying to accomplish and have left a plethora of notes in the lisp trying to understand what its doing. I would be perfectly happy to be coached in the right direction of writing it myself, or just having a finished product with a brief explanation on what's new.  Any help is welcome (and needed), Thank you!

 

 

0 Likes
Accepted solutions (1)
1,436 Views
20 Replies
Replies (20)
Message 2 of 21

Sea-Haven
Mentor
Mentor

I have a window frame package that draws the white lines. Full control of sizes. 

 

SeaHaven_0-1664413518684.png

SeaHaven_1-1664413699065.png

Post me a PM if interested.

 

Adding the mitered mullions is possible. 

 

Anyway a quick way around it is enter offset then pick each pane, you now have the sizes so can work out the line work. Just select all panes and loop through.

 

(defun c:wow ( / off x k co-ord co-ord2)
(setq oldsnap (getvar 'osmode) oldlay (getvar 'clayer))
(setvar 'osmode 0)
(setq off (- (getreal "\nEnter offset ")))
(prompt "\nSelect inside only ")
(setq ss (ssget '((0 . "LWPOLYLINE"))))
(if (= ss nil)
(alert "no panes selected")
(progn
(repeat (setq x (sslength ss))
(setq ent (ssname ss (setq x (1- x))))
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget ent))))
(vla-offset (vlax-ename->vla-object ent) off)
(vla-put-layer (vlax-ename->vla-object (entlast)) "Geometry_0")
(setq co-ord2 (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (entlast)))))
(setq k -1)
(setvar 'clayer "Geometry_0")
(repeat 4
(command "line" (nth (setq k
 (1+ k)) co-ord)(nth k co-ord2) "")
)
)
)
)
(setvar 'osmode oldsnap)
(setvar 'clayer oldlay)
(princ)
)
(c:wow)

 

0 Likes
Message 3 of 21

annoisscary
Advocate
Advocate
While helpful I don't think this is quite what I'm looking for in this particular case. I have a lisp I can use for mass offsetting selection sets inside/outside. I'm wanting to attempt to fit everything into 1 routine to simplify things from running 2 and then drawing miters. On another note, that frame lisp you have looks mighty fine, but again I feel like it might not quite fit what I'm looking for. When we draw these bars the lines don't intersect so if they do you have to go back and manually trim and join everything up. I'm "okay" with the current one drawing what is basically the inverse because its faster to trim the border than the inside of the lines (in my opinion). However I would still be very much interested in playing around with it to see what I can get if thats an option.

Thanks for your input!
0 Likes
Message 4 of 21

annoisscary
Advocate
Advocate

On another note, I have been trying my hand at doing what I am asking starting with putting an IF function for whether or not it is TDL. I have been trying to get it right for awhile now and while I can get it to ask for whether its True or False, I can't for the life of me figure out how to evaluate the variable right. so both True AND False bring up the getreal prompt at the moment.  Again, any help appreciated. butchered code below (lol)


(initget "True False")
(setq tdl (getkword "Is this TDL? [True/False]:"))
(IF(= tdl True)(setq tdlxy (getreal "\nEnter Profile Width: ")))
(setq tdlxy 0)
;IF Function for TDL or SDL

 

 


***EDIT***

 

So I found a workaround, I'm sure this isn't the "proper" way to do this but its the only variation I have had any success with. so now the IF is this :

 

 

(initget "True False")
(setq tdl (getkword "Is this TDL? [True/False.]:"))
		  (IF(= (strlen tdl) 4)(setq tdlxy (getreal "\nEnter Profile Width: ")))
		  (setq tdlxy 0)
		  ;IF Function for TDL or SDL

 

 

I basically just made false be 5 chars long with the period at the end of it. Honestly though I have no clue if the ELSE part is working, i.e. if false setting tdlxy to 0.

 

Also I'm wondering what the purpose of all these (initget 7) lines are? can I just get rid of them?

 

(initget 7)
(setq frm (getreal "\nEnter Frame Offset: "))
;This offset for frame could honestly go but dont know how to get rid of it without breaking everything
(initget 7)
(setq xnum (getint "\nEnter Number of Columns (W): "))
(initget 7)
(setq ynum (getint "\nEnter Number of Rows (H): "))
(initget 7)
(setq xspace(setq yspace (getreal "\nEnter Bar Face: ")))
(initget 7)

 

***EDIT2***

Well apparantly I can just get of them, because I did and it seems like everything is working just fine.

Also, I figured out how to Completely remove the Frame offset from the code. Now for the first hard part, making the profile offset. I'll check in if I make any progress.

 

0 Likes
Message 5 of 21

ВeekeeCZ
Consultant
Consultant

IMHO, if you really want to learn anything, better grab the book and start from scratch. Only that way you use things that you know, understand or search and learn. 

 

Reading your comments, you don't understand INITGET, CONS, even a basic prompt is an issue. Basic things. BTW What stops you from looking into HELP ?

 

If lambda and mapcar are the problems (yet), use the other methods that you know.

(mapcar '(lambda (q p) (/ (+ q p) 2.)) pt1 pt2) returns a midpoint. It's a bit advanced to understand.

As a newbie, I would go with basic polar: (polar pt1 (angle pt1 pt2) (/ (distance pt1 pt2) 2))

0 Likes
Message 6 of 21

annoisscary
Advocate
Advocate

Well I have been looking up help for the different functions and such. I feel like I learn better by example and was just hoping to either have an example of something that works for the end goal or simply a suggestion of a different method, which you advice about polar fits into. I worked on this for a good while last night and I think I'm nearly there I'm just having some issues with getting the inner squares to array/size right. But I'm thinking I can probably get it working with some more work. That being said, still open to ideas.

0 Likes
Message 7 of 21

Kent1Cooper
Consultant
Consultant

@annoisscary wrote:
....
(initget "True False")
(setq tdl (getkword "Is this TDL? [True/False]:"))
(IF(= tdl True)(setq tdlxy (getreal "\nEnter Profile Width: ")))
....

The (initget)/(getkword) approach returns a text string, which will need its quotation marks:

....

(IF (= tdl "True") (setq tdlxy (getreal "\nEnter Profile Width: ")))

....

Kent Cooper, AIA
0 Likes
Message 8 of 21

ВeekeeCZ
Consultant
Consultant

In Excel TRUE/FALSE are symbols. In LISP are T/nil respectively.

0 Likes
Message 9 of 21

Kent1Cooper
Consultant
Consultant

Another little suggestion:  Don't make the choice of the type of divided lights whether it is true or false for one of the options, but rather directly between the two options:

(initget "True Simulated")
(setq tdl (getkword "Which type of divided lights? [True/Simulated]: "))
(if (= tdl "True") ....

Kent Cooper, AIA
0 Likes
Message 10 of 21

annoisscary
Advocate
Advocate
@Kent1Cooper
Ah, man. I'm actually kind of embarrassed I didn't figure that out. I was googling about evaluating strings because I knew it was turning it into one, but Couldn't figure out how to "read" the string to see if it matched.
That definitely helps, thanks!
also, the bit about picking between the types instead of true or false.. is that just a design choice or is there a bigger picture there?
0 Likes
Message 11 of 21

ВeekeeCZ
Consultant
Consultant

The mapcar is actually very nice for your case (= calculating offset point).

 

If you have a point as pt [x,y] and need to add some delta to both coordinates d [dx,dy], then result is pd [x+dx,y+dy]... then mapcar is a very natural tool to use: (mapcar '+ pt d)

 

And for your case...

 

0 Likes
Message 12 of 21

Kent1Cooper
Consultant
Consultant

@annoisscary wrote:
... the bit about picking between the types instead of true or false.. is that just a design choice or is there a bigger picture there?

The "bigger picture" if there is one comes when there are more than two options.  It shouldn't matter if there are only two, but you could, for example, have different mullion/muntin widths, both in true and simulated divided lights, and have all of them available within one choice among options, if you set it up right.  It also makes it clear what the choices are, though that may not be necessary for knowledgeable Users -- a less knowledgeable User might wonder at a prompt like "Is this TDL?" [as opposed to what?].

 

[Also, maybe I'm just subconsciously reacting against the potential for confusion of "True" as a text-string option and T as an AutoLisp symbol, but....

I think if I were doing it as a question of whether or not it's one of the choices, instead of as an explicit choice between specified options, with a prompt such as "Is this TDL?" I would be inclined to use "Yes/No" rather than "True/False".]

Kent Cooper, AIA
0 Likes
Message 13 of 21

annoisscary
Advocate
Advocate
Ah, okay I kind of understand your reasoning, for my application with this code I will only ever have two options, TDL or not TDL. and if TDL is true, the profile width is set to whatever is desired and the space between panes (or the face of the Bar) is set to whatever is desired. with just those 2 distances I think it should cover pretty much any iteration of bar & profile we make. On the subject of true of false, yeah i can see how that might be a little misleading. when I wrote it last night I didn't really understand how it checked for t or nil so I assumed you set it to true or false.

@ВeekeeCZ
The bit of code you supplied is so close to doing what it is I'm looking for with only 1 issue, the .5 offset on the outside is not needed. I think I can manage to make the adjustments myself but the help is very much appreciated!
0 Likes
Message 14 of 21

ВeekeeCZ
Consultant
Consultant
Accepted solution

Just a quick mod, not sure about getting it right. It might still require your hands.

Possibly can adjust the initget for the Bar Face if that could be zero.

0 Likes
Message 15 of 21

annoisscary
Advocate
Advocate

This is perfect! Thank you guys so much for your help, I have definitely learned a lot, still a long way to go before I can write anything like this from scratch though. I'll get there eventually, lol.

0 Likes
Message 16 of 21

Sea-Haven
Mentor
Mentor

When your making the plines you can add them to a list as they are created, then you would just run the code I provided as you now have a selection set, you would just add the code at the end of what you already have there would be no 2nd step, the code was created to show how to do it. 

 

Re True False this is my code

 

(if (not AH:Butts)(load "Multi radio buttons.lsp")) 			; loads the program if not loaded already
(setq ans (ah:butts 1 "V"   '("True or False" "True" "False"))) ; ans holds the button picked value as a string
(cond
((= ans "True")(do something 1))
((= ans "False")(do something 2))
)

 

 

SeaHaven_0-1664502379978.png

There is also a Acet function "Yes no" does something similar.

0 Likes
Message 17 of 21

Sea-Haven
Mentor
Mentor

Another attempt give it a try

 

; Modified by Alan H OCT 2022

(defun c:LP (/ frm xnum ynum xspace yspace xpane ypane pane pane2 ptc pt1 pt2 pt3 pt4 ptp1 ptp2 ptp3 ptp4)

(setq oldsnap (getvar 'osmode) oldlay (getvar 'clayer))

(setvar "CMDECHO" 0)
(setq ss (ssadd))
(initget 7)
(setq frm (getreal "\nEnter Frame Offset: "))
;This offset for frame could honestly go but dont know how to get rid of it without breaking everything
(initget 7)
(setq xnum (getint "\nEnter Number of Columns (W): "))
(initget 7)
(setq ynum (getint "\nEnter Number of Rows (H): "))
(initget 7)
(setq xspace(setq yspace (getreal "\nEnter Bar Face: ")))
(initget 7)
;Example of possible addition below
;
;(setq tdlx (setq tdly (getreal "\nEnter Profile Width: ")))
;Would ideally like to add an IF function that "triggers" this prompt
;Not sure how to code it but logically speaking it would be like so,
; IF TDL = True THEN getreal tdlx, tdly (both x and y would be same value so
;im assuming it could be one variable instead of two
;
(setq pt1 (getpoint "\nSelect Lower Left Window Corner: ")
     pt3 (getpoint pt1 "\nSelect Upper Right Window Corner: ")
     ;getpoints are fine, suitable selection method.
     pt2 (list (car pt3)(cadr pt1))
     pt4 (list (car pt1)(cadr pt3))
     ;Looks like the last 2 points are grabbed by using the opposites x and y
     ptc (mapcar '(lambda (q p) (/ (+ q p) 2.0)) pt1 pt3)
     ;dont really get this one, i know mapcar returns a list of executing a function
     ;but i dont really know what that realistically means
     ;pretty sure lambda is for defining temporary variables that aren't Defun'd
     ;but have no idea what the results of q and p are or why 2 is hard coded
     xlen (- (distance pt1 pt2) (* 2 frm))
     ylen (- (distance pt1 pt4) (* 2 frm))
     ;easy enough to understand, distance between 2 points minus the offset
     ;from either side for "actual" distance
     xpane (/ (- xlen (* (1- xnum) xspace)) xnum) 
     ;Am i reading the above right? xnum-1, *xspace, *xnum, -xylen, /xpane
     ;just trying to understand the structure
     ypane (/ (- ylen (* (1- ynum) yspace)) ynum)
     ptp1 (list (+ (car pt1) frm)(+ (cadr pt1) frm))
     ; the above sets ptp1 X and Y by first
     ;listing X from PT1 with CAR+frm and then lists Y from pt1 with CADR+frm, right?
     ptp2 (list (+ (car ptp1) xpane)(cadr ptp1))
     ptp3 (list (+ (car ptp1) xpane)(+ (cadr ptp1) ypane))
     ptp4 (list (car ptp1)(+ (cadr ptp1) ypane))
)
;Not 100% understanding the code above for defining the points but i get
;the gist of it, I dont know how the frame variable is interacting with everything
;which is why I haven't removed it myself. When i tried it threw everything out of wack
(entmakex (append (list (cons 0 "LWPOLYLINE")
                       (cons 100 "AcDbEntity")
                       (cons 100 "AcDbPolyline")
                       (cons 90 4)
                       (cons 70 1)
                       (cons 10 ptp1)
                       (cons 10 ptp2)
                       (cons 10 ptp3)
                       (cons 10 ptp4))))
;Looks like this draws a single square?
;not really clear on how cons works

(setq pane (entlast))
(setq pane2 (entlast))
(setq ss (ssadd pane ss))

;(setvar 'clayer "Geometry_0")
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget pane))))
(vla-offset (vlax-ename->vla-object pane) frm)
;(vla-put-layer (vlax-ename->vla-object (entlast)) "Geometry_0")
(setq ss (ssadd (entlast) ss))
(setq co-ord2 (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (entlast)))))
(setq k -1)
(repeat 4
(command "line" (nth (setq k  (1+ k)) co-ord)(nth k co-ord2) "")
(setq ss (ssadd (entlast) ss))
)
(setvar 'clayer oldlay)
;sets pane to the square made by to bit of code above right?

(setq ptc (mapcar '(lambda (q p) (/ (+ q p) 2.0)) ptp1 ptp2))
;ptc mapcar thing i dont really understand again

; (setq pane2 (entlast))
; huh? when did a second pane get made?


(cond
   ((AND (= ynum 1)(= xnum 1)) T)
   ((= ynum 1) (command "-array" ss  "" "R" ynum xnum (+ xpane xspace)))
   ((= xnum 1) (command "-array" ss  "" "R" ynum xnum (+ ypane yspace)))
   ((OR (> ynum 1)(> xnum 1)) (command "-array" ss "" "R" ynum xnum (+ ypane yspace) (+ xpane xspace)))
   (t nil)
)
;something to do with creating the array
(setvar 'clayer oldlay)
(princ)

)
(c:lp)

SeaHaven_0-1664592094480.png

 

0 Likes
Message 18 of 21

annoisscary
Advocate
Advocate

I appreciate your time, however I have already landed on a routine that does what I'm lookin for perfectly. not to mention I made quite a few changes to better suite my needs. However, with that in mind I decided to give this a shot and loaded it up and ran a few tests. For some strange reason I cant reproduce your results at all, in fact it seemed like every time I ran the routine I got something different than the last time. Not sure if it has anything to do with the fact that I'm using bricscad or not but I couldn't make sense of it. Clearly this works on your end so I'm sure it just some form of user error. Taking that all into account, I would hate to waste your time so Don't worry about making it work for me as I am quite happy with what I have at the moment.

0 Likes
Message 19 of 21

Sea-Haven
Mentor
Mentor

No worries, works with Bricscad

SeaHaven_0-1664597956432.png

 

0 Likes
Message 20 of 21

annoisscary
Advocate
Advocate

Strange, must be something weird going on with my home copy, even the routine I am using now does things a little odd like draw everything 10 ft away from the frame. Probably some setting I fat fingered at some point. (for reference it works exactly as intended on the work pc)

0 Likes