To Find Self Intersection of LWPOLYLINE

To Find Self Intersection of LWPOLYLINE

MehtaRajesh
Advocate Advocate
11,984 Views
123 Replies
Message 1 of 124

To Find Self Intersection of LWPOLYLINE

MehtaRajesh
Advocate
Advocate

Hi,

I am posting useful function to find Self Intersection for selected LWPOLYLINE.
You might be having other options, but I find this one as a quickest and Simple


(defun IsSelfIntersect (l / vcnt vcnt1 crossresult pt1 pt2 pt3 pt4)
(setq vcnt 0)
(setq crossresult F)
(repeat (1- (length l))
 (setq pt1 (nth vcnt l))
   (setq pt2 (nth (1+ vcnt) l))
   (setq vcnt1 vcnt)
 (setq isdone "T")
 (while isdone
  (if (and (nth (+ 2 vcnt) l) (nth (+ 3 vcnt) l))
  (progn
   (setq pt3 (nth (+ 2 vcnt) l))
   (setq pt4 (nth (+ 3 vcnt) l))
       (if (inters pt1 pt2 pt3 pt4)
   (progn
      (setq crossresult T)
   );progn
   );if
  );progn
  (progn
   (setq isdone nil)
  );progn
  );if
    (setq vcnt (1+ vcnt))
 );while
   (setq vcnt (1+ vcnt1)) 
);repeat
crossresult
);defun

Below Function to get the Coordinate list of LWPOLYLINE

(defun lwptslw (lst / pair rtn)
  (while (setq pair (assoc 10 lst))
    (setq rtn (cons (cdr pair) rtn)
   lst (cdr (member pair lst))
    )
  )
  (reverse rtn)
)

USAGE:
Command: (IsSelfIntersect (LWPTSLW (ENTGET (CAR (ENTSEL "\nSelect Lwpolyline to find Self Intersectioni")))))

Regards,
Rajesh

0 Likes
11,985 Views
123 Replies
Replies (123)
Message 101 of 124

АлексЮстасу
Advisor
Advisor

@marko_ribar 

1. I have written before that Scale is not necessary. We checked it this time too, removing scaling, and got the same results.
2. As before, I think it is better to replace Move with Copy to avoid losing the polyline under any circumstances.


@john.uhden 

3. I don't think it is necessary to consider the coincidence of the first and last vertices as self-intersection. For many AutoCAD commands this is the same as Closed.


4. Now the function accomplishes the task completely, the question of speed remains. A polyline with 4600 vertices is like an indicator. Previous variants ran for 17-25 seconds. This code variant is 2.5 minutes.


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 102 of 124

marko_ribar
Advisor
Advisor

@АлексЮстасу 

I've removed scaling, but remained moving from start point to 0,0,0 origin of WCS and upon finishing back from 0,0,0 to start point...

One overlapping point is now missing, due to failure of intersectwith method without scaling, but all in all everything else is good... Timing is now reduced to about 1 second, so no need for further code improvements... Here is the newest version - all the same, only removed scaling...

