TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: ronjonp on August 08, 2013, 12:55:21 PM

Title: Help Finding Block Route
Post by: ronjonp on August 08, 2013, 12:55:21 PM
So I'm drawing a blank on how to achieve the following result:
I have an existing route that consists of multiple polylines. There are multiple blocks that reside on this "route". The blocks need to traverse this existing route from their insertion point back to a user defined point.


Could someone help out or at least get me started on the thought process?


Attached is a drawing with a simple scenario.


Thanks :)
Title: Re: Help Finding Block Route
Post by: ronjonp on August 09, 2013, 08:44:08 AM
I guess it's not that easy to do.
Title: Re: Help Finding Block Route
Post by: hmspe on August 09, 2013, 09:35:25 AM
If I understand what you are trying to do, random thought:

1.  Create a single pline that overlays the existing plines and follows the backbone for its entire length.  Reverse the pline if necessary so that it starts at the correct end.
2.  Use vlax-curve-getClosestPointTo on each block to get the apparent intersection with the working pline, then get the distance along the working pline from the pline start point to the apparent intersection.   Store the data in an array so that the block data and the distance along the working pline are kept together. 
3.  Determine if each block is to the left of the working pline, on the pline, or to the right of the pline.  Add to the data set for the block in the array.
4.  Sort  the array based on distance of the apparent intersection from the pline start point, closest to start point first.
5.  Iterate through the array.  For points on the left or on the line offset the pline to the left.  Keep a running counter so you can step the offsets by (N * offset distance).  Drop a line from the block to the offset pline.  Trim out the excess offset pline.  Same process on the right, but with a different counter and offsets to the right.
6.  Do whatever is necessary to clean up at the start point.

Title: Re: Help Finding Block Route
Post by: CAB on August 09, 2013, 11:33:53 AM
Ron,
I did not follow the explanation of what you are trying to do.  :(
Title: Re: Help Finding Block Route
Post by: ronjonp on August 09, 2013, 11:41:38 AM
Charles,


Did you download the drawing ? I'm trying to tally wires (grey lines) that are run from each valve to a controller location, but these wire routes have to follow the shortest predetermined path back (white polyline).


Thanks :)
Title: Re: Help Finding Block Route
Post by: hmspe on August 09, 2013, 01:03:27 PM
Ron,

What I posted earlier does not account for the pipes that are branches, but the general procedure should work.  Maybe check for tees and use each tee as a start point for a recursive run through the function.  If the diagram has branches off of branches it could get interesting. 

Two deadlines today so I can't play with this much.

Martin
Title: Re: Help Finding Block Route
Post by: ronjonp on August 09, 2013, 01:06:05 PM
Thanks for the reply Martin. Unfortunately these "networks" can be very complicated and could sometimes contain loops within loops :(.


Perhaps I've bit off more than I can chew. :)
Title: Re: Help Finding Block Route
Post by: Lee Mac on August 09, 2013, 04:56:14 PM
This reeks of Dijkstra's algorithm (http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)...
Title: Re: Help Finding Block Route
Post by: CAB on August 09, 2013, 05:37:41 PM
Yep, looks like the solution.  ::)
Title: Re: Help Finding Block Route
Post by: ronjonp on August 10, 2013, 08:49:14 AM
Thanks guys .. will take a look at it on Monday. Have a nice weekend.
Title: Re: Help Finding Block Route
Post by: MP on August 10, 2013, 12:28:01 PM
Yep, looks like the solution.  ::)

I don't understand, this:

This reeks of Dijkstra's algorithm (http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)...

Seems like a perfectly good response to the question:

Could someone help out or at least get me started on the thought process?

Amongst the other responses in the thread. It identifies the problem, a way to solve it and antes up pseudo code to boot.

What's the problem?
Title: Re: Help Finding Block Route
Post by: ymg on August 10, 2013, 07:11:07 PM
RonJomp,

Not sure If I follow you, but I believe you are after the Traveling Salesman Problem.

Here is a link  http://cadtips.cadalyst.com/linear-objects/tsp-problem (http://cadtips.cadalyst.com/linear-objects/tsp-problem) to a routine that appeared
10 years ago in Cadalyst.

Still works ! that's the joy of Lisp.

ymg
Title: Re: Help Finding Block Route
Post by: CAB on August 10, 2013, 10:20:23 PM
Yep, looks like the solution.  ::)

I don't understand, this:

 Just saying that the pseudo code Lee suggested looks like the solution to the problem.
Title: Re: Help Finding Block Route
Post by: MP on August 10, 2013, 10:35:10 PM
Just saying that the pseudo code Lee suggested looks like the solution to the problem.

Guess I just don't understand how you guys use rolling eyes anymore, seemed like the antithesis of a "Nice find Lee" sentiment.
Title: Re: Help Finding Block Route
Post by: CAB on August 11, 2013, 04:50:26 PM
Just saying that the pseudo code Lee suggested looks like the solution to the problem.

Guess I just don't understand how you guys use rolling eyes anymore, seemed like the antithesis of a "Nice find Lee" sentiment.
Yea, I paid no attention to the "Rolling Eyes" but it looks up to Lee's post above mine. At least it does on my browser & settings.
Sorry for the confusion.
Title: Re: Help Finding Block Route
Post by: ronjonp on August 11, 2013, 06:44:48 PM
Yep, looks like the solution.  ::)

I don't understand, this:

This reeks of Dijkstra's algorithm (http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)...

Seems like a perfectly good response to the question:

Could someone help out or at least get me started on the thought process?

Amongst the other responses in the thread. It identifies the problem, a way to solve it and antes up pseudo code to boot.

What's the problem?


Huh?


Thanks guys .. will take a look at it on Monday. Have a nice weekend.
Title: Re: Help Finding Block Route
Post by: ymg on August 12, 2013, 11:57:32 AM
Ronjomp,

If it is really Dijkstra that you are after, the routine itself is not so bad to program.

The challenging part is to get the input (the graph) in correctly. You basically needs your nodes and edges and their weight (distance).
We could select it from a dwg , assuming your nodes are block and your edges would be polylines.  But this does impose good discipline as you do your drawing.

Here is a link: A Note on Two Problems in Connexion with Graphs (http://www-m3.ma.tum.de/foswiki/pub/MN0506/WebHome/dijkstra.pdf) to his original paper. 

He was a man of few words and a great mind !

ymg
Title: Re: Help Finding Block Route
Post by: Krushert on August 13, 2013, 04:29:19 PM
Ron,

You are probably looking for code approach but I will throw out another method of skinning the cat.

Question though; would the the control wires be on identifiable with layer name or something?  A home run polyline from each remote point back to home and it length and other pertinent data can be extracted utilizing AutoCADs DataExtraction Wizard. 

Check out the attached spreadsheet that I just did yesterday for tallying up cracks and spalls in concrete.  The wizard will dump to a AutoCAD table or Excel.
Title: Re: Help Finding Block Route
Post by: ronjonp on August 13, 2013, 04:41:21 PM
Krushert,


Unfortunately the routes do not exist. I need to automate a way to figure these out :).


Thanks.


Ron
Title: Re: Help Finding Block Route
Post by: Krushert on August 13, 2013, 04:43:14 PM
Whoops!  I thought they were already created.   :-D

I will go back to my cracks now.  Yes I am drawing more crack. 
Title: Re: Help Finding Block Route
Post by: ronjonp on August 13, 2013, 05:02:15 PM
Whoops!  I thought they were already created.   ;D

I will go back to my cracks now.  Yes I am drawing more crack. 


 :D
Title: Re: Help Finding Block Route
Post by: ymg on August 14, 2013, 04:46:31 PM
RonJomp,

In the attached image, do you have a node at position 8.

If it is the case, with Dijkstra  your return would be 7-6-8-4-3-2-1-0

If you don't means you have a branch from 4 to 5 and 5 to 6
but no branch from 4 to 6. In this case the return would be
7-6-5-4-3-2-1-0

In other word if you have a junction box at 8, it should be a node.

ymg

(http://ronjomp.png)
Title: Re: Help Finding Block Route
Post by: ronjonp on August 15, 2013, 10:32:19 AM
My thoughts were to compile a list of points based on each polyline vertex (yellow x's in the image below) . So there would be a "node" at 8 because it's an end point of a polyline.


Thanks for the reply :)
Title: Re: Help Finding Block Route
Post by: ymg on August 16, 2013, 05:22:35 PM
Ronjomp,

Here is my implementation of Dijkstra's algorithm plus a link http://tech-algorithm.com/articles/dijkstra-algorithm/  (http://tech-algorithm.com/articles/dijkstra-algorithm/)
to probably the clearest article I've seen on it.  The test graph is the same as in this article.

You will still have to come up with a way to transform a selection into a valid graph.
There, It very much depends on how you draft your conduits.

ymg

Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ()
  2.    (setq nodes '("a" "b" "c" "d" "e" "f" "g" "h")
  3.          edges '(("a" "b" 1)
  4.                  ("a" "e" 2)
  5.                  ("a" "f" 1)
  6.                  ("b" "c" 2)
  7.                  ("b" "g" 1)
  8.                  ("c" "d" 1)
  9.                  ("d" "e" 1)
  10.                  ("d" "g" 2)
  11.                  ("d" "h" 0.5)
  12.                  ("e" "f" 2)
  13.                  ("g" "h" 0.5)
  14.                 )
  15.   )
  16.  
  17.   (print (minpath "g" "f" nodes edges))
  18.  
  19.   (princ)
  20. )
  21.  
  22. ; Find the path of minimum total length between two given nodes g and f.      ;
  23. ; Using Dijkstra Algorithm                                                    ;
  24. ;                                                                             ;
  25. ; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
  26. ;                                                                             ;
  27. ; Written by ymg   August 2013                                                ;
  28.  
  29. (defun minpath (g f nodes edges / )
  30.         (setq   nodes (vl-remove g nodes)
  31.                 openl (list (list g 0 nil))
  32.               closedl nil
  33.         )            
  34.         (foreach n nodes
  35.              (setq nodes (subst (list n 0 nil) n nodes))
  36.         )
  37.         (while (not (= (caar closedl) f))
  38.             (setq nodname (caar openl)
  39.                   totdist (cadar openl)
  40.                   closedl (cons (car openl) closedl)
  41.                     openl (cdr openl)
  42.                   clnodes (mapcar 'car closedl)
  43.                    
  44.             )
  45.             (foreach e edges
  46.                  (setq brname nil)
  47.                  (if (= (car e) nodname) (setq brname (cadr e)))
  48.                  (if (= (cadr e) nodname) (setq brname (car e)))
  49.                  
  50.                  (if brname
  51.                     (progn
  52.                        (setq new (list brname (+ (caddr e) totdist) nodname))
  53.                        (cond
  54.                           ((member brname clnodes))                              
  55.                           ((setq oldpos (vl-position brname (mapcar 'car openl)))
  56.                              (setq old (nth oldpos openl))
  57.                              (if (< (cadr new) (cadr old))
  58.                                 (setq openl (subst new old openl))
  59.                              )  
  60.                           )    
  61.                           (t (setq openl (cons new openl)))
  62.                        )               
  63.                        (setq edges (vl-remove e edges))
  64.                     )
  65.                  )
  66.             )
  67.             (setq openl (vl-sort openl (function (lambda (a b) (< (cadr a) (cadr b))))))
  68.         )
  69.         (setq minpath (list (car closedl)))
  70.         (foreach n closedl
  71.             (if (= (car n) (caddr (car minpath)))
  72.               (setq minpath (cons n minpath))
  73.             )
  74.         )  
  75.   )
  76.  
Title: Re: Help Finding Block Route
Post by: ronjonp on August 16, 2013, 08:53:15 PM
Thanks ymg ..I'll take a look on Monday. Have a nice weekend. :)
Title: Re: Help Finding Block Route
Post by: Kerry on August 16, 2013, 09:35:07 PM

I haven't read through the entire thread, but I think you'll need a node at each block location and each pline intersection so that your edges can be defined --- that applies if the edge distance (traversal) is important.

I see the problem in 2 parts.
Defining the data. ie: node locations and edge distances.
Determining the traversal.
Title: Re: Help Finding Block Route
Post by: ymg on August 17, 2013, 12:56:38 PM
Quote
Unfortunately the routes do not exist. I need to automate a way to figure these out .

Ronjomp,

Based on that quote, If it is automatic conduit layout that you are after, the problem is much more complicated
than simply following a route in a graph.

All kind of complications arises when you try to define the constraints.

Here is a link to a recent patent http://www.google.com/patents/WO2013086135A1?cl=en (http://www.google.com/patents/WO2013086135A1?cl=en).

Even reading this it is not very clear how they do it.

In the litterature there is also some apps for laying out connection that are somewhat related.

So I am afraid that the problem is really hard.

ymg
Title: Re: Help Finding Block Route
Post by: ymg on August 19, 2013, 01:51:18 PM
Ronjomp,

If my assumptions are right, what you are trying to achieve is:  Given a set of instruments, find a route that will minimize the length of  conduits/wire to connect them all.

This leads you to Minimum Spanning Tree (MST)

You also probably want your conduits to run parrallel to the building lines. So you are now looking for:

 Rectilinear Minimum Spanning Tree (RMST).

 For this the problem is tractable. Look at the following link:

 Efficient minimum spanning tree construction without Delaunay triangulation (http://users.eecs.northwestern.edu/~haizhou/publications/zhou02ipl.pdf)

In there you’ll find some pseudocode describing an efficient way to go about it. What you would do is simply select all the blocks without any connections (No need for LWPolyline joining the blocks) and you could generate the RMST.

However your problem does not stop there.  Because by inserting junction boxes on your conduits network,  you still can minimize the length of it. So this leads you to another beast that they call:

Rectilinear Steiner Minimum Tree (RSMT)

There the problem becomes very difficult.  Here is a quote from the next paper I propose to you:

Quote
However, Garey and Johnson [3] prove that the RSMT problem is NP-complete, indicating that a polynomial-time algorithm to compute an optimal RSMT is unlikely to exist.

It does not mean that the problem cannot be resolved but that a closed solution in reasonable computing time probably does  not exist.  However some heuristic can approach the solution in computable time.

In this paper:

An Efficient Rectilinear Steiner Minimum Tree Algorithm Based on Ant Colony Optimization (http://pdf.aminer.org/000/286/737/an_exact_rectilinear_steiner_tree_algorithm.pdf)

They managed with their Aco-Steiner procedure to get a near optimal solution in about 50 iterations. They also give some pseudocode for achieving it.

Now enough Blah, Blah you got some coding to do :-D.

ymg
Title: Re: Help Finding Block Route
Post by: ronjonp on August 19, 2013, 04:48:47 PM
YMG,


Thanks for looking into this for me. Unfortunately I have some "real" work to do  :)  right now so this is on the back burner. I hope to look at it later in the month.


Thanks,

Ron
Title: Re: Help Finding Block Route
Post by: ribarm on August 20, 2013, 11:35:41 AM
I feel I should thank to ymg for brilliant Dijikstra algorithm... So here are some codes based on it...

THIS IS FOR TIN NETWORK

Code - Auto/Visual Lisp: [Select]
  1. (defun unique ( linlst )
  2.   (if (car linlst) (cons (car linlst) (unique (_vl-remove (car linlst) (_vl-remove (list (cadar linlst) (caar linlst)) (cdr linlst) 1e-6) 1e-6))))
  3. )
  4.  
  5. (defun _vl-remove ( el lst fuzz )
  6.   (vl-remove-if '(lambda ( x ) (and (equal (car x) (car el) fuzz) (equal (cadr x) (cadr el) fuzz))) lst)
  7. )
  8.  
  9. (defun eraseduplin ( ss / i lin p1 p2 linlst linlstn )
  10.   (setq i -1)
  11.   (while (setq lin (ssname ss (setq i (1+ i))))
  12.     (setq p1 (cdr (assoc 10 (entget lin)))
  13.           p2 (cdr (assoc 11 (entget lin)))
  14.     )
  15.     (setq linlst (cons (list p1 p2) linlst))
  16.     (entdel lin)
  17.   )
  18.   (setq linlstn (unique linlst))
  19.   (foreach lin linlstn
  20.     (entmake (list '(0 . "LINE") (cons 10 (car lin)) (cons 11 (cadr lin))))
  21.   )
  22. )
  23.  
  24. (defun AssocOn ( SearchTerm Lst func fuzz )
  25.   (car
  26.     (vl-member-if
  27.       (function
  28.         (lambda (pair) (equal SearchTerm (apply func (list pair)) fuzz))
  29.       )
  30.       lst
  31.     )
  32.   )
  33. )
  34.  
  35. ; Find the path of minimum total length between two given nodes g and f.      ;
  36. ; Using Dijkstra Algorithm                                                    ;
  37. ;                                                                             ;
  38. ; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
  39. ;                                                                             ;
  40. ; Written by ymg   August 2013                                                ;
  41.  
  42. (defun minpath ( g f nodes edges s / brname clnodes closedl dst1 dst2 m minpath mp new nodname old oldpos openl totdist )
  43.   (setq nodes   (vl-remove g nodes)
  44.         openl   (list (list g 0 nil))
  45.         closedl nil
  46.   )
  47.   (foreach n nodes
  48.     (setq nodes (subst (list n 0 nil) n nodes))
  49.   )
  50.   (while (not (equal (caar closedl) f 1e-6))
  51.     (setq nodname (caar openl)
  52.           totdist (cadar openl)
  53.           closedl (cons (car openl) closedl)
  54.           openl   (cdr openl)
  55.           clnodes (mapcar 'car closedl)
  56.  
  57.     )
  58.     (foreach e edges
  59.       (setq brname nil)
  60.       (if (equal (car e) nodname 1e-6)
  61.         (setq brname (cadr e))
  62.       )
  63.       (if (equal (cadr e) nodname 1e-6)
  64.         (setq brname (car e))
  65.       )
  66.  
  67.       (if brname
  68.         (progn
  69.           (setq new (list brname (+ (caddr e) totdist) nodname))
  70.           (cond
  71.             ((member brname clnodes))
  72.             ((setq oldpos (vl-position brname (mapcar 'car openl)))
  73.              (setq old (nth oldpos openl))
  74.              (if (< (cadr new) (cadr old))
  75.                (setq openl (subst new old openl))
  76.              )
  77.             )
  78.             (t (setq openl (cons new openl)))
  79.           )
  80.           (setq edges (vl-remove e edges))
  81.         )
  82.       )
  83.     )
  84.     (setq
  85.       openl (vl-sort openl
  86.                      (function (lambda (a b) (< (cadr a) (cadr b))))
  87.             )
  88.     )
  89.   )
  90.   (setq minpath (list (car closedl)))
  91.   (setq dst1 (cadr (car closedl)))
  92.   (setq m 1)
  93.   (foreach k closedl
  94.     (setq dst2 (cadr k))
  95.     (if (not (equal dst1 dst2 1e-6)) (setq m (1+ m) dst1 dst2))
  96.   )
  97.   (repeat m
  98.     (foreach n closedl
  99.       (if (equal (car n) (caddr (car minpath)) 1e-6)
  100.         (setq mp (cons n mp))
  101.       )
  102.     )
  103.     (setq
  104.       mp (vl-sort mp
  105.                   (function (lambda (a b) (s (vl-position (assocon (caddr a) closedl 'car 1e-6) closedl) (vl-position (assocon (caddr b) closedl 'car 1e-6) closedl))))
  106.          )
  107.     )
  108.     (setq minpath (cons (car mp) minpath))
  109.     (setq mp nil)
  110.   )
  111.   (vl-remove nil minpath)
  112. )
  113.  
  114. (defun make3dpl ( ptlst )
  115.   (entmake
  116.     (list
  117.       '(0 . "POLYLINE")
  118.       '(100 . "AcDbEntity")
  119.       '(100 . "AcDb3dPolyline")
  120.       '(66 . 1)
  121.       '(62 . 3)
  122.       '(10 0.0 0.0 0.0)
  123.       '(70 . 8)
  124.       '(210 0.0 0.0 1.0)
  125.     )
  126.   )
  127.   (foreach pt ptlst
  128.     (entmake
  129.       (list
  130.         '(0 . "VERTEX")
  131.         '(100 . "AcDbEntity")
  132.         '(100 . "AcDbVertex")
  133.         '(100 . "AcDb3dPolylineVertex")
  134.         (cons 10 pt)
  135.         '(70 . 32)
  136.       )
  137.     )
  138.   )
  139.     (list
  140.       '(0 . "SEQEND")
  141.       '(100 . "AcDbEntity")
  142.     )
  143.   )
  144. )
  145.  
  146. (defun c:shorttinpath ( / osm ss i 3df lin p1 p2 p3 linlst ptlst g f dijkstra1 ptlstpth1 dijkstra2 ptlstpth2 )
  147.   (setq osm (getvar 'osmode))
  148.   (setq ss (ssget "_:L" '((0 . "3DFACE") (8 . "*TIN"))))
  149.   (setq i -1)
  150.   (while (setq 3df (ssname ss (setq i (1+ i))))
  151.     (setq p1 (cdr (assoc 11 (entget 3df)))
  152.           p2 (cdr (assoc 12 (entget 3df)))
  153.           p3 (cdr (assoc 13 (entget 3df)))
  154.     )
  155.     (entmake (list '(0 . "LINE") (cons 10 p1) (cons 11 p2)))
  156.     (entmake (list '(0 . "LINE") (cons 10 p2) (cons 11 p3)))
  157.     (entmake (list '(0 . "LINE") (cons 10 p3) (cons 11 p1)))
  158.   )
  159.   (setq ss (ssget "_X" (list '(0 . "LINE") (cons 8 (getvar 'clayer)))))
  160.   (eraseduplin ss)
  161.   (setq ss (ssget "_X" (list '(0 . "LINE") (cons 8 (getvar 'clayer)))))
  162.   (setq i -1)
  163.   (while (setq lin (ssname ss (setq i (1+ i))))
  164.     (setq p1 (cdr (assoc 10 (entget lin)))
  165.           p2 (cdr (assoc 11 (entget lin)))
  166.     )
  167.     (setq linlst (cons (list p1 p2 (distance p1 p2)) linlst))
  168.     (setq ptlst (cons p1 ptlst) ptlst (cons p2 ptlst))
  169.     (entdel lin)
  170.   )
  171.   (setq ptlst (acet-list-remove-duplicates ptlst 1e-6))
  172.   (setvar 'osmode 1)
  173.   (setq g (getpoint "\nPick starting point on TIN : ")
  174.         f (getpoint "\nPick ending point on TIN : ")
  175.   )
  176.   (setq dijkstra1 (minpath g f ptlst linlst >))
  177.   (setq ptlstpth1 (mapcar 'car dijkstra1))
  178.   (setq dijkstra2 (minpath f g ptlst linlst >))
  179.   (setq ptlstpth2 (mapcar 'car dijkstra2))
  180.   (setq dijkstra3 (minpath g f ptlst linlst <))
  181.   (setq ptlstpth3 (mapcar 'car dijkstra3))
  182.   (setq dijkstra4 (minpath f g ptlst linlst <))
  183.   (setq ptlstpth4 (mapcar 'car dijkstra4))
  184.   (make3dpl ptlstpth1)
  185.   (make3dpl ptlstpth2)
  186.   (make3dpl ptlstpth3)
  187.   (make3dpl ptlstpth4)
  188.   (setvar 'osmode osm)
  189.   (prompt "\nShortest path length is : ") (princ (rtos (cadr (last dijkstra1)))) (prompt " - you should check length of all 4 3d polylines to match data")
  190.   (textscr)
  191.   (princ)
  192. )
  193.  

THIS IS FOR LINES NETWORK

Code - Auto/Visual Lisp: [Select]
  1. ; Find the path of minimum total length between two given nodes g and f.      ;
  2. ; Using Dijkstra Algorithm                                                    ;
  3. ;                                                                             ;
  4. ; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
  5. ;                                                                             ;
  6. ; Written by ymg   August 2013                                                ;
  7.  
  8. (defun minpath ( g f nodes edges s / brname clnodes closedl dst1 dst2 m minpath mp new nodname old oldpos openl totdist )
  9.   (setq nodes   (vl-remove g nodes)
  10.         openl   (list (list g 0 nil))
  11.         closedl nil
  12.   )
  13.   (foreach n nodes
  14.     (setq nodes (subst (list n 0 nil) n nodes))
  15.   )
  16.   (while (not (equal (caar closedl) f 1e-6))
  17.     (setq nodname (caar openl)
  18.           totdist (cadar openl)
  19.           closedl (cons (car openl) closedl)
  20.           openl   (cdr openl)
  21.           clnodes (mapcar 'car closedl)
  22.  
  23.     )
  24.     (foreach e edges
  25.       (setq brname nil)
  26.       (if (equal (car e) nodname 1e-6)
  27.         (setq brname (cadr e))
  28.       )
  29.       (if (equal (cadr e) nodname 1e-6)
  30.         (setq brname (car e))
  31.       )
  32.  
  33.       (if brname
  34.         (progn
  35.           (setq new (list brname (+ (caddr e) totdist) nodname))
  36.           (cond
  37.             ((member brname clnodes))
  38.             ((setq oldpos (vl-position brname (mapcar 'car openl)))
  39.              (setq old (nth oldpos openl))
  40.              (if (< (cadr new) (cadr old))
  41.                (setq openl (subst new old openl))
  42.              )
  43.             )
  44.             (t (setq openl (cons new openl)))
  45.           )
  46.           (setq edges (vl-remove e edges))
  47.         )
  48.       )
  49.     )
  50.     (setq
  51.       openl (vl-sort openl
  52.                      (function (lambda (a b) (< (cadr a) (cadr b))))
  53.             )
  54.     )
  55.   )
  56.   (setq minpath (list (car closedl)))
  57.   (setq dst1 (cadr (car closedl)))
  58.   (setq m 1)
  59.   (foreach k closedl
  60.     (setq dst2 (cadr k))
  61.     (if (not (equal dst1 dst2 1e-6)) (setq m (1+ m) dst1 dst2))
  62.   )
  63.   (repeat m
  64.     (foreach n closedl
  65.       (if (equal (car n) (caddr (car minpath)) 1e-6)
  66.         (setq mp (cons n mp))
  67.       )
  68.     )
  69.     (setq
  70.       mp (vl-sort mp
  71.                   (function (lambda (a b) (s (vl-position (assocon (caddr a) closedl 'car 1e-6) closedl) (vl-position (assocon (caddr b) closedl 'car 1e-6) closedl))))
  72.          )
  73.     )
  74.     (setq minpath (cons (car mp) minpath))
  75.     (setq mp nil)
  76.   )
  77.   (vl-remove nil minpath)
  78. )
  79.  
  80. (defun AssocOn ( SearchTerm Lst func fuzz )
  81.   (car
  82.     (vl-member-if
  83.       (function
  84.         (lambda (pair) (equal SearchTerm (apply func (list pair)) fuzz))
  85.       )
  86.       lst
  87.     )
  88.   )
  89. )
  90.  
  91. (defun make3dpl ( ptlst )
  92.   (entmake
  93.     (list
  94.       '(0 . "POLYLINE")
  95.       '(100 . "AcDbEntity")
  96.       '(100 . "AcDb3dPolyline")
  97.       '(66 . 1)
  98.       '(62 . 3)
  99.       '(10 0.0 0.0 0.0)
  100.       '(70 . 8)
  101.       '(210 0.0 0.0 1.0)
  102.     )
  103.   )
  104.   (foreach pt ptlst
  105.     (entmake
  106.       (list
  107.         '(0 . "VERTEX")
  108.         '(100 . "AcDbEntity")
  109.         '(100 . "AcDbVertex")
  110.         '(100 . "AcDb3dPolylineVertex")
  111.         (cons 10 pt)
  112.         '(70 . 32)
  113.       )
  114.     )
  115.   )
  116.     (list
  117.       '(0 . "SEQEND")
  118.       '(100 . "AcDbEntity")
  119.     )
  120.   )
  121. )
  122.  
  123. (defun c:shortlinespath ( / osm ss i lin p1 p2 linlst ptlst g f dijkstra1 ptlstpth1 dijkstra2 ptlstpth2 )
  124.   (setq osm (getvar 'osmode))
  125.   (setq ss (ssget "_:L" '((0 . "LINE"))))
  126.   (setq i -1)
  127.   (while (setq lin (ssname ss (setq i (1+ i))))
  128.     (setq p1 (cdr (assoc 10 (entget lin)))
  129.           p2 (cdr (assoc 11 (entget lin)))
  130.     )
  131.     (setq linlst (cons (list p1 p2 (distance p1 p2)) linlst))
  132.     (setq ptlst (cons p1 ptlst) ptlst (cons p2 ptlst))
  133.   )
  134.   (setq ptlst (acet-list-remove-duplicates ptlst 1e-6))
  135.   (setvar 'osmode 1)
  136.   (setq g (getpoint "\nPick starting point on LINES NETWORK : ")
  137.         f (getpoint "\nPick ending point on LINES NETWORK : ")
  138.   )
  139.   (setq dijkstra1 (minpath g f ptlst linlst >))
  140.   (setq ptlstpth1 (mapcar 'car dijkstra1))
  141.   (setq dijkstra2 (minpath f g ptlst linlst >))
  142.   (setq ptlstpth2 (mapcar 'car dijkstra2))
  143.   (setq dijkstra3 (minpath g f ptlst linlst <))
  144.   (setq ptlstpth3 (mapcar 'car dijkstra3))
  145.   (setq dijkstra4 (minpath f g ptlst linlst <))
  146.   (setq ptlstpth4 (mapcar 'car dijkstra4))
  147.   (make3dpl ptlstpth1)
  148.   (make3dpl ptlstpth2)
  149.   (make3dpl ptlstpth3)
  150.   (make3dpl ptlstpth4)
  151.   (setvar 'osmode osm)
  152.   (prompt "\nShortest path length is : ") (princ (rtos (cadr (last dijkstra1)))) (prompt " - you should check length of all 4 3d polylines to match data")
  153.   (textscr)
  154.   (princ)
  155. )
  156.  

And this one removes duplicate lines and 0 lines - it's different from overkill, for it doesn't combine overlapped lines into big line - it just removes sufficient ones...

Code: [Select]
(defun unique ( linlst )
  (if (car linlst) (cons (car linlst) (unique (_vl-remove (car linlst) (_vl-remove (list (cadar linlst) (caar linlst)) (cdr linlst) 1e-6) 1e-6))))
)

(defun _vl-remove ( el lst fuzz )
  (vl-remove-if '(lambda ( x ) (and (equal (car x) (car el) fuzz) (equal (cadr x) (cadr el) fuzz))) lst)
)

(defun eraseduplin ( ss / i lin p1 p2 lay linlst linlstn )
  (setq i -1)
  (while (setq lin (ssname ss (setq i (1+ i))))
    (setq p1 (cdr (assoc 10 (entget lin)))
          p2 (cdr (assoc 11 (entget lin)))
          lay (cdr (assoc 8 (entget lin)))
    )
    (setq linlst (cons (list p1 p2) linlst))
    (entdel lin)
  )
  (setq linlstn (unique linlst))
  (foreach lin linlstn
    (entmake (list '(0 . "LINE") (cons 8 lay) (cons 10 (car lin)) (cons 11 (cadr lin))))
  )
)

(defun c:eraseduplines-0lines ( / ss s i lin )
  (setq ss (ssget "_:L" '((0 . "LINE"))))
  (setq s (ssadd))
  (setq i -1)
  (while (setq lin (ssname ss (setq i (1+ i))))
    (if (equal (cdr (assoc 10 (entget lin))) (cdr (assoc 11 (entget lin))) 1e-6) (entdel lin) (ssadd lin s))
  )
  (eraseduplin s)
  (princ)
)

(defun c:ed0l nil (c:eraseduplines-0lines))

M.R.
Title: Re: Help Finding Block Route
Post by: ymg on August 20, 2013, 12:35:55 PM
Quote
I feel I should thank to ymg for brilliant Dijikstra algorithm

Marko,

Hope everybody understand that the brilliance is with Dijkstra not with me.

What tou are achieving with your SHORTTINPATH function is actually a subset of the Euclidian Minimum Spanning Tree.
The whole tree should encompass all the points.

For this there is Prim's algorithm, or even Djiktra's but Problem 1 from his 1959 paper.

You are right in the fact that the EMST will always lie along the edges of a Delaunay triangulation.

ymg
Title: Re: Help Finding Block Route
Post by: qdzung on August 22, 2013, 03:55:55 AM
Great!!!
I have try to dev. my tool to automatic cable route and mto with VBA, but ... :ugly:

Finally chang to lisp and I found this topic  :mrgreen:

Thanks for all!
Title: Re: Help Finding Block Route
Post by: ribarm on August 22, 2013, 08:41:58 AM
Not so great!!!

I've found some wrong calculations in Dijkstra... See my attached *.dwg and *.jpg...

So long from being correct... :( :( :(
Title: Re: Help Finding Block Route
Post by: ribarm on August 22, 2013, 03:20:26 PM
I've changed my codes posted at the end of page #2... The problem was in (minpath) subfunction; also had to add (AssocOn) to make it work correctly... Also now it's slower, but that is the fact if wanted to be OK...

Cheers, M.R.
 :-) :-) :-)
Title: Re: Help Finding Block Route
Post by: ymg on August 22, 2013, 03:48:19 PM
Quote
I've found some wrong calculations in Dijkstra...

Marko,

I doubt that you can extend minpath to the sphere just like that.
That why they invented geodetic calculations.

Your distance on a sphere have to be great circle.
You will have also to take care of pole effect.

So Dijkstra's stands if you apply it to the plan.

ymg
Title: Re: Help Finding Block Route
Post by: ribarm on August 22, 2013, 04:33:05 PM
I don't quite know... It gave me correct results after my modifications first time, after that checked once more and it was wrong, then rotated view (3dorbit) and picked points from 3D but now last point as first and first as last and it was OK...

I just don't understand it seems you're right ymg... But now codes are better as it may give correct result in bigger probability...
Title: Re: Help Finding Block Route
Post by: ribarm on August 22, 2013, 06:13:38 PM
So, I've changed codes again... Now it creates 4 different 3d polylines if it's something like geodesic-sphere... One of these should be correct one, I guess...

M.R.
For planar TINs it works fine - all 4 3d polylines overlap each other - all are correct...
Title: Re: Help Finding Block Route
Post by: ribarm on August 23, 2013, 06:01:24 AM
Here they are... FINAL VERSIONS ...  So slooooooooooooow, but finally correct result even for geodesic spheres...

Code - Auto/Visual Lisp: [Select]
  1. (defun unique ( linlst )
  2.   (if (car linlst) (cons (car linlst) (unique (_vl-remove (car linlst) (_vl-remove (list (cadar linlst) (caar linlst)) (cdr linlst) 1e-6) 1e-6))))
  3. )
  4.  
  5. (defun _vl-remove ( el lst fuzz )
  6.   (vl-remove-if '(lambda ( x ) (and (equal (car x) (car el) fuzz) (equal (cadr x) (cadr el) fuzz))) lst)
  7. )
  8.  
  9. (defun eraseduplin ( ss / i lin p1 p2 linlst linlstn )
  10.   (setq i -1)
  11.   (while (setq lin (ssname ss (setq i (1+ i))))
  12.     (setq p1 (cdr (assoc 10 (entget lin)))
  13.           p2 (cdr (assoc 11 (entget lin)))
  14.     )
  15.     (setq linlst (cons (list p1 p2) linlst))
  16.     (entdel lin)
  17.   )
  18.   (setq linlstn (unique linlst))
  19.   (foreach lin linlstn
  20.     (entmake (list '(0 . "LINE") (cons 10 (car lin)) (cons 11 (cadr lin))))
  21.   )
  22. )
  23.  
  24. ; Find the path of minimum total length between two given nodes g and f.      ;
  25. ; Using Dijkstra Algorithm                                                    ;
  26. ;                                                                             ;
  27. ; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
  28. ;                                                                             ;
  29. ; Written by ymg   August 2013                                                ;
  30.  
  31. (defun minpath ( g f nodes edges / brname clnodes closedl dst1 dst2 m minpath minpathn mp new nodname old oldpos openl totdist )
  32.   (setq nodes   (vl-remove g nodes)
  33.         openl   (list (list g 0 nil))
  34.         closedl nil
  35.   )
  36.   (foreach n nodes
  37.     (setq nodes (subst (list n 0 nil) n nodes))
  38.   )
  39.   (while (not (equal (caar closedl) f 1e-6))
  40.     (setq nodname (caar openl)
  41.           totdist (cadar openl)
  42.           closedl (cons (car openl) closedl)
  43.           openl   (cdr openl)
  44.           clnodes (mapcar 'car closedl)
  45.  
  46.     )
  47.     (foreach e edges
  48.       (setq brname nil)
  49.       (if (equal (car e) nodname 1e-6)
  50.         (setq brname (cadr e))
  51.       )
  52.       (if (equal (cadr e) nodname 1e-6)
  53.         (setq brname (car e))
  54.       )
  55.  
  56.       (if brname
  57.         (progn
  58.           (setq new (list brname (+ (caddr e) totdist) nodname))
  59.           (cond
  60.             ((member brname clnodes))
  61.             ((setq oldpos (vl-position brname (mapcar 'car openl)))
  62.              (setq old (nth oldpos openl))
  63.              (if (< (cadr new) (cadr old))
  64.                (setq openl (subst new old openl))
  65.              )
  66.             )
  67.             (t (setq openl (cons new openl)))
  68.           )
  69.           (setq edges (vl-remove e edges))
  70.         )
  71.       )
  72.     )
  73.     (setq
  74.       openl (vl-sort openl
  75.                      (function (lambda (a b) (< (cadr a) (cadr b))))
  76.             )
  77.     )
  78.   )
  79.   (setq minpath (list (list (car closedl))))
  80.   (setq dst1 (cadr (car closedl)))
  81.   (setq m 1)
  82.   (foreach k closedl
  83.     (setq dst2 (cadr k))
  84.     (if (not (equal dst1 dst2 1e-6)) (setq m (1+ m) dst1 dst2))
  85.   )
  86.   (repeat m
  87.     (foreach n closedl
  88.       (if (= (length minpath) 1)
  89.         (if (equal (car n) (caddr (caar minpath)) 1e-6) (setq mp (cons n mp)))
  90.         (mapcar '(lambda (x) (if (equal (car n) (caddr (car x)) 1e-6) (setq mp (cons n mp)))) minpath)
  91.       )
  92.     )
  93.     (setq mp (vl-sort mp '(lambda (a b) (not (equal (car b) (car a) 1e-6)))))
  94.     (if (= (length minpath) 1)
  95.       (setq minpath (mapcar '(lambda (x) (cons x (car minpath))) mp))
  96.       (setq minpath (mapcar '(lambda (x) (mapcar '(lambda (y) (if (equal (car x) (caddr (car y)) 1e-6) (cons x y))) minpath)) mp))
  97.     )
  98.     (setq minpath (mapcar '(lambda (x) (vl-remove nil x)) minpath))
  99.     (if (listp (caaaar minpath)) (setq minpath (apply 'append minpath)))
  100.     (mapcar '(lambda (x) (if (eq (caddr (car x)) nil) (setq minpathn (cons x minpathn)))) minpath)
  101.     (setq mp nil)
  102.   )
  103.   (setq minpathn (acet-list-remove-duplicates minpathn nil))
  104.   (setq minpathn (vl-remove nil minpathn))
  105. )
  106.  
  107. (defun make3dpl ( ptlst )
  108.   (entmake
  109.     (list
  110.       '(0 . "POLYLINE")
  111.       '(100 . "AcDbEntity")
  112.       '(100 . "AcDb3dPolyline")
  113.       '(66 . 1)
  114.       '(62 . 3)
  115.       '(10 0.0 0.0 0.0)
  116.       '(70 . 8)
  117.       '(210 0.0 0.0 1.0)
  118.     )
  119.   )
  120.   (foreach pt ptlst
  121.     (entmake
  122.       (list
  123.         '(0 . "VERTEX")
  124.         '(100 . "AcDbEntity")
  125.         '(100 . "AcDbVertex")
  126.         '(100 . "AcDb3dPolylineVertex")
  127.         (cons 10 pt)
  128.         '(70 . 32)
  129.       )
  130.     )
  131.   )
  132.     (list
  133.       '(0 . "SEQEND")
  134.       '(100 . "AcDbEntity")
  135.     )
  136.   )
  137. )
  138.  
  139. (defun c:shorttinpath ( / osm ss i 3df lin p1 p2 p3 linlst ptlst g f dijkstra ptlstpths pl )
  140.   (setq osm (getvar 'osmode))
  141.   (setq ss (ssget "_:L" '((0 . "3DFACE") (8 . "*TIN"))))
  142.   (setq i -1)
  143.   (while (setq 3df (ssname ss (setq i (1+ i))))
  144.     (setq p1 (cdr (assoc 11 (entget 3df)))
  145.           p2 (cdr (assoc 12 (entget 3df)))
  146.           p3 (cdr (assoc 13 (entget 3df)))
  147.     )
  148.     (entmake (list '(0 . "LINE") (cons 10 p1) (cons 11 p2)))
  149.     (entmake (list '(0 . "LINE") (cons 10 p2) (cons 11 p3)))
  150.     (entmake (list '(0 . "LINE") (cons 10 p3) (cons 11 p1)))
  151.   )
  152.   (setq ss (ssget "_X" (list '(0 . "LINE") (cons 8 (getvar 'clayer)))))
  153.   (eraseduplin ss)
  154.   (setq ss (ssget "_X" (list '(0 . "LINE") (cons 8 (getvar 'clayer)))))
  155.   (setq i -1)
  156.   (while (setq lin (ssname ss (setq i (1+ i))))
  157.     (setq p1 (cdr (assoc 10 (entget lin)))
  158.           p2 (cdr (assoc 11 (entget lin)))
  159.     )
  160.     (setq linlst (cons (list p1 p2 (distance p1 p2)) linlst))
  161.     (setq ptlst (cons p1 ptlst) ptlst (cons p2 ptlst))
  162.     (entdel lin)
  163.   )
  164.   (setq ptlst (acet-list-remove-duplicates ptlst 1e-6))
  165.   (setvar 'osmode 1)
  166.   (setq g (getpoint "\nPick starting point on TIN : ")
  167.         f (getpoint "\nPick ending point on TIN : ")
  168.   )
  169.   (setq dijkstra (minpath g f ptlst linlst))
  170.   (setq ptlstpths (mapcar '(lambda (x) (mapcar 'car x)) dijkstra))
  171.   (mapcar '(lambda (x) (make3dpl x)) ptlstpths)
  172.   (prompt "\nShortest path length is : ") (princ (rtos (setq len (cadr (last (car dijkstra)))))) (prompt " - you should check length to match data")
  173.   (setq ss (ssget "_X" (list '(0 . "POLYLINE") '(70 . 8) (cons 8 (getvar 'clayer)))))
  174.   (setq i -1)
  175.   (while (setq pl (ssname ss (setq i (1+ i))))
  176.     (if (not (equal (vla-get-length (vlax-ename->vla-object pl)) len 1e-6)) (entdel pl))
  177.   )
  178.   (setvar 'osmode osm)
  179.   (textscr)
  180.   (princ)
  181. )
  182.  

Code - Auto/Visual Lisp: [Select]
  1. ; Find the path of minimum total length between two given nodes g and f.      ;
  2. ; Using Dijkstra Algorithm                                                    ;
  3. ;                                                                             ;
  4. ; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
  5. ;                                                                             ;
  6. ; Written by ymg   August 2013                                                ;
  7.  
  8. (defun minpath ( g f nodes edges / brname clnodes closedl dst1 dst2 m minpath minpathn mp new nodname old oldpos openl totdist )
  9.   (setq nodes   (vl-remove g nodes)
  10.         openl   (list (list g 0 nil))
  11.         closedl nil
  12.   )
  13.   (foreach n nodes
  14.     (setq nodes (subst (list n 0 nil) n nodes))
  15.   )
  16.   (while (not (equal (caar closedl) f 1e-6))
  17.     (setq nodname (caar openl)
  18.           totdist (cadar openl)
  19.           closedl (cons (car openl) closedl)
  20.           openl   (cdr openl)
  21.           clnodes (mapcar 'car closedl)
  22.  
  23.     )
  24.     (foreach e edges
  25.       (setq brname nil)
  26.       (if (equal (car e) nodname 1e-6)
  27.         (setq brname (cadr e))
  28.       )
  29.       (if (equal (cadr e) nodname 1e-6)
  30.         (setq brname (car e))
  31.       )
  32.  
  33.       (if brname
  34.         (progn
  35.           (setq new (list brname (+ (caddr e) totdist) nodname))
  36.           (cond
  37.             ((member brname clnodes))
  38.             ((setq oldpos (vl-position brname (mapcar 'car openl)))
  39.              (setq old (nth oldpos openl))
  40.              (if (< (cadr new) (cadr old))
  41.                (setq openl (subst new old openl))
  42.              )
  43.             )
  44.             (t (setq openl (cons new openl)))
  45.           )
  46.           (setq edges (vl-remove e edges))
  47.         )
  48.       )
  49.     )
  50.     (setq
  51.       openl (vl-sort openl
  52.                      (function (lambda (a b) (< (cadr a) (cadr b))))
  53.             )
  54.     )
  55.   )
  56.   (setq minpath (list (list (car closedl))))
  57.   (setq dst1 (cadr (car closedl)))
  58.   (setq m 1)
  59.   (foreach k closedl
  60.     (setq dst2 (cadr k))
  61.     (if (not (equal dst1 dst2 1e-6)) (setq m (1+ m) dst1 dst2))
  62.   )
  63.   (repeat m
  64.     (foreach n closedl
  65.       (if (= (length minpath) 1)
  66.         (if (equal (car n) (caddr (caar minpath)) 1e-6) (setq mp (cons n mp)))
  67.         (mapcar '(lambda (x) (if (equal (car n) (caddr (car x)) 1e-6) (setq mp (cons n mp)))) minpath)
  68.       )
  69.     )
  70.     (setq mp (vl-sort mp '(lambda (a b) (not (equal (car b) (car a) 1e-6)))))
  71.     (if (= (length minpath) 1)
  72.       (setq minpath (mapcar '(lambda (x) (cons x (car minpath))) mp))
  73.       (setq minpath (mapcar '(lambda (x) (mapcar '(lambda (y) (if (equal (car x) (caddr (car y)) 1e-6) (cons x y))) minpath)) mp))
  74.     )
  75.     (setq minpath (mapcar '(lambda (x) (vl-remove nil x)) minpath))
  76.     (if (listp (caaaar minpath)) (setq minpath (apply 'append minpath)))
  77.     (mapcar '(lambda (x) (if (eq (caddr (car x)) nil) (setq minpathn (cons x minpathn)))) minpath)
  78.     (setq mp nil)
  79.   )
  80.   (setq minpathn (acet-list-remove-duplicates minpathn nil))
  81.   (setq minpathn (vl-remove nil minpathn))
  82. )
  83.  
  84. (defun make3dpl ( ptlst )
  85.   (entmake
  86.     (list
  87.       '(0 . "POLYLINE")
  88.       '(100 . "AcDbEntity")
  89.       '(100 . "AcDb3dPolyline")
  90.       '(66 . 1)
  91.       '(62 . 3)
  92.       '(10 0.0 0.0 0.0)
  93.       '(70 . 8)
  94.       '(210 0.0 0.0 1.0)
  95.     )
  96.   )
  97.   (foreach pt ptlst
  98.     (entmake
  99.       (list
  100.         '(0 . "VERTEX")
  101.         '(100 . "AcDbEntity")
  102.         '(100 . "AcDbVertex")
  103.         '(100 . "AcDb3dPolylineVertex")
  104.         (cons 10 pt)
  105.         '(70 . 32)
  106.       )
  107.     )
  108.   )
  109.     (list
  110.       '(0 . "SEQEND")
  111.       '(100 . "AcDbEntity")
  112.     )
  113.   )
  114. )
  115.  
  116. (defun c:shortlinespath ( / osm ss i lin p1 p2 linlst ptlst g f dijkstra ptlstpths pl )
  117.   (setq osm (getvar 'osmode))
  118.   (setq ss (ssget "_:L" '((0 . "LINE"))))
  119.   (setq i -1)
  120.   (while (setq lin (ssname ss (setq i (1+ i))))
  121.     (setq p1 (cdr (assoc 10 (entget lin)))
  122.           p2 (cdr (assoc 11 (entget lin)))
  123.     )
  124.     (setq linlst (cons (list p1 p2 (distance p1 p2)) linlst))
  125.     (setq ptlst (cons p1 ptlst) ptlst (cons p2 ptlst))
  126.   )
  127.   (setq ptlst (acet-list-remove-duplicates ptlst 1e-6))
  128.   (setvar 'osmode 1)
  129.   (setq g (getpoint "\nPick starting point on LINES NETWORK : ")
  130.         f (getpoint "\nPick ending point on LINES NETWORK : ")
  131.   )
  132.   (setq dijkstra (minpath g f ptlst linlst))
  133.   (setq ptlstpths (mapcar '(lambda (x) (mapcar 'car x)) dijkstra))
  134.   (mapcar '(lambda (x) (make3dpl x)) ptlstpths)
  135.   (prompt "\nShortest path length is : ") (princ (rtos (setq len (cadr (last (car dijkstra)))))) (prompt " - you should check length to match data")
  136.   (setq ss (ssget "_X" (list '(0 . "POLYLINE") '(70 . 8) (cons 8 (getvar 'clayer)))))
  137.   (setq i -1)
  138.   (while (setq pl (ssname ss (setq i (1+ i))))
  139.     (if (not (equal (vla-get-length (vlax-ename->vla-object pl)) len 1e-6)) (entdel pl))
  140.   )
  141.   (setvar 'osmode osm)
  142.   (textscr)
  143.   (princ)
  144. )
  145.  

I think it can't be faster...
M.R.
 8-) 8-) 8-)
Title: Re: Help Finding Block Route
Post by: ronjonp on August 26, 2013, 11:23:49 AM
First off I want to thank YMG for converting the algorithm to lisp and Marko for his many examples :).


Here is my contribution (for 2d) which works on a network of polylines and block locations on (or close) to those polylines.
I did a little bit of cleanup to add routes between block locations as well as for points of polylines that reside within a fuzz value of another polyline within the network.


There is still some work to be done to the code for creating the network more correctly, but it seems to be working fairly well for my uses.


Have fun.  ;D
Title: Re: Help Finding Block Route
Post by: ribarm on August 26, 2013, 12:25:29 PM
Well done, Ron...

I didn't follow you what do you initially wanted to achieve, but now I see it... I've picked some other home node, and it returned correct results... What is the problem with fuzz factor? I don't see where it should be different? Fuzz factor - X scale factor of nodes is 10.0 - I've changed it to 1.0 and still it did correctly calculations...
Title: Re: Help Finding Block Route
Post by: ronjonp on August 26, 2013, 01:02:47 PM
Marko,


For the example I posted, the fuzz value will be fine. The line is just there to alert other people using the code that it may need to be adjusted for different scenarios.


 :)
Title: Re: Help Finding Block Route
Post by: ymg on August 26, 2013, 07:10:56 PM
RonJomp,

Glad I could help a bit.  :-)

This being said, I still don't understand what it is you are doing ?

The network of polylines, what does it represents ?

Here,  yet another link to a paper that probably could help qdzung:

A Heuristic Technique For The Generation Of A Network Geometry For Rural Natural Gas Distribution Systems (http://mspace.lib.umanitoba.ca/bitstream/1993/16990/1/Davidson_A_heuristic.pdf)

Good thing they invented Cut&Paste with such long titles.

ymg
Title: Re: Help Finding Block Route
Post by: ronjonp on August 26, 2013, 07:59:41 PM
YMG,


The existing route is a pipe network. The blocks are valves connected to the pipe network. These valves have to be wired to a controller and generally follow the path of the pipes back to the controller. Dijkstra's algorithm finds the shortest route along the pipes from each of these valves back to the controller. Clear as mud ?  ;D


Ron
Title: Re: Help Finding Block Route
Post by: jvillarreal on June 25, 2015, 09:42:58 AM
This is pure brilliance. Should be in the show my stuff section imo.

FYI - The _createedges function errored out for me here:

(>= (distance (setq p2 (vlax-curve-getpointatparam e (1+ (fix pa)))) p) fuzz)

changing it to:
          (setq p2 (vlax-curve-getpointatparam e (1+ (fix pa))))
          (>= (distance p2 p) fuzz)

worked for me.
Title: Re: Help Finding Block Route
Post by: ronjonp on June 25, 2015, 10:24:14 AM
This is pure brilliance. Should be in the show my stuff section imo.

FYI - The _createedges function errored out for me here:

(>= (distance (setq p2 (vlax-curve-getpointatparam e (1+ (fix pa)))) p) fuzz)

changing it to:
          (setq p2 (vlax-curve-getpointatparam e (1+ (fix pa))))
          (>= (distance p2 p) fuzz)

worked for me.
Thanks for reporting the error .. Here's the updated function that checks if there is a point before passing it to the distance command.

Code - Auto/Visual Lisp: [Select]
  1.   ;; If the endpoint is within the fuzz factor distance of another polyline
  2.   ;; and not already at an endpoint, create 'edges' from that point
  3.   ;; to the adjacent vertices
  4.   (defun _createedges (p l fuzz / cp out p p1 p2 pa)
  5.     (foreach e l
  6.       (if (and (setq cp (vlax-curve-getclosestpointto e p))
  7.                (<= (distance p cp) fuzz)
  8.                (setq pa (vlax-curve-getparamatpoint e cp))
  9.                (setq p1 (vlax-curve-getpointatparam e (fix pa)))
  10.                (>= (distance p1 p) fuzz)
  11.                (setq p2 (vlax-curve-getpointatparam e (1+ (fix pa))))
  12.                (>= (distance p2 p) fuzz)
  13.           )
  14.         (setq out (cons (list (list p p1 (distance p p1)) (list p p2 (distance p p2))) out))
  15.       )
  16.     )
  17.     (apply 'append out)
  18.   )
Title: Re: Help Finding Block Route
Post by: Logan on June 25, 2015, 05:38:33 PM
Hello Guys.
Maybe:

A* search algorithm
https://en.wikipedia.org/wiki/A*_search_algorithm (https://en.wikipedia.org/wiki/A*_search_algorithm)
http://www.cadtutor.net/forum/showthread.php?88680-Pathfinding-in-AutoCAD-with-the-A-Star-Algorithm-(A*)

or

Kruskal's algorithm
https://en.wikipedia.org/?title=Kruskal%27s_algorithm



edit kdub: fixed A*_search_algorithm link
Title: Re: Help Finding Block Route
Post by: jvillarreal on November 05, 2015, 03:06:15 PM
Gotta thank you again for this excellent routine Ron and YMG..This routine has saved me dozens of hours as well as clicks. I'm using it today to record distances for 1200 runs..Thank you immensely!
Title: Re: Help Finding Block Route
Post by: ronjonp on November 05, 2015, 04:24:20 PM
Gotta thank you again for this excellent routine Ron and YMG..This routine has saved me dozens of hours as well as clicks. I'm using it today to record distances for 1200 runs..Thank you immensely!
Glad it has helped you out so much!  :)
Title: Re: Help Finding Block Route
Post by: ymg on November 05, 2015, 07:10:49 PM
jvillarreal,

Enhorabuena!,  Glad I could help some.

ymg
Title: Re: Help Finding Block Route
Post by: thanhduan2407 on June 14, 2017, 01:44:53 AM
I use by ID for Point! However! It is as a little slower
Code: [Select]
(defun C:MinLength (/ ID1 ID2 IDEND IDSTART LISTPOINT LTSID LTSIDFIL LTSIDPNT
     LTSID_EDGE LTSLINE LTSPATH LTSPNT LTSPNTALL OLMODE P1 P2
     PNTEND PNTSTART SSLINE X
    )
  (vl-load-com)
  (setvar "CMDECHO" 0)
  (defun *error* (msg)
    (if Olmode
      (setvar 'osmode Olmode)
    )
    (if (not (member msg '("*BREAK,*CANCEL*,*EXIT*")))
      (princ (strcat "\nError: " msg))
    )
    (princ)
  )
  (setq Olmode (getvar 'osmode))
  (Alert
    "Qu\U+00E9t ch\U+1ECDn c\U+00E1c \U+0111\U+1ED1i t\U+01B0\U+1EE3ng l\U+00E0 LINE: "
  )
  (setq ssLine (ssget "_:L" (list (cons 0 "LINE"))))
  (if ssLine
    (Progn
      (setvar 'osmode 1)
      (setq PntStart
     (getpoint
       "\nCh\U+1ECDn \U+0111i\U+1EC3m xu\U+1EA5t ph\U+00E1t:  "
     )
      )
      (setq
PntEnd (getpoint
"\nCh\U+1ECDn \U+0111i\U+1EC3m \U+0111\U+1EBFn:  "
       )
      )
      (setq LtsLine (LM:ss->ent ssLine))
      (setq LtsPntAll (list))
      (foreach eLine LtsLine
(setq
  LtsPntAll (append LtsPntAll
    (list (cdr (assoc 10 (entget eLine)))
  (cdr (assoc 11 (entget eLine)))
    )
    )
)
      )
      (setq LtsPnt (SortAB (LM:UniqueFuzz LtsPntAll 1e-6)))
      (setq LtsIDPnt
     (mapcar '(lambda (x) (list (vl-position x LtsPnt) x))
     LtsPnt
     )
      )
      (setq LtsID
     (mapcar '(lambda (x) (vl-position x LtsPnt))
     LtsPnt
     )
      )
      (setq IDStart
     (caar (vl-remove-if-not
     (function
       (lambda (x) (equal PntStart (cadr x) 1e-6))
     )
     LtsIDPnt
   )
     )
      )
      (setq IDEnd
     (caar
       (vl-remove-if-not
(function (lambda (x) (equal PntEnd (cadr x) 1e-6)))
LtsIDPnt
       )
     )
      )
      (setq LtsID_Edge (list))
      (foreach e LtsLine
(setq P1 (cdr (assoc 10 (entget e))))
(setq P2 (cdr (assoc 11 (entget e))))
(setq
  ID1
   (caar (vl-remove-if-not
   (function (lambda (x) (equal P1 (cadr x) 1e-6)))
   LtsIDPnt
)
   )
)
(setq
  ID2
   (caar (vl-remove-if-not
   (function (lambda (x) (equal P2 (cadr x) 1e-6)))
   LtsIDPnt
)
   )
)
(setq LtsID_Edge
       (append
LtsID_Edge
(list
   (list ID1
ID2
(distance (nth ID1 LtsPnt)
   (nth ID2 LtsPnt)
)
   )
)
       )
)
      )
      (setq LtsIDFil (RemoveIDDup LtsID_Edge))
      (setq LtsPath (minpath1 IDStart IDEnd LtsID LtsIDFil))
      (setq listpoint
     (mapcar '(lambda (x) (nth (car x) LtsPnt)) LtsPath)
      )
      (make3dpl listpoint)
    )
    (Alert "Qu\U+00E9t ch\U+1ECDn ch\U+01B0a c\U+00F3 LINE ")
  )
  (setvar 'osmode Olmode)
  (princ)
)



(defun SortAB (lstPnt /)
  (setq
    Lts-Sort (vl-sort
       (vl-sort lstPnt
'(lambda (e1 e2) (< (cadr e1) (cadr e2)))
       )
       '(lambda (e1 e2) (< (car e1) (car e2)))
     )
  )
  Lts-Sort
)
(defun LM:UniqueFuzz (l f)
  (if l
    (cons (car l)
  (LM:UniqueFuzz
    (vl-remove-if
      (function (lambda (x) (equal x (car l) f)))
      (cdr l)
    )
    f
  )
    )
  )
)
;;; (setq L1 (RemoveIDDup (list '(2 4) '(3 4) '(4 2) '(5  2) '(4 3) )))
(defun RemoveIDDup (l)
  (if l
    (cons (car l)
  (RemoveIDDup
    (vl-remove-if
      (function (lambda (x)
  (or (and (= (car x) (car (car l)))
   (= (cadr x) (cadr (car l)))
      )
      (and (= (car x) (cadr (car l)))
   (= (cadr x) (car (car l)))
      )
  )
)
      )
      (cdr l)
    )
  )
    )
  )
)


(defun LM:ss->ent (ss / i l)
  (if ss
    (repeat (setq i (sslength ss))
      (setq l (cons (ssname ss (setq i (1- i))) l))
    )
  )
)




(defun make3dpl (ptlst)
  (entmake
    (list
      '(0 . "POLYLINE")
      '(100 . "AcDbEntity")
      '(100
.
"AcDb3dPolyline"
       )
      '(66 . 1)
      '(62 . 3)
      '(10 0.0 0.0 0.0)
      '(70 . 8)
      '(210 0.0 0.0 1.0)
    )
  )
  (foreach pt ptlst
    (entmake
      (list
'(0 . "VERTEX")
'(100 . "AcDbEntity")
'(100 . "AcDbVertex")
'(100 . "AcDb3dPolylineVertex")
(cons 10 pt)
'(70 . 32)
      )
    )
  )
  (entmake
    (list
      '(0 . "SEQEND")
      '(100 . "AcDbEntity")
    )
  )
)

(defun minpath1 (g f nodes edges / BRNAME CLNODES CLOSEDL NEW NODNAME
OLD OLDPOS OPENL TOTDIST
)
  (setq nodes (vl-remove g nodes))
  (setq openl (list (list g 0 nil)))
  (setq closedl nil)

  (foreach n nodes
    (setq nodes (subst (list n 0 nil) n nodes))
  )
  (while (not (= (caar closedl) f))
    (setq nodname (caar openl))
    (setq totdist (cadar openl))
    (setq closedl (cons (car openl) closedl))
    (setq openl (cdr openl))
    (setq clnodes (mapcar 'car closedl))
    (foreach e edges
      (progn
(setq brname nil)
(if (= (car e) nodname)
  (setq brname (cadr e))
)
(if (= (cadr e) nodname)
  (setq brname (car e))
)
      )
      (if brname
(progn
  (setq new (list brname (+ (caddr e) totdist) nodname))
  (cond
    ((member brname clnodes))
    ((setq oldpos (vl-position brname (mapcar 'car openl)))
     (setq old (nth oldpos openl))
     (if (< (cadr new) (cadr old))
       (setq openl (subst new old openl))
     )
    )
    (t (setq openl (cons new openl)))
  )
  (setq edges (vl-remove e edges))
)
      )
    )
    (setq
      openl (vl-sort openl
     (function (lambda (a b) (< (cadr a) (cadr b))))
    )
    )
  )
  (setq minpath (list (car closedl)))
  (foreach n closedl
    (if (= (car n) (caddr (car minpath)))
      (setq minpath (cons n minpath))
    )
  )
  minpath
)


[Code]
Title: Re: Help Finding Block Route
Post by: topshelfvalueinc on September 03, 2022, 03:12:04 AM
For the code below is there anyway you can make it work with circles? my drawings usually looks like something in the attachment

Code: [Select]
; Find the path of minimum total length between two given nodes g and f.      ;
; Using Dijkstra Algorithm                                                    ;
;                                                                             ;
; See http://tech-algorithm.com/articles/dijkstra-algorithm/                  ;
;                                                                             ;
; Written by ymg   August 2013                                                ;
 
(defun minpath ( g f nodes edges / brname clnodes closedl dst1 dst2 m minpath minpathn mp new nodname old oldpos openl totdist )
  (setq nodes   (vl-remove g nodes)
        openl   (list (list g 0 nil))
        closedl nil
  )
  (foreach n nodes
    (setq nodes (subst (list n 0 nil) n nodes))
  )
  (while (not (equal (caar closedl) f 1e-6))
    (setq nodname (caar openl)
          totdist (cadar openl)
          closedl (cons (car openl) closedl)
          openl   (cdr openl)
          clnodes (mapcar 'car closedl)
 
    )
    (foreach e edges
      (setq brname nil)
      (if (equal (car e) nodname 1e-6)
        (setq brname (cadr e))
      )
      (if (equal (cadr e) nodname 1e-6)
        (setq brname (car e))
      )
 
      (if brname
        (progn
          (setq new (list brname (+ (caddr e) totdist) nodname))
          (cond
            ((member brname clnodes))
            ((setq oldpos (vl-position brname (mapcar 'car openl)))
             (setq old (nth oldpos openl))
             (if (< (cadr new) (cadr old))
               (setq openl (subst new old openl))
             )
            )
            (t (setq openl (cons new openl)))
          )
          (setq edges (vl-remove e edges))
        )
      )
    )
    (setq
      openl (vl-sort openl
                     (function (lambda (a b) (< (cadr a) (cadr b))))
            )
    )
  )
  (setq minpath (list (list (car closedl))))
  (setq dst1 (cadr (car closedl)))
  (setq m 1)
  (foreach k closedl
    (setq dst2 (cadr k))
    (if (not (equal dst1 dst2 1e-6)) (setq m (1+ m) dst1 dst2))
  )
  (repeat m
    (foreach n closedl
      (if (= (length minpath) 1)
        (if (equal (car n) (caddr (caar minpath)) 1e-6) (setq mp (cons n mp)))
        (mapcar '(lambda (x) (if (equal (car n) (caddr (car x)) 1e-6) (setq mp (cons n mp)))) minpath)
      )
    )
    (setq mp (vl-sort mp '(lambda (a b) (not (equal (car b) (car a) 1e-6)))))
    (if (= (length minpath) 1)
      (setq minpath (mapcar '(lambda (x) (cons x (car minpath))) mp))
      (setq minpath (mapcar '(lambda (x) (mapcar '(lambda (y) (if (equal (car x) (caddr (car y)) 1e-6) (cons x y))) minpath)) mp))
    )
    (setq minpath (mapcar '(lambda (x) (vl-remove nil x)) minpath))
    (if (listp (caaaar minpath)) (setq minpath (apply 'append minpath)))
    (mapcar '(lambda (x) (if (eq (caddr (car x)) nil) (setq minpathn (cons x minpathn)))) minpath)
    (setq mp nil)
  )
  (setq minpathn (acet-list-remove-duplicates minpathn nil))
  (setq minpathn (vl-remove nil minpathn))
)
 
(defun make3dpl ( ptlst )
  (entmake
    (list
      '(0 . "POLYLINE")
      '(100 . "AcDbEntity")
      '(100 . "AcDb3dPolyline")
      '(66 . 1)
      '(62 . 3)
      '(10 0.0 0.0 0.0)
      '(70 . 8)
      '(210 0.0 0.0 1.0)
    )
  )
  (foreach pt ptlst
    (entmake
      (list
        '(0 . "VERTEX")
        '(100 . "AcDbEntity")
        '(100 . "AcDbVertex")
        '(100 . "AcDb3dPolylineVertex")
        (cons 10 pt)
        '(70 . 32)
      )
    )
  )
  (entmake
    (list
      '(0 . "SEQEND")
      '(100 . "AcDbEntity")
    )
  )
)
 
(defun c:shortlinespath ( / osm ss i lin p1 p2 linlst ptlst g f dijkstra ptlstpths pl )
  (vl-load-com)
  (setq osm (getvar 'osmode))
  (setq ss (ssget "_:L" '((0 . "LINE"))))
  (setq i -1)
  (while (setq lin (ssname ss (setq i (1+ i))))
    (setq p1 (cdr (assoc 10 (entget lin)))
          p2 (cdr (assoc 11 (entget lin)))
    )
    (setq linlst (cons (list p1 p2 (distance p1 p2)) linlst))
    (setq ptlst (cons p1 ptlst) ptlst (cons p2 ptlst))
  )
  (setq ptlst (acet-list-remove-duplicates ptlst 1e-6))
  (setvar 'osmode 1)
  (setq g (getpoint "\nPick starting point on LINES NETWORK : ")
        f (getpoint "\nPick ending point on LINES NETWORK : ")
  )
  (setq dijkstra (minpath g f ptlst linlst))
  (setq ptlstpths (mapcar '(lambda (x) (mapcar 'car x)) dijkstra))
  (mapcar '(lambda (x) (make3dpl x)) ptlstpths)
  (prompt "\nShortest path length is : ") (princ (rtos (setq len (cadr (last (car dijkstra)))))) (prompt " - you should check length to match data")
  (setq ss (ssget "_X" (list '(0 . "POLYLINE") '(70 . 8) (cons 8 (getvar 'clayer)))))
  (setq i -1)
  (while (setq pl (ssname ss (setq i (1+ i))))
    (if (not (equal (vla-get-length (vlax-ename->vla-object pl)) len 1e-6)) (entdel pl))
  )
  (setvar 'osmode osm)
  (textscr)
  (princ)
)
 
Title: Re: Help Finding Block Route
Post by: BIGAL on September 04, 2022, 09:18:18 PM
Post a dwg with before and after.
Title: Re: Help Finding Block Route
Post by: siimao on October 18, 2023, 09:46:54 AM
Hi, solution nice!

Is it possible to adopt function to deel not only with endpoints (cdr (assoc 10)) and (cdr (assoc 11)) of lines  but with them interseption points too?

Thank you very much in advance.
Title: Re: Help Finding Block Route
Post by: ribarm on October 21, 2023, 08:59:44 AM
Hi, solution nice!

Is it possible to adopt function to deel not only with endpoints (cdr (assoc 10)) and (cdr (assoc 11)) of lines  but with them interseption points too?

Thank you very much in advance.

Intersection of 2 lines are 4 lines... Obviously, you have to double break all intersecting lines with BREAK command prior running A star minpath algorithm...
Title: Re: Help Finding Block Route
Post by: siimao on October 23, 2023, 05:27:41 AM
Deer Marko,

Thank you for the respond.
You mentioned on "A star minpath algorithm". Is it lisp-function denoted on this chat?

Breaking lines is not the variant.
I think by such way.
If I understand 1) the end point of all lines is collected, 2) algorithm runs

What if we assign intersection points to a set of line endpoints. it’s okay if the lines along the entire length were highlighted.

Left of the picture - algorithm result. Center - I wish I could. Right - polyline result.

I just wanted to clarify if this could work?