某天心血来潮,想知道CAD内部的polyline功能是如何实现的。百度了数次也没有找到合适的资料。

这里介绍一个自己实现的方法。原理是每次鼠标点击的时候,记录下点坐标,并向当前的模型/图纸空间中添加一个临时的线段,然后在最终确认退出的时候,将临时线段删除,将点坐标集合构造成多段线。

当然,正常的方法是调用Jig拖拽类,但是Jig有缺陷,当鼠标移动的时候,界面会不停刷新闪动。

[CommandMethod("DrawPolyline")]

public void DrawPolyline()

Document doc = Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;

DocumentLock dlock = doc.LockDocument();

//为临时图形得到当前的颜色

Autodesk.AutoCAD.Colors.Color col = doc.Database.Cecolor;

//创建一个点集来存储顶点

Point3dCollection pts = new Point3dCollection();

//为所有的顶点设置选择选项

PromptPointOptions opt = new PromptPointOptions("\n设置线段起点或者取消[Undo]", "Undo");

//存储临时线段

List<ObjectId> lines = new List<ObjectId>();

opt.AllowNone = true;

//得到的 polyline 第一点

PromptPointResult res = ed.GetPoint(opt);

while (res.Status == PromptStatus.OK || res.Status == PromptStatus.Keyword)//有点被选中时的操作

pts.Add(res.Value);

if (pts.Count > 1)

using (Transaction tran = db.TransactionManager.StartTransaction())

BlockTableRecord btrs = (BlockTableRecord)tran.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

Line line = new Line(pts[pts.Count - 2], pts[pts.Count - 1]);

lines.Add(btrs.AppendEntity(line));

tran.AddNewlyCreatedDBObject(line, true);

tran.Commit();

//撤销的时候从这里重新进入循环

opt.BasePoint = pts[pts.Count - 1];

opt.UseBasePoint = true;

opt.SetMessageAndKeywords("\n设置线段顶点或者取消[Undo]", "Undo");

res = ed.GetPoint(opt);

if (res.Status == PromptStatus.Keyword)

if (res.StringResult.ToLower() == "undo")

if (lines.Count > 0)

using (Transaction tran = db.TransactionManager.StartTransaction())

lines[lines.Count - 1].GetObject(OpenMode.ForWrite).Erase(true);

lines.RemoveAt(lines.Count - 1);

tran.Commit();

pts.RemoveAt(pts.Count - 1);

if (pts.Count == 1)

else if (res.Status != PromptStatus.OK)

if (pts.Count >= 1)

using (Transaction tr = db.TransactionManager.StartTransaction())

//获取当前的模型/图纸空间

BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

//得到当前的 UCS

Matrix3d ucs = ed.CurrentUserCoordinateSystem;

Point3d origin = new Point3d(0, 0, 0);

Vector3d normal = Vector3d.ZAxis;

//创建一个临时的 plane 来帮助计算

Plane plane = new Plane(origin, normal);

//创建 polyline,同时用已经选择的点的数量来指定顶点数

Polyline pline = new Polyline(pts.Count);

pline.Normal = normal;

foreach (Point3d pt in pts)//对点进行坐标转换,为什么要转换,UCS与 OCS的关系?

Point3d transformedPt = pt.TransformBy(ucs);

pline.AddVertexAt(pline.NumberOfVertices, plane.ParameterOf(transformedPt), 0, 0, 0);

ObjectId plineId = btr.AppendEntity(pline);

tr.AddNewlyCreatedDBObject(pline, true);

//将临时线段从数据库中删除

foreach (var item in lines)

item.GetObject(OpenMode.ForWrite).Erase(true);

tr.Commit();

dlock.Dispose();

此方法仅实现简单的多段线功能,以及撤销操作,未实现复杂的keyword校验。