Request for advice regarding an intersection counting LISP

Request for advice regarding an intersection counting LISP

Anonymous
Not applicable
5,754 Views
30 Replies
Message 1 of 31

Request for advice regarding an intersection counting LISP

Anonymous
Not applicable

I posted about syntax error resulting from this code last week - We solved the syntax issue and now I'm looking for help on improving the LISP for my application so I figured I'd title it something new.

 

The end goal of the LISP is to prompt the user to select a polyline, automatically select all or likely intersecting lines, count the intersections, and then print the # of intersections to an mtext object at the halfway point of the polyline. If the code could cycle through a # of selected polylines that would be a bonus but as long as it is one-click it will fit into our workflow fine.

 

What I have right credit to @Kent1Cooper now counts intersections of selected polyline and lines and prints to the command line. It worked very well when i selected only a small portion of the lines in the drawing near the polyline but counts many extra intersections if i use a command to automatically select ALL lines.

 

(defun c:EONEinterscountKC ( / c i l s x ent sel2 ) ;;define function
(if
(and
(setq ent (car (entsel))) ;;selects Zone polyline
(setq sel2 (ssget '((0 . "LINE") (8 . "LPSLAT")))) ;;selects lateral lines
)
(progn ; wrap into ONE 'then' expression
(setq s (ssadd ent sel2)) ;;adds zone and laterals to same selection set

(repeat (setq i (sslength s)) ; selection set to list of VLA objects
(setq
i (1- i)
l (cons (vlax-ename->vla-object (ssname s i)) l)
) ; setq
) ; repeat

(setq c 0)
(while (setq x (car l))
(foreach y (setq l (cdr l))
(setq c (+ c (/ (length (vlax-invoke x 'intersectwith y acextendnone)) 3)))
)
)

(princ (strcat "\n" (itoa c) " intersection" (if (= 1 c) "" "s") " between " (itoa (sslength s)) " objects."))
) ; progn [end of 'then' expression]
(princ "\nPlease select more than one object.") ; 'else' expression
) ; if

(princ) ;;clean exit
) ; defun

 

My questions are as follows:

 

1. Is there a good way to select all lines in the vicinity of the polyline instead of all lines in the drawing?

2. Is there any reason it might be returning incorrect #s when all lines are selected?

3. What is the easiest way to create an Mtext object with the number of intersections 5 units below the center of the pline?

4. can the code be adjusted easily to loop through all selected polylines?

 

Any advice that anyone can provide is massively appreciated by me. I am doing my best to get a crash course in Autolisp so that I can do more of this myself. 

 

lease also let me know if there is any more information I can provide or if the format of my post is not appropriate for the forum and I will adjust.

 

Thanks!

0 Likes
Accepted solutions (2)
5,755 Views
30 Replies
Replies (30)
Message 2 of 31

hak_vz
Advisor
Advisor

@Anonymous wrote:

1. Is there a good way to select all lines in the vicinity of the polyline instead of all lines in the drawing?

2. Is there any reason it might be returning incorrect #s when all lines are selected?

3. What is the easiest way to create an Mtext object with the number of intersections 5 units below the center of the pline?

4. can the code be adjusted easily to loop through all selected polylines?


@Anonymous  Attach sample drawing so that we can test your code

 

1. Is there a good way to select all lines in the vicinity of the polyline instead of all lines in the drawing?

You can add selection filter to ssget like "W" ....

 

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 3 of 31

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....

1. Is there a good way to select all lines in the vicinity of the polyline instead of all lines in the drawing?

2. Is there any reason it might be returning incorrect #s when all lines are selected?

3. What is the easiest way to create an Mtext object with the number of intersections 5 units below the center of the pline?

4. can the code be adjusted easily to loop through all selected polylines?

....


As a start on some of those:

 

The (vla-get-boundingbox) function will give you the extents of a Polyline:

 

  (vla-getboundingbox (vlax-ename->vla-object PolylineEntityName) 'minpt 'maxpt)
  (setq
    LL (vlax-safearray->list minpt); [ = Lower Left corner ]
    UR (vlax-safearray->list maxpt); [ = Upper Right corner ]
  )

 

Those corners can be used in an (ssget "_C") function to select only Lines that might intersect the Polyline.  The point halfway between them will be the center of the Polyline's extents, and can be used with (polar) to determine the insertion point for the [M]Text [plain Text should be sufficient, and will use less memory].

 

You would select Polylines with (ssget) rather than (entsel) if you want more than one, and use the same kind of:

    (repeat (setq i (sslength s))

technique to step through them to work with each.

Kent Cooper, AIA
0 Likes
Message 4 of 31

hak_vz
Advisor
Advisor

@Anonymous 

 

Here is another approach

Select polyline, extract its coordinates, and create fence (F) selection set.

SSlength  will give us number of intersecting entitiels

 

(defun ssf (pe filters / take pointlist2d po pts)
	(defun take (amount lst / ret)(repeat amount (setq ret (cons (car lst) (take (1- amount) (cdr lst))))))
	(defun pointlist2d (lst / ret) (while lst (setq	ret (cons (take 2 lst) ret) lst (cddr lst))) (reverse ret)) 
	(setq po (vlax-ename->vla-object pe))
	(cond 
		((= (vlax-get po 'ObjectName) "AcDbPolyline")
			(cond 
				((not filters)(setq ss (ssget "_F" (pointlist2d (vlax-get po 'Coordinates)))))
				((and filters)(setq ss (ssget "_F" (pointlist2d (vlax-get po 'Coordinates)) filters)))
			)
		)
	)
	(if (and ss (ssmemb pe ss))(setq ss (ssdel pe ss)))
	ss
)

 

Usage

(setq ss (ssf (car(entsel)) '((0 . "LINE")(62 . 1))))
(setq ss (ssf (car(entsel)) nil))

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 5 of 31

Kent1Cooper
Consultant
Consultant

@hak_vz wrote:

....

Here is another approach

Select polyline, extract its coordinates, and create fence (F) selection set.....


The possible problem with that comes when a Polyline contains arc segments.  If it does, depending on how far they bulge from the straight line between vertices, and depending on the relationship of the Line(s) you're looking for, a Fence selection built from the vertices might "see" Lines that do not intersection the Polyline, and/or it might not see Lines that do.

Kent Cooper, AIA
Message 6 of 31

hak_vz
Advisor
Advisor

@Kent1CooperYou are correct. I've created this according to sample posted in previous request from @Anonymous 

where he uses polyline with line segments. If selected polyline is in current view there should be no problem using this method.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 7 of 31

calderg1000
Mentor
Mentor

Regards @Anonymous 

It is possible that these lines of code for selection by fence instead of selection by window will help you.

calderg1000_0-1635181532102.png

 


Carlos Calderon G
EESignature
>Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

Message 8 of 31

Anonymous
Not applicable

@ calderg1000 and @ Kent1Cooper - It seems like you're both talking about the same method here - It looks promising to me but it seems to be underreporting in most cases. I think due to the nature of these polylines the selection box will need to be bigger.

 

I will attempt to troubleshoot what's happening when I select ALL lines - any insight on that would be appreciated because it seems like it should work but it overreports.

 

Code with select all:

 

;--------------------------------------------------------------------
;EONE Intersect Count from Kent Cooper with select all lines
;--------------------------------------------------------------------

(defun c:EONEinterscountall ( / c i l s x ent sel2 ) ;;define function
(if
(and
(setq ent (car (entsel))) ;;selects Zone polyline
(setq sel2 (ssget "_X" '((0 . "LINE") (8 . "LPSLAT")))) ;;selects lateral lines
)
(progn ; wrap into ONE 'then' expression
(setq s (ssadd ent sel2)) ;;adds zone and laterals to same selection set

(repeat (setq i (sslength s)) ; selection set to list of VLA objects
(setq
i (1- i)
l (cons (vlax-ename->vla-object (ssname s i)) l)
) ; setq
) ; repeat

(setq c 0)
(while (setq x (car l))
(foreach y (setq l (cdr l))
(setq c (+ c (/ (length (vlax-invoke x 'intersectwith y acextendnone)) 3)))
)
)

(princ (strcat "\n" (itoa c) " intersection" (if (= 1 c) "" "s") " between " (itoa (sslength s)) " objects."))
) ; progn [end of 'then' expression]
(princ "\nPlease select more than one object.") ; 'else' expression
) ; if

(princ) ;;clean exit
) ; defun

 

Code with fence select:

;--------------------------------------------------------------------
;EONE Intersect Count from Kent Cooper with fence select
;--------------------------------------------------------------------

(defun c:EONEinterscountmod ( / c i l s x ent sel2 ) ;;define function
(if
(and
(setq ent (car (entsel))) ;;selects Zone polyline
(setq entv(vlax-ename->vla-object ent))
(setq p1(vlax-curve-getstartpoint entv)
p2(vlax-curve-getendpoint entv))
(setq sel2 (ssget "_f" (list p1 p2) '((0 . "LINE") (8 . "LPSLAT")))) ;;selects lateral lines
)
(progn ; wrap into ONE 'then' expression
(setq s (ssadd ent sel2)) ;;adds zone and laterals to same selection set

(repeat (setq i (sslength s)) ; selection set to list of VLA objects
(setq
i (1- i)
l (cons (vlax-ename->vla-object (ssname s i)) l)
) ; setq
) ; repeat

(setq c 0)
(while (setq x (car l))
(foreach y (setq l (cdr l))
(setq c (+ c (/ (length (vlax-invoke x 'intersectwith y acextendnone)) 3)))
)
)

(princ (strcat "\n" (itoa c) " intersection" (if (= 1 c) "" "s") " between " (itoa (sslength s)) " objects."))
) ; progn [end of 'then' expression]
(princ "\nPlease select more than one object.") ; 'else' expression
) ; if
(princ) ;;clean exit
) ; defun

0 Likes
Message 9 of 31

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

@ calderg1000 and @ Kent1Cooper - It seems like you're both talking about the same method here ....


No, they're quite different:

Kent1Cooper_0-1635186450611.png

 

A Fence selection using only the start and end points of the Polyline will miss many of the Lines, but a Crossing-window selection using opposite corners of its bounding box will find them all.

Kent Cooper, AIA
Message 10 of 31

Anonymous
Not applicable

@Kent1Cooper - I see what you mean now - yes they are quite different.

 

I gave yours a shot and I can't seem to get it to return intersections. Maybe I'm just missing something silly? It ends up returning the "Please select more than 1 object" as if there were no selections by the bounding box portion.

 

;--------------------------------------------------------------------
;EONE Intersect Count from Kent Cooper with crossing select
;--------------------------------------------------------------------

(defun c:EONEinterscountmod ( / c i l s x ent sel2 LL UR ) ;;define function
(if
(and
(setq ent (car (entsel (Select Zone Polyline)))) ;;selects Zone polyline

(vla-getboundingbox (vlax-ename->vla-object ent) 'minpt 'maxpt) ;gets bounding box of zone polyline

(setq
LL (vlax-safearray->list minpt); [ = Lower Left corner ]
UR (vlax-safearray->list maxpt); [ = Upper Right corner ]
)

(setq sel2 (ssget "_C" '(LL) '(UR) '((0 . "LINE") (8 . "LPSLAT")))) ;;selects lateral lines based on min and max points of bounding box
)
(progn ; wrap into ONE 'then' expression
(setq s (ssadd ent sel2)) ;;adds zone and laterals to same selection set

(repeat (setq i (sslength s)) ; selection set to list of VLA objects
(setq
i (1- i)
l (cons (vlax-ename->vla-object (ssname s i)) l)
) ; setq
) ; repeat

(setq c 0)
(while (setq x (car l))
(foreach y (setq l (cdr l))
(setq c (+ c (/ (length (vlax-invoke x 'intersectwith y acextendnone)) 3)))
)
)

(princ (strcat "\n" (itoa c) " intersection" (if (= 1 c) "" "s") " between " (itoa (sslength s)) " objects."))
) ; progn [end of 'then' expression]
(princ "\nPlease select more than one object.") ; 'else' expression
) ; if
(princ) ;;clean exit
) ; defun

0 Likes
Message 11 of 31

dgorsman
Consultant
Consultant

FYI - posting your code using the '</>' "Insert/Edit code sample' tool preserved formatting such as indents, and makes it easier to pick out from the rest of the post.  Like this:

 

(defun this_function ( arg1 / val1 val2)
   (princ "\nThis is a sample function.")
)

 

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 12 of 31

Kent1Cooper
Consultant
Consultant

Try this:
  (setq sel2 (ssget "_C" LL UR '((0 . "LINE") (8 . "LPSLAT"))))

without putting those variable names into "quoted lists" [which, in this case, would be for coordinate numbers not requiring any evaluation the way reading a variable does].

Kent Cooper, AIA
0 Likes
Message 13 of 31

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....

(while (setq x (car l))
  (foreach y (setq l (cdr l))

....


That seems an unnecessary part of the process.  It would not only look for intersections between the Polyline [main in a street?] and each Line [lateral], but also between every Line and every other Line in the selection.  Is that really the intent?  Do the lateral Lines ever intersect each other?  [It doesn't look like it in the sample drawing.]  Can't you just look for intersections between the Polyline and each Line?

 

Or do I misunderstand what's going on?

Kent Cooper, AIA
0 Likes
Message 14 of 31

stevor
Collaborator
Collaborator

For question 1: 

For lines, or whatever, at the initial pick point, one could use the SSGET function with the "C" argument; about a million google examples ...

S
0 Likes
Message 15 of 31

Sea-Haven
Mentor
Mentor

My $0.05 there is another intersections post recently, the method I used was to get a entity and compare it to other entities using intersectwith, the example dwg has Plines and Lines, so make 2 lists, plines and lines, get a pline and compare lines if intersects do something, and remove from lines list. Keep going till end of lines. Get new pline do again. Arc not a problem. Now where did I put it.

Message 16 of 31

Anonymous
Not applicable

@Kent1Cooper:

Yes I can - I am not looking for intersections between lines and other lines - your assessment of the real world application is spot-on - intersection between mains and laterals.
l'll look at removing this portion to make it more elegant and less error prone.

 

EDITED: @Kent1Cooper how would you change this to just evaluate a pline against the lines? I'm having a tough time understanding these v___ commands, any advice would be appreciated. 

0 Likes
Message 17 of 31

Anonymous
Not applicable

Good Morning all and thank you all for your help - the response has been overwhelming and very educational! 

 

I had a bit of a  mini-breakthrough in troubleshooting this - I discovered that the the overcounting of intersections when I select ALL lines is due to there being duplicate laterals on top of one another - exactly 9 of them. Eliminating the portion of the code that looks at intersections between lines and lines should fix this issue and allow me to finish out the bells and whistles. - I'll look at this this morning and see what I can do to adjust that section. I did not write that portion so it may take some time for me to wrap my head around it.

 

Thanks again.

0 Likes
Message 18 of 31

Anonymous
Not applicable

@Kent1Cooper 

I decided to try a different approach using a called function developed by lee mac to generate a list of intersection points. I then attempted to get the length of this list and use that as the number of intersections. Something is going haywire with the first two ssget lines - i don't understand why it's happening, it should be simple but it's not allowing me to select properly. I'm trying to select a single polyline and all lines as my selection sets and then generate the list with lee mac's function. Is there something simple I'm missing?

;--------------------------------------------------------------------
;EONE Intersect Count from Kent Cooper with select all lines
;--------------------------------------------------------------------

(defun c:EONEinterscountall ( / c s x ss1 ss2 XSECL ) ;;define function

(setq ss1 (ssget ":S" '((0 . "POLYLINE")(8 . "LPS")))) ;;selects Zone polyline
(setq ss2 (ssget "_X" '((0 . "LINE") (8 . "LPSLAT")))) ;;selects lateral lines.

  (if (/= ss1 nil) ;; if ss1 exists
    
    (progn ; wrap into ONE 'then' expression 
      
      (setq XSECL (LM:intersectionsbetweensets ss1 ss2)) ;; obtains list of intersections
      
      (setq c (length XSECL)) ;; obtains number of intersection points   
      
      (princ (strcat "\n" (itoa c) " intersection" (if (= 1 c) "" "s") " between " (itoa (sslength s)) " objects."))
      
    ) ; progn [end of 'then' expression]
    (princ "\nPlease select a zone polyline.") ; 'else' expression
  ) ; if

  (princ) ;;clean exit
) ; defun

 

0 Likes
Message 19 of 31

hak_vz
Advisor
Advisor
Accepted solution

@Anonymous  For your particular case where lines are created so they join base polyline, here is solution that don't uses intersections at all. Start and end points of all lines in layer LPSLAT are collected into a list and then code asks you to select some polyline. For each point in point list whose distance to polyline is less then 1e-5 counter steps up. Value of counter is created at distance 5 bellow polyline center point as a text and converted to mtext.  Change value of text height ( I choose 25) and name of the function.

 

(defun c:blabla ( / *error* pick_poly ss i pts po tp)
	(defun *error* ( msg )
		(if (not (member msg '("Function cancelled" "quit / exit abort")))
			(princ)
		)
		(setvar 'cmdecho 1)
		(princ)
	)
	(defun pick_poly ()
		(setq e (entsel "\nPick polyline >"))
		(if (and (not e) (= (getvar 'Errno) 7)) (pick_poly) e)
	)
	(setq 
		ss (ssget "X" '((0 . "LINE")(8 . "LPSLAT")))
		i -1
		pts nil
	)
	(while (< (setq i (1+ i)) (sslength ss))
		(setq lo (vlax-ename->vla-object (ssname ss i)))
		(setq pts (cons (vlax-curve-getStartPoint lo) pts))
		(setq pts (cons (vlax-curve-getEndPoint lo) pts))
	)

	(while (and (setq pe (car(pick_poly))))	
		(setq i 0)
		(setq po (vlax-ename->vla-object pe))
		(setq tp (mapcar '+ (vlax-curve-getpointatdist po (* 0.5 (vla-get-Length po))) '(0 -5)))
		(foreach pt pts
			(if (< (distance (vlax-curve-getClosestPointTo po pt) pt) 1e-5)(setq i (1+ i)))
		)
		(setvar 'cmdecho 0)
		(command "_.text" tp 25 0  (itoa i))
		(command "_.txt2mtxt" (entlast) "")
		(setvar 'cmdecho 1)
	)
	(princ "\nDone!")
	(princ)
)

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 20 of 31

Anonymous
Not applicable
@ hak_vz - this works really well! Thanks so much for your input. I would still like to explore how to make it work with the intersection method but this will certainly work for my application and improve my workflow.