Tracing a boundary defined by AutoCAD geometry using .NET

As alluded to in this previous post, today we're going to see some code that makes use of a very cool new API feature in AutoCAD 2011: the Editor.TraceBoundary() function. This little gem performs something developers have struggled with – and have asked us for – for many years. Previously you had to jump through significant hoops (or should that be loops? <groan>) to get this to work: one common approach would be to drive the BOUNDARY command programmatically and check the results appended to the database. All very messy.

Anyway, we got there eventually. This function takes a "seed" point and returns a collection of newly-created entities that define our boundary. We can then either pump these through the transient graphics sub-system or – and this is the approach we're going to take – add them to the drawing to make them persistent.

You need to bear in mind that this function ultimately has similar constraints to the BOUNDARY and BHATCH commands: it also works off AutoCAD's display list and so the user will need to be appropriately ZOOMed into the geometry that is to be used for boundary detection.

Here's some C# code to create boundaries – with a lineweight applied and of an automatically incremented colour index – for points the user selects:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Runtime;

 

namespace TraceBoundary

{

  public class Commands

  {

    static int _index = 1;

 

    [CommandMethod("TB")]

    public void TraceBoundary()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Select a seed point for our boundary

 

      PromptPointResult ppr =

        ed.GetPoint("\nSelect internal point: ");

 

      if (ppr.Status != PromptStatus.OK)

        return;

 

      // Get the objects making up our boundary

 

      DBObjectCollection objs =

        ed.TraceBoundary(ppr.Value, true);

 

      if (objs.Count > 0)

      {

        Transaction tr =

          doc.TransactionManager.StartTransaction();

        using (tr)

        {

          // We'll add the objects to the model space

 

         
;
BlockTable bt =

            (BlockTable)tr.GetObject(

              doc.Database.BlockTableId,

              OpenMode.ForRead

            );

 

          BlockTableRecord btr =

            (BlockTableRecord)tr.GetObject(

              bt[BlockTableRecord.ModelSpace],

              OpenMode.ForWrite

            );

 

          // Add our boundary objects to the drawing and

          // collect their ObjectIds for later use

 

          ObjectIdCollection ids = new ObjectIdCollection();

          foreach (DBObject obj in objs)

          {

            Entity ent = obj as Entity;

            if (ent != null)

            {

              // Set our boundary objects to be of

              // our auto-incremented colour index

 

              ent.ColorIndex = _index;

 

              // Set the lineweight of our object

 

              ent.LineWeight = LineWeight.LineWeight050;

 

              // Add each boundary object to the modelspace

              // and add its ID to a collection

 

              ids.Add(btr.AppendEntity(ent));

              tr.AddNewlyCreatedDBObject(ent, true);

            }

          }

 

          // Increment our colour index

 

          _index++;

 

          // Commit the transaction

 

          tr.Commit();

        }

   
60;  }

    }

  }

}

Here's our TB command in action.

Before…

Our boundaries

After…

Our traced boundaries

In the next post we're going to modify the code to create transparent hatch objects inside these individual boundaries.

3 responses to “Tracing a boundary defined by AutoCAD geometry using .NET”

  1. Great, Kean!

    Thank you very much for still one
    great example...

    Danijel

  2. Tony Tanzillo Avatar

    Hi Kean.

    Gee.

    Have you tried using TraceBoundary()
    with boundaries defined by ACIS curves
    (e.g., splines or ellipses) ?

    Please convey to whomever the programmer(s)
    at Autodesk are that get the credit for this
    parlor trick, thanks for a good laugh.

    1. This just got me! 😀 Splines and ellipses (and any boundary including even just a little bit of them) Get returned as Regions, whereas everything else will get returned as Polylines. I assumed it has to be a polyline for quite some time, until my code started mysteriously crashing :D.

  3. Hi Tony,

    Thanks for reporting the issue - clearly defaulting to the UI behaviour isn't appropriate in this situation.

    A member of my team has submitted it for AutoCAD Engineering to investigate and address.

    Regards,

    Kean

  4. Hi all,

    Very good example.
    But since the 2010 version of Autodesk products we have lost in accuracy on the boundary created.
    This does not correspond to the reality of the boundary.
    There is the same problem with the standard command "Boundary" et your .NET command

    Sorry for my english.
    Olivier

  5. Hi Olivier,

    If you're an Autodesk Developer Network member, please submit the issue via the ADN site, so one of my team can look into this.

    Otherwise I suggest submitting it via your standard support channel (it also sounds as though it may well be a product feature issue, rather than being related to the API).

    Regards,

    Kean

  6. Hi Kean,

    How would you deal with tracing a boundary when you only have points and no other geometry?

    Ben

  7. Hi Ben,

    Do you need some kind of algorithm to find the minimal area of a set of points?

    That's way beyond the scope of this API, which just detects physical (or, at least, existing) boundaries such as those detected by BHATCH.

    Regards,

    Kean

  8. Hi
    Do not tell me how to get a list of the objects bounding area?

  9. You need to iterate through the entities you care about - a selection set or the contents of the model space, for instance - and then get the Extents of each one.

    Kean

  10. Hello Kean,
    Is it possible to use selction set filter like the boundary command, I mean if we want only defined layers to be analyzed.
    regards,

  11. Hello Rusel,

    The capability should only work with visible graphics, so one option would be for your application to turn the layers you don't care about off before running the operation.

    Regards,

    Kean

  12. Dear Kean,
    Thank you very much for your code and idea, it's working perfect with creating boundaries and regions from them in AutoCAD 2012. But later when I deal with region boolean codes with interop, I got error code below. My code is working perfect if I don't use the Traceboundary code, I mean when I create the regions with other code. What may be the problem?
    Thanks,

    System.AccessViolationException was unhandled
    HResult=-2147467261
    Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
    Source=Autodesk.AutoCAD.Interop
    StackTrace:
    at Autodesk.AutoCAD.Interop.AcadSelectionSetClass.SelectByPolygon(AcSelect Mode, Object PointsList, Object FilterType, Object FilterData)

  13. Hi Rusel,

    I have no way of saying what's wrong - it's seems to be in some way related to the calling context. This kind of issue often occurs because of not locking a document when calling from a modeless dialog, but you mention interop, so it could well be something else.

    Regards,

    Kean

  14. nice work Kean. re: this trace boundary blog post - in this particular situation the user has to click individually, and then each boundary is created. is there any way of doing this programmatically so that one runs the command and autocad automatically creates all the boundaries? an interesting theoretical question - (perhaps with some practical application as well)?

    1. You could determine the bounds of the model and feed a series of points to the function (although you may need to zoom appropriately - the boundary is derived from the displayed graphics, not the database objects).

      Kean

      1. I was thinking along the same lines.

        Another interesting question: in this blog post, the boundary object is traced exactly along the border. What if one wants to create a boundary object that is offset by a certain amount (e.g. 5 mm) from the original: is that even possible? Then we would have a boundary within a boundary.

        1. Hi Kean and folks

          I just discovered the GetOffsetCurves method. I suppose it answers the above question.

          there is just soooooooo many things in autocad to learn!

  15. Kean:

    Does this boundry almost act like a ray trace? What I mean is if there was geometry of a corridor then the boundry should produce a rectangle. Are you able to extract the coordinates for all (4) four corners? Also, to produce the boundry is a selection required inside the boundry similiar to the bhatch command?

    1. Lester,

      This API exercises the same code path as BOUNDARY or BHATCH.

      You could certainly analyse the results and extract corners.

      Regards,

      Kean

  16. Hi,

    I there anyway of getting the vertices of the Region selected. I mean, in your case, I need to get the points from the red line.

    1. Sure - you should be able to explode the region(s) to curves and get their start & end points.

      Kean

      1. Jose Manolo Barahona Avatar
        Jose Manolo Barahona

        Thank you very much for your answer
        I will do it
        Blessings

  17. Jose Manolo Barahona Avatar
    Jose Manolo Barahona

    Hello could help me
    I need to do something like this
    1
    I use 1. and I think that using tracebonundary could help.

    Someone has an example of how to use 1 traceboundary

    I can select and calculate the original area. Also draw a line to mark the cutting direction. You could even draw a polyline between the intersections of the area with my line and other features to create the new area.Luego I move the line and recalculating the approximate area until needed.

    But this way is more difficult and I think it should be much better to use something like traceboundary or a method to create a region

    regards

    1. Hi Jose,

      This is beyond the scope of a simple blog post. I suggest posting your request to the AutoCAD .NET forum, in case someone there can be of assistance.

      Best,

      Kean

  18. Hi Kean, in this post, using ed.TraceBoundary(ppr.Value, true) - we have managed to get the object IDs of the boundary objects. Would you know is there any way of creating a polyline of the boundary?

  19. hi Kean ,

    i am facing problem while getting the boundary some case .
    first thing i want to know that TraceBoundary() method will work with zoom to the particular internal point
    in my case i am try to find the boundary of a polygon for that i have only a point which is inside that polygon
    by passing that internal point i am getting the polygon boundary but some time i am not .

    so kindly help......

    1. You may need to zoom in for this to work properly, if that answers your question. It's depending on the information used for the display.

      Kean

      1. hi Kean ,

        thanks for the your help , yes we have to zoom to the particular area which we want to trace
        but my question is related to auto cad version 2007 , what is the alternative of trace boundary method in auto cad 2007 .

        thank you

        1. Kean Walmsley Avatar

          Please post to the discussion groups for general support questions.

          Kean

  20. my question is related to auto cad version 2007 , what is the alternative of trace boundary method in auto cad 2007

    thank you

  21. Is this possible with open object?
    How can we achieve for open polyline or line?

    1. Not that I'm aware of: the point is really that it works with closed boundaries. You might try describing more about the behaviour you're looking for on the AutoCAD .NET forum: someone there might be able to help.

      Kean

Leave a Reply to Ben Cancel reply

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