Author Topic: Help with WBlockCloneObjects  (Read 14869 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #15 on: March 09, 2011, 02:44:06 PM »
If that is okay with you of course
Go for it. :-)

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #16 on: March 15, 2011, 09:32:19 PM »
I have not had time to really work on it, but here is something too see how it does.(If it is too slow, just plain crap etc.....)

This is just a basic method to copy all blocks from every open drawing into the current drawing.

If one drawing is open or none of the other open drawings pass the logical conditions then nothing will happen 

I went a little different route.

Basically here is the run down,
To keep each document from becoming active I just opened the databases and read it from  there.
I iterated the BlockTable and made sure it was not a Layout, from x-ref, anonymous, some things to weed out MEP objects, and has been at least inserted once etc.....

Maybe is not any better or probably worst than what you have just throwing it out there.


Code: [Select]
[CommandMethod("InsertBlocks", CommandFlags.Session)]
        public void InsertBlocks()
        {
            List<string> blockNames = new List<string>(); // A generic list to keep up with all blocks to check later if a block has already inserted.

            DocumentCollection documents = Application.DocumentManager; // All the current open documents

            Document doc = Application.DocumentManager.MdiActiveDocument; // Active Document
            Editor ed = doc.Editor; // Active Document's Editor
            Database db = doc.Database; // Active Document Database

            Document openDocument; // Temporay variable to hold each non-active Document
            Database openDatabase; //Temporay variable to hold each non-active Document's Database

            using (DocumentLock doclock = doc.LockDocument()) // Start Lock on Active Document
            using (Transaction trx = db.TransactionManager.StartTransaction()) // Start Transaction with Active Document's Database
            {
                // Start looping through each document
                foreach (Document document in documents)
                {
                    openDocument = document;
                    string fileName = openDocument.Name;
                    // If the document is the current or Active document skip it
                    if (doc.Name == fileName || fileName == null || fileName == String.Empty)
                        continue;

                    openDatabase = new Database(false, true);
                    // 'Open' Open documents database
                    openDatabase.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, true, "");

                    using (Transaction openDbTrx = openDatabase.TransactionManager.StartTransaction())
                    {//Start Transaction with Open Document's Database

                        BlockTable openBlockTable = openDbTrx.GetObject(openDatabase.BlockTableId, OpenMode.ForRead) as BlockTable;

                        // Loop through each BlockTableRecord
                        foreach (ObjectId btrId in openBlockTable)
                        {
                            BlockTableRecord btr = openDbTrx.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                            // Make sure it is not a ModelSpace or any of the PaperSpaces, any type of Xref
                           // or MEP type Object, or has already been clone before etc.... & and the block has been inserted at least once
                            if (btr.IsLayout || btr.IsAnonymous || btr.IsFromExternalReference || btr.IsFromOverlayReference || blockNames.Contains(btr.Name)
                                || btr.Name.StartsWith("Aec", StringComparison.OrdinalIgnoreCase) || btr.Name.StartsWith("_")
                                || btr.GetBlockReferenceIds(true, false).Count < 1)
                                continue;
                            //Add Block to list of blocks
                            blockNames.Add(btr.Name);

                            //Do Cloning
                            ObjectIdCollection objIdCollection = new ObjectIdCollection();
                            objIdCollection.Add(btr.ObjectId);
                            IdMapping idMap = new IdMapping();
                            openDatabase.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);

                        }
                        openDbTrx.Commit();
                    }//End Transaction with Open Document's Database
                    openDatabase.Dispose(); // Dispose Database
                }// End foreach
                trx.Commit();
            }// End Lock on Active Document & Transaction with Active Document's Database

        }


Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #17 on: March 15, 2011, 11:33:17 PM »
Thanks Jeff. This works on 2 of the drawings mine fails with. It gives me something to work with. Although if it's the open database separately that does it, then I'm not sure what I'll be able to do to get my code working, as I need to be able to gather blocks used in Civil3D object styles and the only way (I know of anyway) is to use the C3D API, which requires the drawing to be current. This is also why I walk through each Layout's BTR.

I see is that you omit Dynamic blocks (by omitting anonymous blocks), which I am also trying to be sure to include....including each Visibility state used. I had thought that this is where my code was getting tripped up. Until I had a drawing with no DB's in it that failed in the same fashion.

I probably won't be able to look into this until this coming weekend, but this has helped me to look in other directions. Thanks!



Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #18 on: March 16, 2011, 01:26:01 AM »
Not fimilar with C3D, so I guess this does not help much but for anyone else who cares you could grab dynamic blocks with some like this added after first logical check.

