Counting nested blocks very fast

Counting nested blocks very fast

Anonymous
Not applicable
3,605 Views
27 Replies
Message 1 of 28

Counting nested blocks very fast

Anonymous
Not applicable
Hi at all,
I have a a performance issue when counting nested blocks and hope that someone could help me.
I want to count blocks on Layers H_60* which have the attributes ArticleID and a Multiplier. These blocks can be nested blocks but will not have any further nested blocks. The drawings can be very big but the counting should work in less than a second.
My approach is in the attachment but it is not fast enough. The method gets the objectIds which aefound on Layer "H_60*"

The profiler shows that that line 92 hits more than 300000 times in a drawing with 2200 blocks of the same type.
Do I need to go through the whole blocktablerecord just to find a specific attribute?
Lines 88-92:
{code}
BlockTableRecord blockTableRecord = (BlockTableRecord)currentBlock.BlockTableRecord.GetObject(OpenMode.ForRead,false);
ObjectIdCollection nestedBlockIds = new ObjectIdCollection();
foreach (ObjectId objectId in blockTableRecord)
{
Entity entity = (Entity)transAction.GetObject(objectId, OpenMode.ForRead);
{code}

Is there a faster way of counting nested blocks with the API? EATTEXT and bcount does not seem to work for me.

Is there a faster way than the code above and running through all objectId or tablerecord like this?
{code}
foreach (ObjectId currentSelectedObjectId in objectIds)
{
Entity currentSelectedEntity = (Entity)transAction.GetObject(currentSelectedObjectId, OpenMode.ForRead);

{
BlockReference currentBlock = (BlockReference)currentSelectedEntity;
...
{code}

Thanks in advanced Edited by: hcaddev on Feb 9, 2009 11:53 AM
0 Likes
3,606 Views
27 Replies
Replies (27)
Message 21 of 28

Anonymous
Not applicable
I'm sorry that I have used the wrong expression 'dynamic attribute'. I think the correct name is unconstant. E.g. the user should be available to change the value of the attribute like the 'multiplier' but he should not change the constant attribute 'articleID'.

Thank for you good hints. I will try to add additional XData/XRecords for the articleID to get them faster.
As far as all my objectIDs on layers H_60* can be nested I try to use your suggestion with blk.GetBlockReferenceIds. And if I understood it correctly I will get the ids of the nested blocks and have to check these again for nested block references, won't I?

You said that it is a bit more complicated with dynamic blocks. What do I have to keep in mind with that? Of cause we do have many dynamic blocks (blocks where you can take a edge and resize it etc.)
0 Likes
Message 22 of 28

Anonymous
Not applicable
>>Thanks for the link, but it's quite unnecessary.
Didn't you just ask why you cannot cast an object of type Line to
an object of type BlockReference?

"Joe Sutphin" wrote in message news:6122550@discussion.autodesk.com...
Who the hell is Steve?

Thanks for the link, but it's quite unnecessary.

Joe ...


"Tony Tanzillo" wrote in message
news:6122530@discussion.autodesk.com...
Steve/Joe, I did not use TryCast() in my example,
because my example was C#, not VB.

Perhaps this might help:

http://msdn.microsoft.com/vstudio/express/beginner/


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6122515@discussion.autodesk.com...
Why did you not use TryCast() in your example?

Joe ...


"Tony Tanzillo" wrote in message
news:6122194@discussion.autodesk.com...
See TryCast() in the docs.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6121944@discussion.autodesk.com...
Why does the following line give me an error "Unable to cast object of type
'Autodesk.AutoCAD.DatabaseServices.Line' to type
'Autodesk.AutoCAD.DatabaseServices.BlockReference'."


Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)


Joe ...


"Tony Tanzillo" wrote in message
news:6121701@discussion.autodesk.com...
{code}

Wrong:

if (entity.GetType().Equals(typeof(BlockReference)))
{
}

Right:

BlockReference blockref = entity as BlockReference;
if( blockref != null )
{
}

{code}

Your code is also not efficient because it is processing
a collection of ObjectIds, but is only interested in those
items that are ids of BlockReferences. The mistake you
make is first casting the result of GetObject() to an Entity,
and then testing the entity's type to see if it is equal to
typeof(BlockReference), which isn't necessary.

You can just cast the result of GetObject() directly to a
BlockReference using 'as', and if the result of the cast is
null, that means the object isn't a block reference:

{code}

Transaction tr = //......

foreach( ObjectId id in idCollection )
{
BlockReference blkref = tr.GetObject(id, OpenMode.ForRead ) as
BlockReference;
if( blkref != null )
{
// found a BlockReference - use it
}
}

{code}

If you can limit yourself to AutoCAD 2009 or later, you can
get even better performance by taking a different approach,
using the new ObjectClass property of ObjectId, like this:

{code}

// Get the RXClass for BlockReference:

RXClass blockRefRXClass = RXObject.GetClass( typeof( BlockReference ) );

ObjectIdCollection ids = //.....
Transaction tr = //....

// Notice that this code does not have to open each
// ObjectId, because it uses the ObjectId's ObjectClass
// property to determine if the id represents an entity of
// the desired type, which is much faster than creating a
// managed wrapper and testing its type:

using( Transaction tr = db.TransactionManager.StartTransaction() )
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass.IsSubClassOf( blockRefRXClass ) )
{
// then it's a BlockReference, so open and use it:

BlockReference blkref = tr.GetObject( id, OpenMode.ForRead ) as
BlockReference;

}
}
}

