Calculating Linear Footage in a drawing, including entities inside a block

Calculating Linear Footage in a drawing, including entities inside a block

Anonymous
Not applicable
1,637 Views
15 Replies
Message 1 of 16

Calculating Linear Footage in a drawing, including entities inside a block

Anonymous
Not applicable

 

Hi There,

 

 

I am having trouble finding an AutoLISP routine that would get all the lines, plines, arcs within a specific layer, named "TOTAL_LENGTH".  Some of the lines that belong to this layer are within a block.  I have seen a routine that works perfectly from Jeff Mishler on this post

 

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/calculate-linear-footage/td-p/133952...

 

(defun c:len_by_lay (/ ent idx lay len lname ss tot)
(vl-load-com)
(while (setq lay (tblnext "layer" (not lay)))
(setq lname (cdr (assoc 2 lay)))
(if (and (/= lname "0"); skip ;ayer "0"
(not (vl-string-position (ascii "|") lname)); skip Xref layers
(setq ss (ssget "x" (list (cons 8 lname)(cons 0 "LINE,LWPOLYLINE"))))
)
(progn
(setq tot 0.0
idx -1)
(while (< (setq idx (1+ idx))(sslength ss))
(setq ent (ssname ss idx)
len (vlax-curve-getdistAtParam ent
(vlax-curve-getEndParam ent))
tot (+ tot len)
)
)
(princ (strcat "\nTotal length of lines/plines on layer " lname " is: "
(rtos tot)))
)
)
)
(princ)
)

 

 

However,  I would like it to do a calculation of a single layer called "TOTAL_LENGTH" and include lines, plines, or arcs within all the blocks included in the drawing.

 

Please let me know, this would be a great help!

0 Likes
Accepted solutions (1)
1,638 Views
15 Replies
Replies (15)
Message 2 of 16

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... I would like it to do a calculation of a single layer called "TOTAL_LENGTH" and include lines, plines, or arcs within all the blocks included in the drawing. ....


[That routine could easily add Arcs, Circles, Ellipses, and Splines to the object types, if desired -- no change to the code would be needed other than expanding that string in the (ssget) filter and adjusting the wording of the reporting prompt.]

 

I saw your revival of that 12-year-old thread over in the Customization Forum, and hoped that you were looking to select objects, including Block insertions or preferably select the nested objects within them.  That would at least seem closer to possible than finding them all within all Blocks.  That's a really daunting task.  A routine would need to open up every Block definition in the drawing, step through every item in it to find those on that Layer [if any], calculate the length of each, and find the number of Insertions of each Block containing such objects, and if such Blocks are always and only Inserted at a uniform scale factor of 1, multiply it all out and add it all up.

 

