Lisp or native way to close polylines that appear closed but aren't

Lisp or native way to close polylines that appear closed but aren't

mpa-la
Advocate Advocate
5,819 Views
12 Replies
Message 1 of 13

Lisp or native way to close polylines that appear closed but aren't

mpa-la
Advocate
Advocate

Looking for a way to select many polylines at once and close the ones that have the same start and end point but aren't closed. I want to do this so that the linetype generation looks perfect (on non-continuous linetypes).  I do NOT want to close ones that do not have the same start and end point.  Thanks!

0 Likes
Accepted solutions (2)
5,820 Views
12 Replies
Replies (12)
Message 2 of 13

Ranjit_Singh
Advisor
Advisor
Accepted solution

Maybe try below. Something very quick and dirty. Minimal testing

(defun c:somefunc  (/ etdata lst)
 (mapcar '(lambda (x)
           (setq lst (cdr (reverse (vl-remove-if-not 'listp (mapcar 'cdr (setq etdata (entget x)))))))
           (if (equal (car lst) (last lst) 1e-6)
            (entmod (subst '(70 . 129) (assoc 70 etdata) etdata))))
         (vl-remove-if 'listp
                       (mapcar 'cadr
                               (ssnamex (ssget '((0 . "lwpolyline") (-4 . "<NOT") (-4 . "&") (70 . 1) (-4 . "NOT>"))))))))

apparently_close.gif

 I am using a fuzz factor of 0.000001 to check the proximity of start and end points. You can eliminate that to make sure the points truly lie on top of each other.

...............
           (if (equal (car lst) (last lst) 1e-6)
            .............
Message 3 of 13

mpa-la
Advocate
Advocate

Perfect!! I just tried it on 2514 polylines at once, and it worked perfectly.  Took about 10-15 seconds to run, but I can't imagine using it on more polylines than that at once, so that is no problem!

 

Thanks!!

0 Likes
Message 4 of 13

mpa-la
Advocate
Advocate

It does dump a boatload of text on the command line, I know there's an easy way to suppress that, but I don't recall how...

0 Likes
Message 5 of 13

Ranjit_Singh
Advisor
Advisor

Add a (princ) before the function close

(defun c:somefunc  (/ etdata lst)
 (mapcar '(lambda (x)
           (setq lst (cdr (reverse (vl-remove-if-not 'listp (mapcar 'cdr (setq etdata (entget x)))))))
           (if (equal (car lst) (last lst) 1e-6)
            (entmod (subst '(70 . 129) (assoc 70 etdata) etdata))))
         (vl-remove-if 'listp
                       (mapcar 'cadr
                               (ssnamex (ssget '((0 . "lwpolyline") (-4 . "<NOT") (-4 . "&") (70 . 1) (-4 . "NOT>")))))))
 (princ))
0 Likes
Message 6 of 13

Ranjit_Singh
Advisor
Advisor
Accepted solution

@mpa-la wrote:

.........Took about 10-15 seconds to run........


Try below. It maybe faster.

(defun c:somefunc  (/ etdata lst ctr ss1)
 (setq ss1 (ssget '((0 . "lwpolyline") (-4 . "<NOT") (-4 . "&") (70 . 1) (-4 . "NOT>")))
       ctr -1)
 (if ss1
  (repeat (sslength ss1)
   (setq lst (vl-remove-if-not '(lambda (x) (= 10 (car x)))
                               (setq etdata (entget (ssname ss1 (setq ctr (1+ ctr)))))))
   (if (equal (cdar lst) (cdr (last lst)) 1e-6)
    (entmod (subst '(70 . 129) (assoc 70 etdata) etdata)))))
 (princ))
0 Likes
Message 7 of 13

Kent1Cooper
Consultant
Consultant

Be aware, if it matters to you, that the routine closes them by adding a closing segment of zero length, that is, a triangular one will still have 4 segments, and 4 vertices with the 4th one in the same place as the 1st one.

 

For several routines designed to close them without  that added zero-length without the added zero-length segment [a triangular one ends up with segments and 3 vertices], see this thread.  Whatever you may find appropriate there would need to be modified [easy enough to do] if you want it to fix apparently-closed ones but leave clearly-unclosed ones alone, because that thread is about closing all selected Polylines, with the no-extra-segment part for those that look closed being a refinement.

Kent Cooper, AIA
Message 8 of 13

mpa-la
Advocate
Advocate

I should have kept a copy of the file with the 2000+ unclosed polylines so I could check the speed, but I didn't, so I can't compare the speed of the new with the old routine, but I'll assume the new one is better and go with that.

0 Likes
Message 9 of 13

mpa-la
Advocate
Advocate

Thanks Kent, that is good to know.  Having that extra segment in there shouldn't cause a problem.  You are correct, I don't want to close them all, just the apparently closed ones.

0 Likes
Message 10 of 13

Anonymous
Not applicable

This is a little simpler is an example but again adds a missing line 

 

 

(while (/= (setq obj (vlax-ename->vla-object (car (entsel)))) nil)
(vla-put-closed obj :vlax-true)
)

 

0 Likes
Message 11 of 13

Y.AUBRY
Advisor
Advisor

Hy from France, 

 

A simple way to close POLYLINE without lisp is to use the PEDIT command 

 

If you want to close all POLYLINE in the drawing the used

YAUBRY_1-1630399833764.png

 

 

If you want to close all POLYLINE in a previous selectionset the used

YAUBRY_0-1630399740937.png

 

Yoan AUBRY

EESignature

0 Likes
Message 12 of 13

mpa-la
Advocate
Advocate

That would close polylines with different end and beginning points, so a C shaped polyline would become an 0 shaped polyline, not what I wanted.  I only wanted to close polylines that appear closed, but are not.

0 Likes
Message 13 of 13

Kent1Cooper
Consultant
Consultant

In looking through this Topic again, one thing I notice about both accepted solutions above is that they force linetype generation on, whether or not it was on for a given Polyline.  If you want to preserve the linetype generation on/off status of Polylines, this does that, though it still only closes with a zero-length segment, leaving the coincident start/end vertices:

 

(vl-load-com); if needed
(defun C:CLPC
  ; = Closed-Looking Polyline Close [keeping coincident start/end vertices, with 0-length segment]
  (/ ss n pl pldata)
  (if (setq ss (ssget "_:L" '((0 . "lwpolyline") (-4 . "<NOT") (-4 . "&") (70 . 1) (-4 . "NOT>"))))
    (repeat (setq n (sslength ss))
      (setq
        pl (ssname ss (setq n (1- n)))
        pldata (entget pl)
      ); setq
      (if (equal (vlax-curve-getStartPoint pl) (vlax-curve-getEndPoint pl) 1e-6)
        (entmod (subst (cons 70 (1+ (cdr (assoc 70 pldata)))) (assoc 70 pldata) pldata))
      ); if [start/end at same place]
    ); repeat
  ); if [found unclosed Polylines]
  (princ)
); defun

 

[It also uses a different approach to some things, principally that it's not necessary to extract a list of all vertices in order to compare whether the start and end ones are in the same place.]

 

But I keep mentioning the zero-length closing segment and coincident start-end vertices issue [see Message 7], because there have been several topics raised here in which some routine didn't work right on Polylines, and it turned out the reason was that they contained coincident vertices.  They can definitely cause problems with certain operations.  If you want to take Polylines that look closed but are not really, and close them without keeping both vertices at the start/end location, and without a zero-length closing segment, this [a modification of something from the Topic linked at Message 7] will do that:

 

(vl-load-com); if needed
(defun C:CLPCE ; = Closed-Looking Polyline Close Eliminating coincident start/end vertices
  (/ ss n pl pldata)
  (if (setq ss (ssget "_:L" '((0 . "lwpolyline") (-4 . "<NOT") (-4 . "&") (70 . 1) (-4 . "NOT>"))))
    (repeat (setq n (sslength ss))
      (setq
        pl (ssname ss (setq n (1- n)))
        pldata (entget pl)
      ); setq
      (if (equal (vlax-curve-getStartPoint pl) (vlax-curve-getEndPoint pl) 1e-6)
        (progn ; then - edit off last segment, and close
          (command "_.pedit" pl "_edit"); end command
          (repeat (- (cdr (assoc 90 pldata)) 2) (command "_next")); move to next-to-last vertex
          (command "_break" "_next" "_go" "_eXit" "_close" "")
        ); progn
      ); if [start/end at same place]
    ); repeat
  ); if [found unclosed Polylines]
  (princ)
); defun

 

 

Kent Cooper, AIA
0 Likes