Author Topic: Copying objects to new db  (Read 7868 times)

0 Members and 1 Guest are viewing this topic.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Copying objects to new db
« on: June 25, 2006, 08:43:24 PM »
I'm struggling with copying objects from one db into a new one, I have done very little with Documents and new db's , blocks etc so any help would be great.

It works but if I open the new drawing with objects that contained xdata in the original there are errors.
Will this mean I need to 'deep' clone? I'll give it a go anyhow and see how it goes.


Here's what I have so far -
Code: [Select]
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows.ToolPalette;
namespace copytester
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Class1
{
[CommandMethod("TESTCOPY")]
public static void CopyToNewDb()
{
Editor ed =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
//Get an entiy to copy to new drg:
PromptEntityResult res = ed.GetEntity("\nSelect an entity to copy to new drg:");
if(res.Status == PromptStatus.Cancel || res.Status != PromptStatus.OK)
return;
Database db = HostApplicationServices.WorkingDatabase;
Transaction tr = db.TransactionManager.StartTransaction();
try
{
//Get the ent to copy:
Entity ent = tr.GetObject(res.ObjectId,OpenMode.ForWrite) as Entity;
if(ent == null)
return;
//new db from template, new trans:
Database newdb = new Database(false,true);
newdb.ReadDwgFile(@"C:\DCS_3D\dcs_std.dwt", System.IO.FileShare.None, false,null);
Transaction tr2 = newdb.TransactionManager.StartTransaction();
try
{
BlockTable bt = tr2.GetObject(newdb.BlockTableId, OpenMode.ForRead, false) as BlockTable;
BlockTableRecord btr = tr2.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
if(btr == null)
return;
//copy our entity to make a new ent to add to new db:
Entity newent = ent.Clone() as Entity;
//append entity to new db:
if(newent == null)
return;
btr.AppendEntity(newent);
tr2.AddNewlyCreatedDBObject(newent,true);
//use existing ent handle for now for drg names:
string filename = @"C:\DCS_3D\testdrgs\drg" + ent.Handle.Value.ToString() + ".dwg";
newdb.SaveAs(filename,null);
tr2.Commit();
}
finally
{
tr2.Dispose();
newdb.Dispose();
}
tr.Commit();
}
finally
{
tr.Dispose();
}
}
}
}
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #1 on: June 25, 2006, 09:29:48 PM »
Something like this perhaps:

Code: [Select]
[CommandMethod("Dolly")]
static public void DollyCommand() {
Editor pEd = acadApp.DocumentManager.MdiActiveDocument.Editor;

PromptEntityResult pRes = pEd.GetEntity("\nSelect an entity to dollify: ");
if (pRes.Status != PromptStatus.OK)
return;

ObjectIdCollection pEntsToClone = new ObjectIdCollection();

pEntsToClone.Add(pRes.ObjectId);

Database pNewDb = new Database(true, true);

using (Transaction pTr = pNewDb.TransactionManager.StartTransaction()) {
BlockTable pBlkTbl = pTr.GetObject(pNewDb.BlockTableId, OpenMode.ForRead, false) as BlockTable;

pNewDb.WblockCloneObjects(pEntsToClone, pBlkTbl[BlockTableRecord.ModelSpace], DuplicateRecordCloning.Ignore, false);


}

pNewDb.SaveAs(@"C:\Temp\Dolly.dwg", DwgVersion.Current);


}

Cheers,
Glenn.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Copying objects to new db
« Reply #2 on: June 25, 2006, 09:32:52 PM »
Quote
[CommandMethod("Dolly")]
 .....

I bet there is a story to go with that name ...
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #3 on: June 25, 2006, 09:51:01 PM »
Something like this perhaps:

.....
Cheers,
Glenn.

heh, thanks Gleen, I took that route actually after battling with deepclone and getting nowwhere :)

