.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Copy of BlockTableRecord (save as)

14 REPLIES 14
Reply
Message 1 of 15
RichardCammeray
1650 Views, 14 Replies

Copy of BlockTableRecord (save as)

I would like to ask question how to mimic Block Definition Save As function.

So far what I have found in this forum and TheSwamp the best way is to use DeepClone of BlockTableRecord but the objects in original BlockTableRecord need to be DeepCloneObjectes into new block. Otherwise new block will have all objects  with ObjectId from old BlockTabkeRecord

Is that right way how to do it or is there some simpler solution.

 

Thanks,

Richard

14 REPLIES 14
Message 2 of 15

Can't you just use Database.WBlockCloneObjects()?

 

 

Cheers,

Stephen Preston
Autodesk Developer Network
Message 3 of 15

Database.WBlockCloneObjects can be used to copy objects between two databases.

In my case I need to make copy of BlockTableRecord in the same database.

 

Any another idea?

 

Thanks.

Message 4 of 15
Hallex
in reply to: RichardCammeray

I thought you need to deepclone main block first,

then deepclone embedded block in the newly created

copy of main instance

, just an idea sorry

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 5 of 15
RichardCammeray
in reply to: Hallex

Thanks for hint but unfortunately my block consists only single entities (line, text).

But let me explain the problem is simple steps.

 

1)You have BlockTableRecord with one Line only

2)DeepClone this BlockTableRecord

3)Get ObjectId of Line in newly created BlockTable and change the length

4) As result the line will change the length in both old and new BlockTable.

 

As it was mention somewhere in this forum DeepClone of BlockTableRecord apparently does not translate ObjectIds of cloned Entities inside of new BlockTableRecord.

 

Message 6 of 15
Hallex
in reply to: RichardCammeray

Hi Richard,

Here is a sample code how to clone block

with embeddingan another block to the same copy

Try to rewrite it to your needs, this one is from my oldies,

so I haven't have tested it enough, sorry

 

    [CommandMethod("CopyXBref")]
        public void testCopyBlockReference()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect main block instance to copy: ");
                peo.SetRejectMessage("\nMust be a type of the BlockReference!");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);

                if (per.Status != PromptStatus.OK) return;

                BlockReference bref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
                ed.WriteMessage("\nBlock Selected with name: {0}", btr.Name);
                PromptStringOptions pso = new PromptStringOptions("\nEnter new block name: ");
                pso.AllowSpaces = true;
                PromptResult sres = ed.GetString(pso);
                if (sres.Status != PromptStatus.OK) return;
                string newname = sres.StringResult;
                if (bt.Has(newname))
                {
                    ed.WriteMessage("\nBlock with name: {0} already exist, try again", newname);
                    return;
                }

                BlockTableRecord newbtr = new BlockTableRecord();
                bt.UpgradeOpen();

                newbtr = (BlockTableRecord)btr.DeepClone(bt, new IdMapping(), true);

                newbtr.Name = newname;
                bt.Add(newbtr);
                //----------------------------------------------------------------//
                peo.Message = "\nSelect block instance to be embedded to main block: ";
                per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK) return;
                BlockReference xbref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                BlockTableRecord xbtr = (BlockTableRecord)tr.GetObject(xbref.BlockTableRecord, OpenMode.ForRead);
                
                PromptPointOptions ppo = new PromptPointOptions("\nSpecify a new location of embedded block: ");
                PromptPointResult ppr = ed.GetPoint(ppo);
                if (ppr.Status != PromptStatus.OK) return;
                Point3d pt = ppr.Value;
              
                foreach (ObjectId id in newbtr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null)continue;                   
                    ent.UpgradeOpen();
                    ent.ColorIndex = 0;
                }
      
               foreach (ObjectId eid in xbtr)
               {
                   Entity xent = tr.GetObject(eid, OpenMode.ForRead) as Entity;
                   if (xent == null)continue;
                   
                   xent.UpgradeOpen();
                   xent.ColorIndex = 0;

                   DBObject obj=((DBObject)xent).DeepClone(newbtr, new IdMapping(), true);
                   ((Entity)obj).TransformBy(Matrix3d.Displacement(pt - bref.Position));
               }
               tr.AddNewlyCreatedDBObject(newbtr, true);

                tr.Commit();
                
            }
        }

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 7 of 15
Hallex
in reply to: RichardCammeray

Richard,

You can change the subentity properties easily,

see example, just change void name, command name