Could check if IsDynamicBlock then get Anonymous references that way

I just copied from http://www.theswamp.org/index.php?topic=31859.msg412448#msg412448
and then used some of Jeff_M's code noted

Probably not the best solution or I am pretty sure there is a better way was just testing out.
Would have to look back into dynamic blocks

Helper Class
Code: [Select]
  public class DynamicBlocks
        {
            public string BlockName { get; set; }
            public List<object> VisibilityProperties;

            public DynamicBlocks(string blockName)
            {
                BlockName = blockName;
                VisibilityProperties = new List<object>();
            }

        }

Code: [Select]
   if (btr.IsDynamicBlock)
                            {
                                DynamicBlocks dynBlks = new DynamicBlocks(btr.Name);
                                ObjectIdCollection brefObjidColl = btr.GetBlockReferenceIds(true, true);
                                ObjectIdCollection anonObjIdsColl = btr.GetAnonymousBlockIds();

                                foreach (ObjectId anonObjId in anonObjIdsColl)
                                {
                                    BlockTableRecord btrAnon = (BlockTableRecord)anonObjId.GetObject(OpenMode.ForRead);
                                    ObjectIdCollection ObjidColl = btrAnon.GetBlockReferenceIds(true, true);
                                    foreach (ObjectId Id in ObjidColl)
                                        brefObjidColl.Add(Id);
                                }

                           
                                foreach (ObjectId brefObjId in brefObjidColl)
                                {
                                    BlockReference bref = brefObjId.GetObject(OpenMode.ForWrite) as BlockReference;
                                    DynamicBlockReferencePropertyCollection dynBrefColl = bref.DynamicBlockReferencePropertyCollection;
                                    foreach (DynamicBlockReferenceProperty dynBrefProps in dynBrefColl)
                                    {
                                        // Jeff_M code
                                        if (dynBrefProps.PropertyTypeCode == 5)
                                        {
                                            dynBlks.VisibilityProperties.Add(dynBrefProps.Value);
                                        }
                                    }
                                }
                            }



Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #19 on: March 16, 2011, 03:06:13 AM »
Tested it real quick to add a refrence for each visibility state at random points for each dynamic block with visibility parameter

