Author Topic: DeepClone Problem  (Read 3637 times)

0 Members and 1 Guest are viewing this topic.

Jeff H

  • Needs a day job
  • Posts: 6144
DeepClone Problem
« on: September 20, 2011, 09:16:15 AM »
Am I completely missing something that is staring me straight in the face?
 
The problem and you might have to regen to get it show both, but this will update the block's clone and original block.
The code is a basic example and it is like the ObjectIds are not being translated correctly.
 
I have even broke it up into 2 commands to do the changing of the Clone Entities to see if the translating was done after the transaction commited but they still both change.
 
This should deepclone a BlockTableRecord and name it 'OriginalName' +  'COPY' then change all the entities in the new BlockTableRecord to red but also changes the original? :? ?
 
It is like the entities in the newly cloned BlockTableRecord and the original BlockTableRecord are pointing to same object, and the ids were not translated.

Code: [Select]
        [CommandMethod("WTF")]
        public void WTF()
        {         
            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect Block Reference: ");
                peo.SetRejectMessage("\n That was not a Block Reference");
                peo.AddAllowedClass(typeof(BlockReference), true);
                PromptEntityResult per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                {
                    return;
                }
                BlockReference bref = (BlockReference)trx.GetObject(per.ObjectId, OpenMode.ForRead);         
             
                BlockTableRecord btr = (BlockTableRecord)trx.GetObject(bref.BlockTableRecord, OpenMode.ForRead);             

                if (btr.Name.EndsWith("COPY"))
                {
                    return;
                }
                string btrName =  btr.Name   "COPY";
 
                BlockTable bt = (BlockTable)trx.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord newBtr = null;
                if (bt.Has(btrName))
                {
                    newBtr = (BlockTableRecord)trx.GetObject(bt[btrName], OpenMode.ForRead);
                }
                else
                {
                    bt.UpgradeOpen();
                    //IdMapping idMap = new IdMapping();
                   
                    //newBtr = (BlockTableRecord)btr.DeepClone(bt, idMap, false);
                    newBtr = (BlockTableRecord)btr.DeepClone(bt, new IdMapping(), true);
                    newBtr.Name = btrName;
                    bt.Add(newBtr);
                    trx.AddNewlyCreatedDBObject(newBtr, true);
                    foreach (ObjectId id in newBtr)
                    {
                        Entity ent = trx.GetObject(id, OpenMode.ForRead) as Entity;
                        if (ent == null)
                        {
                            continue;
                        }
                        ent.UpgradeOpen();
                        ent.ColorIndex = 1;
                    }
                }
                bref.UpgradeOpen();
                bref.BlockTableRecord = newBtr.ObjectId;
                trx.Commit();
            }
        }

 
 
« Last Edit: September 20, 2011, 10:09:14 AM by Jeff H »

Jeff H

  • Needs a day job
  • Posts: 6144
Re: DeepClone Problem
« Reply #1 on: September 20, 2011, 10:55:43 AM »
Okay I think I need to be using
DeepCloneObjects

Bryco

  • Water Moccasin
  • Posts: 1882
Re: DeepClone Problem
« Reply #2 on: September 20, 2011, 11:09:46 AM »
Yes in your code the ents in the blocks have the same ids

Jeff H

  • Needs a day job
  • Posts: 6144
Re: DeepClone Problem
« Reply #3 on: September 20, 2011, 11:12:50 AM »
Thanks Byrco,
 
That fix it.
 
If anyonre needs me post the updated code I will,
I have not cleaned it up since it was for example but if anyone asks I will take the minute to clean up and post
 

kaefer

  • Guest
Re: DeepClone Problem
« Reply #4 on: September 20, 2011, 12:32:32 PM »
Okay I think I need to be using
DeepCloneObjects

Me thinks too. DeepClone(...) on a BlockTableRecord plays havoc with the BlockBegin/BlockEnd markers and messes up big time the ownership of contained objects.

Following is a suggestion written in F#, with Clone() on the BTR and DeepCloneObjects(...) for the rest. Funny thing is, there seems to be a problem with ATTSYNC: When applied to the clone the AttributeReferences on the original block do also change color. Which can be undone by applying ATTSYNC on it too.

