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?