写这篇文章主要是为了记录一下实现功能的思路,如果有更好的思路或者代码错误欢迎大家指正
功能场景大概是:用户选点画圆-选点画圆-两点画线相连,循环下去直到用户esc取消。
扩展功能:实现撤销、标注线长度。
实现思路:用户选择起始点先绘制第一个圆,之后进入循环让用户选点,根据最后两次选点绘制线段。为了方便区分圆和线分别放在不同的图层里。
需要注意的是为了能够及时看到绘制效果,当把cad对象插入到模型空间之后记得到提交事务,再开启新事务进行后续绘制。
撤销的话,当然是以用户选点操作为核心,记录下和本次选点到下次选点这中间里插入到模型空间的对象,当撤销时就删除和最后一个点相关的对象。
我相信这个场景应该还是简单容易实现的,所以提供了完整的代码,以后如果有相对复杂的功能实现,只会提供核心部分代码和我的实现思路,剩余由读者自己完善。授人予鱼不如授人予渔
下面是主要的实现思路:
public void Draw()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
DocumentLock docLock = doc.LockDocument();
Transaction transaction = db.TransactionManager.StartTransaction();
Point3d? baseP = GetPoint();
if (!baseP.HasValue) return;
double radius = 0.5;//圆半径
bool hiddenCircle = false;//是否绘制圆
bool hiddenLine = false;//是否绘制线
Polyline polyline1 = GetFullCircle(baseP.Value, radius);
if (hiddenCircle) InsertDBObject(transaction, db, "圆", polyline1);
//记录下选点相关的绘制数据 为了撤销
List<DrawModel> vlog = new List<DrawModel>();
while (true)
{
List<Entity> temp = new List<Entity>();
double h1 = 2.0;//字高
//设置文本距离线的距离
double mtextDDJ = h1 + 0.5;
bool isUndo = false;
Point3d? selectP = GetPointUndo("选择插入点,", baseP.Value, ref isUndo);
if (isUndo)
{
if (vlog.Count == 0) continue;//已经撤销到最初的绘制状态
foreach (var item in vlog.LastOrDefault().ents)
{
DBObject obj = transaction.GetObject(item.ObjectId, OpenMode.ForWrite);
if (obj != null)
{
obj.Erase();
}
}
baseP = vlog.LastOrDefault().point;//切换到最后一个点位置
vlog.RemoveAt(vlog.Count - 1);
transaction.Commit();
transaction = db.TransactionManager.StartTransaction();
continue;
}
if (!selectP.HasValue) break;//用户没有选点 esc操作
if(!hiddenCircle)
{
polyline1 = GetFullCircle(baseP.Value, radius);
InsertDBObject(transaction, db, "圆", polyline1);
temp.Add(polyline1);
transaction.Commit();
transaction = db.TransactionManager.StartTransaction();
}
Line line = new Line(baseP.Value, selectP.Value);
if(!hiddenLine)
{
InsertDBObject(transaction, db, "线", line);
temp.Add(line);
}
Point3d midPoint3d = new Point3d((line.StartPoint.X + line.EndPoint.X) / 2.0, (line.StartPoint.Y + line.EndPoint.Y) / 2.0, 0.0);
if (!hiddenCircle)
{
Polyline polyline2 = GetFullCircle(selectP.Value, radius);
InsertDBObject(transaction, db, "圆", polyline2);
temp.Add(polyline2);
}
string dj = Math.Ceiling(Math.Round(line.Length, 4)).ToString("0") + "m";
double mangle = line.Angle;
//线角度是二三象限时 注意调整文本的角度
if(mangle > Math.PI/2 && mangle < Math.PI)
{//90-180度
mangle += Math.PI;
}
else if(mangle >= Math.PI && mangle < Math.PI * 1.5)
{//180-270度
mangle -= Math.PI;
}
Entity mt1 = DrawMText(transaction, db, dj, midPoint3d.Add(Vector3d.XAxis.RotateBy(line.Angle + Math.PI / 2, Vector3d.ZAxis) * mtextDDJ), h1, "长度", mangle);
temp.Add(mt1);
transaction.Commit();
transaction = db.TransactionManager.StartTransaction();
vlog.Add(new DrawModel() { point = baseP.Value, ents = temp });
baseP = selectP;
}
transaction.Commit();
transaction.Dispose();
if (docLock != null)
{
docLock.Dispose();
}
}
下面是功能实现用到的工具方法:
/// <summary>
/// 绘制文本
/// </summary>
/// <param name="transaction"></param>
/// <param name="db"></param>
/// <param name="textString">文本内容</param>
/// <param name="point"></param>
/// <param name="TextHeight">字高</param>
/// <param name="layerName">图层</param>
/// <param name="rotation">角度</param>
/// <returns></returns>
public Entity DrawMText(Transaction transaction, Database db, string textString, Point3d point, double TextHeight, string layerName, double? rotation)
{
MText txt = new MText();
txt.TextHeight = TextHeight;
txt.Location = point;
InsertDBObject(transaction, db, layerName, txt);
if (!txt.IsWriteEnabled) txt.UpgradeOpen();
txt.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByLayer, 256);
txt.Attachment = AttachmentPoint.MiddleCenter;
txt.Rotation = rotation.Value;
txt.Contents = textString;
txt.Visible = true;
return txt;
}
private Point3d? GetPoint()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
PromptPointOptions prPointOptions = new PromptPointOptions("选择插入点");
PromptPointResult prPointRes = doc.Editor.GetPoint(prPointOptions);
if (prPointRes.Status == PromptStatus.OK)
{
return prPointRes.Value;
}
return null;
}
/// <summary>
/// 绘制圆(用polyline表示实心效果
/// </summary>
/// <param name="center"></param>
/// <param name="radius"></param>
/// <returns></returns>
private Polyline GetFullCircle(Point3d center, double radius)
{
Polyline pline = new Polyline();
pline.AddVertexAt(0, center.Add(Vector3d.YAxis * radius / 2).toPoint2d(), 1, radius, radius);
pline.AddVertexAt(1, center.Add(Vector3d.YAxis * -radius / 2).toPoint2d(), 1, radius, radius);
pline.AddVertexAt(2, center.Add(Vector3d.YAxis * radius / 2).toPoint2d(), 0, 0, 0);
return pline;
}
//选点(支持撤销
private Point3d? GetPointUndo(string mess, Point3d basePoint, ref bool isUndo)
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
PromptPointOptions prPointOptions = new PromptPointOptions("");
prPointOptions.UseDashedLine = true;
prPointOptions.UseBasePoint = true;
prPointOptions.BasePoint = basePoint;
prPointOptions.SetMessageAndKeywords("\n" + mess + "[Undo]: ", "Undo");
PromptPointResult prPointRes = doc.Editor.GetPoint(prPointOptions);
if (prPointRes.Status == PromptStatus.Keyword && prPointRes.StringResult == "Undo")
{
isUndo = true;
return null;
}
if (prPointRes.Status == PromptStatus.OK)
{
return prPointRes.Value;
}
return null;
}
//插入cad对象到模型空间
private void InsertDBObject(Transaction transaction, Database db, string layerName, params Entity[] objs)
{
CreateLayer(transaction, db, layerName, false, false);
BlockTable bt = transaction.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
BlockTableRecord btr = transaction.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
foreach (Entity ent in objs)
{
ent.Layer = layerName;
ObjectId oi = btr.AppendEntity(ent);
transaction.AddNewlyCreatedDBObject(ent, true);
}
}
//创建图层
private void CreateLayer(Transaction transaction, Database db, string layerName)
{
LayerTable lt = transaction.GetObject(db.LayerTableId, OpenMode.ForWrite) as LayerTable;
if (!string.IsNullOrEmpty(layerName) && !lt.Has(layerName))
{
LayerTableRecord ltr = new LayerTableRecord();
ltr.Name = layerName;
lt.Add(ltr);
transaction.AddNewlyCreatedDBObject(ltr, true);
}
}