Kean Walmsley

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Twitter Updates

    follow me on Twitter



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

    May 02, 2008

    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.

    TrackBack

    TrackBack URL for this entry:
    http://www.typepad.com/services/trackback/6a00d83452464869e200e55217dce78834

    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.

    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

    Thanks for these informative posts. I thought that with this one, I could write a function to select all entities from a list of layers, but I am ignorant of what we are doing with the "TypedValue" calls. Could you direct me to where I can get more info on this?

    Thanks,
    Allan

    Allan,

    You need to use the "or" operator (by adding enclosing "<or" and "or>" elements to the list):

    TypedValue[] tvs =
      new TypedValue[4] {
          new TypedValue(
            (int)DxfCode.Operator,
            "<or"
          ),
          new TypedValue(
            (int)DxfCode.LayerName,
            layerName
          ),
          new TypedValue(
            (int)DxfCode.LayerName,
            layerName2
          ),
          new TypedValue(
            (int)DxfCode.Operator,
            "or>"
          )
        };
    

    This is a good topic for a follow-up post.

    Kean

    Verify your Comment

    Previewing your Comment

    This is only a preview. Your comment has not yet been posted.

    Working...
    Your comment could not be posted. Error type:
    Your comment has been posted. Post another comment

    The letters and numbers you entered did not match the image. Please try again.

    As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

    Having trouble reading this image? View an alternate.

    Working...

    Post a comment

    Feed & Share

    Search