.NET

Reply
Valued Contributor
RichardCammeray
Posts: 53
Registered: ‎12-08-2010
Message 1 of 15 (570 Views)

Copy of BlockTableRecord (save as)

570 Views, 14 Replies
08-30-2012 05:49 PM

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

Board Manager
StephenPreston
Posts: 418
Registered: ‎05-22-2006
Message 2 of 15 (536 Views)

Re: Copy of BlockTableRecord (save as)

08-31-2012 01:09 PM in reply to: RichardCammeray

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

 

 

Cheers,

Stephen Preston
Autodesk Developer Network
Valued Contributor
RichardCammeray
Posts: 53
Registered: ‎12-08-2010
Message 3 of 15 (494 Views)

Re: Copy of BlockTableRecord (save as)

09-02-2012 04:33 PM in reply to: StephenPreston

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.

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 4 of 15 (476 Views)

Re: Copy of BlockTableRecord (save as)

09-02-2012 10:08 PM 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
Valued Contributor
RichardCammeray
Posts: 53
Registered: ‎12-08-2010
Message 5 of 15 (470 Views)

Re: Copy of BlockTableRecord (save as)

09-02-2012 11:37 PM 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.

 

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 6 of 15 (465 Views)

Re: Copy of BlockTableRecord (save as)

09-03-2012 12:32 AM 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
*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 7 of 15 (454 Views)

Re: Copy of BlockTableRecord (save as)

09-03-2012 01:36 AM 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
Valued Contributor
RichardCammeray
Posts: 53
Registered: ‎12-08-2010
Message 8 of 15 (424 Views)

Re: Copy of BlockTableRecord (save as)

09-03-2012 07:16 PM 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();

            }
        }

 

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 9 of 15 (412 Views)

Re: Copy of BlockTableRecord (save as)

09-03-2012 09:50 PM 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
Valued Contributor
RichardCammeray
Posts: 53
Registered: ‎12-08-2010
Message 10 of 15 (406 Views)

Re: Copy of BlockTableRecord (save as)

09-03-2012 10:09 PM 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

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!