TheSwamp

Code Red => .NET => Topic started by: wannabe on July 04, 2009, 02:41:53 PM

Title: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 04, 2009, 02:41:53 PM
Hi Everyone,

I'm trying to access blocks from other drawings for manipulation purposes, but I only want those that reside in paper space. Initially I looked at the DXFCodes, but I couldn't see one that was applicable for a typedValue filter. I then checked out PromptSelectionOptions() which only allows me to get all blocks from the active space. If the drawing isn't actually open, would paper space be the active space (I'm copying drawings into Database references via the ReadDWG() method to make global changes)?

Are there any DXF codes that can do this to save me from checking each selected block against the ObjectId for Model Space, which seems a "dirty" way of operating. The layoutName doesn't seem robust enough.

EDIT: Actually, I think the LayoutName DXF Code will be fine. I'll post up if I get any reported problems.


As always, comments are appreciated.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 04, 2009, 04:00:25 PM
When I tried it on the host drawing it worked. When I copied a selection of drawings into a Database reference it failed to recognise any blocks not in paper space with the filtering criteria in the post above.

Any suggestions?
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 04, 2009, 04:09:52 PM
Hi,

Did you try (67, 1) ?

Another way should be iterating through each layout, and in each layout block table reference, through each object looking for a block references.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 04, 2009, 04:18:02 PM
Yeah, I just realised that using a selection filter won't work when the Editor object is only going to work on open drawings.

So now it's a case of scanning each layout as you suggest. Not a problem, but could be cleaner.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 04, 2009, 04:49:52 PM
Here's a quick and dirty.
Let me know if there's a cleaner way (I'm newby and learning...)

Code: [Select]
public ArrayList GetBlockRefInLayouts()
{
    Database db = Application.DocumentManager.MdiActiveDocument.Database;
    ArrayList result = new ArrayList();
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        DBDictionary NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
        DBDictionary layouts = (DBDictionary)tr.GetObject(NOD.GetAt("ACAD_LAYOUT"), OpenMode.ForRead);
        foreach (DBDictionaryEntry entry in layouts)
        {
            if (entry.Key != "Model")
            {
                Layout lay = (Layout)tr.GetObject(entry.Value, OpenMode.ForRead);
                BlockTableRecord layoutBtr = (BlockTableRecord)tr.GetObject(lay.BlockTableRecordId, OpenMode.ForRead);
                foreach (ObjectId id in layoutBtr)
                {
                    BlockReference blk = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
                    if (blk != null)
                        result.Add(blk);
                }
            }
        }
        tr.Commit();
    }
    return result;
}
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 04, 2009, 05:07:14 PM
Thats basically what I did, with slight differences that provide the same result.

Cheers for posting.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Kerry on July 04, 2009, 11:50:16 PM
gile,
thats essentially how I'd do it as well.

except there is no necessity to tr.Commit() because you are not revising the database , so there is nothing to commit.
... at least that's my understanding

:)

/// kdub
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: sinc on July 05, 2009, 12:01:11 AM
If you don't commit, then the transaction aborts, and a commit has less overhead than an abort.  At least, according to some of Kean's blog posts.  It might be an interesting thing to test.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Kerry on July 05, 2009, 12:18:36 AM
Richard, yes, appears I was incorrect ..

I found that reference
http://through-the-interface.typepad.com/through_the_interface/2007/04/iterating_throu.html


Quote
There's a DevNote on the ADN site covering this topic:

http://adn.autodesk.com/adn/servlet/devnote?siteID=4814862&id=5546971&linkID=4900509

Here's an excerpt:

>>>
... there is a huge performance difference between Commit() and Abort(). So, when opening objects for read, you definitely want to explicitly call Commit() even though you didn't really change anything. As evidenced by a few test functions, Abort() should only be used under "duress" because of the performance hit.
<<<

