Two methods for selecting entities at a particular location

This entry was contributed by an old friend who recently rejoined the ADN team, Jeremy Tammik. Jeremy has been in and around the Autodesk family for many years - he actually delivered the first ever ARX training in San Rafael, back when it was still called ARX - and I'm very pleased he chose to rejoin our team earlier this year. It also happens to be Jeremy's birthday this coming weekend (on Sunday 26th November), for anyone who's interested. 🙂

The question came in from an ADN member and revolved around the need to select objects at a particular location from an AutoCAD .NET application. Here's Jeremy's response...

I see two approaches for selecting all entities of a given type in a crossing window.

One approach is to use the predefined EditorInput.SelectCrossingWindow() method, which is similar to the built-in AutoCAD user interactive selection method. This has the advantage of being fast in a big database with many entities, because it makes use of clever internal algorithms to filter away all entities that are not applicable. The disadvantage is that it only works in the currently visible part of the screen.

Another approach is more programmatic: to iterate over the entire database and select all applicable entities yourself. This approach could be more complex, depending on the type of entity being selected (it's not always easy to establish whether a complex entity is located at a particular point).

I have appended the complete source for a project containing an example of each approach, one selecting text entities, the other selecting lines.

Here is the relevant C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

namespace SelectCrossing

{

  public class Commands

  {

    /// <summary>

    /// Demonstrates the SelectCrossingWindow()

    /// method of Autodesk.AutoCAD.EditorInput.

    /// 

    /// This example selects all text

    /// entities at a given point.

    /// </summary>

    [CommandMethod("WinEd")]

    public void SelectCrossingEditor()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

      try

      {

        PromptPointOptions ptOpts =

          new PromptPointOptions(

            "\nPick a point at which to select all text entities: "

          );

        PromptPointResult ptRes =

          ed.GetPoint(ptOpts);

        if (PromptStatus.OK == ptRes.Status)

        {

          Point3d p = ptRes.Value;

          Point3d p1 =

            new Point3d(p.X - 0.01, p.Y - 0.01, 0.0);

          Point3d p2 =

            new Point3d(p.X + 0.01, p.Y + 0.01, 0.0);

          TypedValue[] values =

            {

              new TypedValue(

                (int)DxfCode.Start,

                "TEXT"

              )

            };

          SelectionFilter filter =

            new SelectionFilter(values);

          PromptSelectionResult res =

            ed.SelectCrossingWindow(p1, p2, filter);

          SelectionSet ss =

            res.Value;

          int n = 0;

          if (ss != null)

          {

            n = ss.Count;

          }

          ed.WriteMessage(

            string.Format(

              "\n{0} text entit{1} selected.",

              n, 1 == n ? "y" : "ies"

            )

          );

        }

      }

      catch (System.Exception e)

      {

        ed.WriteMessage("\nException {0}.", e);

      }

    }

    /// <summary>

    /// Demonstrate how to select entities

    /// by iterating over the model space.

    /// 

    /// The example selects all line

    /// entities at a given point.

    /// </summary>

    [CommandMethod("WinDb")]

    public void SelectCrossingDatabase()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed =

        doc.Editor;

      try

      {

        PromptPointOptions ptOpts =

          new PromptPointOptions(

            "\nPick a point at which to select all lines: "

          );

        PromptPointResult ptRes = ed.GetPoint(ptOpts);

        if (PromptStatus.OK == ptRes.Status)

        {

          ObjectIdCollection ids =

            new ObjectIdCollection();

          Point3d p = ptRes.Value;

          Database db = doc.Database;

          Transaction tr =

            db.TransactionManager.StartTransaction();

          using( tr )

          {

            BlockTable bt =

              (BlockTable)tr.GetObject(

                db.BlockTableId,

                OpenMode.ForRead

              );

            BlockTableRecord btr =

              (BlockTableRecord)tr.GetObject(

                bt[BlockTableRecord.ModelSpace],

                OpenMode.ForRead

              );

            foreach( ObjectId id in btr )

            {

              DBObject obj =

                tr.GetObject( id, OpenMode.ForRead );

              Line dbLine = obj as Line;

              if (dbLine != null)

              {

                LineSegment3d lineSegment =

                  new LineSegment3d(

                    dbLine.StartPoint,

                    dbLine.EndPoint

                  );

                PointOnCurve3d q =

                  lineSegment.GetClosestPointTo(p);

                if (p.DistanceTo( q.Point ) < 0.01)

                {

                  ids.Add( dbLine.ObjectId );

                }

              }

            }

            tr.Commit();

          }

          int n = ids.Count;

          ed.WriteMessage(

            string.Format(

              "\n{0} line{1} selected.",

              n, 1 == n ? "" : "s"

            )

          );

        }

      }

      catch( System.Exception e )

      {

        ed.WriteMessage("\nException {0}.", e);

      }

    }

  }

}

2 responses to “Two methods for selecting entities at a particular location”

  1. Thank you very much!I found it's very difficult to find some books talk about ARX(using .net),especially include example ones.So,here is the best place to learn arx I think.And would you mind give me some suggestions to learn arx?and which book should I read?thank you!

  2. Kean Walmsley Avatar

    There are a few ObjectARX (C++) books out there. Charles McAuley (an old friend and ex-member of DevTech) wrote one for AutoCAD 2000, which is still largely relevant. I don't know of any .NET-oriented books currently available.

    Until more are on the market, you might consider coming along to one of the training classes my team provides: autodesk.com/api...

    Regards,

    Kean

  3. Kean's comment in regard to SelectCrossingWindow...

    "The disadvantage is that it only works in the currently visible part of the screen."

    I was going nuts for hours trying to figure out why SelectCrossingWindow seemed to randomly return an error. This explains it. Thank you!!!

  4. what does DxfCode.Start do?

  5. It just gives me the right code (which happens to be 0). I prefer not to hardcode numbers if they are defined in an appropriate enumeration.

    Kean

  6. Hi,
    I came across this article when i was searching for SelectCrossingWindow, but what i need to do is select entities in block definition
    How can i do that?

  7. nevermind, I suppose, i should use the second approach

  8. Kean, I think aaron means what DxfCode.Start's function is?
    Indeed, objectArx's help documents is rather simple, and lots of things are not explained clearly.
    Why does not Autodesk make a set of more helpful help documents?

    here, can you explain DxfCode.Start for us?

  9. DxfCode.Start is 0, which is the group code used for the entity name (or the type of the entity, of your prefer).

    More information can be found in the online documentation, which seems very clear to me, at least.

    Kean

  10. Thank you very much.
    We, not myself, learn so much knowledge from your blog.

    Thank you very much.

  11. Try the following VB.net code it works better!

    Dim inspt As Point3d = New Point3d(x, y, z)
    Dim acTypValAr(3) As TypedValue
    acTypValAr.SetValue(New TypedValue(DxfCode.Operator, "<and"), 0)="" actypvalar.setvalue(new="" typedvalue(dxfcode.start,="" "text"),="" 1)="" actypvalar.setvalue(new="" typedvalue(dxfcode.xcoordinate,="" inspt),="" 2)="" actypvalar.setvalue(new="" typedvalue(dxfcode.operator,="" "and="">"), 3)

    a SelectionFilter object
    Dim acSelFtr As SelectionFilter = New SelectionFilter(acTypValAr)

    selRes = ed.SelectAll(acSelFtr)
    If selRes.Status <> Autodesk.AutoCAD.EditorInput.PromptStatus.OK Then

  12. Hi, the online documentation does seem a lot more clear but I believe that cairunbin may have been talking about the docs that come with the SDK - there really isn't much in there and i had a very frustrating time working with them.

    1 minute after learning about the online help I found what I was looking for - thanks a lot!

  13. Hi,Kean,
    I have used the SelectCrossingWindow() method like this fllowed:
    1.Getting a polyline's or something else's extents in a list of polyline or other entities;
    2.Then, when once getting a polyline's extents, using the Editor::SelectCrossingWindow(extents.MinPoint,extents.MaxPoint) to get the SelectionResult.

    And the problem is that when the first time to traverse all the entities I have gotten , the method is OK. But when the seconde time or the other time to call this method ,it returned an error.

    So, what is the wrong with my code?
    Thank you very much for your helping.

  14. Kean Walmsley Avatar

    Hi Tomans,

    I can't say what's wrong with your code, but bear in mind that selection is based on the display list, and so the entities to be selected need to be on screen.

    If that doesn't help, try posting your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Kean

  15. Are there any known issues with using the EditorInput.SelectCrossingWindow method outside the context of a command? I'm trying to call it from an Overrule WorldDraw override and all I get is an Error status...

  16. Calling Editor selection during WorldDraw() can be problematic - I can't remember what's recommended, off the top of my head. I suggest posting the question either via ADN or on the discussion forum - someone on my team should be able to provide the answer.

    Kean

  17. Thanks Kean,

    I got what I'm trying to do working using the "iterate over the entire database" method, but as pointed out that could be problematic for large dwgs...

    I'll submit to ADN.

  18. Dear Kean,

    I follow your blog and find it very useful for developers.

    I am developing with .NET, I have made applications for AutoCAD with many languages ​​before.

    If it's SelectionSets, I want to consult you about a related issue. Is there a method in .net to create multiple selectionsets?

    For example, selectionsets could be named in VBA.

    How do we categorize selectionsets on .NET.

    I would be very happy if you have a resource to point out or a solution to this issue.

    1. Dear Serkan,

      I'm no longer working with AutoCAD (and never provided technical support, even when I did). Can you please direct your questions to the AutoCAD .NET (or VBA) forum?

      Many thanks,

      Kean

Leave a Reply

Your email address will not be published. Required fields are marked *