BIG QUESTIONS:  Would such Blocks ever be inserted at other-than-1 scale factors?  Would they ever have different X and Y scale factors?  [If they might, not only would it need to find everything on that Layer in every Block definition, but for each Insertion individually, it would have to multiply the total length of such objects in that Block definition by a factor calculated from that Insertion's relative X and Y scale factors.]  Would any Blocks ever have dimension in the Z direction, and could any objects on that Layer ever extend in that direction, and not lie flat in or parallel to the XY plane?

Kent Cooper, AIA
Message 3 of 16

Anonymous
Not applicable

Thank you for your response Kent! really appreciate it!

 

Yes, I've been struggling for awhile with this issue, luckily I found this old thread 🙂

 

All the blocks would always be inserted at a scale factor of 1, all X and Y scale factors are the same, and these blocks would have 0 on their Z axis. some blocks will be repeated.  Could I perhaps use a list of block names for the search to be done? 

 

Again,  Thank you very much for taking the time to pay attention to my request.

0 Likes
Message 4 of 16

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... 

All the blocks would always be inserted at a scale factor of 1, all X and Y scale factors are the same, and these blocks would have 0 on their Z axis. some blocks will be repeated.  Could I perhaps use a list of block names for the search to be done? 

....


That certainly makes it more within the realm of possibility.  If only certain Blocks would contain anything on that Layer, and if there would be a lot of other Blocks that don't, then it's probably worth incorporating a list of applicable Block names, rather than having a routine plow through all Block definitions looking for such objects when it's not going to find any in most of them.  If there would be comparatively few that don't contain any, it may as well just plow through them all.

Kent Cooper, AIA
Message 5 of 16

Ranjit_Singh
Advisor
Advisor

Hi @Anonymous, what constitutes a block sub-entity being on the subject layer? The block is on the subject layer? or the block can be on any layer but the sub-entity is on the subject layer. Mostly all sub-entities are on layer 0 and block is on the subject layer. Is this the case in your drawing?

0 Likes
Message 6 of 16

Anonymous
Not applicable

Hi Ranjit, thank you for responding to my question.

 

I guess I should have explained the sole purpose of this routine.

 

I'm working on a retail roll-out that has blocked fixtures.  These fixtures are pretty standard, drag, drop, copy.  I would like to incorporate a line/pline inside the standard blocks, so that when it is pasted in the drawings, we don't need to re-draw these lines, and we can generate this total linear footage with a command, for merchandising purposes.  The fixtures will be on our FIXTURES layer, all sub entities are on the 0 layer.  I hope this clarifies it a bit.

0 Likes
Message 7 of 16

Ranjit_Singh
Advisor
Advisor

Yes. That clarifies quite a lot. In the original post you said "Some of the lines that belong to this layer are within a block" That confused me.

Try the below code. You call it by typing (somefunc "yourlayername") at the command prompt

(defun somefunc  (lay / edata ent lst)
 (mapcar '(lambda (x)
           (cond ((wcmatch (cdr (assoc 0 (setq edata (entget x)))) "*POLYLINE,ARC,LINE")
                  (setq lst (cons (getpropertyvalue x "length") lst)))
                 (t
                  (setq ent (cdr (assoc -2 (tblsearch "block" (cdr (assoc 2 edata))))))
                  (while ent
                   (and (wcmatch (cdr (assoc 0 (entget ent))) "*POLYLINE,ARC,LINE")
                        (setq lst (cons (getpropertyvalue ent "length") lst)))
                   (setq ent (entnext ent))))))
         (mapcar 'cadr (ssnamex (ssget "_x" (list (cons 0 "*POLYLINE,ARC,LINE,INSERT") (cons 8 lay))))))
 (apply '+ lst))

 

Message 8 of 16

Anonymous
Not applicable

Hi @Ranjit_Singh ,

 

Thank you very much for this routine, at first, I tried to run it when a line that belongs to the target layer, is outside the block, and it gave me the calculation (is it possible to change the unit into feet?), which works great!

 

When I placed it inside the block and ran the routine, it gave me this message: 

 

Command: (somefunc "TOTAL_LENGTH")
; error: bad argument type: lselsetp nil

 

not sure if I ran it properly.

 

I really appreciate you taking a look at this.  Thank you

0 Likes
Message 9 of 16

Ranjit_Singh
Advisor
Advisor

It basically cannot find any polyline, arc, line or block entities on that layer in your drawing. Do you have that layer in your drawing? Are the blocks on that layer? I may have misunderstood. Based on post 6 I understand that the blocks are on layer "TOTAL_LENGTH" and that is all that is needed for the routine to run. To make things simpler, paste a drawing with a few sample blocks and circle the ones which the routine needs to identify.

Message 10 of 16

Anonymous
Not applicable

Hi @Ranjit_Singh 

 

My apologies, the routine works beautifully, I did not realize that the drawing was in metric.  When I ran the routine into an imperial drawing, it worked.  However, our fixture blocks are on the "FIXTURES" layer.  it seems that when the block is in the "TOTAL_LENGTH" layer, it considers the "0" layered lines inside it as part of the calculation.  Is it possible for the function to ignore the "0" layered elements within the block? there is a line inside the block that belongs to the "TOTAL_LENGTH", and that is the one that I would like the calculation to capture, if possible.

 

 

Thank you very much, I hope I'm not taking up too much of your time.

0 Likes
Message 11 of 16

Ranjit_Singh
Advisor
Advisor

OK. Lets try below routine. This will ignore the layers that the blocks are inserted at, and basically go through every single block and get only the sub-entities in blocks that are on the correct layer. Also note that it will get any other entities on the correct layer that aren't in the block.

(defun somefunc  (lay / edata ent lst)
 (mapcar '(lambda (x)
           (cond ((and (wcmatch (cdr (assoc 0 (setq edata (entget x)))) "*POLYLINE,ARC,LINE")
                       (= (strcase lay) (strcase (cdr (assoc 8 edata)))))
                  (setq lst (cons (getpropertyvalue x "length") lst)))
                 (t
                  (setq ent (cdr (assoc -2 (tblsearch "block" (cdr (assoc 2 edata))))))
                  (while ent
                   (and (and (wcmatch (cdr (assoc 0 (setq edata (entget ent)))) "*POLYLINE,ARC,LINE")
                             (= (strcase lay) (strcase (cdr (assoc 8 edata)))))
                        (setq lst (cons (getpropertyvalue ent "length") lst)))
                   (setq ent (entnext ent))))))
         (mapcar 'cadr (ssnamex (ssget "_x" (list (cons -4 "<or") (cons 0 "INSERT") (cons -4 "<and") (cons 0 "*POLYLINE,ARC,LINE") (cons 8 lay) (cons -4 "and>") (cons -4 "or>"))))))
 (princ (strcat "Total Length = : " (rtos (apply '+ lst) 2 2) "'"))
 (princ))

Don't worry about my time. I am here because I enjoy coding in LISP. I guess everyone responding in these forums is here for the same reason, I maybe wrong though. 

Message 12 of 16

Anonymous
Not applicable

you are amazing @Ranjit_Singh

 

This worked flawlessly!!  I have two questions however.  First, is it possible to simplify the command to maybe TOTLNFT, and this would just automatically run the (somefun "total_length") command ? And second, would it be possible to divide the total length by 12, so I can get the answer in feet instead of inches?  I believe my unit setting for lengths determines the unit of the result.

 

 

Thank you thank you thank you so much, you are a life saver!

 

(on another note, do you have any suggestions as to how I can learn how to code?  I have started going through the courses on Afralisp.net, but if you have any other suggestions, I am fully open to it!)

0 Likes
Message 13 of 16

Ranjit_Singh
Advisor
Advisor
Accepted solution

OK. See below. Hopefully it works as you intend.

(defun c:TOTLNFT  ( / edata ent lst)
 (mapcar '(lambda (x)
           (cond ((and (wcmatch (cdr (assoc 0 (setq edata (entget x)))) "*POLYLINE,ARC,LINE")
                       (= (strcase "total_length") (strcase (cdr (assoc 8 edata)))))
                  (setq lst (cons (getpropertyvalue x "length") lst)))
                 (t
                  (setq ent (cdr (assoc -2 (tblsearch "block" (cdr (assoc 2 edata))))))
                  (while ent
                   (and (and (wcmatch (cdr (assoc 0 (setq edata (entget ent)))) "*POLYLINE,ARC,LINE")
                             (= (strcase "total_length") (strcase (cdr (assoc 8 edata)))))
                        (setq lst (cons (getpropertyvalue ent "length") lst)))
                   (setq ent (entnext ent))))))
         (mapcar 'cadr (ssnamex (ssget "_x" (list (cons -4 "<or") (cons 0 "INSERT") (cons -4 "<and") (cons 0 "*POLYLINE,ARC,LINE") (cons 8 "total_length") (cons -4 "and>") (cons -4 "or>"))))))
 (princ (strcat "Total Length = : " (rtos (/ (apply '+ lst) 12.0) 2 2) "'"))
 (princ))

I would recommend AutoCAD help. It lists every single function and even examples where necessary. Have your AutoCAD running and type every single code you come up with or find on these forums. See how it is evaluated. Ask your questions on these forums. Good luck.

Message 14 of 16

Anonymous
Not applicable

Hi @Ranjit_Singh  The solution that you've provided was perfect!  Thank you very much!

 

 

Now, I was wondering if it is possible to have the same outcome on this command, once I add lines into a dynamic block with different lengths for every visibility state?  I tried it, and it added up all the lines within the dynamic blocks, including each visibility state.  Is it too much to ask for this additional information? there's no rush or anything 🙂

 

 

Thank you again!

0 Likes
Message 15 of 16

Ranjit_Singh
Advisor
Advisor

I will give it a try. I honestly don't know if it is possible. But, we will find out Smiley Wink

Message 16 of 16

Anonymous
Not applicable

thank you @Ranjit_Singh you're the best!

0 Likes