.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Retrieving all objects by layer

6 REPLIES 6
SOLVED
Reply
Message 1 of 7
autogis
2197 Views, 6 Replies

Retrieving all objects by layer

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.

6 REPLIES 6
Message 2 of 7
_gile
in reply to: autogis

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.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 7
autogis
in reply to: _gile

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.

Message 4 of 7
_gile
in reply to: autogis

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();
                }
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 7
autogis
in reply to: _gile

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. Smiley Happy

Message 6 of 7
_gile
in reply to: autogis

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();
                }
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 7
cgcamilo
in reply to: _gile

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.

Camilo Cifuentes
Tags (2)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost