Folks this is my first autocad development project. I am trying to retrieve all the leaders from a specific layer. This is what I have so far:
static public void ExtractObjectsFromFileByLayer(string fileName) { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; string objectFilter = "LEADER"; string layerFilter = "HOMES"; // Create a database and try to load the file Database db = new Database(false, true); using (db) { try { db.ReadDwgFile( fileName, System.IO.FileShare.Read, false, "" ); } catch (System.Exception) { ed.WriteMessage("\nUnable to read drawing file."); return; } } // Create a TypedValue array to define the filter // by object types (dxf code 0) and layers (dxf code 8) TypedValue[] tvs = new TypedValue[] { new TypedValue(0, objectFilter), new TypedValue(8, layerFilter) }; // Assign the filter criteria to a SelectionFilter object SelectionFilter filter = new SelectionFilter(tvs); // Setup a Prompt Selection Result object with the SelectionFilter criteria PromptSelectionResult res = ed.SelectAll(filter); if (res.Status == PromptStatus.OK) { Transaction tr = db.TransactionManager.StartTransaction(); using (tr) { foreach (ObjectId objId in res.Value.GetObjectIds()) { Entity ent = (Entity)tr.GetObject( objId, OpenMode.ForRead ); // Let's get rid of the standard namespace const string prefix = "Autodesk.AutoCAD.DatabaseServices."; string typeString = ent.GetType().ToString(); if (typeString.Contains(prefix)) typeString = typeString.Substring(prefix.Length); ed.WriteMessage( "\nEntity " + ent.ObjectId.ToString() + " of type " + typeString + " found on layer " + ent.Layer + " with colour " + ent.Color.ToString() ); } } } }
I am getting an error in the following line: if (res.Status == PromptStatus.OK)
If anyone can provide me some assistance it would be much appreciated.
Thanks before hand.
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Hi,
On one hand, you're using a side Database and on the other you're making a selection set in the current document.
Then you start a Transaction with the side Database TransactionManager to open ObjectId from the current Database...
This won't work.
What do you want to achieve ?
If you want to get all "LEADER" objects on "HOMES" layer from the side Database (as suggested by the method name) you have to keep in mind you haven't access to the Editor of the side Database document.
You may have to iterate the model space BlockTableRecord entities (and possibly paper spaces) to achieve this.
gile, thank you for your help. Basically this is what I would like to do: I would like to load an "existing" dwg file (readonly) and then loop through all the leaders for the "HOMES" layer.
Try this:
static public void ExtractObjectsFromFileByLayer(string fileName) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Database db = new Database(false, true)) { try { db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, null); } catch (System.Exception ex) { ed.WriteMessage("\nError: {0}", ex.Message); return; } using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead); foreach (ObjectId id in modelSpace) { if (id.ObjectClass.DxfName == "LEADER") { Leader leader = (Leader)tr.GetObject(id, OpenMode.ForRead); if (leader.Layer == "HOMES") { ed.WriteMessage( "\nEntity {0} of type {1} found on layer {2} with color {3}", id, leader.GetType().Name, leader.Layer, leader.Color); } } } tr.Commit(); } } }
Thank you gile that worked great! I have a question for you. I did notice it took a long time (the foreach) since it is searching through all object types and all layers (100+ layers in that file). Is there a way to use some type of filter like I was attempting before it goes into the foreach? Learning something new every day.
The number of layers isn't taken in account.
The foreach loop checks every object in the model space (as a Selectall does).
The code is quite opitmized as ObjectIdS are filtered using their ObjectClass property so that only Leader entities are opened to check their Layer property.
Try this LISP expression, which uses a filtered selection, in the file, it may take a long time too...
(sssetfirst nil (ssget "_X" '((0 . "LEADER") (8 . "HOMES"))))
Perhaps directly checking the RXClass object of objectIdS is cheaper than checking the RXClass.DxfName, but I'm not certain it's noticeable (I used the DxfName to make the code more readable).
Another performance improvement shoud be use an OpenCloseTransaction instead of a simple Transaction as there's no need for an Undo group.
static public void ExtractObjectsFromFileByLayer(string fileName) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Database db = new Database(false, true)) { try { db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, null); } catch (System.Exception ex) { ed.WriteMessage("\nError: {0}", ex.Message); return; } using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead); RXClass leaderClass = RXClass.GetClass(typeof(Leader)); foreach (ObjectId id in modelSpace) { if (id.ObjectClass == leaderClass) { Leader leader = (Leader)tr.GetObject(id, OpenMode.ForRead); if (leader.Layer == "HOMES") { ed.WriteMessage( "\nEntity {0} of type {1} found on layer {2} with color {3}", id, leader.GetType().Name, leader.Layer, leader.Color); } } } tr.Commit(); } } }
A bit old replay.
I guess you should consider also "BlockReference" entities. Something like:
Entity ent = tr.GetObject(id, OpenMode.ForRead);
if (ent is BlockReference)
{
BlockReference reference = ent as BlockReference;
BlockTableRecord ms_reference = (BlockTableRecord)tr.GetObject(reference.BlockTableRecord, OpenMode.ForRead);
// traverse all entities for this new "ms_reference"
}
No? Because I have noticed that not all entities from the current ModelSpace's BlockTableRecord reference to a Layer, unless you consider the block references.