{code}

As far as the balance of your code goes, I'm not entirely sure what
the ultimate goal is, but if you are going through model space and
collecting attributes, but are only interested in certain attributes with
specific tags, you can use this specilization of Dictionary to find the
needed attributes without having to open and look at every attribute
in each block reference:

{code}

public class AttributeDictionary : Dictionary
{
private int found = 0;

public AttributeDictionary( BlockReference blockref, params string[]
tags )
: base( StringComparer.InvariantCultureIgnoreCase )
{
if( tags != null )
{
foreach( string tag in tags )
{
base.Add( tag, string.Empty );
}
}

Transaction tr =
blockref.Database.TransactionManager.TopTransaction;
if( tr == null )
throw new InvalidOperationException(" no transaction! ");

foreach( ObjectId id in blockref.AttributeCollection )
{
AttributeReference att = tr.GetObject( id, OpenMode.ForRead ) as
AttributeReference;
string tag = att.Tag.Trim();
if( base.ContainsKey( tag ) )
{
base[tag] = att.TextString;
if( base.Count == ++found )
break;
}
else if( tags == null )
base.Add( tag, att.TextString );
}
}
}

// Example use:


BlockReference myBlockRef = myTrans.GetObject( blah blah... );

// this gets the two attributes whose tags are "COST"
// and "COLOR", and once it finds both of those it will
// not continue looking at any additional attributes:

AttributeDictionary atts =
new AttributeDictionary( myBlockRef, "COST", "COLOR");

// then, the attribute values can be referenced using the
// tag as an index key:

string cost = atts["COST"];
string color = atts["COLOR"];

{code}



--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


wrote in message news:6121562@discussion.autodesk.com...
We are using AutoCAD 2009 (has to work in 2008 but maybe it is ok just to
support 2009) The visual Studio Version ins 2008 I had the same idea with
saving used block in a dictionary. Code attached. The code is not jet
finished. It i just a prototype to see if this way is the better one
(currently it workes iterative). Is that way better? I think the problem is
that I look at the blocktablerecord to find a spezific attribute. But I go
through the whole blocktablerecord.
0 Likes
Message 23 of 28

Anonymous
Not applicable
No, I ask "Why did you not use TryCast() in your example?"

Joe ...


