I want to create a command, it could copy the contents of another drawing to the current drawing directly, not XERF, Is there anyone can give me a simple example?
Thanks very much
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Here's a little sample
public static ObjectIdCollection ImportModelSpace(string filename) { if (!File.Exists(filename)) throw new FileNotFoundException("File not found", filename); Database targetDb = HostApplicationServices.WorkingDatabase; ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb); IdMapping idMap = new IdMapping(); using (Database sourceDb = new Database()) { sourceDb.ReadDwgFile(filename, FileShare.Read, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartTransaction()) { BlockTableRecord mSpace = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(sourceDb), OpenMode.ForRead); ObjectIdCollection ids = new ObjectIdCollection(mSpace.Cast<ObjectId>().ToArray()); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false); tr.Commit(); } } return new ObjectIdCollection( idMap .Cast<IdPair>() .Where(p => p.IsCloned) .Select(p => p.Value) .ToArray()); }
I think the code is still a little complicated for me,
Can you help me achieve the following process? It will be a better way.
For example, there is a source drawing which contains a BlockReference called tstrm in the D drive,
Then execute custom command in the new drawing, this target block above will be copied to the new drawings.
Attachment has the source drawings
Extremely grateful
I do not quite understand the difference between these two
But the result I want is equivalent to using Autocad COPY command , just like copy the graphics to a new drawing, the graphics is same with the old one.
The new command that I want to get will work as below:
1,Exceute the command,
2,Automatic drawing that graphics at my specified position, in fact this step the program will access the source drawing and then copy that graphics
This small command will save some time during copy, just like select target object and so on
First, IMO, if you want to make autoCAD customization, especially with a as sophisticated technology as .NET, you must, above all, master the autoCAD basics as the difference between a block definition (BlockTableRecord) and an insertion of this definition (BlockReference).
The AutoCAD COPY command do not allow to copy a graphic object between different drawing (either between two spaces). This can be done with the Windows clipboard technology (Copy/Paste commands) which is tolerate by AutoCAD.
The "AutoCAD way" to do what you describe is using the DesignCenter to import the block definition from another drawing and insert a reference of this block in the model space or elsewhere. This can be done programmatically using the WblockCloneObjects() method as shown upper.
You can find a method to import a block definition from an external drawing in this recent thread (reply #7):
Thank you very much, I have a learn about WBlockCloneObjects() method in the AutoCAD Developer Guide, it works well.
but I am not very unstudand about your ImportBlock() method, this one has some problem.
Can you fix my code? Just let it work,
For example:
filePath=@"D:\SourceDwg\sourceDrawing.dwg"
BlockName="tstrm"
The Block will be import at origin
The above attachment has the drawing.
Blow is code,
using System.IO; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Runtime; [assembly: CommandClass(typeof(AutocadCommandCollection.test6))] namespace AutocadCommandCollection { class test6 { [CommandMethod("test6")] public static void CopyFrom() { Document acDoc = Application.DocumentManager.MdiActiveDocument; Database acCurDb = acDoc.Database; using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) { BlockTable acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable; ObjectId Id = ImportBlock(@"D:\SourceDwg\sourceDrawing.dwg", "tstrm"); BlockTableRecord btr = (BlockTableRecord)acTrans.GetObject(Id, OpenMode.ForRead); acBlkTbl.Add(btr); acTrans.AddNewlyCreatedDBObject(btr, true); acTrans.Commit(); } } private static ObjectId ImportBlock(string fileName, string blockName) { if (!File.Exists(fileName)) throw new FileNotFoundException("File not found", fileName); Document acDoc = Application.DocumentManager.MdiActiveDocument; Database targetDb = acDoc.Database; ObjectId owner = targetDb.BlockTableId; using (Database sourceDb = new Database()) { sourceDb.ReadDwgFile(fileName, System.IO.FileShare.Read, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartOpenCloseTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) return ObjectId.Null; ObjectId id = bt[blockName]; ObjectIdCollection ids = new ObjectIdCollection(); ids.Add(id); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false); return idMap[id].IsCloned ? idMap[id].Value : ObjectId.Null; } } } } }
I think I finally find the new block after run the code above, the block is existing int the BlockTable or maybe, I can find it throuht the Insert Block drop down list of the Insert Menu.
But It doesn't show as same as the old one after insert manully, I just want Insert the Block in the new drawing, It will be same with the old one.
Can you help me? Very thanks
private void ImportBlockReference(string blockName, string filenName) { if (!File.Exists(filenName)) throw new FileNotFoundException("File not found", filenName); Database targetDb = HostApplicationServices.WorkingDatabase; ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb); using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) throw new ArgumentException("Block definition not found", blockName); ObjectIdCollection ids = new ObjectIdCollection(); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead); ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); if (br.OwnerId == mSpaceId) { ids.Add(id); break; } } if (ids.Count == 0) throw new ArgumentException("Block reference not found", blockName); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false); } } }
Thank you very much for your help, the above code have finished the above function I seted, a celebration~
At before, I thought if I can achieve the above code, then I can make changes, and then complete the final function, but I can’t -_-
The above code is still need one step, in fact, I want to control the position copied into the new graphics ,
For example, I want the block which in the original drawing coordinates is ( 0,0,0 ) will be copied to a new position specfied by cursor in the new drawing, I think this needs to move an object , the method may be used is similar with:
acCirc.TransformBy (Matrix3d.Displacement (acVec3d));
But I can not find something equivalent to the acCirc object form your code.
Can you finish it?
The problem is I am not familiar with WblockCloneObjects () method, and IdMapping class, I do not know how to use.
Let me think about my mastery of AtuoCAD, now I'm not too familiar with AutoCAD 's API, The basic API I know all learn from AutoCAD Developer Guide, I just basically modify the sample code.
I very much hope to further study, but there is no sample code in ObjectARX_2010_Win_64_and_32Bit, it seems not easy to understand, do you have any good way?
Sincere wishes!
Yes, I think I need the new ObjectId of this block in the new drawing, then I can get the new BlockReference in the new drawing, then move and so on.
How can I get it, maybe I can get it though the idMap?
I have solve this move problem, thank you very much and a celebration : )
May be you can tell me how to learn AutoCAD's API~~~
below is code
using System; using System.IO; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; [assembly: CommandClass(typeof(AutocadCommandCollection.test9))] namespace AutocadCommandCollection { class test9 { [CommandMethod("test9")] public static void CopyFrom() { Document acDoc = Application.DocumentManager.MdiActiveDocument; Database acCurDb = acDoc.Database; using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) { ImportBlockReference("tstrm",@"D:\SourceDwg\sourceDrawing.dwg"); acTrans.Commit(); } } private static void ImportBlockReference(string blockName, string filenName) { if (!File.Exists(filenName)) throw new FileNotFoundException("File not found", filenName); Database targetDb = HostApplicationServices.WorkingDatabase; ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb); using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) throw new ArgumentException("Block definition not found", blockName); ObjectIdCollection ids = new ObjectIdCollection(); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead); ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb); ObjectId brefId = new ObjectId(); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); if (br.OwnerId == mSpaceId) { ids.Add(id); brefId = id; break; } } if (ids.Count == 0) throw new ArgumentException("Block reference not found", blockName); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false); Document acDoc = Application.DocumentManager.MdiActiveDocument; Database acCurDb = acDoc.Database; using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) { BlockReference bref = acTrans.GetObject(idMap[brefId].Value, OpenMode.ForWrite) as BlockReference; if (bref != null) { Application.ShowAlertDialog(bref.Position.ToString()); Point3d newPoint = new Point3d(100,100,0); Point3d oldPoint = new Point3d(0,0,0); Vector3d acVec3d = oldPoint.GetVectorTo(newPoint); bref.TransformBy(Matrix3d.Displacement(acVec3d)); Application.ShowAlertDialog(bref.Position.ToString()); } acTrans.Commit(); } } } } } }
Hi,
You can make the importBlockReference() method return the newly created ObjectId to the calling function from where you move the newly created block reference.
[CommandMethod("TEST")] public void Tet() { ObjectId id = ImportBlockReference("tstrm", @"D:\SourceDwg\sourceDrawing.dwg"); if (id != ObjectId.Null) { Database db = HostApplicationServices.WorkingDatabase; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite); br.TransformBy(Matrix3d.Displacement(new Vector3d(10, 20, 0))); tr.Commit(); } } } private ObjectId ImportBlockReference(string blockName, string filenName) { if (!File.Exists(filenName)) throw new FileNotFoundException("File not found", filenName); Database targetDb = HostApplicationServices.WorkingDatabase; ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb); using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) throw new ArgumentException("Block definition not found", blockName); ObjectIdCollection ids = new ObjectIdCollection(); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead); ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); if (br.OwnerId == mSpaceId) { ids.Add(id); break; } } if (ids.Count == 0) throw new ArgumentException("Block reference not found", blockName); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false); return idMap[ids[0]].Value; } } }
Can't find what you're looking for? Ask the community or share your knowledge.