(defun c:selfinters ( / *error* selfsinfo unique selfinters cmd lw ti mult sp selfs )

  (or (not (vl-catch-all-error-p (vl-catch-all-apply (function vlax-get-acad-object) nil))) (vl-load-com))

  (defun *error* ( m selfs sp )
    (if (= 8 (logand 8 (getvar (quote undoctl))))
      (if command-s
        (command-s "_.undo" "_e")
        (vl-cmdf "_.undo" "_e")
      )
    )
    (if cmd
      (setvar (quote cmdecho) cmd)
    )
    (if m
      (progn
        (prompt "\n")
        (if selfs
          (selfsinfo selfs)
        )
        (prompt "\n")
        (prompt m)
        (princ)
      )
      (progn
        (prompt "\n")
        (if selfs
          (selfsinfo selfs)
        )
        (prompt "\n")
        (princ)
      )
    )
  )

  (defun selfsinfo ( selfs )
    (setq selfs (mapcar (function (lambda ( x ) (mapcar (function +) sp x))) (unique selfs 1e-12)))
    ;(setq selfs (mapcar (function (lambda ( x ) (mapcar (function (lambda ( y ) (* y 1e+6))) x))) (unique selfs 1e-12)))
    (princ
      (strcat "("
        (vl-string-right-trim " "
          (apply (function strcat)
            (mapcar
              (function
                (lambda ( x )
                  (strcat "("
                    (vl-string-right-trim " "
                      (apply (function strcat)
                        (mapcar
                          (function
                            (lambda ( y )
                              (strcat (rtos y 2 16) " ")
                            )
                          )
                          x
                        )
                      )
                    )
                    ") "
                  )
                )
              )
              selfs
            )
          )
        )
        ")"
      )
    )
  )

  (defun unique ( lst fuzz / a ll )
    (while (setq a (car lst))
      (if (vl-some (function (lambda ( x ) (equal x a fuzz))) (cdr lst))
        (setq ll (cons a ll) lst (vl-remove-if (function (lambda ( x ) (equal x a fuzz))) (cdr lst)))
        (setq ll (cons a ll) lst (cdr lst))
      )
    )
    (reverse ll)
  )

  (defun selfinters ( e sp mult / @2d @dupes pts dupes obj flat ints copy items css n leg d1 d2 d ppp ents selfs )

    ;; John F. Uhden (11-22-2024 through 12-17-2024)
    ;; Function finds all self intersections of a LWPolyline,
    ;;   including intersections between vertices and at vertices
    ;;   where parameters are not consecutive.
    ;; Returns a list of self intersections.
    ;; This version explodes a copy of the polyline
    ;;   and operates on each resulting segment.
    ;; This version places a red circle at each vertex
    ;;   and a slightly larger green circle at each self intersection.
    ;;   Feel free to remove or rem out the lines containing (entmakex ...).
    ;; I may try a version that does not copy or explode to see if it's faster.

    (defun @2d ( p ) (mapcar (function *) p (list 1.0 1.0)))

    (defun @dupes ( lst / a rtn )
      (while (setq a (car lst))
        (if (vl-position a (cdr lst))
          (setq rtn (cons a rtn))
        )
        (setq lst (cdr lst))
      )
      (unique rtn 1e-8)
    )

    (setq pts (mapcar (function cdr) (vl-remove-if (function (lambda ( x ) (/= (car x) 10))) (entget e))))
    (setq dupes (@dupes pts))
    (setq pts (unique pts 1e-8))
    (setq ppp pts)
    (setq ppp (mapcar (function (lambda ( x ) (mapcar (function +) sp x))) (unique ppp 1e-12)))
    ;(setq ppp (mapcar (function (lambda ( x ) (mapcar (function (lambda ( y ) (* y 1e+6))) x))) (unique ppp 1e-12)))
    (foreach p ppp (entmakex (list (cons 0 "CIRCLE") (cons 10 p) (cons 40 (* mult 0.2)) (cons 62 1))))
    (setq obj (vlax-ename->vla-object e))
    (setq flat (vlax-invoke obj (quote intersectwith) obj 0))
    (while flat
      (repeat 3 (setq item (cons (car flat) item) flat (cdr flat)))
      (setq ints (cons (@2d (reverse item)) ints) item nil)
    )
    (setq copy (vlax-vla-object->ename (vla-copy obj)))
    (vl-cmdf "_.explode" copy)
    (setq css (ssget "_P"))
    (setq ents
      (vl-remove-if
        (function listp)
        (mapcar
          (function cdr)
          (ssnamex css)
        )
      )
    )
    (repeat (setq n (sslength css))
      (setq leg (ssname css (setq n (1- n))))
      (foreach int (append ints pts)
        (if (vlax-curve-getparamatpoint leg int)
          (progn
            (setq d (vlax-curve-getdistatpoint leg int))
            (setq d1 (vlax-curve-getdistatpoint leg (vlax-curve-getstartpoint leg)))
            (setq d2 (vlax-curve-getdistatpoint leg (vlax-curve-getendpoint leg)))
            (if
              (and
                (not (vl-position int selfs))
                (or
                  (and
                    (or
                      (equal d d1 1e-8)
                      (equal d d2 1e-8)
                    )
                    (vl-some
                      (function
                        (lambda ( x )
                          (and
                            (vlax-curve-getparamatpoint x int)
                            (not (equal 0.0 (vlax-curve-getparamatpoint x int) 1e-8))
                          )
                        )
                      )
                      (vl-remove leg ents)
                    )
                  )
                  (vl-position int dupes)
                  (and
                    (not (equal d d1 1e-8))
                    (not (equal d d2 1e-8))
                  )
                )
              )
              (setq selfs (cons int selfs))
            )
          )
        )
      )
    )
    (setq ppp selfs)
    (setq ppp (mapcar (function (lambda ( x ) (mapcar (function +) sp x))) (unique ppp 1e-12)))
    ;(setq ppp (mapcar (function (lambda ( x ) (mapcar (function (lambda ( y ) (* y 1e+6))) x))) (unique ppp 1e-12)))    
    (foreach p ppp (entmakex (list (cons 0 "CIRCLE") (cons 10 p) (cons 40 (* mult 0.3)) (cons 62 3))))
    (vl-cmdf "_.erase" css "")
    selfs
  )

  (setq cmd (getvar (quote cmdecho)))
  (setvar (quote cmdecho) 0)
  (if (= 8 (logand 8 (getvar (quote undoctl))))
    (vl-cmdf "_.undo" "_e")
  )
  (vl-cmdf "_.undo" "_be")
  (if (setq lw (car (entsel "\nPick LWPOLYLINE to find self-intersecting points...")))
    (if (= (cdr (assoc 0 (entget lw))) "LWPOLYLINE")
      (progn
        (initget 6)
        (setq mult (cond ( (getdist "\nPick or specify multiplication factor for circles size <1.0> : ") ) ( 1.0 )))
        (setq ti (car (_vl-times)))
        ;(vl-cmdf "_.scale" lw "" "_non" (list 0.0 0.0 0.0) 1e-6)
        (vl-cmdf "_.move" lw "" "_non" (setq sp (vlax-curve-getstartpoint lw)) "_non" (list 0.0 0.0 0.0))
        (setq selfs (selfinters lw sp mult))
        (vl-cmdf "_.move" lw "" "_non" (list 0.0 0.0 0.0) "_non" sp)
        ;(vl-cmdf "_.scale" lw "" "_non" (list 0.0 0.0 0.0) 1e+6)
        (prompt "\nElapsed time : ") (princ (rtos (- (car (_vl-times)) ti) 2 16)) (prompt " milliseconds...")
      )
      (prompt "\nPicked wrong entity type... Picked entity must be LWPOLYLINE... Better luck next time...")
    )
    (prompt "\nMissed... Better luck next time...")
  )
  (*error* nil selfs sp)
)

 