"Paul Richardson" wrote in message
news:6122665@discussion.autodesk.com...
>>Thanks for the link, but it's quite unnecessary.
Didn't you just ask why you cannot cast an object of type Line to
an object of type BlockReference?

"Joe Sutphin" wrote in message
news:6122550@discussion.autodesk.com...
Who the hell is Steve?

Thanks for the link, but it's quite unnecessary.

Joe ...


"Tony Tanzillo" wrote in message
news:6122530@discussion.autodesk.com...
Steve/Joe, I did not use TryCast() in my example,
because my example was C#, not VB.

Perhaps this might help:

http://msdn.microsoft.com/vstudio/express/beginner/


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6122515@discussion.autodesk.com...
Why did you not use TryCast() in your example?

Joe ...


"Tony Tanzillo" wrote in message
news:6122194@discussion.autodesk.com...
See TryCast() in the docs.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6121944@discussion.autodesk.com...
Why does the following line give me an error "Unable to cast object of type
'Autodesk.AutoCAD.DatabaseServices.Line' to type
'Autodesk.AutoCAD.DatabaseServices.BlockReference'."


Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)


Joe ...


"Tony Tanzillo" wrote in message
news:6121701@discussion.autodesk.com...
{code}

Wrong:

if (entity.GetType().Equals(typeof(BlockReference)))
{
}

Right:

BlockReference blockref = entity as BlockReference;
if( blockref != null )
{
}

{code}

Your code is also not efficient because it is processing
a collection of ObjectIds, but is only interested in those
items that are ids of BlockReferences. The mistake you
make is first casting the result of GetObject() to an Entity,
and then testing the entity's type to see if it is equal to
typeof(BlockReference), which isn't necessary.

You can just cast the result of GetObject() directly to a
BlockReference using 'as', and if the result of the cast is
null, that means the object isn't a block reference:

{code}

Transaction tr = //......

foreach( ObjectId id in idCollection )
{
BlockReference blkref = tr.GetObject(id, OpenMode.ForRead ) as
BlockReference;
if( blkref != null )
{
// found a BlockReference - use it
}
}

{code}

If you can limit yourself to AutoCAD 2009 or later, you can
get even better performance by taking a different approach,
using the new ObjectClass property of ObjectId, like this:

{code}

// Get the RXClass for BlockReference:

RXClass blockRefRXClass = RXObject.GetClass( typeof( BlockReference ) );

ObjectIdCollection ids = //.....
Transaction tr = //....

// Notice that this code does not have to open each
// ObjectId, because it uses the ObjectId's ObjectClass
// property to determine if the id represents an entity of
// the desired type, which is much faster than creating a
// managed wrapper and testing its type:

using( Transaction tr = db.TransactionManager.StartTransaction() )
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass.IsSubClassOf( blockRefRXClass ) )
{
// then it's a BlockReference, so open and use it:

BlockReference blkref = tr.GetObject( id, OpenMode.ForRead ) as
BlockReference;

}
}
}

{code}

As far as the balance of your code goes, I'm not entirely sure what
the ultimate goal is, but if you are going through model space and
collecting attributes, but are only interested in certain attributes with
specific tags, you can use this specilization of Dictionary to find the
needed attributes without having to open and look at every attribute
in each block reference:

{code}

public class AttributeDictionary : Dictionary
{
private int found = 0;

public AttributeDictionary( BlockReference blockref, params string[]
tags )
: base( StringComparer.InvariantCultureIgnoreCase )
{
if( tags != null )
{
foreach( string tag in tags )
{
base.Add( tag, string.Empty );
}
}

Transaction tr =
blockref.Database.TransactionManager.TopTransaction;
if( tr == null )
throw new InvalidOperationException(" no transaction! ");

foreach( ObjectId id in blockref.AttributeCollection )
{
AttributeReference att = tr.GetObject( id, OpenMode.ForRead ) as
AttributeReference;
string tag = att.Tag.Trim();
if( base.ContainsKey( tag ) )
{
base[tag] = att.TextString;
if( base.Count == ++found )
break;
}
else if( tags == null )
base.Add( tag, att.TextString );
}
}
}