and default length of line to your needs:

 

    [CommandMethod("reline")]
        static public void SwapSubEntity()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            Transaction tr = doc.TransactionManager.StartTransaction();
            using (tr)
            {
                PromptNestedEntityOptions pno = new PromptNestedEntityOptions("\nSelect Line >>");
                pno.AllowNone = false;
                PromptNestedEntityResult rs = ed.GetNestedEntity(pno);
                if (rs.Status != PromptStatus.OK)
                    return;
                Entity selent = (Entity)tr.GetObject(rs.ObjectId, OpenMode.ForWrite);
                BlockTableRecord btrec = tr.GetObject(selent.OwnerId, OpenMode.ForWrite) as BlockTableRecord;
                Line ln = selent as Line;
                if (ln != null)
                {

                 if (!ln.IsWriteEnabled)   ln.UpgradeOpen();
                 double leg = ln.Length;
                 PromptDoubleOptions pdo = new PromptDoubleOptions("\nSpecify new line length: ");
                 pdo.AllowNegative = false;
                 pdo.AllowZero = false;
                 pdo.AllowNone = true;
                 pdo.DefaultValue = 12;
                 PromptDoubleResult res = ed.GetDouble(pdo);
                 if (res.Status != PromptStatus.OK && res.Status != PromptStatus.Keyword) return;
                 double newleg = res.Value;
                 ln.TransformBy(Matrix3d.Scaling(newleg / leg, ln.StartPoint));     
                    btrec.DowngradeOpen();

                }
                doc.TransactionManager.QueueForGraphicsFlush();

                doc.TransactionManager.FlushGraphics();

                doc.Editor.UpdateScreen();

                tr.Commit();

                ed.Regen();
            }
        }

 

Then you can clone this block as I've wrote above,

let me know if you need more help

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 8 of 15
RichardCammeray
in reply to: Hallex

Hi Hallex,

I think I found what problem is in my case.

Probably I should mention on the beginning that I need to also change BlockReference.BlockTableRecord once a new BlockTable is created.

I modified your first example and at the end I added line to change BlockReference.

 

Could you please try create block with some lines and insert at least two blocks into drawing and try run modified CopyXBref command on one block.

When I run REGEN command lines change colour  in both (old and new) blocks

 

Thanks for your examples.

Richard.

 

 

[CommandMethod("CopyXBref")]
        public void testCopyBlockReference()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect main block instance to copy: ");
                peo.SetRejectMessage("\nMust be a type of the BlockReference!");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);

                if (per.Status != PromptStatus.OK) return;

                BlockReference bref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
                ed.WriteMessage("\nBlock Selected with name: {0}", btr.Name);
                PromptStringOptions pso = new PromptStringOptions("\nEnter new block name: ");
                pso.AllowSpaces = true;
                PromptResult sres = ed.GetString(pso);
                if (sres.Status != PromptStatus.OK) return;
                string newname = sres.StringResult;
                if (bt.Has(newname))
                {
                    ed.WriteMessage("\nBlock with name: {0} already exist, try again", newname);
                    return;
                }

                BlockTableRecord newbtr = new BlockTableRecord();
                bt.UpgradeOpen();

                newbtr = (BlockTableRecord)btr.DeepClone(bt, new IdMapping(), true);

                newbtr.Name = newname;
                bt.Add(newbtr);
                //----------------------------------------------------------------//

                foreach (ObjectId id in newbtr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null) continue;
                    ent.UpgradeOpen();
                    ent.ColorIndex = 0;
                }


                tr.AddNewlyCreatedDBObject(newbtr, true);

 

                //Change BlockReference
                bref.BlockTableRecord = newbtr.Id;

 

                tr.Commit();

            }
        }

 

Message 9 of 15
Hallex
in reply to: RichardCammeray

In this case you have to change properties

of all subentities inside the both BlockTableRecords,

try this one

 

        [CommandMethod("CopyXBref")]
        public void testCopyBlockReference()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect main block instance to copy: ");
                peo.SetRejectMessage("\nMust be a type of the BlockReference!");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);

                if (per.Status != PromptStatus.OK) return;

                BlockReference bref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForWrite);

                BlockTableRecord bdef = (BlockTableRecord)tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
                foreach (ObjectId id in bdef)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null) continue;
                    ent.UpgradeOpen();
                    ent.ColorIndex = 1;
                }
               // BlockTableRecord cursp = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                ed.WriteMessage("\nBlock Selected with name: {0}", bdef.Name);
                PromptStringOptions pso = new PromptStringOptions("\nEnter new block name: ");
                pso.AllowSpaces = true;
                PromptResult sres = ed.GetString(pso);
                if (sres.Status != PromptStatus.OK) return;
                string newname = sres.StringResult;
                if (bt.Has(newname))
                {
                    ed.WriteMessage("\nBlock with name: {0} already exist, try again", newname);
                    return;
                }

                BlockTableRecord newbtr = new BlockTableRecord();
                bt.UpgradeOpen();

                newbtr = (BlockTableRecord)bdef.DeepClone(bt, new IdMapping(), true);

                newbtr.Name = newname;
                bt.Add(newbtr);
                //----------------------------------------------------------------//

                foreach (ObjectId id in newbtr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null) continue;
                    ent.UpgradeOpen();
                    ent.ColorIndex = 1;
                }


                tr.AddNewlyCreatedDBObject(newbtr, true);

 

                //Change BlockReference
                bref.BlockTableRecord = newbtr.Id;


                ed.Regen();
                tr.Commit();

            }
        }

 

