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
Solved! Go to Solution.
Solved by Moshe-A. Go to Solution.
@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,
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
@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
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
@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,
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
@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:
but it seems to be about something that AutoCAD used to be able to do for you, but won't any more.
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
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
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
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) )
@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,
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
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))) ) )
@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.
Can't find what you're looking for? Ask the community or share your knowledge.