Code: [Select]
     ///////////////////////////////////Start Add/////////////////////////////
        public class DynamicBlocks
        {
            public string BlockName { get; set; }
            public List<object> VisibilityProperties;

            public DynamicBlocks(string blockName)
            {
                BlockName = blockName;
                VisibilityProperties = new List<object>();
            }

        }
        ///////////////////////////////////End Add/////////////////////////////

        //A method to iterate all open drawings and to get all blocks that are inserted in each
        //drawing and copying them over to the current active document.
        [CommandMethod("InsertBlocks", CommandFlags.Session)]
        public void InsertBlocks()
        {
            List<string> blockNames = new List<string>(); // A generic list to keep up with all blocks to check later if a block has already inserted.

            List<DynamicBlocks> dynamicBlocks = new List<DynamicBlocks>();//Added

            DocumentCollection documents = Application.DocumentManager; // All the current open documents

            Document doc = Application.DocumentManager.MdiActiveDocument; // Active Document
            Editor ed = doc.Editor; // Active Document's Editor
            Database db = doc.Database; // Active Document Database

            Document openDocument; // Temporay variable to hold each non-active Document
            Database openDatabase; //Temporay variable to hold each non-active Document's Database

            using (DocumentLock doclock = doc.LockDocument()) // Start Lock on Active Document
            using (Transaction trx = db.TransactionManager.StartTransaction()) // Start Transaction with Active Document's Database
            {
                // Start looping through each document
                foreach (Document document in documents)
                {
                    openDocument = document;
                    string fileName = openDocument.Name;
                    // If the document is the current or Active document skip it
                    if (doc.Name == fileName || fileName == null || fileName == String.Empty)
                        continue;

                    openDatabase = new Database(false, true);
                    // 'Open' Open documents database
                    openDatabase.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, true, "");

                    using (Transaction openDbTrx = openDatabase.TransactionManager.StartTransaction())
                    {//Start Transaction with Open Document's Database

                        BlockTable openBlockTable = openDbTrx.GetObject(openDatabase.BlockTableId, OpenMode.ForRead) as BlockTable;

                        // Loop through each BlockTableRecord
                        foreach (ObjectId btrId in openBlockTable)
                        {
                            BlockTableRecord btr = openDbTrx.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                            // Make sure it is not a ModelSpace or any of the PaperSpaces, any type of Xref
                           // or MEP type Object, or has already been clone before etc.... & and the block has been inserted at least once
                            if (btr.IsLayout || btr.IsAnonymous || btr.IsFromExternalReference || btr.IsFromOverlayReference || blockNames.Contains(btr.Name)
                                || btr.Name.StartsWith("Aec", StringComparison.OrdinalIgnoreCase) || btr.Name.StartsWith("_")
                                || btr.GetBlockReferenceIds(true, false).Count < 1)
                                continue;

                            ///////////////////////////////////Start Add/////////////////////////////
                            if (btr.IsDynamicBlock)
                            {
                                DynamicBlocks dynBlks = new DynamicBlocks(btr.Name);
                                ObjectIdCollection brefObjidColl = btr.GetBlockReferenceIds(true, true);
                                ObjectIdCollection anonObjIdsColl = btr.GetAnonymousBlockIds();

                                foreach (ObjectId anonObjId in anonObjIdsColl)
                                {
                                    BlockTableRecord btrAnon = (BlockTableRecord)anonObjId.GetObject(OpenMode.ForRead);
                                    ObjectIdCollection ObjidColl = btrAnon.GetBlockReferenceIds(true, true);
                                    foreach (ObjectId Id in ObjidColl)
                                        brefObjidColl.Add(Id);
                                }

                                foreach (ObjectId brefObjId in brefObjidColl)
                                {
                                    BlockReference bref = brefObjId.GetObject(OpenMode.ForWrite) as BlockReference;
                                    DynamicBlockReferencePropertyCollection dynBrefColl = bref.DynamicBlockReferencePropertyCollection;
                                    foreach (DynamicBlockReferenceProperty dynBrefProps in dynBrefColl)
                                    {
                                        // Jeff_M code
                                        if (dynBrefProps.PropertyTypeCode == 5)
                                        {
                                            dynBlks.VisibilityProperties.Add(dynBrefProps.Value);
                                        }
                                    }
                                }
                                dynamicBlocks.Add(dynBlks);
                            }
                            ///////////////////////////////////End Add/////////////////////////////
                            //Add Block to list of blocks
                            blockNames.Add(btr.Name);

                            //Do Cloning
                            ObjectIdCollection objIdCollection = new ObjectIdCollection();
                            objIdCollection.Add(btr.ObjectId);
                            IdMapping idMap = new IdMapping();
                            openDatabase.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);

                        }
                        openDbTrx.Commit();
                    }//End Transaction with Open Document's Database
                    openDatabase.Dispose(); // Dispose Database
                }// End foreach
                trx.Commit();
            }// End Lock on Active Document & Transaction with Active Document's Database

            ///////////////////////////////////Start Add/////////////////////////////
            using (DocumentLock doclock = doc.LockDocument())
            using (Transaction trx = db.TransactionManager.StartTransaction()) // Start Transaction with Active Document's Database
            {
                BlockTable bt = trx.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord ms = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite) as BlockTableRecord;
                Random rdn = new Random();
                foreach (DynamicBlocks dynBlks in dynamicBlocks)
                {
                    foreach (string visi in dynBlks.VisibilityProperties)
                    {
                        BlockTableRecord btr = bt[dynBlks.BlockName].GetObject(OpenMode.ForRead) as BlockTableRecord;
                        double rdnDouble = rdn.Next(100);
                        BlockReference bref = new BlockReference(new Point3d(rdnDouble, rdnDouble, 0.0), btr.ObjectId);
                        ms.AppendEntity(bref);
                        trx.AddNewlyCreatedDBObject(bref, true);

                        DynamicBlockReferencePropertyCollection dynBrefColl = bref.DynamicBlockReferencePropertyCollection;
                        foreach (DynamicBlockReferenceProperty dynBrefProps in dynBrefColl)
                        {
                            if (dynBrefProps.PropertyTypeCode == 5)
                            {
                                dynBrefProps.Value = visi;
                            }
                        }                 

                    }
                   
                }

                trx.Commit();
            }
            ///////////////////////////////////End Add/////////////////////////////
        }
« Last Edit: March 16, 2011, 03:10:36 AM by Jeff H »

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #20 on: March 17, 2011, 12:03:37 AM »
Had a chance to play around tonight. Your last code worked for the most part...I had to switch around the Dynamic block code to before the other conditions, otherwise if a DB had been inserted and it had been altered (dynamic property changed) leaving no BlockReferences being shown, then the DB portion of code never got touched. Doing the switch corrected that.

Then I thought to try that working code and change it to set each doc current like I need. It now fails...so there's definitely an issue with setting documents current then coming back to the start document. I think this is where I need to focus my research on now.

