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();
}
}
}
}
}
Here’s our TB command in action.
Before…
After…
In the next post we’re going to modify the code to create transparent hatch objects inside these individual boundaries.