My result which is very similar only I'm using a template that has our default layers etc. -
Code: [Select]
[CommandMethod("TESTCOPY")]
public static void CopyToNewDb()
{
Editor ed =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
//Get an entiy to copy to new drg:
PromptEntityResult res = ed.GetEntity("\nSelect an entity to copy to new drg:");
if(res.Status == PromptStatus.Cancel || res.Status != PromptStatus.OK)
return;
Database db = HostApplicationServices.WorkingDatabase;
Transaction tr = db.TransactionManager.StartTransaction();
try
{
//Get the ent to copy, only need id to add to ObjectId collection:
ObjectIdCollection coll = new ObjectIdCollection();
//add our object to copy:
coll.Add(res.ObjectId);
//new db from template:
Database newdb = new Database(false,true);
newdb.ReadDwgFile(@"C:\DCS_3D\dcs_std.dwt", System.IO.FileShare.None, false,null);
//wblock entity to new db:
db.Wblock(newdb,coll,new Point3d(),DuplicateRecordCloning.Ignore);
//use existing ent handle for now for drg names:
string filename = @"C:\DCS_3D\testdrgs\drg" + res.ObjectId.Handle.Value.ToString() + ".dwg";
newdb.SaveAs(filename,null);
newdb.Dispose();
tr.Commit();
}
finally
{
tr.Dispose();
}
}

I actually want to copy groups into new drgs, I need to get hold of the new objects in the new db now and create a group that matches the one in the model. If I'm adding multiple groups this may be difficult to get the last added ents, more study required :)
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #4 on: June 25, 2006, 10:42:19 PM »
Thanks Bobby for the eventhandler samples :)

I should be able to work with this -
Code: [Select]
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows.ToolPalette;
namespace copytester
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Class1
{
[CommandMethod("TESTCOPY")]
public static void CopyToNewDb()
{
Editor ed =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
//Get an entiy to copy to new drg:
PromptEntityResult res = ed.GetEntity("\nSelect an entity to copy to new drg:");
if(res.Status == PromptStatus.Cancel || res.Status != PromptStatus.OK)
return;
Database db = HostApplicationServices.WorkingDatabase;
Transaction tr = db.TransactionManager.StartTransaction();
try
{
//Get the ent to copy, only need id to add to ObjectId collection:
ObjectIdCollection coll = new ObjectIdCollection();
//add our object to copy:
coll.Add(res.ObjectId);
//new db from template:
Database newdb = new Database(false,true);
newdb.ReadDwgFile(@"C:\DCS_3D\dcs_std.dwt", System.IO.FileShare.None, false,null);

//add an event handler to catch the newly added db objects:
newdb.ObjectAppended += new ObjectEventHandler(OnObjectAppended);

//wblock entity to new db:
db.Wblock(newdb,coll,new Point3d(),DuplicateRecordCloning.Ignore);

//delete the event handler:
newdb.ObjectAppended -= new ObjectEventHandler(OnObjectAppended);

//use existing ent handle for now for drg names:
string filename = @"C:\DCS_3D\testdrgs\drg" + res.ObjectId.Handle.Value.ToString() + ".dwg";
newdb.SaveAs(filename,null);
newdb.Dispose();
tr.Commit();
}
finally
{
tr.Dispose();
}
}

private static void OnObjectAppended(object sender, ObjectEventArgs e)
{
Editor ed =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("\nHandle of new object added to new db: " + e.DBObject.GetType().Name);
}
}
}

Thanks Guys.
« Last Edit: June 25, 2006, 11:17:30 PM by MickD »
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #5 on: June 25, 2006, 11:56:15 PM »
I would be EXTREMELY carefull with the OnObjectAppended event, for several reasons, not the least of which, is that the entity your passed is probably still in an "open for write" state by AutoCAD from memory...

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #6 on: June 26, 2006, 12:03:27 AM »
Is there another way you could suggest?

I did notice the output wasn't quite as I suspected too but this may be normal. If I do a 'move' 'all' in the new drg it only picks up the 1 object as picked from the original drg but the function shows it added twice??.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #7 on: June 26, 2006, 12:08:41 AM »
I notice your using wblock and not wblockcloneobjects as I used...have you tried it my way?

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #8 on: June 26, 2006, 12:12:17 AM »
Also, try printing up the handle of the object being appended, not the type as your screen cappy goes - this should tell you immediately if the objects are indeed the same...even better, print the objectId's if you can get them, as handles are only guaranteed to be unique for a drawing NOT across all drawings open in a session, whereas objectid's are unique across all drawings open in a given session.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #9 on: June 26, 2006, 12:57:13 AM »
Ok, the output using just wblock is the first, using wblockcloneobjects is the second -
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #10 on: June 26, 2006, 06:15:46 PM »
Of course, now I'm saving the ObjId's of the newly appended objects I'm getting 2 of each and crashes my group creation code.
Some more testing is involved now to see why 'object appended' is being called twice??
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #11 on: June 26, 2006, 07:34:22 PM »
Mick,