// Example use:


BlockReference myBlockRef = myTrans.GetObject( blah blah... );

// this gets the two attributes whose tags are "COST"
// and "COLOR", and once it finds both of those it will
// not continue looking at any additional attributes:

AttributeDictionary atts =
new AttributeDictionary( myBlockRef, "COST", "COLOR");

// then, the attribute values can be referenced using the
// tag as an index key:

string cost = atts["COST"];
string color = atts["COLOR"];

{code}



--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


wrote in message news:6121562@discussion.autodesk.com...
We are using AutoCAD 2009 (has to work in 2008 but maybe it is ok just to
support 2009) The visual Studio Version ins 2008 I had the same idea with
saving used block in a dictionary. Code attached. The code is not jet
finished. It i just a prototype to see if this way is the better one
(currently it workes iterative). Is that way better? I think the problem is
that I look at the blocktablerecord to find a spezific attribute. But I go
through the whole blocktablerecord.
0 Likes
Message 24 of 28

Anonymous
Not applicable
>>Why does the following line give me an error "Unable to cast object of type 'Autodesk.AutoCAD.DatabaseServices.Line' to type
>>'Autodesk.AutoCAD.DatabaseServices.BlockReference'."
>>Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)

I did not post the example. Here is your question. You took Tony's code which used 'as'
to return null if the cast fails and did understand how to do the same in VB. Where did you
mention or use trycast here?

The reason we all know you are the person who uses the Steve alias to cowardly attack others
is because you used the Steve email with your real name in a post recently. Should I find it for
you?


"Joe Sutphin" wrote in message news:6122794@discussion.autodesk.com...
No, I ask "Why did you not use TryCast() in your example?"

Joe ...


"Paul Richardson" wrote in message
news:6122665@discussion.autodesk.com...
>>Thanks for the link, but it's quite unnecessary.
Didn't you just ask why you cannot cast an object of type Line to
an object of type BlockReference?

"Joe Sutphin" wrote in message
news:6122550@discussion.autodesk.com...
Who the hell is Steve?

Thanks for the link, but it's quite unnecessary.

Joe ...


"Tony Tanzillo" wrote in message
news:6122530@discussion.autodesk.com...
Steve/Joe, I did not use TryCast() in my example,
because my example was C#, not VB.

Perhaps this might help:

http://msdn.microsoft.com/vstudio/express/beginner/


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6122515@discussion.autodesk.com...
Why did you not use TryCast() in your example?

Joe ...


"Tony Tanzillo" wrote in message
news:6122194@discussion.autodesk.com...
See TryCast() in the docs.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6121944@discussion.autodesk.com...
Why does the following line give me an error "Unable to cast object of type
'Autodesk.AutoCAD.DatabaseServices.Line' to type
'Autodesk.AutoCAD.DatabaseServices.BlockReference'."


Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)


Joe ...


"Tony Tanzillo" wrote in message
news:6121701@discussion.autodesk.com...
{code}

Wrong:

if (entity.GetType().Equals(typeof(BlockReference)))
{
}

Right:

BlockReference blockref = entity as BlockReference;
if( blockref != null )
{
}

{code}

Your code is also not efficient because it is processing
a collection of ObjectIds, but is only interested in those
items that are ids of BlockReferences. The mistake you
make is first casting the result of GetObject() to an Entity,
and then testing the entity's type to see if it is equal to
typeof(BlockReference), which isn't necessary.

You can just cast the result of GetObject() directly to a
BlockReference using 'as', and if the result of the cast is
null, that means the object isn't a block reference:

{code}

Transaction tr = //......

foreach( ObjectId id in idCollection )
{
BlockReference blkref = tr.GetObject(id, OpenMode.ForRead ) as
BlockReference;
if( blkref != null )
{
// found a BlockReference - use it
}
}