Thank you much for your time and insight, Jeff. You've also shown me alternate (better?) ways of going about some things that will help me in the future. Much appreciated.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #21 on: March 17, 2011, 01:40:19 AM »
The last part was not implemented very well and that is weird the basic funtionality differs between C3D and ACAD.

I am sure you got an idea what you are going to do but when I get a chance will post what I come up with changing active drawings.



You are creating a type of symbol legend?


Take care and have a good one.

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #22 on: March 17, 2011, 02:01:15 AM »
A Legend, yes, of just blocks actually inserted into the chosen or open drawings.

C3D is different in that the API (both .NET and COM) were written such that you can only access certain properties and use methods when the drawing the C3D object exists in is current. And since blocks are used to display Point Symbols and Structures (Manhole type structures), in order to find which blocks are in use by these objects I need the dwg current.

One other thing I'm not quite getting....on some drawings it works just fine (my original code), but most others it breaks the drawing which starts the command. It's like there's a limit to how many table entries get added (block/text/layer, these all get added if not in the target drawing but are in use by the block definition). I've got enough now to submit this to ADN, perhaps they can clue me in on what can be done.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #23 on: March 17, 2011, 02:10:10 AM »
I know WblockCloneObjects will fail on some MEP objects and you use a CloningHelper class
might be similar?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Help with WBlockCloneObjects
« Reply #24 on: March 17, 2011, 10:09:07 AM »
I remember Tony T telling me that .Net could not set a document current within a code.  Current document does not mean the active one in reality.  I wonder if that is the issue you are having, and if it is, if you can ever hope to get it working with .Net.  You can set a document current with Arx though.  I'll see if I can find the post.  I think it's on the Adesk site.

Maybe a P/Invoke would work?

Edit:  Found post.  Look at his second in this thread.
[ http://forums.autodesk.com/t5/NET/Updating-blocks-in-open-non-current-drawing/m-p/2678788/highlight/true#M19093 ]
« Last Edit: March 17, 2011, 10:34:26 AM by T.Willey »
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #25 on: March 17, 2011, 12:05:30 PM »
^
did a quick test with some of my old code in arx, and have been able to generate the table from all open drawings and to insert the table in the current one, don't have all my new code for tables (still it is on my all broke pc), just noticed that I don't get the block previews from the non current drawings, edit: forgot to add the cloning process, it returns the block name, and the block count on the drawings.
« Last Edit: March 17, 2011, 12:23:08 PM by LE »

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #26 on: March 17, 2011, 01:45:36 PM »
Hi Jeff_M,

and here it is a binary file to run a test under 2010 or 2011 and see if works in c3d, it is a quick one no more than 20-30 minutes of coding...

Steps:
1. Load instable18.arx
2. Open drawings with blocks
3. Run from your current drawing: INSTABLE and select the insertion point for the table.
4. ***Press <RETURN> to erase cloned blocks...  this will erase the temp cloned blocks from the current drawing - might find a better aproach for this, but it is just a sample of how can be possible done from the arx side.

5. For the source code, in case it is useful, PM me.
6. HTH.

edit: updated without the manifest file
« Last Edit: March 17, 2011, 05:35:47 PM by LE »

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #27 on: March 17, 2011, 05:25:03 PM »
Thanks, Luis. Only have a few minutes before I must leave for a meeting, but first attempt in 2011:

instable18.arx is incompatible with this version of AutoCAD.
AcRxDynamicLinker failed to load 'c:\users\jeff-i7\downloads\instable18.arx'
C:\Program Files\Autodesk\AutoCAD Civil 3D 2011\acad.exeUnable to load
instable18.arx file.

Off to try 2010.....

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #28 on: March 17, 2011, 05:33:01 PM »
Oops... must be the 'manifest file' that it is set to on... let me recompile it.

Thanks, Luis. Only have a few minutes before I must leave for a meeting, but first attempt in 2011:

instable18.arx is incompatible with this version of AutoCAD.
AcRxDynamicLinker failed to load 'c:\users\jeff-i7\downloads\instable18.arx'
C:\Program Files\Autodesk\AutoCAD Civil 3D 2011\acad.exeUnable to load
instable18.arx file.

Off to try 2010.....

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #29 on: March 17, 2011, 05:33:54 PM »
...C3D2010 it works, Luis. This is quite fast, but it looks like it uses the same idea Jeff_H used of not making each drawing current. If so, the .NET version works, too, but not quite as quickly.

Tim, thanks for that link. I'm going to have to look into that some more, but I'm not sure it applies since I'm not altering anything graphical in the other databases. But it may be a related issue, I guess.