Have you used the IdMapping object returned from the wblockcloneobjects? It will contain id's of the original and the clones...you should be able to go from there.

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #12 on: June 26, 2006, 08:35:20 PM »
Is that only in 2007??

I could iterate the db it contains but I already have both db's.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #13 on: June 26, 2006, 08:49:45 PM »
From the ObjectARX 2006 docs:

WblockCloneObjects
Autodesk.AutoCAD.DatabaseServices.IdMapping

WblockCloneObjects(

Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection identifiers,

Autodesk.AutoCAD.DatabaseServices.ObjectId id,

Autodesk.AutoCAD.DatabaseServices.DuplicateRecordCloning cloning,

System.Boolean deferTranslation)

Parameters
identifiers Input Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection object. 
id Input Autodesk.AutoCAD.DatabaseServices.ObjectId object. 
cloning Input Autodesk.AutoCAD.DatabaseServices.DuplicateRecordCloning object. 
deferTranslation Input System.Boolean object. 

Return Type
Autodesk.AutoCAD.DatabaseServices.IdMapping



Wraps the following functions:
AcDbDatabase::wblockCloneObjects

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: Copying objects to new db
« Reply #14 on: June 26, 2006, 09:26:48 PM »
Yes, I knew it returned an IdMapping, I was looking for something obvious like an id collection property...looked harder and found the enumerater...doh!

Anyway, thanks Glenn, works a treat and deleted the reactor -
Code: [Select]
IdMapping idmap = new IdMapping();
//wblock entity to new db:
using(Transaction tr2 = newdb.TransactionManager.StartTransaction())
{
BlockTable bt = tr2.GetObject(
newdb.BlockTableId,OpenMode.ForWrite) as BlockTable;
if(bt == null)
return;
idmap = db.WblockCloneObjects(
coll,bt[BlockTableRecord.ModelSpace],
DuplicateRecordCloning.Ignore,false);
}

foreach(IdPair idp in idmap)
{
if(idp.IsPrimary)//otherwise you'll get all which are not req'd in this case!
{
ed.WriteMessage("\nOriginal db ObjId: {0}, Destination db ObjId: {1}",
idp.Key.ToString(),idp.Value.ToString());
}
}
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Glenn R

  • Guest
Re: Copying objects to new db
« Reply #15 on: June 26, 2006, 09:49:13 PM »
Sorry Mick, I must have misread your post.

I was going to post up something about the idPair but you figured it out with my nudging ;)

Good one.

Cheers,
Me.

sinc

  • Guest
Re: Copying objects to new db
« Reply #16 on: January 01, 2009, 12:26:03 PM »
I'm trying to do something similar to this, but I'm trying to let the user pick an entity in an XREF, and clone the entity in the current drawing.  How do I go about that?

In the code below, "obj" is the object selected by the user, and returned by SelectNestedEntity.  It is therefore an entity that exists in the XREF, but it was retrieved using the current drawing's database, and is "from external reference".

Code: [Select]
BlockTableRecord currentSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
IdMapping mapping = new IdMapping();
DBObject clone = obj.WblockClone(currentSpace, mapping, false);

The above code is contained inside the standard Transaction, and I am committing the transaction at the end.  The code creates an object that gets assigned to 'clone', and I can see it in the debugger, and the code runs with no errors, but the cloned entity does not show up in the current drawing.

Am I going about this wrong?  Do I need to explicitly open the XREF database using ReadDWGFile, and then use WBlockCloneObjects() to clone entities between databases?  Or is there some way to use WBlockClone to copy a selected item from a loaded XREF into the current drawing?