create a link between blocks

create a link between blocks

jtm2020hyo
Collaborator Collaborator
1,656 Views
8 Replies
Message 1 of 9

create a link between blocks

jtm2020hyo
Collaborator
Collaborator

I need create polylines between nearest blocks that link their base points.

example ( image B ) :

1.- the first polyline ( color YELLOW ) should be the longest polyline
2.- the second polyline ( color magenta ) create a link between nearest leftovers blocks and link with YELLOW
3.- the third polyline ( color green ) connect with leftovers of leftovers nearest blocks and link with MAGENTA

image.png

 

 

 

I found a LISP that works great but does not do what I need.

(defun c:connect ( / ss i e plist p nextpt plist-sorted rtn pp )
  (while (or (prompt "\nSelect blocks or circles...") (not (setq ss (ssget '((0 . "INSERT,CIRCLE"))))))
    (prompt "\nEmpty sel. set...")
  )
  (repeat (setq i (sslength ss))
    (setq e (ssname ss (setq i (1- i))))
    (setq plist (cons (cdr (assoc 10 (entget e))) plist))
  )
  (setq p (getpoint "\nPick or specify start point - use osnap cen or ins : "))

  (defun nextpt ( p plist / car-sort pp )

    (defun car-sort ( l f / removenth r k )

      (defun removenth ( l n / k )
        (setq k -1)
        (vl-remove-if '(lambda ( x ) (= (setq k (1+ k)) n)) l)
      )

      (setq k -1)
      (vl-some '(lambda ( a ) (setq k (1+ k)) (if (vl-every '(lambda ( x ) (apply f (list a x))) (removenth l k)) (setq r a))) l)
      r
    )  

    (setq plist (vl-remove-if '(lambda ( x ) (equal x p 1e-3)) plist))
    (setq pp (car-sort plist '(lambda ( a b ) (<= (distance p a) (distance p b)))))
    (list pp plist)
  )

  (if p
    (progn
      (while (cadr plist)
        (setq plist-sorted (cons p plist-sorted))
        (setq rtn (nextpt p plist))
        (setq pp (car rtn) plist (cadr rtn))
        (setq p pp)
      )
      (setq plist-sorted (cons (car plist) plist-sorted))
      (setq plist-sorted (reverse plist-sorted))
      (entmake
        (append
          (list
            '(0 . "LWPOLYLINE")
            '(100 . "AcDbEntity")
            '(100 . "AcDbPolyline")
            (cons 90 (length plist-sorted))
            (cons 70 (if (= 1 (getvar 'plinegen)) 128 0))
            '(38 . 0.0)
          )
          (mapcar '(lambda ( p ) (cons 10 p)) plist-sorted)
          (list '(210 0.0 0.0 1.0))
        )
      )
    )
  )
  (princ)
)

here a example of what do this LISP:

image.png

 

0 Likes
1,657 Views
8 Replies
Replies (8)
Message 2 of 9

pbejse
Mentor
Mentor

@jtm2020hyo wrote:

I need create polylines between nearest blocks that link their base points.

example ( image B ) :

1.- the first polyline ( color YELLOW ) should be the longest polyline
2.- the second polyline ( color magenta ) create a link between nearest leftovers blocks and link with YELLOW
3.- the third polyline ( color green ) connect with leftovers of leftovers nearest blocks and link with MAGENTA

 


Need to set conditions to come up with something like that.

  1.  What are the conditions for this?  I'm not seeing the pattern for the longest polyline
  2. At the seventh point (yellow line), if the "nearest" rule applies, the circle nearest the seventh point should be the one on the left, same goes for the 12th circle
  3. same issue as number 2.

 

0 Likes
Message 3 of 9

john.uhden
Mentor
Mentor

This is for starters.  It's written for circles, but that's an easy change.

I just don't know offhand how to determine a separate branch.

 

(defun c:route ( / ss i p plist route @closer)
  ;; Routine to draw a polyline along the shortest route from
  ;; any starting point through all circles in Modelspace
  ;; John Uhden (07-22-18)
  (defun @closer (a b c)(< (distance a b)(distance a c)))
  (and
    (setq ss (ssget "X" '((0 . "CIRCLE")(410 . "Model"))))
    (setq p (getpoint "\nStarting point: "))
    (repeat (setq i (sslength ss))
      (setq plist (cons (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) plist))
    )
    (setq route (list p))
    (while plist
      (setq p (car (vl-sort plist '(lambda (a b)(@closer p a b))))
            plist (vl-remove p plist)
            route (cons p route) 
) ) (setvar "osmode" 0) (setvar "cmdecho" 0) (vl-cmdf "_.pline") (mapcar 'vl-cmdf (reverse route)) (vl-cmdf "") ) (princ) )

 

John F. Uhden

0 Likes
Message 4 of 9

john.uhden
Mentor
Mentor

If the branch nodes were on a different layer then it could be done.  Not easily, but certainly much faster than doing it by hand.  Where things could fall apart is where two nodes from different branches are closer than two intended nodes of the same branch.  A maximum distance between branch nodes would help a lot.

I don't think any of us around here is as smart as Algernon (remember the movie "Charlie" starring Cliff Robertson?).  I may becoming more like Charlie at the end of the movie. 😕

John F. Uhden

0 Likes
Message 5 of 9

Kent1Cooper
Consultant
Consultant

Something closely related has >come up before<.  It's different in having the paths already drawn, not Block to be connected, but you may get some insights into the problems involved in the branching decisions in particular, if you read through that thread.

Kent Cooper, AIA
0 Likes
Message 6 of 9

jtm2020hyo
Collaborator
Collaborator

@john.uhden wrote:

If the branch nodes were on a different layer then it could be done.  Not easily, but certainly much faster than doing it by hand.  Where things could fall apart is where two nodes from different branches are closer than two intended nodes of the same branch.  A maximum distance between branch nodes would help a lot.

I don't think any of us around here is as smart as Algernon (remember the movie "Charlie" starring Cliff Robertson?).  I may becoming more like Charlie at the end of the movie. 😕


 

I respect your work. thanks for your reply.

...Its possible create a long line that connects a max number of blocks nearby and connects other lines to the longest like branches?

0 Likes
Message 7 of 9

jtm2020hyo
Collaborator
Collaborator

@Kent1Cooper wrote:

Something closely related has >come up before<.  It's different in having the paths already drawn, not Block to be connected, but you may get some insights into the problems involved in the branching decisions in particular, if you read through that thread.


 

 hello  @pbejse @Kent1Cooper @john.uhden  @pbejse, in such post, this code is how should be the first longest polyline.

 

 

 

(defun c:processtree ( / treechain trunkconst processreverse c ti ch r rr treeentities outerbranches trunk trunks dmax d trunkmax ) ;;; variable sss is global

  (vl-load-com)

  (defun treechain ( c / sp ep rtn ) ;;; r is global
    (setq sp (vlax-curve-getstartpoint c))
    (setq ep (vlax-curve-getendpoint c))
    (setq rtn (append (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" sp sp)))) (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" ep ep))))))
    (foreach e rtn
      (if (not (vl-position e r))
        (progn
          (setq r (cons e r))
          (if (not (eq e c))
            (treechain e)
          )
        )
      )
    )
  )

  (defun trunkconst ( c / sp ep rtn nextc ) ;;; r is global
    (setq sp (vlax-curve-getstartpoint c))
    (setq ep (vlax-curve-getendpoint c))
    (cond
      ( (and (car (vl-remove c r)) (ssmemb (car (vl-remove c r)) (ssget "_C" sp sp)))
        (setq rtn (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" ep ep)))))
      )
      ( (and (car (vl-remove c r)) (ssmemb (car (vl-remove c r)) (ssget "_C" ep ep)))
        (setq rtn (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" sp sp)))))
      )
      ( t
        (setq rtn (append (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" sp sp)))) (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" ep ep))))))
      )
    )
    (setq nextc (car (vl-sort (vl-remove-if '(lambda ( x ) (or (vl-position x r) (vl-position x rr))) (vl-remove c rtn)) '(lambda ( a b ) (< (vlax-curve-getdistatparam a (vlax-curve-getendparam a)) (vlax-curve-getdistatparam b (vlax-curve-getendparam b)))))))
    (if (not (vl-position c r))
      (setq r (cons c r))
    )
    (if nextc
      (trunkconst nextc)
    )
  )

  (defun processreverse ( c / sp ep rtn nextc ) ;;; rr is global
    (setq sp (vlax-curve-getstartpoint c))
    (setq ep (vlax-curve-getendpoint c))
    (cond
      ( (and (car (vl-remove c rr)) (ssmemb (car (vl-remove c rr)) (ssget "_C" sp sp)))
        (setq rtn (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" ep ep)))))
      )
      ( (and (car (vl-remove c rr)) (ssmemb (car (vl-remove c rr)) (ssget "_C" ep ep)))
        (setq rtn (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" sp sp)))))
      )
      ( t
        (setq rtn (append (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" sp sp)))) (vl-remove-if 'listp (mapcar 'cadr (ssnamex (ssget "_C" ep ep))))))
      )
    )
    (setq nextc (car (vl-sort (vl-remove-if '(lambda ( x ) (or (vl-position x r) (vl-position x rr))) (vl-remove c rtn)) '(lambda ( a b ) (< (vlax-curve-getdistatparam a (vlax-curve-getendparam a)) (vlax-curve-getdistatparam b (vlax-curve-getendparam b)))))))
    (if (not (vl-position c rr))
      (setq rr (cons c rr))
    )
    (if (vl-position nextc (apply 'append trunks))
      (processreverse nextc)
    )
  )

  (alert "Set zoom of view such that complete tree of interest is visible on screen and only then apply routine...")
  (while (or (not (setq c (car (entsel "\nPick tree outer branch curve entity...")))) (if c (or (vl-catch-all-error-p (vl-catch-all-apply 'vlax-curve-getstartpoint (list c))) (and (> (sslength (ssget "_C" (vlax-curve-getstartpoint c) (vlax-curve-getstartpoint c))) 1) (> (sslength (ssget "_C" (vlax-curve-getendpoint c) (vlax-curve-getendpoint c))) 1)))))
    (prompt "\nMissed or picked wrong entity type or picked curve not tree outer branch entity...")
  )
  (initget "Yes No")
  (setq ch (getkword "\nProcess only picked branch (Yes) or iterate through all tree branches (No) [Yes/No] <Yes> : "))
  (if (null ch)
    (setq ch "Yes")
  )
  (setq ti (car (_vl-times)))
  (treechain c)
  (setq treeentities r)
  (setq r nil)
  (if (= ch "Yes")
    (progn
      (trunkconst c)
      (setq trunk r)
      (setq trunks (cons trunk trunks))
      (while (and r (not (vl-every '(lambda ( x ) (vl-position x (apply 'append trunks))) treeentities)))
        (processreverse (car trunk))
        (setq r (cdr (member (car rr) trunk)))
        (if r
          (trunkconst (car r))
        )
        (setq trunk r)
        (setq trunks (cons trunk trunks))
      )
      (if (null dmax)
        (setq dmax 0.0)
      )
      (foreach trunk trunks
        (setq d (apply '+ (mapcar '(lambda ( x ) (vlax-curve-getdistatparam x (vlax-curve-getendparam x))) trunk)))
        (if (> d dmax)
          (setq dmax d trunkmax trunk)
        )
      )
    )
    (progn
      (setq outerbranches (vl-remove-if-not '(lambda ( x ) (or (= (sslength (ssget "_C" (vlax-curve-getstartpoint x) (vlax-curve-getstartpoint x))) 1) (= (sslength (ssget "_C" (vlax-curve-getendpoint x) (vlax-curve-getendpoint x))) 1))) treeentities))
      (foreach branch outerbranches
        (trunkconst branch)
        (setq trunk r)
        (setq trunks (cons trunk trunks))
        (while (and r (not (vl-every '(lambda ( x ) (vl-position x (apply 'append trunks))) treeentities)))
          (processreverse (car trunk))
          (setq r (cdr (member (car rr) trunk)))
          (if r
            (trunkconst (car r))
          )
          (setq trunk r)
          (setq trunks (cons trunk trunks))
        )
        (if (null dmax)
          (setq dmax 0.0)
        )
        (foreach trunk trunks
          (setq d (apply '+ (mapcar '(lambda ( x ) (vlax-curve-getdistatparam x (vlax-curve-getendparam x))) trunk)))
          (if (> d dmax)
            (setq dmax d trunkmax trunk)
          )
        )
        (setq trunks nil rr nil r nil)
      )
    )
  )
  (setq sss (ssadd))
  (foreach c trunkmax
    (ssadd c sss)
  )
  (prompt "\nHighlighted trunk of maximum length... Sel.set is stored in variable \"sss\". You can call it with (c:sss)...")
  (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds...")
  (sssetfirst nil sss)
  (princ)
)

 

here an example of how this lisp work.

 

image.png

 

0 Likes
Message 8 of 9

john.uhden
Mentor
Mentor
The branching decisions are the key. In the code I offered all the nodes
are included in the main run. The reason is that there are no constraints
provided, such as to have the run make a right instead of a left, or to
stop if the distance to the next exceeds some maximum, or the nodes are on
differing layers or have blocks of a different name, or the run can't cross
a previous leg. IMHO, there have to be some guiding constraints, even if
done by eye.

John F. Uhden

0 Likes
Message 9 of 9

3wood
Advisor
Advisor

Even your example also has many options, such as the one below.

You need set up some rules to make it work.

Capture5.PNG

0 Likes