{code}

If you can limit yourself to AutoCAD 2009 or later, you can
get even better performance by taking a different approach,
using the new ObjectClass property of ObjectId, like this:

{code}

// Get the RXClass for BlockReference:

RXClass blockRefRXClass = RXObject.GetClass( typeof( BlockReference ) );

ObjectIdCollection ids = //.....
Transaction tr = //....

// Notice that this code does not have to open each
// ObjectId, because it uses the ObjectId's ObjectClass
// property to determine if the id represents an entity of
// the desired type, which is much faster than creating a
// managed wrapper and testing its type:

using( Transaction tr = db.TransactionManager.StartTransaction() )
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass.IsSubClassOf( blockRefRXClass ) )
{
// then it's a BlockReference, so open and use it:

BlockReference blkref = tr.GetObject( id, OpenMode.ForRead ) as
BlockReference;

}
}
}

{code}

As far as the balance of your code goes, I'm not entirely sure what
the ultimate goal is, but if you are going through model space and
collecting attributes, but are only interested in certain attributes with
specific tags, you can use this specilization of Dictionary to find the
needed attributes without having to open and look at every attribute
in each block reference:

{code}

public class AttributeDictionary : Dictionary
{
private int found = 0;

public AttributeDictionary( BlockReference blockref, params string[]
tags )
: base( StringComparer.InvariantCultureIgnoreCase )
{
if( tags != null )
{
foreach( string tag in tags )
{
base.Add( tag, string.Empty );
}
}

Transaction tr =
blockref.Database.TransactionManager.TopTransaction;
if( tr == null )
throw new InvalidOperationException(" no transaction! ");

foreach( ObjectId id in blockref.AttributeCollection )
{
AttributeReference att = tr.GetObject( id, OpenMode.ForRead ) as
AttributeReference;
string tag = att.Tag.Trim();
if( base.ContainsKey( tag ) )
{
base[tag] = att.TextString;
if( base.Count == ++found )
break;
}
else if( tags == null )
base.Add( tag, att.TextString );
}
}
}

// Example use:


BlockReference myBlockRef = myTrans.GetObject( blah blah... );

// this gets the two attributes whose tags are "COST"
// and "COLOR", and once it finds both of those it will
// not continue looking at any additional attributes:

AttributeDictionary atts =
new AttributeDictionary( myBlockRef, "COST", "COLOR");

// then, the attribute values can be referenced using the
// tag as an index key:

string cost = atts["COST"];
string color = atts["COLOR"];

{code}



--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


wrote in message news:6121562@discussion.autodesk.com...
We are using AutoCAD 2009 (has to work in 2008 but maybe it is ok just to
support 2009) The visual Studio Version ins 2008 I had the same idea with
saving used block in a dictionary. Code attached. The code is not jet
finished. It i just a prototype to see if this way is the better one
(currently it workes iterative). Is that way better? I think the problem is
that I look at the blocktablerecord to find a spezific attribute. But I go
through the whole blocktablerecord.
0 Likes
Message 25 of 28

Anonymous
Not applicable
It would be nice since I have no knowledge of this occurring. If someone is
using my signature for their posts that's unfortunate.

I, unlike many others [you included] post my full email address and have
stated numerous times that anyone is welcome to email me directly at
anytime.

Joe ...


"Paul Richardson" wrote in message
news:6122817@discussion.autodesk.com...
>>Why does the following line give me an error "Unable to cast object of
>>type 'Autodesk.AutoCAD.DatabaseServices.Line' to type
>>'Autodesk.AutoCAD.DatabaseServices.BlockReference'."
>>Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)

I did not post the example. Here is your question. You took Tony's code
which used 'as'
to return null if the cast fails and did understand how to do the same in
VB. Where did you
mention or use trycast here?

The reason we all know you are the person who uses the Steve alias to
cowardly attack others
is because you used the Steve email with your real name in a post recently.
Should I find it for
you?