Regards, M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 103 of 124

АлексЮстасу
Advisor
Advisor

@marko_ribar,

I didn't make it in 1 second:

Команда: SELFINTERS
Pick LWPOLYLINE to find self-intersecting points...
Elapsed time : 318047 milliseconds...
Команда: SELFINTERS
Pick LWPOLYLINE to find self-intersecting points...
Elapsed time : 208078 milliseconds...
((7653912.613957368 6229064.962335566) (7653912.613957532 6229064.962335717))
Команда: SELFINTERS
Pick LWPOLYLINE to find self-intersecting points...
Elapsed time : 169422 milliseconds...
((7653288.087277066 6229052.952317797) (7653288.08727723 6229052.952317947) (7652990.315149783 6229574.36978839) (7652990.079111385 6229574.941561909))

SELFINTERSMR3.png


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 104 of 124

john.uhden
Mentor
Mentor

@marko_ribar ,

Might it be that the OP is too old?

No way.  I'll betcha that I am older than he is (or was).  🤔

John F. Uhden

0 Likes
Message 105 of 124

АлексЮстасу
Advisor
Advisor

@john.uhden, this task predates the birth of OP. 🙂

 

We found an AutoCAD command that will declare self-intersections of non-closed polylines - _REVOLVE.
This may be needed for a function that returns only T or nil - in some cases this may be enough.
So could complete that cheating solution from #42, which worked exceptionally fast.
But we don't have the qualification to intercept the execution of this command in the absence of self-intersections. Otherwise, on polylines with thousands of vertices it can take a very long time to execute.
Is there no analog for _REVOLVE execution with vla- or similar?


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 106 of 124

john.uhden
Mentor
Mentor

@АлексЮстасу ,

So I guess you're not taking my bet.  😞

 

Nope.  I have never heard of the "Revolve" command.

OMG, it is in my 2002!  I don't understand what it does but it's fascinating.

John F. Uhden

0 Likes
Message 107 of 124

АлексЮстасу
Advisor
Advisor

@john.uhden,

I responded to your bet in #92, #95, #97.

 

Both are needed:
- Need a function to get a very fast T or nil on self-intersections/overlaps for use in programs that create Regions, Hatches, calculate Areas, do Offset, etc.
- Need a program to detect self-intersection/overlap points - manually searching for them is difficult and time-consuming.

 


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 108 of 124

marko_ribar
Advisor
Advisor

Hi @АлексЮстасу 

I think that faster than this can't be created by using LISP and Solid modelling operations...

(defun c:chkselfint ( / chkselfint cu rtn ti )

  (defun chkselfint ( cu / el ll )
    (setq el (entlast))
    (while (entnext el)
      (setq el (entnext el))
    )
    (if (= 8 (logand 8 (getvar (quote undoctl))))
      (vl-cmdf "_.UNDO" "_E")
    )
    (vl-cmdf "_.UNDO" "_BE")
    (vl-cmdf "_.EXTRUDE" cu "" 1.0)
    (while (< 0 (getvar (quote cmdactive)))
      (vl-cmdf "")
    )
    (while (setq el (entnext el))
      (setq ll (cons el ll))
    )
    (vl-cmdf "_.U")
    (> (length ll) 1)
  )

  (if (setq cu (car (entsel "\nPick curve to determine if it's self intersecting or not...")))
    (progn
      (setq ti (car (_vl-times)))
      (prompt "\n")
      (setq rtn (chkselfint cu))
      (prompt "\nElapsed time : ") (princ (rtos (- (car (_vl-times)) ti) 2 16)) (prompt " milliseconds...")
      (prompt "\n")
      (if rtn
        (prompt "\nPicked curve is self intersecting curve...")
        (prompt "\nPicked curve is NOT self intersecting curve...")
      )
    )
    (prompt "\nMissed picking curve... Better luck next time...")
  )
  (princ)
)

 

Regards, M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
Message 109 of 124

АлексЮстасу
Advisor
Advisor

@marko_ribar,

There's something wrong with entlast/entnext/_.UNDO in the code, but the _.EXTRUDE idea is great! Two birds with one stone. 🙂
Too bad that 3000 pages ago, when I suggested using _REGION, nobody suggested _.EXTRUDE!
And very fast - even if there are no self-intersections, no longer than 11-18 seconds on a contour with 4600 vertices.


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 110 of 124

marko_ribar
Advisor
Advisor

@АлексЮстасу 

Look nothing is bad in the code you mentioned, only thing is that it doesn't work in AutoCAD, but works in BricsCAD...

AutoCAD throws error that says that picked curve entity is not valid as CAD can't sweep or extrude self-intersecting curves... In BricsCAD there is no error and it finds self-intersecting curves in contrast to AutoCAD which always states that curve is NOT self-intersecting one, due to 'rtn' value which is always nil, because 'll' ending variable in sub function chkselfint is also nil and so the last expression returns nil (> (length ll) 1) [ (> 0 1) ] is always false - nil...

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 111 of 124