Code: [Select]
           ...
           let newBtrId =
                if bt.Has newBtrName then
                    bt.[newBtrName]
                else
                    bt.UpgradeOpen()
                    let newBtr = btr.Clone() :?> BlockTableRecord
                    newBtr.Name <- newBtrName
                    let newBtrIdTmp = bt.Add newBtr
                    tr.AddNewlyCreatedDBObject(newBtr, true)
                    let oidc = new ObjectIdCollection()
                    for oid in btr do
                        oidc.Add oid |> ignore
                    let idMap = new IdMapping()
                    db.DeepCloneObjects(oidc, newBtrIdTmp, idMap, false)
                    for o in idMap do
                        let idPair = o :?> IdPair
                        if idPair.IsPrimary then
                            match tr.GetObject(idPair.Value, OpenMode.ForWrite) with
                            | :? Entity as ent ->
                                ent.ColorIndex <- 1
                            | _ -> ()
                    newBtrIdTmp

            bref.UpgradeOpen()
            bref.BlockTableRecord <- newBtrId
           ...

Beware of idPair.IsPrimary == false, which indicates processing of AttributeReference/SequenceEnd of nested blocks.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: DeepClone Problem
« Reply #5 on: September 04, 2012, 08:10:33 PM »
Thanks Byrco,
 
That fix it.
 
If anyonre needs me post the updated code I will,
I have not cleaned it up since it was for example but if anyone asks I will take the minute to clean up and post
 
Got a PM about this and sorry for the mess but maybe this help out.
 
Just copied what was below and made minor edits to get it to work.
 
Code - C#: [Select]
  1.  
  2.          [CommandMethod("WTF2")]
  3.         public void WTF2()
  4.         {
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;
  8.             using (Transaction trx = db.TransactionManager.StartTransaction())
  9.             {
  10.                 PromptEntityOptions peo = new PromptEntityOptions("\nSelect Block Reference: ");
  11.                 peo.SetRejectMessage("\n That was not a Block Reference");
  12.                 peo.AddAllowedClass(typeof(BlockReference), true);
  13.                 PromptEntityResult per = ed.GetEntity(peo);
  14.                 if (per.Status != PromptStatus.OK)
  15.                 {
  16.                     return;
  17.                 }
  18.                 BlockReference bref = (BlockReference)trx.GetObject(per.ObjectId, OpenMode.ForRead);
  19.                 BlockTableRecord btr = (BlockTableRecord)trx.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
  20.                 ObjectIdCollection ids = new ObjectIdCollection();
  21.                 foreach (ObjectId id in btr)
  22.                 {
  23.                     ids.Add(id);
  24.                 }
  25.                 if (btr.Name.EndsWith("COPY"))
  26.                 {
  27.                     return;
  28.                 }
  29.                 string btrName = btr.Name + "COPY";
  30.                 BlockTable bt = (BlockTable)trx.GetObject(db.BlockTableId, OpenMode.ForRead);
  31.                 BlockTableRecord newBtr = null;
  32.                 if (bt.Has(btrName))
  33.                 {
  34.                     newBtr = (BlockTableRecord)trx.GetObject(bt[btrName], OpenMode.ForRead);
  35.                 }
  36.                 else
  37.                 {
  38.                     bt.UpgradeOpen();
  39.                     newBtr = new BlockTableRecord();
  40.                     newBtr.Name = btrName;
  41.                    ObjectId newBtrId =  bt.Add(newBtr);
  42.                     trx.AddNewlyCreatedDBObject(newBtr, true);
  43.                     IdMapping idMap = new IdMapping();
  44.  
  45.                     db.DeepCloneObjects(ids, newBtrId, idMap, true);
  46.                
  47.                     foreach (ObjectId id in newBtr)
  48.                     {
  49.                         Entity ent = trx.GetObject(id, OpenMode.ForRead) as Entity;
  50.                         if (ent == null)
  51.                         {
  52.                             continue;
  53.                         }
  54.                         ent.UpgradeOpen();
  55.                         ent.ColorIndex = 1;
  56.                        
  57.                     }
  58.                 }
  59.                 bref.UpgradeOpen();
  60.                 bref.BlockTableRecord = newBtr.ObjectId;
  61.                 trx.Commit();
  62.             }
  63.         }
  64.