I have a lisp routine that creates a layer legend in your drawing. My apologies to the source who wrote it, I simply can't recall where I ran across it. It works pretty well, and with a couple tweaks it would be great.
It basically reads the layer table and creates a legend in your drawing. You have to have a height assigned first to your current text style, not a big deal (I can take care of that in the code) but it would be nice to not have to remember to do that but the main issue is that it sorts (possibly) on the order the layers were created in the file. It would be great if it sorted based on name, alphabetically. So can it be sorted first before it reads tblnext "Layer"?
I'm not technically a programmer so any help would be greatly appreciated. Again my apologies to the source. Thanks.
It is attached and here is the code:
(defun c:layerlegend (/ osm ortho clayer celtype cecolor start-point line-length text-height *error*)
(defun *error* (msg)
(setvar "osmode" osm)
(setvar "orthomode" ortho)
(setvar "clayer" clayer)
(setvar "celtype" celtype)
(setvar "cecolor" cecolor)
(princ msg)
)
(defun mfp (pt pa) (list (+ (car pt) (car pa)) (+ (cadr pt) (cadr pa)) (+ (caddr pt) (caddr pa))))
(setq osm (getvar "osmode"))
(setq ortho (getvar "orthomode"))
(setq clayer (getvar "clayer"))
(setq celtype (getvar "celtype"))
(setq cecolor (getvar "cecolor"))
(setq start-point (getpoint "\nSelect point to start legend: "))
(setvar "orthomode" 1)
(setq line-length (getdist start-point "\nEnter length of line or click end point: "))
(setq text-height (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
(setvar "osmode" 0)
(setvar "clayer" (cdr (assoc 2 (tblnext "Layer" T))))
(setvar "celtype" "ByLayer")
(setvar "cecolor" "ByLayer")
(command "_line" start-point (mfp start-point (list line-length 0 0)) "")
(command "-text" (mfp start-point (list 0 1 0)) "0" (getvar "clayer"))
(while (setq layer (tblnext "Layer"))
(setvar "clayer" (cdr (assoc 2 layer)))
(setq start-point (mfp start-point (list 0 (- 0 (+ text-height 4)) 0)))
(command "_line" start-point (mfp start-point (list line-length 0 0)) "")
(command "-text" (mfp start-point (list 0 1 0)) "0" (getvar "clayer"))
)
(setvar "osmode" osm)
(setvar "orthomode" ortho)
(setvar "clayer" clayer)
(setvar "celtype" celtype)
(setvar "cecolor" cecolor)
)
Solved! Go to Solution.
Solved by Kent1Cooper. Go to Solution.
@tmullins wrote:I have a lisp routine that creates a layer legend in your drawing. ....
It basically reads the layer table and creates a legend in your drawing. ....the main issue is that it sorts (possibly) on the order the layers were created in the file. It would be great if it sorted based on name, alphabetically. So can it be sorted first before it reads tblnext "Layer"?....
I don't think there's any way to sort the Layer table before stepping through it. You would need to make a list of Layer names, sort that, and step through it, using a name from the sorted list rather than from the Layer table at each step, something like this [untested]:
....
(while (setq lay (cdadr (tblnext "layer" (not lay)))); make list of Layer names
(setq laylist (cons lay laylist))
)
(foreach
lay
(vl-sort laylist '<); sorted alphabetically
(setvar 'clayer lay)
(setq start-point (mfp start-point (list 0 (- 0 (+ text-height 4)) 0)))
(command
"_line" start-point (mfp start-point (list line-length 0 0)) ""
"-text" (mfp start-point (list 0 1 0)) "0" lay ; [could leave (getvar 'clayer) in there]
)
); foreach
....
Thanks Kent, worked great!
Here is the revised code if anyone wants it:
(defun c:layerlegend (/ osm ortho clayer celtype cecolor start-point line-length text-height *error*)
(defun *error* (msg)
(setvar "osmode" osm)
(setvar "orthomode" ortho)
(setvar "clayer" clayer)
(setvar "celtype" celtype)
(setvar "cecolor" cecolor)
(princ msg)
)
(defun mfp (pt pa) (list (+ (car pt) (car pa)) (+ (cadr pt) (cadr pa)) (+ (caddr pt) (caddr pa))))
(setq osm (getvar "osmode"))
(setq ortho (getvar "orthomode"))
(setq clayer (getvar "clayer"))
(setq celtype (getvar "celtype"))
(setq cecolor (getvar "cecolor"))
(setq start-point (getpoint "\nSelect point to start legend: "))
(setvar "orthomode" 1)
(setq line-length (getdist start-point "\nEnter length of line or click end point: "))
(setq text-height (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
(setvar "osmode" 0)
(setvar "celtype" "ByLayer")
(setvar "cecolor" "ByLayer")
(command "_line" start-point (mfp start-point (list line-length 0 0)) "")
(command "-text" (mfp start-point (list 0 1 0)) "0" (getvar "clayer"))
(while (setq lay (cdadr (tblnext "layer" (not lay)))); make list of Layer names
(setq laylist (cons lay laylist))
)
(foreach
lay
(vl-sort laylist '<); sorted alphabetically
(setvar 'clayer lay)
(setq start-point (mfp start-point (list 0 (- 0 (+ text-height 4)) 0)))
(command
"_line" start-point (mfp start-point (list line-length 0 0)) ""
"-text" (mfp start-point (list 0 1 0)) "0" lay ; [could leave (getvar 'clayer) in there]
)
); foreach
(setvar "osmode" osm)
(setvar "orthomode" ortho)
(setvar "clayer" clayer)
(setvar "celtype" celtype)
(setvar "cecolor" cecolor)
)
hi, just come across this topic, and i give it a try to the lisp..after load the lisp and at command prompt, i type "layerlegend", somehow i see the end resut is just a line and a text above it..i just dun see any purpose or maybe i have misunderstand something..
@lai wrote:hi, just come across this topic, and i give it a try to the lisp..after load the lisp and at command prompt, i type "layerlegend", somehow i see the end resut is just a line and a text above it..i just dun see any purpose or maybe i have misunderstand something..
I haven't loaded it and run it, but some possibilities come to mind:
Does your drawing have more than one Layer in it? Is your current Text Style defined with 0 height? [I think the code is built for a fixed-height style.] Or, could it be a metric-vs.-imperial units issue? Is it truly "just a line," or might it be multiple lines very close together? And is it just one Text entity, or multiples on top of each other, or nearly so?
You need to change the "-text" command line to at least the following
(command "-text" (mfp start-point (list 0 1 0)) 5 "E" (getvar "clayer"))
and the line
"-text" (mfp start-point (list 0 1 0)) 5 "E" lay ; [could leave (getvar 'clayer) in there]
the 0 that was there is not setting the size of the text like it used to (Style override). (At least for AutoCAD 2010)
@RFCengr wrote:
You need to change the "-text" command line to at least the following
(command "-text" (mfp start-point (list 0 1 0)) 5 "E" (getvar "clayer"))
and the line
"-text" (mfp start-point (list 0 1 0)) 5 "E" lay ; [could leave (getvar 'clayer) in there]
the 0 that was there is not setting the size of the text like it used to (Style override). (At least for AutoCAD 2010)
The 0's involved were not for "setting the size of the text" [a Text command won't accept 0 for a height] -- they were for its rotation [you can use E instead if that fits your Units angular settings]. The code was written for use with a Text Style with fixed height, in which case there will be no height prompt, but you're obviously using a Style without that [with 0 defined height], in which case, yes, you will need to add something to answer the height prompt.
Hi, really thanks for the code!! It save me a lot of time!!
I found a problem in the code if you run it more than a time.
It duplicate the layer with the same name
I modified the first line of the code in this way to clean all the variable at the end of the routine.
(defun c:layerlegend (/ osm ortho clayer celtype cecolor start-point line-length text-height lay laylist *error*)
the entire code is now:
(defun c:layerlegend (/ osm ortho clayer celtype cecolor start-point line-length text-height lay laylist *error*) (defun *error* (msg) (setvar "osmode" osm) (setvar "orthomode" ortho) (setvar "clayer" clayer) (setvar "celtype" celtype) (setvar "cecolor" cecolor) (princ msg) ) (defun mfp (pt pa) (list (+ (car pt) (car pa)) (+ (cadr pt) (cadr pa)) (+ (caddr pt) (caddr pa)))) (setq osm (getvar "osmode")) (setq ortho (getvar "orthomode")) (setq clayer (getvar "clayer")) (setq celtype (getvar "celtype")) (setq cecolor (getvar "cecolor")) (setq start-point (getpoint "\nSelect point to start legend: ")) (setvar "orthomode" 1) (setq line-length (getdist start-point "\nEnter length of line or click end point: ")) (setq text-height (cdr (assoc 40 (tblsearch "style" (getvar "textstyle"))))) (setvar "osmode" 0) (setvar "celtype" "ByLayer") (setvar "cecolor" "ByLayer") (command "_line" start-point (mfp start-point (list line-length 0 0)) "") (command "-text" (mfp start-point (list 0 1 0)) "0" (getvar "clayer")) (while (setq lay (cdadr (tblnext "layer" (not lay)))); make list of Layer names (setq laylist (cons lay laylist)) ) (foreach lay (vl-sort laylist '<); sorted alphabetically (setvar 'clayer lay) (setq start-point (mfp start-point (list 0 (- 0 (+ text-height 4)) 0))) (command "_line" start-point (mfp start-point (list line-length 0 0)) "" "-text" (mfp start-point (list 0 1 0)) "0" lay ; [could leave (getvar 'clayer) in there] ) ); foreach (setvar "osmode" osm) (setvar "orthomode" ortho) (setvar "clayer" clayer) (setvar "celtype" celtype) (setvar "cecolor" cecolor) )
It is still necessary to set manually the hight of the text
This is a really great Lisp, Thank you @d.volo , @tmullins
One small request if it is easy enough. Can you modify the Lisp to 25 or so layer, then move to another column of 25? Instead of one long column that is 300+ layers?
My company is looking at moving from ctb to stb and reevaluating all our layer styles, etc. so I'm using this lisp a bunch of times.
Thanks Again!
@Patrick.G wrote:
.... Can you modify the Lisp to 25 or so layer, then move to another column of 25? Instead of one long column that is 300+ layers?
....
That would probably mean having some notion of the lengths of your Layer names in the current text font & height [in drawing units, not in characters]. Or possibly it could get the bounding box of each Layer name as it goes, and determine the right-most extent of any Layer name, to decide how far over to move for the next column. Would it be acceptable for the column spacings to vary, affected by the lengths of Layer names in each column?
@Kent1Cooper It didn't occur to me that the layer names could get in the way, I see your point. I was keeping the line length well beyond the text so that you can really see the style. I was thinking a default same distance between columns based on 0.15 times the length of the line entered? If that makes sense. So if you enter 15 units for the line length it makes the spacing 2.25.
If the name becomes too long, the user could make the line longer?
AS you do the cons make layer list do a strlen this gives number of characters multiply by Height or a fuzzy factor of height, monotext is widest. Save max length.