View Full Version : Measuring pline lengths
Dan
16th Jun 2003, 03:01 pm
Afternoon chaps and chappetts
I have a landscape drawing with a large number of polylines that represent hedges (they are not joined), is there a way of collectively measuring all the polylines. I am using 2002, i can measure each line individually using the list tool but is there a way of collectivley measuring??
Thanks for anyones help. :D
hyposmurf
16th Jun 2003, 07:40 pm
How about the list command :idea: ,then select all your hedges and all your lenghts are listed for you,together with other information such as which layer the polylines are on etc.Problem you might have is figuring out which length applies to which polyline,but if your just using it for a total hedge length then its useful
CADTutor
16th Jun 2003, 11:18 pm
Dear friends, it's such a long time since I last did any serious LISPing but when Dan asked about measuring total lengths of polylines I had a strange sense of Deja Vu. Back in the deep mists of time I wrote a little routine to measure and report total length and or areas from all polylines on any layer. Anyway, here it is. The only modification I had to make to bring it up to date is that it now works with LW Polylines rather than the old "heavy" polylines.
Fuccaro, marks out of 10?
; Area and Length Measurement of LWPolylines by Layer
; David Watson 1995, updated 2003
;
(defun c:zone ( / ssl aret pert)
(princ "\nPick any entity on the required layer\n")
(setq ssl (ssget))
(if (= ssl nil)(princ "\n*** Nothing was selected! ***\n\n")
(progn
(setq lay (cdr (assoc 8 (entget (ssname ssl 0)))))
(setq ssl (ssget "X" (list (cons 8 lay))))
(princ (strcat "\nLayer " lay " selected"))
(initget "Length Area")
(setq res (getkword "\nWould you like to measure Length/<Area> : "))
(if (= res "Length")(mlen)(meas))
);end progn
);end if
(princ)
);END ZONE
(defun meas ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq aret 0)
(setq count 0)
(setq nop 0)
(setq ope 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (/= ple "LWPOLYLINE")
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(setq plc (cdr (assoc 70 (entget pnt))))
(if (= plc 0)
(progn
(setq ope (+ 1 ope))
(princ "\nWarning! *** Polyline is not closed\n")
);END PROGN
);END IF
(command "area" "e" pnt)
(setq are (getvar "area"))
(setq aret (+ are aret))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen entities were polylines")(princ (strcat "\n" (itoa nop) " non polyline entities were filtered")))
(if (= ope 0)(princ "\nAll polylines were closed")(princ (strcat "\n" (itoa ope) " polylines were not closed")))
(princ (strcat "\nTotal area for layer " lay " = " (rtos aret 2 0) "m2 or "(rtos (/ aret 10000) 2 2) " Ha in " (itoa alen) " areas"))
(princ)
);END MEAS
(defun mlen ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq pert 0)
(setq count 0)
(setq nop 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (/= ple "LWPOLYLINE")
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(command "area" "e" pnt)
(setq per (getvar "perimeter"))
(setq pert (+ per pert))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen entities were polylines")(princ (strcat "\n" (itoa nop) " non polyline entities were filtered")))
(princ (strcat "\nTotal length for layer " lay " = " (rtos pert 2 1) "m or " (rtos (/ pert 0.3048) 2 0) " feet in " (itoa alen) " lengths" ))
(princ)
);END MLEN
Happy measuring :D
Dan
17th Jun 2003, 08:45 am
Thanks for the response, I have never done any 'Lisping' before and I am sure there is a tutorial somewhere on this site but I cannot find it - could you please point me in the right direction. I have found your guid for Rel 14 but i am using 2002??
thanks again.
CADTutor
17th Jun 2003, 10:24 am
Dan - copy the code (all the green stuff) shown above. Paste into a new Notepad document. Save the document and call it zone.lsp - the "lsp" extension is important.
Start AutoCAD, go to Tools>AutoLISP>Load... or type APPLOAD at the command prompt. Select the file you just saved using the file navigation window and then click on the "Load" button. You should see a message on the command line and in the dialogue box telling you that zone.lsp was successfully loaded.
Once you have done this, you can use the routine just like any other AutoCAD command. simply type ZONE at the command line and follow the prompts.
This routine works by giving a total length or a total area of all polylines on any particular layer. If you want a total length for hedging, just put all your hedge polylines on a layer called "Hedges" or whatever and the routine will give the total length expressed in metres and feet. The routine assumes that drawing units are metres.
Let me know how you get on.
hyposmurf
17th Jun 2003, 01:47 pm
Loooks like in my rushihng about I missed the bit about you using the list command!Anyway I dug something else up on measuring polyline lengths:
How to calculate the LENGTH of polylines?
There are two ways:
the obvious, using the AREA command which is quite "noisy" (prints the result), but works even with splines.
;;; add up the LENGTH of all selected objects, NOISY, you can do the
;;; same with AREAs: simply change the last line to (getvar "AREA")
(defun C:LEN-OF ()
(command "_AREA" "_A" "_E") ;add up objects (works in R12+R13)
(ssmap 'command (ssget)) ;renamed, pass all elements to AutoCAD
(command "" "") ;two returns
(getvar "PERIMETER")) ;this is the length
Doing some math, but only for simple entities. Here is best to define some helper functions again. This is also an introduction for the next chapter [24], some bulge trigonometry for curved segments.
;;; calculates length of pline, quiet
(defun POLY-LENGTH (poly / seg)
(apply '+ ; the sum of all single segment lengths
(mapcar
'(lambda (seg) ;length of segment
(if (zerop (car seg))
(distance (cadr seg) (caddr seg)) ;line segment or
(abs (arclen seg seg)))) ;curved: see below at [24]
(pline-segs poly))))
;;; returns all group codes of the complex element
;;; (vertices, attributes) as list, similar to (edlgetent)
(defun CPLX-LIST (grp ele / lst)
(if (= 1 (getval 66 ele))
(progn (setq ele (entnext (entity ele)))
(while (and ele (not (istypep ele "SEQEND")))
(setq lst (cons (getval grp ele) lst)
ele (entnext ele)))
(reverse lst))))
;;; PLINE-SEGS - Creates a segment list for the polyline pname
;;; as a list of '(bulge p1 p2). A straight line has bulge 0.0
;;; Compute pts in ECS of pname. Accepts LWPOLYLINE's
(defun PLINE-SEGS (pname / pts segs)
(setq segs
(mapcar 'list
(if (istypep pname "LWPOLYLINE")
(group-only 42 (entget pname))
(cplx-list 42 pname))
(setq pts (getpts pname))
(rot1 pts))) ; ->[20.1]
(if (flagsetp 1 pname)
segs ;closed
(butlast segs))) ;open: without the last segment, ->[20.1]
;;; Example: (a bit optimized for brevity :)
;;; add up all the lengths of all polylines, QUIET
;;; To accept also other entities, add those to pline-segs
(defun C:POLYLEN ()
(apply '+ (ssmap 'poly-length (ssget '((0 . "*POLYLINE")))))) ; renamed
Maybe david's option is better but at least you have a choice
CADTutor
17th Jun 2003, 04:38 pm
Just couldn't help tinkering with the old code to make it more usable. The Zone routine now works with both LWPolylines and old-format Polylines. This covers for the posibility that you might be working with old drawings or have your PLINETYPE system variable set to 0 or 1. I also took the opportunity to change the word "entity" to the more modern "object" - gosh, how things have changed in 8 years :!:
; Area and Length Measurement of Polylines by Layer
; Works with both Lightweight (optimized) Polylines and old-format Polylines
; The PLINETYPE system variable is unaffected
;
; David Watson 1995, updated 2003
;
(defun c:zone ( / ssl aret pert)
(princ "\nPick any object on the required layer\n")
(setq ssl (ssget))
(if (= ssl nil)(princ "\n*** Nothing was selected! ***\n\n")
(progn
(setq lay (cdr (assoc 8 (entget (ssname ssl 0)))))
(setq ssl (ssget "X" (list (cons 8 lay))))
(princ (strcat "\nLayer " lay " selected"))
(initget "Length Area")
(setq res (getkword "\nWould you like to measure Length/<Area> : "))
(if (= res "Length")(mlen)(meas))
);end progn
);end if
(princ)
);END ZONE
(defun meas ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq aret 0)
(setq count 0)
(setq nop 0)
(setq ope 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (and (/= ple "LWPOLYLINE")(/= ple "POLYLINE"))
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(setq plc (cdr (assoc 70 (entget pnt))))
(if (= plc 0)
(progn
(setq ope (+ 1 ope))
(princ "\nWarning! *** Polyline is not closed\n")
);END PROGN
);END IF
(command "area" "e" pnt)
(setq are (getvar "area"))
(setq aret (+ are aret))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen objects were polylines")(princ (strcat "\n" (itoa nop) " non polyline objects were filtered")))
(if (= ope 0)(princ "\nAll polylines were closed")(princ (strcat "\n" (itoa ope) " polylines were not closed")))
(princ (strcat "\nTotal area for layer " lay " = " (rtos aret 2 0) "m2 or "(rtos (/ aret 10000) 2 2) " Ha in " (itoa alen) " areas"))
(princ)
);END MEAS
(defun mlen ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq pert 0)
(setq count 0)
(setq nop 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (and (/= ple "LWPOLYLINE")(/= ple "POLYLINE"))
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(command "area" "e" pnt)
(setq per (getvar "perimeter"))
(setq pert (+ per pert))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen objects were polylines")(princ (strcat "\n" (itoa nop) " non polyline objects were filtered")))
(princ (strcat "\nTotal length for layer " lay " = " (rtos pert 2 1) "m or " (rtos (/ pert 0.3048) 2 0) " feet in " (itoa alen) " lengths" ))
(princ)
);END MLEN
Feedback welcome.
Dan
18th Jun 2003, 04:17 pm
Thank you both for your help it has helped me no end. As my first 'lisp' I have become worringly excited about the potential of 'lisping'. David your way worked a treat and i am about to try the alternatives suggested by hyposmurf.
Could i ask you another question that has arrisen as a result of this lisp. In future i will make sure all drawings that may need to be measured are drawn as polylines (closed for area measurements). However when we draw polylines that have a zig zag line type, and the line is not straight, the line type is not consistant and looks bad on the drawings - so we use a spline. But you cannot measure a spline in the same way.
So my question is can you convert a spline to a polyline or how do you get a polyline line type to 'behave' around corners. I hope that makes sense it seems very long winded.
Thanks once again for your help :D :D :D :D
hyposmurf
18th Jun 2003, 04:50 pm
Heres a previous post that refers to converting splines to polylines
http://cadtutor.net/forum/viewtopic.php?t=154&highlight=spline
CADTutor
18th Jun 2003, 11:44 pm
You can use the "Ltype Gen" option of the PEDIT command to improve the look of linetypes along polylines.
Dan
19th Jun 2003, 09:09 am
Hyposmurf thanks for link. Excuse my ignorance but what do i do with a .VLX file???
David thanks for lintype tip.
Malo-Malone
14th Sep 2005, 08:07 pm
I was very interested in reading your response to reporting the length properties of the pline object, I am very new to the lisp scene so bear with me, I have a slightly similar problem and not being a guru on AutoCad, I thought I would ask someone who was.
The dilemma:
I am PM for a project that is basically drawing plines to represent cable runs., We have around 20 different types of cables (pline types) and need to report a BOM (Bill of materials) for our client.
The question is,
a: can I export pline data (layer, length, quantity) into Excel for easy manipulation.
b: Can autoCAD automatically produce a BOM on the drawing, maybe within a table, or
c: if linked to a database with the fields required, can AutoCAD populate the database.
I am just trying to find the quickest way of producing a BOM really, at the moment our AutoCAD guys are doing this manually which takes an awful long time and a little daft with todays software.
Any ideas/ help would be very much appreciated, I'm sure that someone has come accross this before... :cry:
Dear friends, it's such a long time since I last did any serious LISPing but when Dan asked about measuring total lengths of polylines I had a strange sense of Deja Vu. Back in the deep mists of time I wrote a little routine to measure and report total length and or areas from all polylines on any layer. Anyway, here it is. The only modification I had to make to bring it up to date is that it now works with LW Polylines rather than the old "heavy" polylines.
Fuccaro, marks out of 10?
; Area and Length Measurement of LWPolylines by Layer
; David Watson 1995, updated 2003
;
(defun c:zone ( / ssl aret pert)
(princ "\nPick any entity on the required layer\n")
(setq ssl (ssget))
(if (= ssl nil)(princ "\n*** Nothing was selected! ***\n\n")
(progn
(setq lay (cdr (assoc 8 (entget (ssname ssl 0)))))
(setq ssl (ssget "X" (list (cons 8 lay))))
(princ (strcat "\nLayer " lay " selected"))
(initget "Length Area")
(setq res (getkword "\nWould you like to measure Length/<Area> : "))
(if (= res "Length")(mlen)(meas))
);end progn
);end if
(princ)
);END ZONE
(defun meas ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq aret 0)
(setq count 0)
(setq nop 0)
(setq ope 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (/= ple "LWPOLYLINE")
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(setq plc (cdr (assoc 70 (entget pnt))))
(if (= plc 0)
(progn
(setq ope (+ 1 ope))
(princ "\nWarning! *** Polyline is not closed\n")
);END PROGN
);END IF
(command "area" "e" pnt)
(setq are (getvar "area"))
(setq aret (+ are aret))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen entities were polylines")(princ (strcat "\n" (itoa nop) " non polyline entities were filtered")))
(if (= ope 0)(princ "\nAll polylines were closed")(princ (strcat "\n" (itoa ope) " polylines were not closed")))
(princ (strcat "\nTotal area for layer " lay " = " (rtos aret 2 0) "m2 or "(rtos (/ aret 10000) 2 2) " Ha in " (itoa alen) " areas"))
(princ)
);END MEAS
(defun mlen ()
(setq len (sslength ssl))
(setq alen (sslength ssl))
(setq pert 0)
(setq count 0)
(setq nop 0)
(while (/= len count)
(setq pnt (ssname ssl count))
(setq ple (cdr (assoc 0 (entget pnt))))
(if (/= ple "LWPOLYLINE")
(progn
(setq nop (+ 1 nop))
(setq alen (- alen 1))
(princ "\nNon polyline filtered\n")
);END PROGN
(progn
(command "area" "e" pnt)
(setq per (getvar "perimeter"))
(setq pert (+ per pert))
);END PROGN
);END IF
(setq count (+ count 1))
);END WHILE
(if (= nop 0)(princ "\nAll chosen entities were polylines")(princ (strcat "\n" (itoa nop) " non polyline entities were filtered")))
(princ (strcat "\nTotal length for layer " lay " = " (rtos pert 2 1) "m or " (rtos (/ pert 0.3048) 2 0) " feet in " (itoa alen) " lengths" ))
(princ)
);END MLEN
Happy measuring :D
David Bethel
14th Sep 2005, 08:19 pm
Dan:
This link to the FAQ section also contains a version c:zone along with the loading instructions.
http://cadtutor.net/forum/viewtopic.php?t=2942
Malo-Malone:
Yes ACAD can make BOM and or tables via AutoLISP. It is usually a user / company specific type of project, so that generic routines don't normally cut it..
I am not an Excel kind of person, but I am sure it could also be done. -David
Malo-Malone
14th Sep 2005, 08:34 pm
Thanks David, very much appreciate your comments.
I would like to do something really simple rather than list, copy into Excel and then sort/ filter out stuff.
Basically I have set up separate layers for each pline (cable)
All I would really like to do is to just output the layer name and each instance of the pline on that layer, or even better have this information populated intto a simple table.
eg
Number Layer_Name PLINE
1 CABLE 1 100M
2 CABLE 1 50M
3 CABLE 1 23M
And then to repeat this for each layer.
Something I know must be simple but I have a really simple mind.... :shock:
Cheers for your help, very much appreciated
Kevin
David Bethel
14th Sep 2005, 10:12 pm
Kevin, It is not really that simple.
Here would be an engine that can gather the PLINE data:
(defun c:cable (/ ll output tdef ss i en hn)
(while (setq tdef (tblnext "LAYER" (not tdef)))
(setq ll (cons (cdr (assoc 2 tdef)) ll)))
(foreach l ll
(and (setq ss (ssget "X" (list (cons 0 "*POLYLINE")
(cons 8 l)
(cons 67 (if (= (getvar "TILEMODE") 1) 0 1)))))
(setq i (sslength ss))
(while (not (minusp (setq i (1- i))))
(setq en (ssname ss i)
hn (cdr (assoc 5 (entget en))))
(command "_.AREA" "_E" en)
(setq output (cons (list l hn (getvar "PERIMETER")) output)))))
(prin1 output)
(prin1))
-David
hendie
15th Sep 2005, 08:30 am
I was very interested in reading your response to reporting the length properties of the pline object, I am very new to the lisp scene so bear with me, I have a slightly similar problem and not being a guru on AutoCad, I thought I would ask someone who was.
The dilemma:
I am PM for a project that is basically drawing plines to represent cable runs., We have around 20 different types of cables (pline types) and need to report a BOM (Bill of materials) for our client.
The question is,
a: can I export pline data (layer, length, quantity) into Excel for easy manipulation.
b: Can autoCAD automatically produce a BOM on the drawing, maybe within a table, or
c: if linked to a database with the fields required, can AutoCAD populate the database.
Any ideas/ help would be very much appreciated, I'm sure that someone has come accross this before... :cry:
QA ~ Yes, you can collect and export any data to almost any program. Excel is okay but Access is better (for some things)
QB ~ Yes, you can automatically produce BoM's, Tables or any other data set you wish to.
QC ~ Yes, you can even make the Acad/Database bi-directional if you so wish, although it requires a lot more coding.
I produced a routine a while back that was very similar to what you describe. It was based on Pipe runs, not cable runs but that was the only difference (Autocad wouldn't know the difference.)
The routine automatically collected all the data on entities on a specific layer, calculated the total length, number of unions, bends, joins etc. Then created a BoM in the drawing, exported the BoM to Excel, formatted the Excel spreadsheet, inserted the BoM info, prepared a report, and costed the project.
It cut a days work down to about 20 seconds with one click of a button.
SO to answer your question... Yes, it can all be done very successfully.
Malo-Malone
15th Sep 2005, 12:25 pm
Great news David,
Is the routine you had written for sale?
Could be a starting point for me, I have exactly the same problem, too much time spent on producing BOM's.
Many thanks for your advice, it is very much appreciated.
Kind regards
Kevin
David Bethel
15th Sep 2005, 12:50 pm
Kevin,
While monies are seldom turned down, this type of snipets posted in public forums are usually there for the asking. Interestingly enough, they are protected by copyright laws. I doubt that these are truely enforcable in that the same type of operation has probably been created hundreds if not thousands of times before.
So feel free to grab code posted like this for your own use, unless the author has expressly forbidden it.
Converting a list of lists into a BOM easy a fairly straight forward task. Good luck! -David
Powered by vBulletin™ Version 4.1.2 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.