"Joe Sutphin" wrote in message
news:6122794@discussion.autodesk.com...
No, I ask "Why did you not use TryCast() in your example?"

Joe ...


"Paul Richardson" wrote in message
news:6122665@discussion.autodesk.com...
>>Thanks for the link, but it's quite unnecessary.
Didn't you just ask why you cannot cast an object of type Line to
an object of type BlockReference?

"Joe Sutphin" wrote in message
news:6122550@discussion.autodesk.com...
Who the hell is Steve?

Thanks for the link, but it's quite unnecessary.

Joe ...


"Tony Tanzillo" wrote in message
news:6122530@discussion.autodesk.com...
Steve/Joe, I did not use TryCast() in my example,
because my example was C#, not VB.

Perhaps this might help:

http://msdn.microsoft.com/vstudio/express/beginner/


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6122515@discussion.autodesk.com...
Why did you not use TryCast() in your example?

Joe ...


"Tony Tanzillo" wrote in message
news:6122194@discussion.autodesk.com...
See TryCast() in the docs.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


"Joe Sutphin" wrote in message
news:6121944@discussion.autodesk.com...
Why does the following line give me an error "Unable to cast object of type
'Autodesk.AutoCAD.DatabaseServices.Line' to type
'Autodesk.AutoCAD.DatabaseServices.BlockReference'."


Dim blockRef As BlockReference = ta.GetObject(objID, OpenMode.ForRead)


Joe ...


"Tony Tanzillo" wrote in message
news:6121701@discussion.autodesk.com...
{code}

Wrong:

if (entity.GetType().Equals(typeof(BlockReference)))
{
}

Right:

BlockReference blockref = entity as BlockReference;
if( blockref != null )
{
}

{code}

Your code is also not efficient because it is processing
a collection of ObjectIds, but is only interested in those
items that are ids of BlockReferences. The mistake you
make is first casting the result of GetObject() to an Entity,
and then testing the entity's type to see if it is equal to
typeof(BlockReference), which isn't necessary.

You can just cast the result of GetObject() directly to a
BlockReference using 'as', and if the result of the cast is
null, that means the object isn't a block reference:

{code}

Transaction tr = //......

foreach( ObjectId id in idCollection )
{
BlockReference blkref = tr.GetObject(id, OpenMode.ForRead ) as
BlockReference;
if( blkref != null )
{
// found a BlockReference - use it
}
}

{code}

If you can limit yourself to AutoCAD 2009 or later, you can
get even better performance by taking a different approach,
using the new ObjectClass property of ObjectId, like this:

{code}

// Get the RXClass for BlockReference:

RXClass blockRefRXClass = RXObject.GetClass( typeof( BlockReference ) );

ObjectIdCollection ids = //.....
Transaction tr = //....

// Notice that this code does not have to open each
// ObjectId, because it uses the ObjectId's ObjectClass
// property to determine if the id represents an entity of
// the desired type, which is much faster than creating a
// managed wrapper and testing its type:

using( Transaction tr = db.TransactionManager.StartTransaction() )
{
foreach( ObjectId id in ids )
{
if( id.ObjectClass.IsSubClassOf( blockRefRXClass ) )
{
// then it's a BlockReference, so open and use it:

BlockReference blkref = tr.GetObject( id, OpenMode.ForRead ) as
BlockReference;

}
}
}

{code}

As far as the balance of your code goes, I'm not entirely sure what
the ultimate goal is, but if you are going through model space and
collecting attributes, but are only interested in certain attributes with
specific tags, you can use this specilization of Dictionary to find the
needed attributes without having to open and look at every attribute
in each block reference:

{code}