marko_ribar
Advisor
Advisor

@АлексЮстасу 

Since you are just wanting to know if picked curve is self-intersecting or not (without knowing points data), this version now works for both AutoCAD and BricsCAD...

(defun c:chkselfint ( / *error* chkselfint cmd nom cu pt rtn ti )

  (defun *error* ( m )
    (if nom
      (setvar (quote nomutt) nom)
    )
    (if cmd
      (setvar (quote cmdecho) cmd)
    )
    (if m
      (prompt m)
    )
    (princ)
  )

  (defun chkselfint ( cu pt / p1 p2 el ll rr par )

    (or (not (vl-catch-all-error-p (vl-catch-all-apply (function vlax-get-acad-object) nil))) (vl-load-com))

    (setq el (entlast))
    (while (entnext el)
      (setq el (entnext el))
    )
    (if (= 8 (logand 8 (getvar (quote undoctl))))
      (vl-cmdf "_.UNDO" "_E")
    )
    (vl-cmdf "_.UNDO" "_BE")
    (cond
      ( (= (strcase (getvar (quote program))) "ACAD")
        (setvar (quote nomutt) 0)
        (vl-catch-all-apply (function vl-cmdf) (list "_.EXTRUDE" "_MO" "_SO" (ssadd cu) "" pt pt))
        (while (< 0 (getvar (quote cmdactive)))
          (vl-cmdf "")
        )
        (if
          (or
            (= (getvar (quote lastprompt)) "Cannot sweep or extrude a self-intersecting curve.")
            (= (getvar (quote lastprompt)) "1 object removed from selection set.")
            (= (getvar (quote lastprompt)) "Nothing selected.")
          )
          (setq rr t)
        )
        (vl-cmdf "_.U")
        rr
      )
      ( (= (strcase (getvar (quote program))) "BRICSCAD")
        (setvar (quote nomutt) 1)
        (setq p1 pt p2 (mapcar (function +) (cdr (assoc 210 (entget cu))) pt))
        (vl-catch-all-apply (function vl-cmdf) (list "_.EXTRUDE" "_MO" "_SO" (ssadd cu) "" "_D" p1 p2))
        (while (< 0 (getvar (quote cmdactive)))
          (vl-cmdf "")
        )
        (while (setq el (entnext el))
          (setq ll (cons el ll))
        )
        (vl-cmdf "_.U")
        (if
          (or
            (> (length ll) 1)
            (and (not (vlax-curve-isclosed cu)) (= (length ll) 1))
          )
          (setq rr t)
        )
        (if (not rr)
          (progn
            (setq ll nil)
            (setq el (entlast))
            (while (entnext el)
              (setq el (entnext el))
            )
            (vla-explode (vlax-ename->vla-object cu))
            (while (setq el (entnext el))
              (setq ll (cons el ll))
            )
            (vl-some
              (function
                (lambda ( x )
                  (if (not rr)
                    (vl-some
                      (function
                        (lambda ( y )
                          (setq par nil)
                          (if
                            (and
                              (not rr)
                              (or
                                (setq par (vlax-curve-getparamatpoint x (vlax-curve-getstartpoint y)))
                                (setq par (vlax-curve-getparamatpoint x (vlax-curve-getendpoint y)))
                              )
                              (/= par (vlax-curve-getstartparam x))
                              (/= par (vlax-curve-getendparam x))
                            )
                            (setq rr t)
                            rr
                          )
                        )
                      )
                      (vl-remove x ll)
                    )
                    rr
                  )
                )
              )
              ll
            )
            (foreach e ll
              (if (and e (not (vlax-erased-p e)))
                (entdel e)
              )
            )
          )
        )
        (setvar (quote nomutt) 0)
        rr
      )
    )
  )

  (setq cmd (getvar (quote cmdecho)))
  (setvar (quote cmdecho) 0)
  (setq nom (getvar (quote nommut)))
  (if
    (and
      (setq cu (entsel "\nPick curve to determine if it's self intersecting or not..."))
      (not (vl-catch-all-error-p (setq pt (vl-catch-all-apply (function vlax-curve-getclosestpointto) (list (car cu) (cadr cu))))))
    )
    (progn
      (setq ti (car (_vl-times)))
      (prompt "\n")
      (setq rtn (chkselfint (setq cu (car cu)) pt))
      (prompt "\nElapsed time : ") (princ (rtos (- (car (_vl-times)) ti) 2 16)) (prompt " milliseconds...")
      (prompt "\n")
      (if rtn
        (prompt "\nPicked curve IS self intersecting curve...")
        (prompt "\nPicked curve IS NOT self intersecting curve...")
      )
    )
    (prompt "\nMissed picking curve, or picked entity not a curve... Better luck next time...")
  )
  (*error* nil)
)

 

