Author Topic: Searching for nested BLOCKs ( Recursive )  (Read 2486 times)

0 Members and 1 Guest are viewing this topic.

David Bethel

  • Swamp Rat
  • Posts: 656
Searching for nested BLOCKs ( Recursive )
« on: January 12, 2017, 01:56:04 PM »

I'm trying to compile a list of BLOCKs names ( selected and nested in the selection set )

I'm no expert on recursive functions, but this looks like the only way.

My kludge so far :

  • No dynamics blocks
  • Just a single name ( no counting req'd )
  • Just simple model space

Code - Auto/Visual Lisp: [Select]
  1. ;;RECURSIVE SEARCH
  2. (defun nw_nestb (b / nt ne nd nb)
  3.   (setq nt (tblsearch "BLOCK" b)
  4.         ne (cdr (assoc -2 nt)))
  5.   (while ne
  6.     (setq nd (entget ne))
  7.     (and (= "INSERT" (cdr (assoc 0 nd)))
  8.          (setq nb (cdr (assoc 2 nd)))
  9.          (not (member nb bl))
  10.          (setq bl (cons nb bl))
  11.          (nw_nestb nb))
  12.      (setq ne (entnext ne))    )
  13.   (length bl))
  14.  
  15.  
  16. ;;;MAIN PROGRAM
  17. (defun c:nestblk (/ ss i en ed bn) ; bl
  18.   (setq bl nil)
  19.   (while (not ss)
  20.          (princ "\nSelect Blocks To Search...")
  21.          (setq ss (ssget '((0 . "INSERT")))))
  22.   (setq i 0)
  23.   (while (setq en (ssname ss i))
  24.          (setq ed (entget en)
  25.                bn (cdr (assoc 2 ed)))
  26.          (and (not (member bn bl))
  27.               (setq bl (cons bn bl))
  28.               (nw_nestb bn))
  29.          (setq i (1+ i)))
  30.  
  31.   (setq bl (acad_strlsort bl))
  32.  
  33.   (prin1 bl))

It is slow as molasses and ugly as sin.


Any suggestions ?  TIA  -David
R12 Dos - A2K

Lee Mac

  • Seagull
  • Posts: 12906
  • London, England
Re: Searching for nested BLOCKs ( Recursive )
« Reply #1 on: January 12, 2017, 02:24:28 PM »
Quickly written - not sure if this will be any quicker to run:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:nestblk ( / b i l s )
  2.     (if (setq s (ssget '((0 . "INSERT"))))
  3.         (repeat (setq i (sslength s))
  4.             (setq b (cdr (assoc 2 (entget (ssname s (setq i (1- i)))))))
  5.             (or (member b l)
  6.                 (foreach n (nested b)
  7.                     (or (member n l) (setq l (cons n l)))
  8.                 )
  9.             )
  10.         )
  11.     )
  12.     (setq nested:cache nil)
  13.     (print l) (princ)
  14. )
  15. (defun nested ( b / e l n x )
  16.     (cond
  17.         (   (assoc b nested:cache))
  18.         (   (setq e (tblobjname "block" b))
  19.             (while (setq e (entnext e))
  20.                 (if (= "INSERT" (cdr (assoc 0 (setq x (entget e)))))
  21.                     (foreach n (cons (setq n (cdr (assoc 2 x))) (nested n))
  22.                         (or (member n l) (setq l (cons n l)))
  23.                     )
  24.                 )
  25.             )
  26.             (car (setq nested:cache (cons (cons b l) nested:cache)))
  27.         )
  28.     )
  29. )

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: Searching for nested BLOCKs ( Recursive )
« Reply #2 on: January 12, 2017, 02:47:55 PM »
My attempt:

Code - Auto/Visual Lisp: [Select]
  1. (defun NestedBlock ( blk / Lst )
  2.     (cond
  3.       ((and (eq "AcDbBlockReference" (vla-get-ObjectName o)) (not (member (vla-get-EffectiveName o) Lst)))
  4.         (setq Lst (cons (vla-get-EffectiveName o) Lst))
  5.         (NestedBlock o)
  6.       )
  7.     ); cond
  8.   ); vlax-for
  9.   (cons (vla-get-EffectiveName blk) (reverse Lst))
  10. ); defun NestedBlock

Code - Auto/Visual Lisp: [Select]
  1. (defun C:test ( / blk )
  2.   (if
  3.     (and
  4.       (setq blk (car (entsel "\nPick a block: ")))
  5.       (= "INSERT" (cdr (assoc 0 (entget blk))))
  6.     )
  7.     (alert (vl-princ-to-string (NestedBlock (vlax-ename->vla-object blk))))
  8.   )
  9.   (princ)
  10. ); defun test

Result is like:
Code - Auto/Visual Lisp: [Select]
  1. ("MyMainBlock" "MyFirstBlock" "MySecondBlock" "MyThirdBlock")

I was thinking about this before and thought that it would be cool if the return list is nested, representing the nested levels inside the block, like the above should be:
Code - Auto/Visual Lisp: [Select]
  1. ("MyMainBlock" ("MyFirstBlock" ("MySecondBlock" ("MyThirdBlock"))))
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

David Bethel

  • Swamp Rat
  • Posts: 656
Re: Searching for nested BLOCKs ( Recursive )
« Reply #3 on: January 12, 2017, 03:00:46 PM »
Quickly written - not sure if this will be any quicker to run:

Thanks Lee !  I'll look into it.  It does seem to be all the some what of the same thought pattern.

Grrr,

I'm sorry I should have mentioned that I don't have access to any type of VL calls.  Just plain AutoLISP

-David
R12 Dos - A2K

David Bethel

  • Swamp Rat
  • Posts: 656
Re: Searching for nested BLOCKs ( Recursive )
« Reply #4 on: January 13, 2017, 04:59:29 AM »
Lee,  your's  works fine and is a bit faster.  Thank you

Grrr, I tried dissecting yours but I'm so unfamiliar with the visual lisp functions that's its pretty pathetic on my part.  Thanks for the effort.  Hopefully you will find a use -David
R12 Dos - A2K

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Searching for nested BLOCKs ( Recursive )
« Reply #5 on: January 13, 2017, 05:45:33 AM »
@Grrr1337: Why do you have line 6 in your NestedBlock function? :idea:

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: Searching for nested BLOCKs ( Recursive )
« Reply #6 on: January 13, 2017, 06:48:19 AM »
Grrr, I tried dissecting yours but I'm so unfamiliar with the visual lisp functions that's its pretty pathetic on my part.  Thanks for the effort.  Hopefully you will find a use -David

David, heres some light about it:
vlax-for is visual lisp's alternative to foreach [vlax-for <obj> <collection>] ~ [foreach <x> <list>]
Code: [Select]
(vla-item (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object))) (vla-get-EffectiveName blk))means obtaining the block definition's collection [something like (tblobjname "BLOCK" blockname)], but the difference is that collection is something like list, that can be iterated.

Code: [Select]
(eq "AcDbBlockReference" (vla-get-ObjectName o))The above means something like:
Code: [Select]
(eq "INSERT" (cdr (assoc 0 (entget o))))HTH.


@Grrr1337: Why do you have line 6 in your NestedBlock function? :idea:

My fault - thanks for spotting this, Roy!
 Re-tested (not experienced with recursions). It was iterating thru the first level only, so this one is should be closer:
Code - Auto/Visual Lisp: [Select]
  1. (defun NestedBlock ( blk / Lst )
  2.     (cond
  3.       ((and (eq "AcDbBlockReference" (vla-get-ObjectName o)) (not (member (vla-get-EffectiveName o) Lst)))
  4.         (setq Lst (vl-remove nil (cons (vla-get-EffectiveName o) Lst)))
  5.         (setq Lst (vl-remove nil (cons (NestedBlock o) Lst)))
  6.       )
  7.     ); cond
  8.   ); vlax-for
  9.   (reverse Lst)
  10. ); defun NestedBlock
  11.  
  12. (defun C:test ( / blk r )
  13.   (if
  14.     (and
  15.       (setq blk (car (entsel "\nPick a block: ")))
  16.       (= "INSERT" (cdr (assoc 0 (entget blk))))
  17.     )
  18.     (alert (vl-princ-to-string (setq r (NestedBlock (vlax-ename->vla-object blk)))))
  19.   )
  20.   r
  21. ); defun test

Heres a dwg with multi-nested block that can be tested: http://www.megafileupload.com/p28K/NestTest.dwg


The correct return (I think) would be:
Code - Auto/Visual Lisp: [Select]
  1. '(NestedRectangleBlocks
  2.   (Fifth_And_Sixth
  3.     (Fifth Sixth)
  4.   )
  5.   (FirstSecondThirdFourth
  6.     (First_And_Second
  7.       (First Second)
  8.     )
  9.     (Fourth_And_Third
  10.       (Fourth Third)
  11.     )
  12.   )
  13. )
ATM I got:
Code - Auto/Visual Lisp: [Select]
  1. ("Fifth_And_Sixth"
  2.   ("Fifth" "Sixth")
  3.   "FirstSecondThirdFourth"
  4.   ("First_And_Second" ("First" "Second")
  5.     "Fourth_And_Third" ("Third" "Fourth")
  6.   )
  7. )
Lee's version flattens them:
Code - Auto/Visual Lisp: [Select]
  1. ("Fifth_And_Sixth" "Sixth" "Fifth" "FirstSecondThirdFourth" "Third" "Fourth" "Fourth_And_Third" "First" "Second" "First_And_Second" "NestedRectangleBlocks")

Atleast I think that it would be more precise to display the nesting tree/levels (that was my older thought).  :roll:
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

Lee Mac

  • Seagull
  • Posts: 12906
  • London, England
Re: Searching for nested BLOCKs ( Recursive )
« Reply #7 on: January 13, 2017, 01:44:38 PM »
Lee,  your's  works fine and is a bit faster.  Thank you

Excellent - you're most welcome David.  :-)