public class AttributeDictionary : Dictionary
{
private int found = 0;

public AttributeDictionary( BlockReference blockref, params string[]
tags )
: base( StringComparer.InvariantCultureIgnoreCase )
{
if( tags != null )
{
foreach( string tag in tags )
{
base.Add( tag, string.Empty );
}
}

Transaction tr =
blockref.Database.TransactionManager.TopTransaction;
if( tr == null )
throw new InvalidOperationException(" no transaction! ");

foreach( ObjectId id in blockref.AttributeCollection )
{
AttributeReference att = tr.GetObject( id, OpenMode.ForRead ) as
AttributeReference;
string tag = att.Tag.Trim();
if( base.ContainsKey( tag ) )
{
base[tag] = att.TextString;
if( base.Count == ++found )
break;
}
else if( tags == null )
base.Add( tag, att.TextString );
}
}
}

// Example use:


BlockReference myBlockRef = myTrans.GetObject( blah blah... );

// this gets the two attributes whose tags are "COST"
// and "COLOR", and once it finds both of those it will
// not continue looking at any additional attributes:

AttributeDictionary atts =
new AttributeDictionary( myBlockRef, "COST", "COLOR");

// then, the attribute values can be referenced using the
// tag as an index key:

string cost = atts["COST"];
string color = atts["COLOR"];

{code}



--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


wrote in message news:6121562@discussion.autodesk.com...
We are using AutoCAD 2009 (has to work in 2008 but maybe it is ok just to
support 2009) The visual Studio Version ins 2008 I had the same idea with
saving used block in a dictionary. Code attached. The code is not jet
finished. It i just a prototype to see if this way is the better one
(currently it workes iterative). Is that way better? I think the problem is
that I look at the blocktablerecord to find a spezific attribute. But I go
through the whole blocktablerecord.
0 Likes
Message 26 of 28

Anonymous
Not applicable
{quote}

As far as all my objectIDs on layers H_60* can be nested I try to use your
suggestion with blk.GetBlockReferenceIds. And if I understood it correctly I
will get the ids of the nested blocks and have to check these again for
nested block references, won't I?

{quote}

No, GetBlockReferenceIds() simply returns the ObjectIds of all insertions of
the block. They can be inserted into any owner/parent block (including
model space), so that's the purpose of testing the BlockId property. The
BlockId is the ObjectId of the BlockTableRecord which each BlockReference is
inserted into. For non-nested blockrefs, it will be the id of either the
model space or a paper space block. Otherwise, it's the id of the block
which the blockreference is inserted into.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm


wrote in message news:6122641@discussion.autodesk.com...
I'm sorry that I have used the wrong expression 'dynamic attribute'. I think
the correct name is unconstant. E.g. the user should be available to change
the value of the attribute like the 'multiplier' but he should not change
the constant attribute 'articleID'. Thank for you good hints. I will try to
add additional XData/XRecords for the articleID to get them faster. As far
as all my objectIDs on layers H_60* can be nested I try to use your
suggestion with blk.GetBlockReferenceIds. And if I understood it correctly I
will get the ids of the nested blocks and have to check these again for
nested block references, won't I? You said that it is a bit more complicated
with dynamic blocks. What do I have to keep in mind with that? Of cause we
do have many dynamic blocks (blocks where you can take a edge and resize it
etc.)
0 Likes
Message 27 of 28

Anonymous
Not applicable
{quote}

"Joe Sutphin" wrote:

LOL .... you are so gullible.

{quote}

Well, that's better than being as dumb as a doorknob.


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009
http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm
0 Likes
Message 28 of 28

Anonymous
Not applicable
Thank you very much for your help Tony and NathTry.
Now I can count 100 diffrerent blocks that appear more than 10000 times where some of them appeare as nested blocks in 0.6 seconds. That fits my needs...for now 🙂

Now I use only normal attributes (no constant attributes) to avoid going through the whole blocktable.
I only go through this when I need the nested block references.

By saving the results/quantities of nested blocks for a processed block I'm getting the speed I need.
A further improvement could be saving the quantities if a nested block has nested blocks directly an not only if it appeares as "root" block.
0 Likes