During the first part of this series, we looked at ways to drive the PLINE command while retaining (or regaining) the thread of execution in your application.
During this and the next post (yes, I've decided to spread the series a little thinner :-) we're going to look at how to completely replace the user-interface to the polyline command, a very useful technique in certain situations. This post focuses on the simple use of GetPoint() to request vertex information from the user; the next post will look at a more advanced technique, the Jig.
Even the "simple" user-interface implemented in the below code takes some effort. To keep things as simple as possible, the below UI code only allows the user to define zero-width, linear polyline segments - no arcs, widths, etc. As mentioned in the previous post, this might well be an advantage in your application, depending on whether you want to hide certain options from the user. This approach is certainly not ideal if you do want to allow interactive selection of arc segments; the two approaches suggested last time, or the one shown in the next entry, would work better in that case.
A few notes on the implementation:
- Temporary graphics are used to draw each polyline segment as soon as both its vertices have been defined
- The actual polyline entity is only created once all the vertices have been selected
- Point selection happens in the User Coordinate System, so we need to do some work to transform selected points to the Entity Coordinate System (or Object Coordinate System) belonging to the polyline. 2-dimensional polylines are planar entities and have their vertices defined as 2D points relative to the origin and normal of the polyline, so we use a "Plane" object to help us get the 2D points to feed to the polyline's AddVertexAt() function
Here's the code in C#:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Colors;
namespace MyPlineApp
{
public class MyPlineCmds
{
[CommandMethod("MYPOLY")]
public void MyPoly()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Get the current color, for our temp graphics
Color col = doc.Database.Cecolor;
// Create a point collection to store our vertices
Point3dCollection pts = new Point3dCollection();
// Set up the selection options
// (used for all vertices)
PromptPointOptions opt =
new PromptPointOptions(
"\nSelect polyline vertex: "
);
opt.AllowNone = true;
// Get the start point for the polyline
PromptPointResult res = ed.GetPoint(opt);
while (res.Status == PromptStatus.OK)
{
// Add the selected point to the list
pts.Add(res.Value);
// Drag a temp line during selection
// of subsequent points
opt.UseBasePoint = true;
opt.BasePoint = res.Value;
res = ed.GetPoint(opt);
if (res.Status == PromptStatus.OK)
{
// For each point selected,
// draw a temporary segment
ed.DrawVector(
pts[pts.Count - 1], // start point
res.Value, // end point
col.ColorIndex, // current color
false); // highlighted?
}
}
if (res.Status == PromptStatus.None)
{
// Get the current UCS
Matrix3d ucs =
ed.CurrentUserCoordinateSystem;
Point3d origin = new Point3d(0, 0, 0);
Vector3d normal = new Vector3d(0, 0, 1);
normal = normal.TransformBy(ucs);
// Create a temporary plane, to help with calcs
Plane plane = new Plane(origin, normal);
// Create the polyline, specifying
// the number of vertices up front
Polyline pline = new Polyline(pts.Count);
pline.Normal = normal;
foreach (Point3d pt in pts)
{
Point3d transformedPt =
pt.TransformBy(ucs);
pline.AddVertexAt(
pline.NumberOfVertices,
plane.ParameterOf(transformedPt),
0, 0, 0
);
}
// Now let's add the polyline to the modelspace
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.ForWrite
);
ObjectId plineId = btr.AppendEntity(pline);
tr.AddNewlyCreatedDBObject(pline, true);
tr.Commit();
ed.WriteMessage("\nPolyline entity is: " +
plineId.ToString()
);
}
}
// Clear the temp graphics (polyline should be in
// the same location, if selection was not cancelled)
// We could "redraw" instead of "regen" here
ed.Regen();
}
}
}
Here's what happens when we execute this code:
Command: mypoly
Select polyline vertex:
Select polyline vertex:
Select polyline vertex:
Regenerating model.
Polyline entity is: (2130239560)
Next time we'll look at how we can use a Jig for this task.