HTH.

M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
Message 112 of 124

АлексЮстасу
Advisor
Advisor

@marko_ribar,

It works in AutoCAD in general. Thanks!
Still, something is wrong with entlast/entnext/_.UNDO in the code.
If a polyline without self-intersections was checked, it seems that it is taken for the next checks instead of the specified polyline.

 

Polylines with 4600 vertices with self-intersections/overlaps are checked instantly - less than 0.1 second!

Now it takes about 18 seconds to check a polyline without self-intersections with 4600 vertices. Apparently it takes so long because EXTRUDE is executed/canceled.
It would be really nice if there was a way not to execute this command, but only to make sure that it can be executed...


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 113 of 124

marko_ribar
Advisor
Advisor

@АлексЮстасу 

I've changed the code slightly, but not sure what are you experiencing... Can you describe more in detail what is the error, what CAD throwed as result of running *.lsp... Maybe all that's needed is to change (vl-cmdf "_.U") to (vl-cmdf "_.UNDO" 1)... We need more info about that (entlast) (entnext) UNDO that you are constantly pointing out...

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 114 of 124

marko_ribar
Advisor
Advisor

@АлексЮстасу 

I changed my lastly posted code again as it had lacks with BricsCAD portion of *.lsp... It should now work as desired with big lwpolylines as curves, but it takes longer to finish calculations - the problem was middle lwpolyline with 4600 vertices - it reported previously as NOT self intersecting, but it had overlapping vertex where magenta line described - so with both AutoCAD and BricsCAD now it reports correctly as IS self intersecting curve...

Marko Ribar, d.i.a. (graduated engineer of architecture)
Message 115 of 124

АлексЮстасу
Advisor
Advisor

@marko_ribar,

Thank you! Great results!
I, on the contrary, got almost 3 seconds faster on a long polyline - 15 seconds instead of 17-18.
On self-intersecting polylines it still works almost instantly - less than 0.1 seconds.
And the running time is no longer affected by which object was checked by the previous one - previously, if the previous one was a long polyline without self-intersections, polylines with self-intersections were checked for the same long time. Now this side effect is gone!

 

It would be really great if it was possible not to do a full EXTRUDE for polylines without self-intersections, but only to check the possibility - to speed things up. But we don't know how to do that.....

 

By the way, to make the program work for everyone, you need to add the appropriate lines on AutoCAD localization language, for example:

          (or
            (= (getvar "LASTPROMPT") "Cannot sweep or extrude a self-intersecting curve.")
            (= (getvar "LASTPROMPT") "Нельзя сдвинуть или выдавить самопересекающуюся кривую.")
            (= (getvar "LASTPROMPT") "1 object removed from selection set.")
            (= (getvar "LASTPROMPT") "1 объект изъят из набора.")
            (= (getvar "LASTPROMPT") "Nothing selected.")
            (= (getvar "LASTPROMPT") "Ничего не выбрано.")
            (= (getvar "LASTPROMPT") "Не удается выдавить выбранный объект.")
          )

