Entity.DeepClone() vs. Database.DeepCloneObjects()
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Up until now, I have been using Database.WblockCloneObjects() to copy entities from other drawings, and using Database.DeepCloneObjects() to copy entities in the same drawing/database many times and never feld the need to call Entity.DeepClone() on individual entities.
In my current project, I run into the need to copy a single entity. Since when user decides to create a copy of the entity, it has already been opend in a trnasaction (as Entity), I though I'd simply call Entity.DeepClone() to create the copy, instead calling Database.DeepCloneObjects() as I am used to. I was surprised to find out the entity copy generated by Entity.DeepClone() does not show in AutoCAD editor, until the drawing is closed and re-opened in AutoCAD. Of course, when cloneing entity with Database.DeepCloneObjects(), this issue does not occur.
Here is the code (and video clip) to show the difference of the 2 cloning approaches:
using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using CadApp = Autodesk.AutoCAD.ApplicationServices.Application; [assembly: CommandClass(typeof(ODDataDeepClone.MyCommands))] namespace ODDataDeepClone { public class MyCommands { [CommandMethod("DoClone")] public static void RunMyCommand() { var doc = CadApp.DocumentManager.MdiActiveDocument; var ed = doc.Editor; ObjectId entId; Matrix3d transform; bool entClone; if (GetInputs(ed, out entId, out transform, out entClone)) { if (entClone) { DoEntityDeepClone(entId, transform); // Following 2 lines of code have no effect // to get DeepCloned entity showing ////doc.TransactionManager.FlushGraphics(); ////ed.Regen(); } else { DoDatabaseDeepClone(entId, transform); } } } private static bool GetInputs( Editor ed, out ObjectId entId, out Matrix3d transform, out bool entDeepClone) { entId = ObjectId.Null; transform = new Matrix3d(); entDeepClone = true; var eRes = ed.GetEntity("\nSelect an entity:"); if (eRes.Status == PromptStatus.OK) { entId = eRes.ObjectId; var basePt = eRes.PickedPoint; var opt = new PromptPointOptions( "\nSelect \"Move-To\" point:"); opt.UseBasePoint = true; opt.BasePoint = basePt; var pRes = ed.GetPoint(opt); if (pRes.Status == PromptStatus.OK) { transform = Matrix3d.Displacement( basePt.GetVectorTo(pRes.Value)); var kOpt = new PromptKeywordOptions( "\nEntity.DeepClone() or Database.DeepCloneObject()?"); kOpt.Keywords.Add("Entity"); kOpt.Keywords.Add("Database"); kOpt.Keywords.Default = "Entity"; var kRes = ed.GetKeywords(kOpt); if (kRes.Status == PromptStatus.OK) { entDeepClone = kRes.StringResult == "Entity" ? true : false; return true; } else { return false; } } else { return false; } } else { return false; } } private static void DoEntityDeepClone( ObjectId entId, Matrix3d transform) { using (var tran = entId.Database.TransactionManager.StartTransaction()) { var ent = (Entity)tran.GetObject(entId, OpenMode.ForRead); var owner = (BlockTableRecord)tran.GetObject( ent.OwnerId, OpenMode.ForWrite); var mapping = new IdMapping(); var cloned = (Entity)ent.DeepClone(owner, mapping, true); cloned.TransformBy(transform); tran.AddNewlyCreatedDBObject(cloned, true); tran.Commit(); } } private static void DoDatabaseDeepClone( ObjectId entId, Matrix3d transform) { using (var tran = entId.Database.TransactionManager.StartTransaction()) { var ent = (Entity)tran.GetObject(entId, OpenMode.ForRead); ObjectId ownerId = ent.OwnerId; var mapping = new IdMapping(); ObjectIdCollection ids = new ObjectIdCollection( new ObjectId[] { entId }); entId.Database.DeepCloneObjects(ids, ownerId, mapping, false); foreach (IdPair pair in mapping) { if (pair.IsCloned) { var cloned = tran.GetObject( pair.Value, OpenMode.ForRead) as Entity; if (cloned != null) { cloned.UpgradeOpen(); cloned.TransformBy(transform); } } } tran.Commit(); } } } }
I delibrately move the cloned entity away from its source, so the cloning can be visibly witnessed (well, in the case of calling Database.DeepCloneObjects().
I did a search and did not find any thing on this issue. Am I missing something? I tried the same code with AutoCAD 2017 and 2018, got the same result. Anyone knows on this?
As I said, I have been always used Database.DeepCloneObjects(), so, this issue is not clritical to me at all, but like to know if I missed something?