Author Topic: BlockTableRec.GetBlockReferenceIds returning "ghosts" after array command  (Read 2785 times)

0 Members and 1 Guest are viewing this topic.

redbrandAPI

  • Guest
Greetings all,

I'm working on (what I foolishly believed to be) a simple tool that would count the number of blocks on a certain layer.  Just the number of instances of any blocks on that layer.  The below works just fine if there are only individual block instances placed and associated with the desired layer.

IF, however, one foolishly makes an array of those blocks, there are now additional "ghost" block references and even if I delete the entire array and there are no visible objects in the drawing, there is still between 1 and 3 ghost objects indicated by GetBlockReferenceIds(). 

QUESTION:  How can I tell that these ghosts are not block references to count? 
Would love any insight about how to approach this problem differently or more effectively etc.  Just want the total visible instances of all block instances on any particular layer.

Thanks in advance!
-Ken


Code - C#: [Select]
  1. BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
  2. foreach (ObjectId objId in bt)
  3. {
  4.     BlockTableRecord btr = (BlockTableRecord)objId.GetObject(OpenMode.ForRead);
  5.  
  6.     if (btr.IsLayout) {continue; }
  7.  
  8.     foreach (ObjectId id in btr.GetBlockReferenceIds(true, false))
  9.     {
  10.           Entity acEntity = trx.GetObject(id, OpenMode.ForRead) as Entity;
  11.  
  12.           string layerName = acEntity.Layer;
  13.            if (WeWantThisLayer(layerName))
  14.                      CountIt++;
  15.      }
  16. }
  17.  

Atook

  • Swamp Rat
  • Posts: 1029
  • AKA Tim
I'm not sure what you mean by ghosts, but it might be a good case to implement filters.

I haven't compiled or tested, but maybe this will help:

Code - C#: [Select]
  1. public int NumberOfBlocksOnLayer(string layerName)
  2. {
  3.   int result = 0;
  4.  
  5.   // set us up the editor
  6.   Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  7.   Editor ed = doc.Editor;
  8.  
  9.   // set us up the filter
  10.   TypedValue[] filterArray = new[]
  11.   {
  12.     new TypedValue((int) DxfCode.Operator, "<and"),
  13.     new TypedValue((int) DxfCode.Start, "INSERT"),
  14.     new TypedValue((int) DxfCode.LayerName, layerName),
  15.     new TypedValue((int) DxfCode.Operator, "and>"),
  16.   };
  17.   SelectionFilter filter = new SelectionFilter(filterArray);
  18.  
  19.   // select us up the blocks on the layer
  20.   PromptSelectionResult psr =
  21.   ed.SelectAll(filter);
  22.   if (psr.Status == PromptStatus.OK)
  23.   {
  24.     result = psr.Value.GetObjectIds().Length;
  25.   }
  26.  
  27.   return result;
  28. }
  29.  
  30.  

Good luck.

redbrandAPI

  • Guest
Hi Atook,

Thanks for looking at this and thank you very much for the suggestion.  I will try that out first thing tomorrow.  (really just need to get this done at this point so if it works then awesome!)

As for the ghosts I'll try to put together a more comprehensive example and test file as I would be curious to learn more.  It seems that the AutoCAD DB is a bit murky and would love some clarity.

Thanks again!
-Ken

redbrandAPI

  • Guest
I'm going to venture a guess and say that the Array command is actually creating some kind of secret (anonymous?) block (dynamic or otherwise) behind the scenes.  Before creating the array, I have one block reference and one block in Purge listed under "items you cannot purge".  No blocks listed under items I can purge.

Once I create the array I now have blocks *U9, *U10, and the original block listed as "cannot purge".

If I delete the array: now *U10 is listed as "Can" purge whereas *U9 and original block are still listed as cannot purge.

Thoughts on how to tell when I've got a reference to a *Ux block?  IsAnonymous doesn't seem to work though will investigate further tomorrow.  As a last resort I suppose I can check for *xx in the BlockTableRecord Name property. 

redbrandAPI

  • Guest
So, the selection code ran but did no better at counting the actual instances.  I have one array of 12 blocks and the report is 1 item selected.  (the array)

I believe this is what is happening (and would be happy to have any clarification on this):
When the user creates an Array of a block, the first thing that happens is that AutoCAD creates an anonymous block, say *U3 which references the original block "myBlock", making "myBlock" a nested block of *U3.  It then proceeds to create *U4 which is what I will call "AutoCAD's secret dynamic block for arrays" which then references *U3 as many times as there are instances of the *U3 block.  So *U4 ALSO has a nested reference to "myBlock"!

So, calling GetBlockReferenceIds with DirectOnly = True, I get "1"
calling with DirectOnly = False (i.e., include nested blocks) I get "13"

There are 12 items on screen: this is quite disconcerting. 

Any suggestions on how to sort this out?  I don't seem to be able to find any way to determine if the block is actually referenced in a "placed" instance of the block.  Meaning that when I delete the array entirely, I still have references to "myBlock" returned by *U3 which seems to "wait in the wings" even though there are no instances of "myBlock" actually placed in the drawing.

I'm feeling like "GetBlockReferenceIds" may not be the correct way to go about this, is there a way to iterate the actual placed objects and see if they are blocks?

How would anyone do an automated takeoff on any drawing that includes arrayed items?

Thanks again for any suggestions, clarifications, or comments

sonny3g

  • Newt
  • Posts: 27
I am curious if the array is created as an associated array, or in other words, the array has 12 objects, but the way it is created it is seen as a group object of 1?

Don't know if this helps you with your program, but, might help identify the problem with the arrayed blocks.

redbrandAPI

  • Guest
Hi Sonny,

Very good question, I'm also battling a bit of "I don't really know much about AutoCAD" as I've been 100% Revit API for years now. 

Here's how I created the array in AutoCAD 2017:
1. place one instance of the "myBlock"
2. type Array command
3. select the placed "myBlock"
4. Choose "Rectangular"
5. Enter (which seems to create a default 4x3 array, hence the 12 objects)

is this an "associated array"?

sonny3g

  • Newt
  • Posts: 27
There is a selection to make it an associated array when you create it.  The best way to know if it is an associated array is to pick one of the objects.  If they all highlight, then it was created as an associated array.

n.yuan

  • Bull Frog
  • Posts: 348
"Array" command in AutoCAD evolved from purely a way to drawing multiple entities in one command (e.g. after the command, no matter how many rows/lines of the entities, they are still individual ones, not "associated to others), to later the result of array being an dynamic block with grips that user can drag the dynamic block to increase/decrease rows/lines (I am not since when this change happened, maybe Acad2005 when dynamic block was introduced?).

Now AutoCAD has command Array(or ARRAYRECT/ARRAYPOLAR) and ARRAYCLASSIC. ARRAYCLASSIC is the old, original ARRAY command in earlier AutoCAD that results in individual entities.

Since ARRAYing block creates a new dynamic block, which add block reference entity into new anonymous block definition, so, yes, when you count particular blockreference, you have to decide if you want to count the block reference nested in other block definition (anonymous block definition, in your case).

Also, there is another type of block referemce: MInsertBlock, which looks like multiple block references to the same block definition, but it is actually a single entity with multiple block definition visually shown. That is, it is one reference to the block definition, but visually showing multiple times. it is different from an block array (a dynamic block reference).