-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 116 of 124

john.uhden
Mentor
Mentor

@АлексЮстасу & @marko_ribar ,

I still haven't given up.  Read the remarks within the code (below).

Try this one out including the time test. I can't do any time testing because:

  1. I'm not going to make a 4,500 vertex polyline.
  2. I'm still running ACAD2002.
  3. My computer is just slightly faster than a paralyzed slug.

Notice the difference in results between E2, E4, and E5.  E2 has an invalid self intersection at parameter 5.  It appears that vlax-curve-getdistatpoint sometimes screws up with clockwise arced segments.  Same is true for vlax-curve-getparamatpoint.

johnuhden_0-1735430616988.png

(defun selfinters2 (e / @2d @remdupes @dupes -pts -dupes -obj -flat -ints -items -found -selfs)
  ;; John F. Uhden (11-22-2024 through 12-28-2024)
  ;; Function finds all self intersections of a LWPolyline,
  ;;   including intersections between vertices and at vertices
  ;;   where parameters are not consecutive.
  ;; Can return a list of self intersections...
  ;;   Just change the last line from (if selfs T nil) to just selfs
  ;; This version neither copies nor explodes a copy of the polyline.
  ;; I don't know if it's any faster or not.
  ;; This version places a red circle at each vertex
  ;;   and a slightly larger green circle at each self intersection.
  ;;   Feel free to remove or rem out the lines containing (entmakex ...).
  (foreach atom '(@2d @remdupes @dupes pts dupes obj flat ints param items found selfs) (set atom nil))
  (defun @2d (p)(mapcar '* p '(1 1)))
  ;; Considering that a list may be all numbers (real and/or integer),
  ;; then we should account for a fuzz factor:
  (defun @remdupes (old fuzz / new)
    (foreach item old
      (if (vl-every '(lambda (x)(not x))(mapcar '(lambda (x)(equal item x fuzz)) new))(setq new (cons item new)))
    )
    (reverse new)
  )
  (defun @dupes (pts fuzz / dupe dupes)
    (foreach p pts
      (if (>= (length (vl-remove-if-not (function (lambda (x)(equal p x fuzz))) pts)) 2)
        (setq dupes (cons p dupes))
      )
    )
    (@remdupes dupes fuzz)
  )
  (and
    (setq pts (mapcar 'cdr (vl-remove-if-not (function (lambda (x)(= (car x) 10))) (entget e))))
    (foreach p pts (entmakex (list '(0 . "CIRCLE")(cons 10 p)(cons 40 0.2)(cons 62 1))))
    ;; Dupes are where two or more vertices meet at the same point:
    (setq dupes (@dupes pts 1e-8) selfs dupes)
    (setq pts (mapcar (function (lambda (x)(cons (vlax-curve-getdistatpoint e x) x))) pts))
    (setq pts (vl-sort pts (function (lambda (a b)(< (car a)(car b))))))
    (setq obj (vlax-ename->vla-object e))
    (setq flat (vlax-invoke obj 'intersectwith obj 0)) ;; flat list
    (while flat
      (repeat 3 (setq item (cons (car flat) item) flat (cdr flat)))
      (setq ints (cons (@2d (reverse item)) ints) item nil)
      1
    )
    (setq ints (mapcar (function (lambda (x)(cons (vlax-curve-getdistatpoint e x) x))) ints))
    (setq ints (vl-sort ints (function (lambda (a b)(< (car a)(car b))))))
    ;; Find self intersections between vertices, if any,
    ;;   by comparing distances along the path:
    (foreach int ints
      (setq found nil items pts)
      (while (and (not found)(>= (length items) 2))
        (setq found (< (caar items)(car int)(caadr items)) items (cdr items))
      ;; or maybe
      ;;  (setq found (vl-remove-if-not (function (lambda (a b)(< (car a)(car int)(car b)))) pts))
      )
  ;;    (print found)
      (if found (setq selfs (cons (cdr int) selfs)) 1)
    )
    (or (terpri) 1)
    (foreach p selfs (entmakex (list '(0 . "CIRCLE")(cons 10 p)(cons 40 0.3)(cons 62 3))))
  )
  (if selfs T nil)
)

 

John F. Uhden

0 Likes
Message 117 of 124

АлексЮстасу
Advisor
Advisor

@john.uhden,

The yellow circles are what's not found:

ju2812.png
Nothing found in million coordinates.
But with “houses” it's found.


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 118 of 124

john.uhden
Mentor
Mentor

Thanks, Alex.

I have succeeded in baffling myself.  😖

But there has to be a reason, right?  😩

Of course my deceased brother-in-law always told me the story about his philosophy final...

The question was "Why?"

The top student got an A++ with his answer, "Why not?"

John F. Uhden

0 Likes
Message 119 of 124

john.uhden
Mentor
Mentor

@АлексЮстасу & @marko_ribar ,

Except for scaling, this version appears to work properly.

Please test for satisfaction and time.

johnuhden_0-1735779895738.png

(defun selfinters3 (e / @2d @fence -obj -item -flat filter ss -ints -selfs)
  ;; John F. Uhden (11-22-2024 through 01-01-2025)
  ;; Function finds all self intersections of a LWPolyline,
  ;;   including intersections between vertices and at vertices
  ;;   where parameters are not consecutive.
  ;; Returns T for any self-intersections or nil if none.
  ;; This version neither copies nor explodes a copy of the polyline.
  ;;   Nor does it use distances anlong the polyline path.
  ;; This version uses a square fence to ssget the polyline at all intersections
  ;;   and ssnamex to determine the number of spokes coming out of each point.
  ;;   More than 2 spokes means a self intersection.
  ;; This version places a red circle at each intersection
  ;;   and a slightly larger green circle at each self intersection.
  ;;   Feel free to remove or rem out the lines containing (entmakex ...).
  (foreach atom '(@2d @fence obj item flat ints selfs) (set atom nil))
  (defun @2d (p)(mapcar '* p '(1 1)))
  (defun @fence (p w)
    ;; where w is actually half width
    (list
      (mapcar '+ p (list w w)) ;; upper right
      (mapcar '+ p (list (- w) w)) ;; upper left
      (mapcar '- p (list w w)) ;; lower left
      (mapcar '+ p (list w (- w))) ;; lower right
      (mapcar '+ p (list w w)) ;; upper right (beginning but not closed)
    )
  )
  (setq obj (vlax-ename->vla-object e))
  (setq flat (vlax-invoke obj 'intersectwith obj 0)) ;; flat list
  (while flat
    (repeat 3 (setq item (cons (car flat) item) flat (cdr flat)))
    (setq ints (cons (@2d (reverse item)) ints) item nil)
  )
  (setq filter (list '(0 . "LWPOLYLINE")))
  (foreach p ints 
    (entmakex (list '(0 . "CIRCLE")(cons 10 p)(cons 40 0.2)(cons 62 1)))
    (and
      (setq ss (ssget "_F" (@fence p 0.25) filter))
      (> (length (mapcar 'cadr (cdddr (last (ssnamex ss 0))))) 2)
      (setq selfs (cons p selfs))
      (entmakex (list '(0 . "CIRCLE")(cons 10 p)(cons 40 0.3)(cons 62 3)))
    )
  )
  (if selfs T nil)
)

John F. Uhden

Message 120 of 124

АлексЮстасу
Advisor
Advisor

@john.uhden,

О! Now almost everything is found!
Except for two cases in my test start_test_100-100_ju3_test.dwg, everything is found:

ju3.png
Unstable results in my test mill_pl.dwg with coordinates in millions - either finds nothing or finds a lot of unnecessary things.
I attach a polyline with a small number of vertices, in normal coordinates, where false results are obtained - pl181.dwg.


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes