Select 2D Plines (Light/Heavy) & 3D Plines by number of vertex ?

Select 2D Plines (Light/Heavy) & 3D Plines by number of vertex ?

braudpat
Mentor Mentor
1,779 Views
16 Replies
Message 1 of 17

Select 2D Plines (Light/Heavy) & 3D Plines by number of vertex ?

braudpat
Mentor
Mentor

Hello

 

I am looking for a Lisp Utility to select ALL 2D/3D Plines by number of vertex ... And I don't find it !?

2D Plines : light/heavy, closed or not, splined or not, curved or not

3D Plines : closed or not, splined or not

 

How I see the Routine :

 

1) Classic ACAD selection ...

2) Retain ONLY ALL 2D/3D Plines ...

3) Question 1 : Number of vertex (Default = 2) : ?

4) Question 2 : Which Test ( = , < , > , <= , >= Default: =  : ?

Of course : < 2 , = 0 , = 1 , etc, are forbiden !

So with 2 Return I will get ALL 2D/3D Plines with only 2 vertex !

5) Process ALL selected Plines depending on the test ...

6) At the end: get a selection of all concerned 2D/3D Plines ...

 

Do you see what I mean ?

 

Thanks in advance, THE HEALTH (Stay Safe, Stay Home, Stay Live), Regards, Patrice

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Accepted solutions (1)
1,780 Views
16 Replies
Replies (16)
Message 2 of 17

Kent1Cooper
Consultant
Consultant

For LightWeight Polylines, the DXF-90 entry in entity data is the number of vertices.  So this will "see" only 2-vertex LW Polylines among what the User selects:

(ssget '((0 . "LWPOLYLINE") (90 . 2)))

 

Some fancier filter code could accomplish the different tests [<  >  /=].

 

But that doesn't work for "heavy" Polylines [2D or 3D], because each vertex has its own entity name, and they're not stored under the umbrella of the overall Polyline in the same way they are for LW Polylines, so the selection can't be filtered for number of vertices.  One possibility is to have a routine see all  such Polylines in a selection, and step through checking the length of each one's Coordinates VLA property, to calculate the number of vertices, keeping in the selection only those with the desired number.  Is that worth pursuing?

Kent Cooper, AIA
0 Likes
Message 3 of 17

braudpat
Mentor
Mentor

Hello @Kent1Cooper 

 

Thanks for your attention !

 

YES Please I would like a general purpose Lisp routine ! ... For ALL kind of 2D/3D Plines !

 

I have updated my Topic and have added a DWG Test ...

 

THE HEALTH, Regards, Patrice

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Message 4 of 17

CodeDing
Advisor
Advisor

@braudpat ,

 

I don't work with 3D polylines or Splines much, so this was a good learning experience for me. I have created a function that returns what you're asking for. Hopefully you can find a good place to implement it somewhere into some existing code you have?

(defun c:TEST ( / nVerts ss)
  (initget 7) (setq nVerts (getint "\nEnter Number of Vertices: "))
  (if (setq ss (SSGetVerts nVerts))
    (progn
      (princ "\nHere's your selection set: ")
      (princ ss)
      (sssetfirst nil ss)
    );progn
  ;else
    (prompt "\nNo items returned with that number of vertices.")
  );if
  (princ)
);defun

(defun SSGetVerts (nV / ss1 ss2 e eg eType CheckAdd cnt tmp eTmp)
  ;nV - int, of # of vertices to retrieve of LWPOLYLINE,POLYLINE, or SPLINE
;returns - sel set, if 3dpoly, 2dpoly, or splines w/ matching # of vertices found, else nil (setq ss2 (ssadd)) (setq CheckAdd (lambda (n e) (if (= nV n) (ssadd e ss2)))) (if (setq ss1 (ssget '((0 . "*POLYLINE,SPLINE")))) (progn (repeat (setq cnt (sslength ss1)) (setq e (ssname ss1 (setq cnt (1- cnt)))) (setq eg (entget e)) (setq eType (cdr (assoc 0 eg))) (cond ((eq "LWPOLYLINE" eType) (CheckAdd (cdr (assoc 90 eg)) e) );cond 1 ((eq "POLYLINE" eType) (setq tmp 0) (setq eTmp e) (while (/= "SEQEND" (cdr (assoc 0 (entget (setq eTmp (entnext eTmp)))))) (setq tmp (1+ tmp)) );while (CheckAdd tmp e) );cond 2 ((eq "SPLINE" eType) (CheckAdd (cdr (assoc 74 eg)) e) );cond 3 );cond );repeat (if (> (sslength ss2) 0) ss2) );progn );if );defun

 

---Edit---

After seeing your posted drawing, this function does not appear to account for every possibility in the way you would expect.. Primarily when you change the "Fit/Smooth" property. I will have to look further into this issue..

 

Best,

~DD

Message 5 of 17

braudpat
Mentor
Mentor

Hello 

 

Thanks for your effort !

 

If possible please a complete defun c:xxxxx routine ?!

 

THE HEALTH, Regards, Patrice

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Message 6 of 17

Kent1Cooper
Consultant
Consultant

Here's something of a problem....  A routine like that needs to ask the User for the test to use on the number of vertices.  I tried the (initget)/(getkword) approach, but it turns out [Help says] that keywords can contain only letters, numbers and hyphens.  It seems that somehow  =  is also accepted, but not  <  or  > .  So some other way has to be found to ask that question -- it could be just (getstring), but the User then does not have the choice to pick  their option as would be the case in an (initget)/(getkword) operation.  Since keywords wouldn't involve any real abbreviation anyway, maybe it wouldn't matter that they need to type in the operation to use.  In quick trial I had trouble finding a way to convert [for example] "=" as a text string  into (=) as a function.  I tried (read) like this:

Command: ((read "=") 2 2)
bad function: =

and (quote) similarly.  But I find this can be used:

(apply (read "=") (list YourDesiredNumber ThePolyline'sNumberOfVertices))

Kent Cooper, AIA
0 Likes
Message 7 of 17

braudpat
Mentor
Mentor

Hello @Kent1Cooper 

 

Thanks for your effort !

 

OK so the second question (The Test) could be (only with letters) : equal , more , less , more_equal , less_equal , not_equal (or different) !?

 

Is it possible ?

 

THE HEALTH, Regards, Patrice

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Message 8 of 17

Kent1Cooper
Consultant
Consultant
Accepted solution

Because it's a little easier, here's a version that has the User type in the function [none more than 2 characters, so not much more work than the (initget)/(getkword) approach], and seems to work in your sample drawing:

 

(defun C:PSNV ; = Polyline Selection by Number of Vertices
  (/ ss test ref n pl verts)
  (if (setq ss (ssget '((0 . "*POLYLINE"))))
    (progn ; then
      (setq
        test (getstring "\nTest on number of vertices {type  =  or  /=  or  <  or  >  or  <=  or  >=}: ")
        ref (getint "\nNumber of vertices to compare to: ")
      ); setq
      (repeat (setq n (sslength ss))
        (setq
          pl (ssname ss (setq n (1- n)))
          verts
            (/
              (length (vlax-get (vlax-ename->vla-object pl) 'Coordinates))
              (if (member '(0 . "POLYLINE") (entget pl)) 3 2)
            ); / & verts
        ); setq
        (if (not (apply (read test) (list verts ref))); fails test?
          (ssdel pl ss); then -- remove from set
        ); if
      ); repeat
      (sssetfirst nil ss); select/highlight/grip what remains
    ); progn
  ); if
  (princ)
); defun

 

 

Kent Cooper, AIA
Message 9 of 17

Sea-Haven
Mentor
Mentor

Using vl may be simpler as already get 'C0ORDINATES use get-name

use cond and divide by correct number 2 or 3 length of co-ords for

"AcDb3dPolyline" = 3

"AcDbPolyline" = 2

"AcDbSpline" = 2

 

0 Likes
Message 10 of 17

Sea-Haven
Mentor
Mentor

Another way, but must check is closed 

 

 

 

(defun c:nvert ()
   (vl-load-com)
   (setq Pl_Ent (car (entsel "\nSelect polyline: ")))
   (setq VL_Obj (vlax-ename->vla-object Pl_Ent))
   (setq endParam (vlax-curve-getEndParam Vl_Obj))
    (if (= (vla-get-closed VL_obj) :VLAX-TRUE)
      (setq NumVert endParam)
      (setq NumVert (+ 1 endParam))
    )
   (princ (strcat "\n" (rtos NumVert 2 0) " vertices"))
   (princ)
)

 

 

 

 but must check is closed 

Message 11 of 17

ВeekeeCZ
Consultant
Consultant

Here's my version with a different 'UI' taken from another routine...

Kudos for Kent for the simple length approach to get a number of vertices.

 

(vl-load-com)

(defun c:SelectPolylinesVerticesRange ( / o1 v1 o2 v2 ss ed no s1 si)
  
  (setq si (ssget "_I" '((0 . "*POLYLINE"))))
  (initget "L LE E GE G")
  (setq o1 (cond ((getkword "\nSelect operation for first condition [L </LE <=/E =/GE >=/G >] : "))
		 ("E")))
  (initget 1)
  (setq v1 (getdist (strcat "\nNo. of vertices, " (nth (vl-position o1 '("L" "LE" "E" "GE" "G"))
						       '("Less than" "Less than or equal to" "Equal to" "Greater than" "Greater than or equal to"))
			    ": ")))
  (if (and (/= o1 "E")
	   (not (initget "L LE E GE G"))
	   (setq o2 (getkword (strcat "Select operation for second condition [" (if (wcmatch o1 "L*") "GE >=/G >" "L </LE <=") "] : ")))
	   )
    (setq v2 (getdist (strcat "\n" (nth (vl-position o1 '("L" "LE" "E" "GE" "G"))
					'("Less than" "Less than or equal to" "Equal to" "Greater than" "Greater than or equal to"))
			      ": "))))
  
  (princ "\nSelect *polylines or press  for ALL,")
  (if (setq s1 (ssadd)
	    ss (cond (si)
		     ((ssget '((0 . "*POLYLINE"))))
		     ((ssget "_A" '((0 . "*POLYLINE"))))))
    (repeat (setq i (sslength ss))
      (setq en (ssname ss (setq i (1- i)))
	    no (/ (length (vlax-get (vlax-ename->vla-object en) 'Coordinates))
		  (if (= "POLYLINE" (cdr (assoc 0 (entget en))))
		    3
		    2)))
      
      (if (and (apply (read (nth (vl-position o1 '("L" "LE" "E" "GE" "G"))
				 '("<" "<=" "=" ">=" ">")))
		      (list no v1))
	       (if v2
		 (apply (read (nth (vl-position o2 '("L" "LE" "E" "GE" "G"))
				   '("<" "<=" "=" ">=" ">")))
			(list no v2))
		 T)
	       )
	(ssadd en s1))))
  (if si (sssetfirst nil nil))
  (if (and s1 (> (sslength s1) 0)) (sssetfirst nil s1))
  (princ)
  )

 

 
Message 12 of 17

ВeekeeCZ
Consultant
Consultant

@Sea-Haven wrote:

Another way, but must check is closed 

...

 but must check is closed 


 

I was trying a parameter too... it's not the way to go. With more complex curvate settings it gets too complicated.

And as a top issue, I was not able to distinguish these two... EndParam, codes 70 or 75... all the same. Just too complicated for this purpose.

0 Likes
Message 13 of 17

Kent1Cooper
Consultant
Consultant

@Sea-Haven wrote:

Using vl may be simpler as already get 'C0ORDINATES use get-name

use cond and divide by correct number 2 or 3 length of co-ords for

"AcDb3dPolyline" = 3

"AcDbPolyline" = 2

"AcDbSpline" = 2


Splines are not  part of the problem, and never have been.  Only spline-curved Polylines, which are still Polylines.

Kent Cooper, AIA
Message 14 of 17

CodeDing
Advisor
Advisor

@braudpat ,

 

Do you need the # of "vertices" on a SPLINE (not 3dpolyline)? That can be quite complex..

If you DO, then what do you consider a "Vertex"? Control points? fit points? 

 

Best,

~DD

0 Likes
Message 15 of 17

braudpat
Mentor
Mentor

Hello @Kent1Cooper @CodeDing @ВeekeeCZ @Sea-Haven 

 

1) Thanks for your effort !

 

2) Question of Mr CodeDing concerning 2D/3D Plines which have been splined ! ...

 

3) For ME "Number of Vertex" (My first question) means :

Number of the Original Vertex (before Spline !)

Which are "in fact" the Blue Grips ...

 

Is it possible ?

 

THE HEALTH, Regards, Patrice

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Message 16 of 17

CodeDing
Advisor
Advisor

@braudpat ,

 

Here's my take. This seems to be working as expected for me. I have attached the .lsp file, but I am also posting the code. the command is SBV (Select By Vertices).

(defun GetMainVertices (e / eg eTmp egTmp eType plType lstVerts MultiAssoc VertCheck)
  ;e - ename, of LWPOLYLINE or POLYLINE
  ;returns - list, of Primary vertices of polyline
  (setq eg (entget e))
  (setq eType (cdr (assoc 0 eg)))
  (cond
    ((eq "LWPOLYLINE" eType)
      (setq MultiAssoc (lambda (k l / i) (if (setq i (assoc k l)) (cons (cdr i) (MultiAssoc k (cdr (member i l)))))))
      (setq lstVerts (MultiAssoc 10 eg))
    );cond 1
    ((eq "POLYLINE" eType)
      (setq eTmp e)
      (setq plType (cdr (assoc 70 eg)))
      (setq VertCheck
        (cond
          ((> (logand 2 plType) 0)           ;<-- Curve-fit vertices
            (lambda (i) (zerop i))           ;<-- Default vertex test
          );cond 1
          ((> (logand 4 plType) 0)           ;<-- Spline-fit vertices
            (lambda (i) (> (logand i 16) 0)) ;<-- Spline Control Points test
          );cond 2
          ((> (logand 8 plType) 0)           ;<-- 3D Polyline
            (lambda (i) (> (logand i 32) 0)) ;<-- 3D Polyline vertex test
          );cond 3
          (t (lambda (i) t))
        );cond
      );setq
      (while (/= "SEQEND" (cdr (assoc 0 (setq egTmp (entget (setq eTmp (entnext eTmp)))))))
        (if (VertCheck (cdr (assoc 70 egTmp)))
          (setq lstVerts (cons (cdr (assoc 10 egTmp)) lstVerts))
        );if
      );while
      lstVerts
    );cond 2
  );cond
);defun

(defun c:SBV ( / ss comparisons iStr gStr cnt compType nVerts e len)
  ;Select By Vertices
(prompt "\nSelect Polylines") (if (setq ss (ssget '((0 . "*POLYLINE")))) (progn ;Prep for user input/prompts (setq comparisons '( ("<" "Less Than") ("<=" "Less Than or Equal To") ("=" "Equal To") (">=" "Greater Than or Equal To") (">" "Greater Than") ));list/setq (setq iStr "" gStr "" cnt 1) (foreach comp comparisons (if (eq (car comp) (car (last comparisons))) (setq iStr (strcat iStr (itoa cnt) " ... " (car comp) " " (cadr comp)) gStr (strcat gStr (itoa cnt) " ... " (car comp) " " (cadr comp))) (setq iStr (strcat iStr (itoa cnt) " ... " (car comp) " " (cadr comp) " ") gStr (strcat gStr (itoa cnt) " ... " (car comp) " " (cadr comp) "/") cnt (1+ cnt)) );if );foreach ;Get user input (initget 1 iStr) (setq compType (nth (1- (atoi (getkword (strcat "\nSelect Comparison Type [" gStr "]: ")))) comparisons)) (initget 7) (setq nVerts (getint (strcat "\nNumber of Polyline Vertices must be " (cadr compType) ": "))) ;Do work (repeat (setq cnt (sslength ss)) (setq e (ssname ss (setq cnt (1- cnt)))) (if (not (and (setq len (length (GetMainVertices e))) ((eval (read (car compType))) len nVerts))) (setq ss (ssdel e ss)) );if );repeat
;Present final selset to user (if (> (sslength ss) 0) (progn
(sssetfirst nil nil)
(sssetfirst nil ss)
);progn
;else
(alert "No Polylines matched your criteria.") );if );progn );if (princ) );defun

 

---Edit---

Oh, and I forgot to mention that I was able to get the correct vertices from the Polylines, by checking the Polyline Entity Data (link) and then checking each Vertex Entity Data (link).

 

Best,

~DD

Message 17 of 17

braudpat
Mentor
Mentor

Hello @Kent1Cooper

 

1) THANKS !

 

2) I am impressed by the Kent Routine ... SO SHORT !

 

3) Thank you everybody for your attention !

 

THE HEALTH (Stay Safe, Stay Home, Stay Live), Regards, Patrice

 

 

 

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes