Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

scan blocks and nested blocks

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
Moshe-A
2664 Views, 16 Replies

scan blocks and nested blocks

Hi ALL

 

I would like to write a program that scans the block table records

to find blocks and nested blocks.

 

(setq BlocksTable (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))))

(vlax-for BlkTblRec  BlocksTable

 .........................

)

 

if a BlkTblRec contains nested blocks i would like to scan it's block table

i know i can scan the BlkTblRec for it's Objects and find inserts and from there go to the

block definition but this is not good enought because not all blocks have inserts

 

is there any solusion to this except writeout/copy the block definition to a new

document and scan it's block table?

 

thanks in advance

Moshe

 

  

16 REPLIES 16
Message 2 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

Hi ALL

 

I would like to write a program that scans the block table records

to find blocks and nested blocks.

....

i know i can scan the BlkTblRec for it's Objects and find inserts and from there go to the

block definition but this is not good enought because not all blocks have inserts

....  


There have been various questions here before about listing nested blocks.  I did a quick Search, and the first couple of threads I looked at seemed to be based on insertions, not just definitions.  But I didn't look very far through the Search results list -- there may well be something in there that does what you want.

Kent Cooper, AIA
Message 3 of 17
Moshe-A
in reply to: Kent1Cooper

Kent,

thank you for your reply

i did searched here before putting this and did another search now and still did not find the best solution.

Are you sure this can be done without coping the block definition out to a new database document?

Moshe

 

Message 4 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

....

Are you sure this can be done without coping the block definition out to a new database document?

....


If what you want is just a list of Block definitions, including nested Blocks, that's easy, because nested Blocks' definitions are also in the Block table, which doesn't care about such things:

 

(while

  (setq ins (cdadr (tblnext "block" (not ins))))

  (setq inslist (cons ins inslist))

)

 

That returns a list of all Block definitions, nested or otherwise, and saves it to the 'inslist' variable.  I assume you are not looking for something like a count, or something involving a user selection, because of your wanting Blocks that are not inserted to be included.

 

[It would also include Xrefs and Windows Metafiles, which are also "INSERT" objects, and old-style Hatch patterns (which you could filter out by removing ones with names starting with "*X"), and even dimensions (which you could filter out by their "*D" beginnings).  At least it does in my ol' 2004, though some of that may have changed since.]

 

If you want something else, such as a distinction between which Blocks are top-level and which are nested, that's more complicated [or, it might not be possible -- a nested Block can also be inserted at top level independently of any Block definition in which it may also happen to be nested].

 

Or maybe you want something that lists which Block definitions are nested within which other Block definitions.  I have something that will do that for a user-selected Block insertion, which could probably be modified to work through the Block table instead.

 

If I haven't described what you're really looking for, maybe you can describe more specifically what you would want to come out the other end of a routine.

Kent Cooper, AIA
Message 5 of 17
Moshe-A
in reply to: Kent1Cooper

Kent

 

Or maybe you want something that lists which Block definitions are nested within which other Block definitions.  I have something that will do that for a user-selected Block insertion, which could probably be modified to work through the Block table instead

 

Yes that exectly what i am looking for but also want to know if there are also blocks that are nested and

doesn't have a reference at all

 

Moshe

 

 

 

 

Message 6 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

....something that lists which Block definitions are nested within which other Block definitions.  I have something that will do that for a user-selected Block insertion, which could probably be modified to work through the Block table instead

 

Yes that exectly what i am looking for but also want to know if there are also blocks that are nested and

doesn't have a reference at all

.... 


Here's that routine.  Somehow, it should be adjustable to go through the Block table and make a sub-list of all Blocks in other Blocks' definitions.  Then I guess something could be added to search for insertions of a given Block and of any Block(s) that it's nested in.

Kent Cooper, AIA
Message 7 of 17
Moshe-A
in reply to: Kent1Cooper

Kent,

 

thank you but (you know) that this only gets the ones that has a reference

 

it's weird that AutoCAD didn't give us the tool to do this because i am very sure

this information is in the current document (otherwise AutoCAD it self could not

write out a WBLOCK or do other task with blocks)

 

again thank you very much

 

Moshe

 

 

 

Message 8 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

.... 

thank you but (you know) that this only gets the ones that has a reference

 

....i am very sure

this information is in the current document (otherwise AutoCAD it self could not

write out a WBLOCK or do other task with blocks)

.... 


Yes, that's what I meant about adjusting it to look through the table, rather than require a User selection.  I may give that a try some time soon, but not today.  But if you have an idea what kind of format you would prefer for the reporting of the results, that would be helpful.  I'm thinking maybe a list of sub-lists, each sub-list starting with a Block name and continuing with all the names of Blocks that are nested in its definition.  But maybe some kind of text file would be more useful for your purposes -- how would you use the information?

 

All AutoCAD needs to write out a WBLOCK, etc., is the Block definitions, which you can get a list of easeily enough [see Message 4].  For such purposes, I don't think it really has any need to know whether any of them are nested in others.

 

I wondered whether this might have come up before, and found this thread:

http://forums.autodesk.com/t5/Visual-LISP-AutoLISP-and-General/Block-Tree-View/m-p/804933/highlight/...

but it seems to be about something that AutoCAD used to be able to do for you, but won't any more.

Kent Cooper, AIA
Message 9 of 17
Moshe-A
in reply to: Kent1Cooper

Kent,

 

I'm thinking maybe a list of sub-lists, each sub-list starting with a Block name and continuing with all the names of Blocks that are nested in its definition.  But maybe some kind of text file would be more useful for your purposes -- how would you use the information?

 

the output format should be a simple one that would give a quick relation between

the parent block and it's nested ones (a text file is OK)

 

the idea to writting such a program came to me this week. times i encounter situations were user want

to purge a block from drawing and can not because the block is nested

or want to detach an xref and can not because it is nested or have multiple references

 

i want to find the block tree and help the user how should he fix it.

Moshe

 

 

 

 

Message 10 of 17
Moshe-A
in reply to: Kent1Cooper

Kent,

 

did some search (in online-help) for the Block Object & Document Object and

was suprise to discover that there is no method to direct copy/write out a Block Object

to other document or save it to a file

 

the only way i found is to insert the block and then use Wblock method to save it to a file

or use copyObject Method to copy it to another document by specifing a new owner document

 

Did you find somthing else?

 

Moshe

 

Message 11 of 17
Moshe-A
in reply to: Moshe-A

Kent,

 

did some work on this yesterday,  i have writting some code and what i have found is this:-

there is no such thing Block with Nested Block that have no reference

(sorry if i a little mislead you on that)

 

if you have a file let call it "A.DWG" and it contains block "B" and "C"

block "B" has reference but block "C" have not

 

if "A.DWG" is insert in current dwg, block "A" contains block "B" as nested block

but block "C" is not although block "C" is copied in.

for many years i thought block "C" is nested in "A" even if it does not have a reference

 

so i guess thats take me back to your code

 

have a nice weekend.

Moshe

 

 

Message 12 of 17
_gile
in reply to: Moshe-A

Hi,

 

Something like this ?

 

 

(defun c:ScanBlocks (/ foo efName name def)
  (vl-load-com)
  (defun foo (pref blk)
    (vlax-for o	blk
      (if
	(and
	  (= (vla-get-ObjectName o) "AcDbBlockReference")
	  (setq	name (vla-get-Name o)
		efName (vlax-get o
			       (if (vlax-property-available-p o 'EffectiveName)
				 'EffectiveName
				 'Name
			       )
		     )
	  )
	  (setq def (vla-item *blocks* efName))
	  (= (vla-get-IsXref def) :vlax-false)
	)
	 (progn
	   (princ (strcat "\n"
			  pref
			  "\""
			  name
			  "\""
			  (if (/= name efName)
			    (strcat "(" efName ")")
			    ""
			  )
		  )
	   )
	   (foo (strcat "  " pref) def)
	 )
	 ""
      )
    )
  )
  (or *acad* (setq *acad* (vlax-get-acad-object)))
  (or *acdoc* (setq *acdoc* (vla-get-ActiveDocument *acad*)))
  (or *blocks* (setq *blocks* (vla-get-Blocks *acdoc*)))
  (vlax-for b *blocks*
    (if	(and (= (vla-get-IsXref b) :vlax-false)
	     (= (vla-get-IsLayout b) :vlax-false)
	)
      (progn
	(princ (strcat "\n\n_\"" (vla-get-Name b) "\""))
	(foo "  |_" b)
      )
    )
  )
  (textscr)
  (princ)
)

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 13 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

....there is no such thing Block with Nested Block that have no reference

.... 

if you have a file let call it "A.DWG" and it contains block "B" and "C"

block "B" has reference but block "C" have not

 

if "A.DWG" is insert in current dwg, block "A" contains block "B" as nested block

but block "C" is not.... 


That doesn't align with my experience.  We have a drawing with common/typical kitchen cabinet elevations as Block definitions, but it contains nothing actually drawn or inserted.  We used to insert that drawing into a drawing for Kitchen Interior Elevations for a particular job, and it brought all the Block definitions with it, though none of them are referenced.  We now do it differently, with a routine that calls up the Design Center in that drawing's Block list, so that we don't put all those Block definitions into every job, and so we don't need to purge the ones we don't use [typically, many more than the ones we do use in a particular job].  But the "concept" of inserting a drawing containing un-referenced Block definitions, and having those definitions available in the drawing that's inserted into, remains valid for us, even though we don't do it that way any more.  Could that be a version-specific difference?  We're back in 2004.

Kent Cooper, AIA
Message 14 of 17
Moshe-A
in reply to: Kent1Cooper

Kent,

i think you did understand me partly

here my qoute:-

if "A.DWG" is insert in current dwg, block "A" contains block "B" as nested block

but block "C" is not although block "C" is copied in.

the unreferenced block "C" is copied in (inserted) but it is not

part of block "A" and you can purge it right after the insert - am i right?

Moshe

Message 15 of 17
_gile
in reply to: Moshe-A

Hi,

 

Here're some routines to purge blocks, get all block record references (inserted in the drawing and/or nested in block records), evaluate if a block is referenced. from this thread :

http://www.theswamp.org/index.php?topic=37186.0

 

 

;; gc:GetReferences
;; Returns the unerased block reference list for the block
;;
;; Arguments
;; bname: block name
;; flag:  sum of the following binary codes
;;	  1 = nested in blocks
;;	  2 = inserted in model space
;;         4 = inserted in paper space
(defun gc:GetReferences	(bname flag / blk refs elst)
  (if
    (and
      (setq blk (tblobjname "BLOCK" bname))
      (setq refs (vl-remove-if-not 'cdr
		   (mapcar
		     (function
		       (lambda (x)
			 (if (setq elst (entget x))
			   (cons x (entget (cdr (assoc 330 elst))))
			 )
		       )
		     )
		     (gc:massoc 331 (entget (cdr (assoc 330 (entget blk)))))
		   )
		 )
      )
    )
     (if (= 7 flag)
       (mapcar 'car refs)
       (if (< 0 flag 7)
	 (mapcar 'car
		 (vl-remove-if
		   (function
		     (lambda (x)
		       (wcmatch	(strcase (cdr (assoc 2 (cdr x))))
				(cond
				  ((= 1 flag) "`**_SPACE*")
				  ((= 2 flag) "~`*MODEL_SPACE")
				  ((= 3 flag) "`*PAPER_SPACE*")
				  ((= 4 flag) "~`*PAPER_SPACE*")
				  ((= 5 flag) "`*MODEL_SPACE*")
				  ((= 6 flag) "~`**_SPACE*")
				)
		       )
		     )
		   )
		   refs
		 )
	 )
       )
     )
  )
)

;; gc:IsReferenced
;; Evaluates if the block is referenced
;;
;; Argument
;; bname: block name
(defun gc:IsReferenced (bname / blk)
  (and
    (setq blk (tblobjname "BLOCK" bname))
    (setq blkRec (cdr (assoc 330 (entget blk))))
    (setq blkRefs (vl-remove nil (mapcar 'entget (gc:massoc 331 (entget blkRec)))))
    (vl-some 'vl-consp (mapcar '(lambda (x) (entget (cdr (assoc 330 x)))) blkRefs))
  )
)

;; gc:purgeBlock
;; Purges the blocks which names matches with tha pattern
;;
;; Argument
;; pat: pattern (wildcard patterns allowed, not case sensitive)

(defun gc:purgeBlock (pat / massoc blk name blst loop)
  (vl-load-com)
  (while (setq blk (tblnext "BLOCK" (not blk)))
    (if
      (and
	(wcmatch (strcase (setq name (cdr (assoc 2 blk)))) (strcase pat))
	(< (cdr (assoc 70 (setq elst (entget (tblobjname "BLOCK" name))))) 4)
      )
      (setq blst (cons (cdr (assoc 330 elst)) blst))
    )
  )
  (setq loop T)
  (while (and loop blst)
    (setq loop nil)
    
    (foreach b blst
      (or (vl-some 'entget (gc:massoc 331 (entget b)))
	(progn
	  (setq blk (vlax-ename->vla-object b))
	  (vlax-for o blk
	    (if	(= (vla-get-ObjectName o) "AcDbBlockReference")
	      (vla-Delete o)
	    )
	  )
	  (vla-delete blk)
	  (setq blst (vl-remove b blst))
	  (setq loop T)
	)
      )
    )
  )
)

;; gc:massoc
;; Returns the list of all values for the specified group code in an association list
;;
;; Arguments
;; code: group code
;; alst: association list
(defun gc:massoc (code alst)
  (if (setq alst (member (assoc code alst) alst))
    (cons (cdar alst) (gc:massoc code (cdr alst)))
  )
)

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 16 of 17
Kent1Cooper
in reply to: Moshe-A


@Moshe-A wrote:

....

the output format should be a simple one that would give a quick relation between

the parent block and it's nested ones (a text file is OK)

 

.... times i encounter situations were user want

to purge a block from drawing and can not because the block is nested ....


If the idea is to find Blocks nested in other Blocks/Xrefs, so that you can find where to go to eliminate them if possible, in order to be able to Purge them, then I assume you don't have any need to list Blocks/Xrefs that have no nested Blocks in them [there could be lots of those you wouldn't want to wade through].  And I assume you don't care about old-style Hatch patterns, or Dimension "blocks" that can have arrowhead Blocks nested in them [there could be lots of those].

 

The attached seems to work to list only Blocks/Xrefs that have other Insert objects nested in them [but it has comments on how to include even those that don't, if you want].  It reports in list-of-lists form, with a sub-list for each Block that contains nested Blocks [or for each Block name, if you choose].  Each sub-list starts with the parent Block name, and follows that with all names of Blocks contained at the top level in its definition.  Anything nested further down would appear in the list for the parent Block in which it is on the top level.

Kent Cooper, AIA
Message 17 of 17
Moshe-A
in reply to: Kent1Cooper

Excellent Kent, thank you very much it's works like a charm.

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


AutoCAD Beta