Total lenght of 3D polylines with different Z-values

Total lenght of 3D polylines with different Z-values

thomas.schive
Enthusiast Enthusiast
1,616 Views
11 Replies
Message 1 of 12

Total lenght of 3D polylines with different Z-values

thomas.schive
Enthusiast
Enthusiast

Hello!

 

I thought about writing a LISP that should add the lenght of all found polylines in a drawing. This sounds quite easy, and probably a lot of you guys who have done this before, but I have yet to find a routine that includes 3D polylines with a variable Z-value a long the line.

 

So, I began writing my own routine, but I got stuck quite early...

 

What I'm thinking is kind of like this:

 

1) User gets to choose wether he/she wants to select all 3D polylines, all 2D polylines or all polylines.

2) If the user chooses all 3D polylines, these lines will be selected, their lengths added together and a total presented to the user. Same with the other two options.

 

So I began like this:

 

(Defun C:LPA (/ tall 3dlines)

(prompt "\ Find the lenght of: 1 = All 3D pl, 2 = All 2D pl, 3 = All pl or ESC)

(setq tall (getstring "\ 1, 2, 3 or ESC"))

 

(if (= tall "1")

(progn

(setq 3dlines (sssetfirst nil (ssget "_X" '((0 . "POLYLINE")(-4 . "&")(70 . 8)))))

(setq totalnumber3d (sslength 3dlines))

 

;__ So, so far I can select  all 3D pl found in the drawing. Next up I wanted to get their lengths by using (command "_lengthen") for all the selected 3D polylines, extract their lengths and add them to each other in a list. And it is here where I could need some help s'il vous plaît. I suspect that it is done with a loop, maybe a foreach? Or is it better to get the lenghts by using vla-get-length somehow?

 

Thanks in advance.

 

/ts

 

0 Likes
Accepted solutions (1)
1,617 Views
11 Replies
Replies (11)
Message 2 of 12

DannyNL
Advisor
Advisor

Try this

 

(defun c:Test (/ T_Option T_Selection T_Total)
   (initget "All 3D 2D")
   (setq T_Option (getkword "\nSelect which polylines [All/2D/3D] <All>: "))
   (setq T_Option
      (cond
         (
            (or
               (not T_Option)
               (= T_Option "All")
            )
            "*POLYLINE"
         )
         (
            (= T_Option "2D")            
            "LWPOLYLINE"
         )
         (
            (= T_Option "3D")            
            "POLYLINE"
         )
         (
            T
            nil
         )
      )
   )
   (if
      (and
         T_Option
         (setq T_Selection (ssget "X" (list (cons 0 T_Option))))
      )
      (progn
         (setq T_Total 0)
         (foreach T_Entity (ssnamex T_Selection)
            (setq T_Total (+ T_Total (vla-get-Length (vlax-ename->vla-object (cadr T_Entity)))))
         )
         (princ (strcat "\nTotal polyline length: " (rtos T_Total)))
      )
   )
   (princ)
)
Message 3 of 12

thomas.schive
Enthusiast
Enthusiast

Thanks for another good answer!

 

The mechanism to calculate the lengths seems to work just fine, although I can't get it to separate between 3D and 2D (it chooses all lines), but I will try to work this part out 🙂

 

/ts

0 Likes
Message 4 of 12

DannyNL
Advisor
Advisor

Let me know if you can solve it.

If not, please post a (part of your) drawing so I'm able to see and investigate the differences of the polylines in your drawing and see why it doesn't separate 2D and 3D.

 

I've tested on my side with a normale polyline (LWPOLYLINE) and one drawn specifically with the 3DPOLY command (POLYLINE).

Message 5 of 12

thomas.schive
Enthusiast
Enthusiast

Hey, I "reconstructed" it a bit (mixed yours and mine) and it seems to work, besides that I need to put in something that makes it a bit more flexible when it comes to choosing which lines you want to measure. Chose to use a lot of if's to separate it and added some extra to the ssgets to make it separate between the 3D polys and the 2D ones.

 

(princ "Ecrivez LPA pour commencer ...");_ Melding til bruker etter innlasting.
(Defun C:lpa ( / T_valg T_valgtelinjer T_Entitet T_Total);_ Legg inn benyttete variable etter /.
    (initget "Alle 3D 2D")
    (setq T_valg (getkword "\ Velg hvilke polylinjer du vil summere lengdene til [Alle/2D/3D] <Alle>: "))
        (if (or (= T_valg "Alle")(= T_valg "3D")(= T_valg "2D"))
            (progn
                (if (= T_valg "Alle")
                    (progn
                        (setq T_valgtelinjer (ssget "_X" '((0 . "*POLYLINE"))))
                    );_ progn
                );_ if
                (if (= T_valg "2D")
                    (progn
                        (setq T_valgtelinjer (ssget "_X" '((0 . "LWPOLYLINE"))))
                    );_ progn
                );_ if
                (if (= T_valg "3D")
                    (progn
                        (setq T_valgtelinjer (ssget "_X" '((0 . "POLYLINE")(-4 . "&")(70 . 8))))
                    );_ progn
                );_ if
            (princ (strcat "Utvalget er satt til: " T_valg))
            );progn
        (print "Non! Ecrivez Alle, 2D eller 3D!")
        );_if for bestemmelse av T_valg    
    (setq T_Total 0)
                (foreach T_Entitet (ssnamex T_valgtelinjer)
                    (setq T_Total (+ T_Total (vla-get-Length (vlax-ename->vla-object (cadr T_Entitet)))))
                )
    (princ (strcat "\nTotal lengde: " (rtos T_Total)))
   (princ)
);_ defun finit

 

/ts

Message 6 of 12

DannyNL
Advisor
Advisor

Looks good! Good thinking to add the DXF code 70 to the SSGET. 

 

But I think you could leave out the -4 code as the result of the selection will be the same without it. Also you could bundle the different IF's into one COND statement.

However, that is only to make the code pretty and it will not change the result. Most important is that it works which it does Smiley Happy

Message 7 of 12

Kent1Cooper
Consultant
Consultant

@thomas.schive wrote:

....
                (if (= T_valg "2D")
                    (progn
                        (setq T_valgtelinjer (ssget "_X" '((0 . "LWPOLYLINE"))))
                    );_ progn
                );_ if
                (if (= T_valg "3D")
                    (progn
                        (setq T_valgtelinjer (ssget "_X" '((0 . "POLYLINE")(-4 . "&")(70 . 8))))
                    );_ progn
                );_ if

....


Careful....  There are 2D Polylines that are not LWPOLYLINEs.  The "POLYLINE" entity type name covers not just 3D Polylines, but also "heavy" 2D Polylines, which you can get from PLINETYPE being set to draw them that way instead of LightWeight, or from PEDITing a LWPolyline with the Fit or Spline option, or from the CONVERTPOLY command, and maybe from some other causes.  The distinction you make will miss those entirely, since one of those (ssget)s finds only LW ones and the other restricts itself to only 3D ones with the (70 . 8) ingredient.

 

You can also distinguish "heavy" 2D Polylines from 3D ones, even though their (assoc 0) value is the same, using the last (assoc 100) value in entity data:

 

(cdr (assoc 100 (reverse TheEntityDataList)))

 

returns "AcDbPolyline" for LW, "AcDb2dPolyline" for "heavy" 2D, and "AcDb3dPolyline" for 3D.  You can also get those from the "ObjectName" VLA Property.  It's a little odd that just "Polyline" is the portion after the AcDb prefix for LWPolylines, but its uppercase equivalent is the (assoc 0) value for the other  two kinds.

 

Unfortunately, you can't filter for that distinction in (ssget), because there's an earlier (assoc 100) entry in the list that gets in the way.  To be sure, you probably need to (ssget) for all "POLYLINE" entities and then step through and check for each one whether it's 2D or 3D.

 

You could  also use (vlax-curve-isPlanar) on entity names, which will return T for any LW or "heavy" 2D Polyline, but also for any 3D Polyline that lies in a flat plane, even if that's not parallel to the WCS or current UCS plane.

Kent Cooper, AIA
Message 8 of 12

stevor
Collaborator
Collaborator

 My do it, attached, maybe.

S
Message 9 of 12

thomas.schive
Enthusiast
Enthusiast

Hello!

 

Thanks for the reply Kent. So my selection set for "all" works, my set for 3D polylines works, but my set for 2D polylines filters out every "heavy weight" polyline - is that so? I'm not sure if I get how this filtering (to select both HW and LW polylines) is supposed to look in my code.

 

Should these two be included in the ssget somehow ("AcDbPolyline" & "AcDb2dPolyline")?

 

Also, another question ... In the start of my routine where the user chooses wether he'd like to calculate all, 3D or 2D, I've found out that my "standard option" for all doesn't work - you have to write "alle" to get it to work, it's not enough to click enter although it looks like it when you're using it - any tips to get it to choose "all" (alle in my routine), even if the user doesn't write it? As a standard option.

 

/ts

0 Likes
Message 10 of 12

DannyNL
Advisor
Advisor
Accepted solution

OK, taking Kent's comments into account, see the code below.

 

It will now select all polylines and check with vlax-curve-isPlanar if a polyline is contained in a plane or not. If true the polyline is considered a 2D polyline.

 

But be aware that it depends on your definition of a 2D polyline. If your definition is a flat polyline in any UCS this code will be accurate, but if your definition is a flat polyline in WCS with Z=0 this code needs to be modified and code needs to be added to check the vertice coordinates on WCS before deciding if a polyline is 2D or 3D.

 

Also setting "Alle" when a user presses enter is now handled at the beginning of the code

 

 

(princ "Ecrivez LPA pour commencer ...");_ Melding til bruker etter innlasting.
(Defun C:lpa ( / T_valg T_valgtelinjer T_Entitet T_Object T_Total);_ Legg inn benyttete variable etter /.
    (initget "Alle 3D 2D")
    (setq T_valg (getkword "\ Velg hvilke polylinjer du vil summere lengdene til [Alle/2D/3D] <Alle>: "))
    (if
        (not T_valg)
        (setq T_valg "Alle")
    )
    (if
       (or (= T_valg "Alle")(= T_valg "3D")(= T_valg "2D"))
       (progn
          (setq T_valgtelinjer (ssget "_X" '((0 . "*POLYLINE"))))
          (setq T_Total 0)
          (setq T_Count 0)
          (foreach T_Entitet (ssnamex T_valgtelinjer)
             (setq T_Object (vlax-ename->vla-object (cadr T_Entitet)))
             (if
                (or
                   (= T_valg "Alle")
                   (and
                      (= T_valg "3D")
                      (not (vlax-curve-isPlanar T_Object)) 
                   )
                   (and
                      (= T_valg "2D")
                      (vlax-curve-isPlanar T_Object)
                   )
                )
                (progn
                   (setq T_Count (1+ T_Count))
                   (setq T_Total (+ T_Total (vla-get-Length T_Object)))
                )
             )
          )
          (princ (strcat "\nTotal lengde for " (itoa T_Count) " polylinjer: " (rtos T_Total)))

       );progn
       (print "Non! Ecrivez Alle, 2D eller 3D!")
   );_if for bestemmelse av T_valg    
   (princ)
);_ defun finit

 

Message 11 of 12

thomas.schive
Enthusiast
Enthusiast

Thanks Danny! This seems to work just fine! Sending some wellearned kudos and an accepted solution your way.  🙂

 

/ts

0 Likes
Message 12 of 12

DannyNL
Advisor
Advisor

You're welcome and glad I could help Smiley Happy

0 Likes