~'J'~

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 10 of 15
RichardCammeray
in reply to: Hallex

I think you misunderstood my last message.

I don’t want to change original block at all. What I was trying to show you in my example is that changing of colour of entities in new block will change colour of entities in original block (that is what I do not want).

 

Thanks,

Richard

Message 11 of 15
Hallex
in reply to: RichardCammeray

Richard, try first to create 2 similar blocks

with different names manually

and set color property for all subentities

in the first block to byblock and for the second one

to bylayer, then see what happens

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 12 of 15
RichardCammeray
in reply to: Hallex

I have tried to create manually two blocks as you advised and inserted them into drawing (two per each one).

Then I run my version of  CopyXBref command. Unfortunately original block had change colour as well.

 

Thank you for your patience

 

Richard

Message 13 of 15
Hallex
in reply to: RichardCammeray

No problems,

Now you try this code on your manually created block<

but create layer before, see comments at the end of code

 

        [CommandMethod("CopyXB")]
        public void CopyBlockDef()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect parent block instance to copy: ");
                peo.SetRejectMessage("\nMust be a type of the BlockReference!");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);

                if (per.Status != PromptStatus.OK) return;

                BlockReference bref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
                ed.WriteMessage("\nBlock Selected with name: {0}", btr.Name);
                PromptStringOptions pso = new PromptStringOptions("\nEnter new block name: ");
                pso.AllowSpaces = true;
                PromptResult sres = ed.GetString(pso);
                if (sres.Status != PromptStatus.OK) return;
                string newname = sres.StringResult;
                if (bt.Has(newname))
                {
                    ed.WriteMessage("\nBlock with name: {0} already exist, try again", newname);
                    return;
                }

                BlockTableRecord newbtr = new BlockTableRecord();
                bt.UpgradeOpen();

                newbtr = (BlockTableRecord)btr.DeepClone(bt, new IdMapping(), true);

                newbtr.Name = newname;
                bt.Add(newbtr);
                ed.Regen();
                //----------------------------------------------------------------//

                foreach (ObjectId id in newbtr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null) continue;
                    ent.UpgradeOpen();
                    ent.ColorIndex = 256;
                }


                tr.AddNewlyCreatedDBObject(newbtr, true);

                //Change BlockReference
                bref.BlockTableRecord = newbtr.ObjectId;
                // change layer, "RedColoredLayer" must be created before
                bref.Layer = "RedColoredLayer";
 
                tr.Commit();

            }
        }

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 14 of 15
RichardCammeray
in reply to: Hallex

Did not work either.

I set subentities in original block to color 3 but after running this command subentities were assigned to color ByLayer (ColorIndex = 256) in new and original block.

As I said at the beginning of the thread, ObjectIds of subentities in original and new blocks are the same and that is an issue.

 

I decided to create new empty Block and use DeepCloneObjects instead. Example below.

Hallex, Thank you for your help and very good examples.

 

Richard

 

        [CommandMethod("CopyXC")]
        public void testCopyBlockReference()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect main block instance to copy: ");
                peo.SetRejectMessage("\nMust be a type of the BlockReference!");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);

                if (per.Status != PromptStatus.OK) return;

                BlockReference bref = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
                ed.WriteMessage("\nBlock Selected with name: {0}", btr.Name);
                PromptStringOptions pso = new PromptStringOptions("\nEnter new block name: ");
                pso.AllowSpaces = true;
                PromptResult sres = ed.GetString(pso);
                if (sres.Status != PromptStatus.OK) return;
                string newname = sres.StringResult;
                if (bt.Has(newname))
                {
                    ed.WriteMessage("\nBlock with name: {0} already exist, try again", newname);
                    return;
                }

                ObjectIdCollection ids = new ObjectIdCollection();
                foreach (ObjectId id in btr)
                {
                    ids.Add(id);
                }

                BlockTableRecord newbtr = new BlockTableRecord();
                bt.UpgradeOpen();

                newbtr.Name = newname;
                ObjectId newBtrId = bt.Add(newbtr);
                tr.AddNewlyCreatedDBObject(newbtr, true);
                //----------------------------------------------------------------//


                IdMapping idMap = new IdMapping();
                db.DeepCloneObjects(ids, newBtrId, idMap, true);

                foreach (ObjectId id in newbtr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent == null) continue;
                    ent.UpgradeOpen();
                    ent.ColorIndex = 1;
                }

                //Change BlockReference
                bref.BlockTableRecord = newbtr.Id;

                tr.Commit();

            }
        }

Message 15 of 15
Hallex
in reply to: RichardCammeray

Glad you've solved it,

Cheers Smiley Happy

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost