I had this question come in via a blog comment. I would usually suggest asking this type of question on the relevant online forum, but something about it intrigued me:
Now i would like to ask you that to post an item showing how to get the vertexs of 2d solid to create a boundary, could you add one which shows exporting the entity to other format like .shp.?
My first thought was “wow – someone still uses 2D solid objects inside AutoCAD! I wonder what the Solid object’s .NET API is like?”. (Hopefully this comment doesn’t start a flood of hate-mail from die-hard users of the humble SOLID entity… ;-)
But anyway, for those of you who are new(ish) to the product, the reason 3D AutoCAD solids have the DXF name of 3DSOLID and API classes called AcDb3dSolid and Solid3d is as follows: there is such a thing as a 2D solid in the product. It has been around since the very early, pre-3D days and at the time was used to describe an area containing a solid 2D fill.
The object is kinda quirky: it has either three or four vertices when you draw it, and if you only define three then the fourth will be a copy of the third. The you also don’t define the third and fourth vertices of a 4-vertex solid in the order you’d expect: it doesn’t follow in a loop as if creating a closed polyline, for instance. You have to flip them, otherwise you end up with a bow-tie shape.
So all in all it was actually quite fun to get this working. The code I wrote actually could be considered an EXPLODE for 2D solids – as the EXPLODE command doesn’t work with them, interestingly – but I’ve just implemented it as a command that generates polyline boundaries around the existing 2D solid objects.
Here’s the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace BoundaryExtraction
{
public class Commands
{
[CommandMethod("SB")]
static public void SolidBoundaries()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
// Set up our selection to only select 2D solids
var pso = new PromptSelectionOptions();
pso.MessageForAdding = "\nSelect 2D solid objects";
var sf =
new SelectionFilter(
new TypedValue[]
{
new TypedValue((int)DxfCode.Start, "SOLID")
}
);
var psr = ed.GetSelection(pso, sf);
if (psr.Status != PromptStatus.OK)
return;
int boundaries = 0;
var tr = doc.TransactionManager.StartTransaction();
using (tr)
{
foreach (SelectedObject so in psr.Value)
{
var sol =
tr.GetObject(so.ObjectId, OpenMode.ForRead) as Solid;
if (sol != null)
{
// We'll collect our points from the Solid
var pts = new Point3dCollection();
// Use a flipped indexing scheme: the 3rd & 4th vertices
// need to be flipped to go clockwise/anti-clockwise
foreach (var s in new short[] { 0, 1, 3, 2 })
{
var pt = sol.GetPointAt(s);
// If we have only 3 points then the 4th is a repeat
// of the 3rd (which in our case means the point in
// pts with an index of 1, as we flipped the indices)
if (
s != 2 ||
pt.DistanceTo(pts[2]) > Tolerance.Global.EqualPoint
)
{
pts.Add(pt);
}
}
// We'll add our replacement boundary to the current
// space
var btr =
(BlockTableRecord)tr.GetObject(
db.CurrentSpaceId,
OpenMode.ForWrite
);
// We need a plane to define our polyline's 2D points
var plane = new Plane(pts[0], sol.Normal);
// Create the empty polyline in the plane of the solid
var pl = new Polyline(pts.Count);
pl.Normal = sol.Normal;
// Fill it with 2D points
for (int i = 0; i < pts.Count; i++)
{
// Add our converted 2D point to the vertex list
var pt2 = pts[i].Convert2d(plane);
pl.AddVertexAt(i, pt2, 0, 0, 0);
}
// Close the polyline
pl.Closed = true;
// Move it so that it overlaps the Solid
pl.TransformBy(
Matrix3d.Displacement(pts[0].GetAsVector())
);
// Add it to the current space and transaction
btr.AppendEntity(pl);
tr.AddNewlyCreatedDBObject(pl, true);
boundaries++;
}
}
tr.Commit();
}
ed.WriteMessage(
"\nCreated boundary polylines for {0} 2D solid objects.",
boundaries
);
}
}
}
Here are some 2D solid objects inside an AutoCAD drawing, created using the SOLID command:
And here are the results of running the SB command and selecting them (with the currently layer’s lineweight and colour set to values that make the boundaries visible):
I’m still not clear what the part of the comment regarding exporting to .shp is about (whether to AutoCAD’s SHP format or to ESRI’s ShapeFile format), but hopefully it’s clear from this code how it’s possible to access and use the Solid object’s vertex information.