效果如下:
代码如下:
using IfoxDemo;
//[assembly: CommandClass(typeof(IFoxDemo.凸包class))]//只允许此类快捷键命令
namespace IFoxDemo
{
public class 凸包class
{
public static class 凸包助手
{
/// <summary>
/// 计算点集的凸包并返回多段线
/// </summary>
/// <param name="pts">点集合</param>
/// <returns>凸包多段线</returns>
public static Polyline 计算凸包(List<Point2d> pts)
{
if (pts == null || pts.Count < 3)
{
throw new ArgumentException("至少需要三个点来计算凸包。");
}
// 计算凸包点集
List<Point2d> convexHullPoints = 筛选凸包点(pts);
// 创建多段线
Polyline convexHullPolyline = new Polyline();
for (int i = 0; i < convexHullPoints.Count; i++)
{
convexHullPolyline.AddVertexAt(i, convexHullPoints[i], 0, 0, 0);
}
// 闭合多段线
convexHullPolyline.AddVertexAt(convexHullPoints.Count, convexHullPoints[0], 0, 0, 0);
convexHullPolyline.Closed = true;
return convexHullPolyline;
}
/// <summary>
/// 使用 Andrew's monotone chain 算法计算凸包
/// </summary>
/// <param name="points">输入点集</param>
/// <returns>凸包点集</returns>
private static List<Point2d> 筛选凸包点(List<Point2d> points)
{
// 按 X 坐标排序,如果 X 相同则按 Y 排序
points.Sort((a, b) => a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X));
List<Point2d> hull = new List<Point2d>();
// 构建下凸包
foreach (var pt in points)
{
while (hull.Count >= 2 && Cross(hull[hull.Count - 2], hull[hull.Count - 1], pt) <= 0)
{
hull.RemoveAt(hull.Count - 1);
}
hull.Add(pt);
}
// 构建上凸包
int lowerHullCount = hull.Count + 1;
for (int i = points.Count - 1; i >= 0; i--)
{
var pt = points[i];
while (hull.Count >= lowerHullCount && Cross(hull[hull.Count - 2], hull[hull.Count - 1], pt) <= 0)
{
hull.RemoveAt(hull.Count - 1);
}
hull.Add(pt);
}
// 移除最后一个点,因为它是第一个点的重复
hull.RemoveAt(hull.Count - 1);
return hull;
}
/// <summary>
/// 计算叉积
/// </summary>
/// <param name="O">起点</param>
/// <param name="A">点 A</param>
/// <param name="B">点 B</param>
/// <returns>叉积值</returns>
private static double Cross(Point2d O, Point2d A, Point2d B)
{
return (A.X - O.X) * (B.Y - O.Y) - (A.Y - O.Y) * (B.X - O.X);
}
}
public class 凸包Demo类
{
[CommandMethod("tub")]
public void 凸包Demo()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
var pts = new List<DBPoint>();
if (! ed.GetEntities(out pts ,"") ) return;
//List<Point2d> points = new List<Point2d>();
//foreach (DBPoint p in pts)
//{
// points.Add(new Point2d(p.Position.X,p.Position.Y));
//}下面为lambda等效写法
List<Point2d> points = pts.Select(p => new Point2d(p.Position.X, p.Position.Y)).ToList();
#region
获取点集合(这里假设用户已经选择了一些点)
//PromptPointOptions ppo = new PromptPointOptions("\n选择点: ");
//ppo.AllowNone = false;
//ppo.Keywords.Add("Done");
//List<Point2d> points = new List<Point2d>();
//while (true)
//{
// PromptPointResult ppr = ed.GetPoint(ppo);
// if (ppr.Status == PromptStatus.Keyword && ppr.StringResult == "Done")
// {
// break;
// }
// points.Add(new Point2d(ppr.Value.X, ppr.Value.Y));
//}
//if (points.Count < 3)
#endregion
if (points.Count < 3)
{
ed.WriteMessage("\n至少需要三个点来计算凸包。");
return;
}
// 计算凸包
Polyline pl = 凸包助手.计算凸包(points);
// 将多段线添加到当前图形
#region
//using (Transaction tr = db.TransactionManager.StartTransaction())
//{
// BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
// btr.AppendEntity(convexHullPolyline);
// tr.AddNewlyCreatedDBObject(convexHullPolyline, true);
// tr.Commit();
//}
#endregion
using var dbtrans = new DBTrans();
dbtrans.CurrentSpace.AddEntity(pl);
ed.WriteMessage("\n凸包多段线已创建。");
}
}
public class 产生随机点
{
[CommandMethod("cssjd")]
public void CreateRandomPoints()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// 提示用户输入点的数量
PromptIntegerOptions pio = new PromptIntegerOptions("\n请输入要创建的点数量: ");
pio.AllowNegative = false;
pio.AllowZero = false;
pio.DefaultValue = 10;
PromptIntegerResult pir = ed.GetInteger(pio);
if (pir.Status != PromptStatus.OK)
{
ed.WriteMessage("\n用户取消操作。");
return;
}
int pointCount = pir.Value;
// 提示用户输入随机点的范围
PromptPointOptions ppo = new PromptPointOptions("\n指定随机点的范围(左下角点): ");
PromptPointResult ppr1 = ed.GetPoint(ppo);
if (ppr1.Status != PromptStatus.OK)
{
ed.WriteMessage("\n用户取消操作。");
return;
}
ppo.Message = "\n指定随机点的范围(右上角点): ";
PromptPointResult ppr2 = ed.GetPoint(ppo);
if (ppr2.Status != PromptStatus.OK)
{
ed.WriteMessage("\n用户取消操作。");
return;
}
Point3d lowerLeft = ppr1.Value;
Point3d upperRight = ppr2.Value;
// 创建随机点
Random random = new Random();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
for (int i = 0; i < pointCount; i++)
{
double x = lowerLeft.X + (upperRight.X - lowerLeft.X) * random.NextDouble();
double y = lowerLeft.Y + (upperRight.Y - lowerLeft.Y) * random.NextDouble();
Point2d randomPoint2d = new Point2d(x, y);
Point3d randomPoint3d = new Point3d(randomPoint2d.X, randomPoint2d.Y, 0);
// 创建点实体
DBPoint dbPoint = new DBPoint(randomPoint3d);
btr.AppendEntity(dbPoint);
tr.AddNewlyCreatedDBObject(dbPoint, true);
}
tr.Commit();
}
ed.WriteMessage($"\n成功创建 {pointCount} 个随机点。");
}
}
}
}
逆时针最小夹角
cad 二次开发、插件代写↓↓↓