« Autodesk University 2008: putting it to a vote | Main | Storing custom AutoCAD application settings in the Registry using .NET »

Finding all the AutoCAD entities on a particular layer using .NET

This question came in recently by email:

Is there a way to obtain the object IDs of all the object on a layer? I found the GetAllObjects() method of the Transaction object but it doesn't work.

That's right: GetAllObjects() will return the objects accessed via (or added to) the transaction - it has nothing to do with retrieving objects based on any particular property.

What you need to do is Editor.SelectAll(), the equivalent of acedSSGet("X") in ObjectARX and (ssget "X") in AutoLISP. You need the version where you pass in a SelectionFilter specifying the layer for which to search.

Here's some C# code doing just this, with the hard work encapsulated in a function (GetEntitiesOnLayer()) to make it easier to integrate into your code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;


namespace EntitySelection

{

  public class Commands

  {

    [CommandMethod("EOL")]

    static public void EntitiesOnLayer()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;


      PromptResult pr =

        ed.GetString("\nEnter name of layer: ");

      if (pr.Status == PromptStatus.OK)

      {

        ObjectIdCollection ents =

          GetEntitiesOnLayer(pr.StringResult);

        ed.WriteMessage(

          "\nFound {0} entit{1} on layer {2}",

          ents.Count,

          (ents.Count == 1 ? "y" : "ies"),

          pr.StringResult

        );

      }

    }


    private static ObjectIdCollection

      GetEntitiesOnLayer(string layerName)

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;


      // Build a filter list so that only entities

      // on the specified layer are selected


      TypedValue[] tvs =

        new TypedValue[1] {

            new TypedValue(

              (int)DxfCode.LayerName,

              layerName

            )

          };

      SelectionFilter sf =

        new SelectionFilter(tvs);

      PromptSelectionResult psr =

        ed.SelectAll(sf);


      if (psr.Status == PromptStatus.OK)

        return

          new ObjectIdCollection(

            psr.Value.GetObjectIds()

          );

      else

        return new ObjectIdCollection();

    }

  }

}

Running EOL simply counts the entities on a particular layer (the following is from running in the 3D House.dwg sample drawing):

Command: EOL

Enter name of layer: A-Beam

Found 1 entity on layer A-Beam

Command: EOL

Enter name of layer: A-Concrete

Found 1 entity on layer A-Concrete

Command: EOL

Enter name of layer: Furniture

Found 14 entities on layer Furniture

Command: EOL

Enter name of layer: Legs

Found 16 entities on layer Legs

It would be straightforward to do something more than just count the results of the GetEntitiesOnLayer() function, of course, or even to adapt the function to filter on other properties.

May 2, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Selection | Permalink

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/876965/28566024

Listed below are links to weblogs that reference Finding all the AutoCAD entities on a particular layer using .NET:

Comments

Hi Kean,

This approach works fine for small amount of entities.

What I did for huge drawings was a solution using a database reactor and a map to store an AcDbObjectIdArray of entities for each Layer's AcDbObjectId which will be the map KEY.

The idea was to catch these events:
objectAppended
objectErased
objectModified
objectReAppended
objectUnAppended

For each notification, get the entity`s layer AcDbObjectId and add/remove into proper map entry array.

The result is a instant cache to get the entity list for each desired layer.

You can store this cache through an AcDbObject entry inside NOD or build it on the fly everytime you load the DWG. The last will cause a small delay when loading the drawing but will avoid the use of a custom entity or a XRecord entry.

Of course this cache must be per-document and MDI-aware.

Regards,
Fernando.

Posted by: Fernando Malard | May 1, 2008 6:36:55 AM

That's right - this will be adequate for many (if not most) cases, but when performance is an issue implementing a cache is the way to go.

Kean

Posted by: Kean | May 1, 2008 10:06:01 AM

Post a comment