A read-only transaction (even one that opens objects for write, but doesn't modify them) will not set the database modified flag (DBMOD) when committed. It's the individual "set" methods that call assertWriteEnabled(), forcing DBMOD to non-zero.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 05, 2009, 03:05:23 AM
Thanks all,

I was lucky if the 'commit' way is the right way.
The commit/dispose/abort stuff keeps difficult to undersand for me.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 06, 2009, 11:20:58 AM
I thought I was told by Tony T. that you didn't want to return an object, but rather an ObjectId.  I'm talking about this section of gile's code

Code: [Select]
                foreach (ObjectId id in layoutBtr)
                {
                    BlockReference blk = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
                    if (blk != null)
                        result.Add(blk);
                }

I would even think that one would want to return the handle, as the ObjectId is created upon opening the database ( drawing ), and would not be the same the next time you open the drawing, but the handle always would be, so the handle and the drawing name would be the best way to go.

That was my understanding at least.  If I'm wrong, carry on.   :-)
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: sinc on July 06, 2009, 12:34:05 PM
I thought I was told by Tony T. that you didn't want to return an object, but rather an ObjectId.  I'm talking about this section of gile's code

Yeah, good catch.  That piece of code is creating a transaction and getting objects, then trying to return the objects after closing the transaction.  That's the no-no.

You can return objects in a method, but the transaction should still be active when you do so.

I'm not sure why you would want the handle...  It depends on your code, and what it does.  But for most purposes, the ObjectId is preferable.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 06, 2009, 01:15:40 PM
and also, it will be much easier to return an ObjectIdCollection, since you can just call:

result layoutBtr.GetBlockReferenceIds();


maybe?
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 06, 2009, 02:02:19 PM
Thanks for the confirmation Sinc.

Luis,

That would just get all the inserts of that specific block definition, not all the blocks that are inserted ( nested ) within the definition.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 06, 2009, 02:45:30 PM
So, if I understand, it should have been :
Code: [Select]
foreach (ObjectId id in layoutBtr)
                {
                    BlockReference blk = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
                    if (blk != null)
                        result.Add(id); // or result.Add(id.Handle);
                }

Or is there another way to evaluate if the object is a BlockReference ?
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 06, 2009, 02:57:03 PM
Thanks for the confirmation Sinc.

Luis,

That would just get all the inserts of that specific block definition, not all the blocks that are inserted ( nested ) within the definition.


dang!.... sorry

lately I'm way out of my miserable C# skills (== -0)

4 slaps on my face.   :oops:
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 06, 2009, 03:01:56 PM
For most instances the Id will be fine to work with.  In rare cases the Handle will have to be used, but here I think you can stick with the Id.

As for testing if it's a BlockReference, what you have works, and would most likely be what I used ( take that for what it's worth ).  If you wanted another way, you could just cast it as an entity, then test it with the ' is ' keyword ( I think below is how it works ).  Just another option.

Code: [Select]
Entity Ent = tr.GetObject( id, OpenMode.ForRead ) as Entity
if ( Ent is BlockReference )
    result.Add( id );
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 06, 2009, 03:03:13 PM
Thanks for the confirmation Sinc.

Luis,

That would just get all the inserts of that specific block definition, not all the blocks that are inserted ( nested ) within the definition.


dang!.... sorry

lately I'm way out of my miserable C# skills (== -0)

4 slaps on my face.   :oops:

Not a problem Luis.   :-)
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 06, 2009, 03:11:33 PM
Thanks Tim.

My C# 'stuff' isn't much more than hacking some snippets here and there :-(
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 06, 2009, 03:46:46 PM
Thanks Tim.

My C# 'stuff' isn't much more than hacking some snippets here and there :-(

You're welcome Gile.  I'm learning just like you, and I see you with some good stuff, and I'm sure you will keep at it and develop some good stuff.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 07, 2009, 07:30:31 AM
Thanks Tim.

My C# 'stuff' isn't much more than hacking some snippets here and there :-(

The guys on here recommended Pro C# 2008 and the .NET platform. It was a great read, but I already had a good foundation of C# by then. Headfirst C# is a great entry-level hands-on book, though (in my opinion).

What level are you currently at?
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 07, 2009, 10:52:17 AM
Well, I have some time to play today with little c# and here it is Gile's function with some touch ups.... HTH-maybe :)

Code: [Select]
public ObjectIdCollection GetBlockRefInLayouts()
{
    ObjectIdCollection ids = new ObjectIdCollection();
    Database db = Application.DocumentManager.MdiActiveDocument.Database;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        DBDictionary layoutDict = (DBDictionary)tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead);
        foreach (DBDictionaryEntry entry in layoutDict)
        {
            if (entry.Key == "Model") continue;
            Layout layout = (Layout)tr.GetObject(entry.Value, OpenMode.ForRead);
            BlockTableRecord layoutBtr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead, false);
            if (!layoutBtr.IsAnonymous)
            {
                foreach (ObjectId id in layoutBtr)
                {
                    BlockReference blk = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
                    if (blk != null) ids.Add(id);
                }
            }
        }
        tr.Commit();
    }
    return ids;
}

[CommandMethod("PSBLOCKS")]
public void psblocks()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    ObjectIdCollection ids = new ObjectIdCollection();
    ids = GetBlockRefInLayouts();
    ed.WriteMessage("\nBlocks on paper-space: {0}", ids.Count.ToString());
}
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: wannabe on July 07, 2009, 12:26:25 PM
That's a touch closer to the methodology I used. Rather than going through the NOD I directly grabbed the LayoutDictionaryID from each database I readDWg()'ed.

The only part I would like to query is the .IsAnonyMous property. I think I've read somewhere, or deduced from someone else's  code that this means is not in an Xref? Close? :-)

Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 07, 2009, 12:29:03 PM
Una vez más, muchas gracias Luis.

He apprendido el uso de ObjectIdCollection, db.LayoutDictionaryId y continue, pero nunca he visto de anonymous layout block.
¿Cuáles son esos objetos?

I learned the using of ObjectIdCollection, db.LayoutDictionaryId and continue but I never saw any anonymous layout block.
What kind of objects are there ?
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 07, 2009, 12:43:09 PM
Una vez más, muchas gracias Luis.

He apprendido el uso de ObjectIdCollection, db.LayoutDictionaryId y continue, pero nunca he visto de anonymous layout block.
¿Cuáles son esos objetos?

I learned the using of ObjectIdCollection, db.LayoutDictionaryId and continue but I never saw any anonymous layout block.
What kind of objects are there ?

:)

For example, remove the IsAnonymous condition, and then in the drawing draw one dimension... it will count the anonymous block.

Also, on this line:

BlockTableRecord layoutBtr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead, false);

notice the false argument, this will ignore the recent erased blocks.

And also about the continue, we can use that here too:

 if (layoutBtr.IsAnonymous) continue;

To skip the anonymous blocks.

EDIT:.... --- I need to finish some work, and if someone can insert an anonymous block and tested... I'll be back.

Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: gile on July 07, 2009, 01:04:16 PM
OK, I know anonymous blocks, but AFAIK, they're stored in the blocks collection, not in the layout block.

As far as I understand, layoutBtr refers to the layout block definition as the object got with the vlisp expression (I'm more comfortable with LISP):
(vla-get-Block (vla-item (vla-get-Layouts ...) "Layout1")).

If I'm true, the false parameter should have been here:

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

EDIT: I tried both an exploded dimension and a dynamic bloc.
Only the dynamic bloc is founded whatever the IsAnonymous condition, even I found "*D2" and "*U4" in the block collection (BlockTable).
And it seems there's no need to the false parameter if a block reference have been erased.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 07, 2009, 01:07:42 PM
OK, I know anonymous blocks, but AFAIK, they're stored in the blocks collection, not in the layout block.

As far as I understand, layoutBtr refers to the layout block definition as the object got with the vlisp expression (I'm more comfortable with LISP):
(vla-get-Block (vla-item (vla-get-Layouts ...) "Layout1")).

If I'm true, the false parameter should have been here:

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

I need another coffee... and need to play a little more with C#.

Have been lately in the miserable ATL COM stuff... and that might be my excuse...
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 07, 2009, 01:24:15 PM
I don't think you need to check if the block is anonymous, because I don't think a layout could have an anonymous block associated with it.

I'm not sure if you would need to check if the block has been erased either, as it might not be in the layout dictionary, but a quick test could be done.  Just create a layout, and run the code.  Then delete the layout, and run the code.  Then you should be able to tell if the layout information is still in the dictionary.
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 07, 2009, 01:25:03 PM
OK, I know anonymous blocks, but AFAIK, they're stored in the blocks collection, not in the layout block.

As far as I understand, layoutBtr refers to the layout block definition as the object got with the vlisp expression (I'm more comfortable with LISP):
(vla-get-Block (vla-item (vla-get-Layouts ...) "Layout1")).

If I'm true, the false parameter should have been here:

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

EDIT: I tried both an exploded dimension and a dynamic bloc.
Only the dynamic bloc is founded whatever the IsAnonymous condition, even I found "*D2" and "*U4" in the block collection (BlockTable).
And it seems there's no need to the false parameter if a block reference have been erased.

Yep... did that too.... I'm glad that I don't code in C# for a living....  :-P
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: Spike Wilbury on July 07, 2009, 01:26:47 PM
I don't think you need to check if the block is anonymous, because I don't think a layout could have an anonymous block associated with it.

I'm not sure if you would need to check if the block has been erased either, as it might not be in the layout dictionary, but a quick test could be done.  Just create a layout, and run the code.  Then delete the layout, and run the code.  Then you should be able to tell if the layout information is still in the dictionary.

We (me) did that already Tim.... and you right.

thanks! to refresh my 3 brain cells... left
Title: Re: "Cleanest" Method For Selecting All Blocks in PaperSpace
Post by: T.Willey on July 07, 2009, 01:52:31 PM
I don't think you need to check if the block is anonymous, because I don't think a layout could have an anonymous block associated with it.

I'm not sure if you would need to check if the block has been erased either, as it might not be in the layout dictionary, but a quick test could be done.  Just create a layout, and run the code.  Then delete the layout, and run the code.  Then you should be able to tell if the layout information is still in the dictionary.

We (me) did that already Tim.... and you right.

thanks! to refresh my 3 brain cells... left

My pleasure Luis.  You probably forgot more about programming that I will ever know.  :wink: