CAD中面域转多段线的主要思路是,首先把面域分解为若干个线条,然后把这些线条根据算法来首尾相连排序,最后,再获取所有曲线的节点,创建新的闭合多段线。全部代码如下
#region 面域转多段线-全新的正确算法
#region 面域转多段线调用
/// <summary>
/// 面域转多段线调用入口
/// </summary>
/// <param name="regList">面域列表</param>
/// <param name="gap">容差</param>
/// <param name="isPLClosed">多段线是否闭合</param>
/// <param name="pLColorInex">多段线颜色,默认与面域同色</param>
/// <returns></returns>
public static List<Polyline> GetPolylineFromRegion(this List<Region> regList, double gap, bool isPLClosed, int pLColorInex = -1)
{
List<Polyline> newPLList = new List<Polyline>();
if (regList.Count > 0)
{
for (int i = 0; i < regList.Count; i++)
{
Region rg = regList[i] as Region;
DBObjectCollection dbcoll = new DBObjectCollection();
rg.Explode(dbcoll);
List<Entity> curveList = new List<Entity>();
foreach (Entity item in dbcoll)
{
curveList.Add(item);
}
List<List<Entity>> GetConnectCueveGroupList = curveList.ConnectCurves(gap);
List<Polyline> GetConnectPLList = GetConnectCueveGroupList.CreatePLFromCurveGroup(gap, true);
if (pLColorInex < 0)
{
GetConnectPLList.ForEach(e => e.ColorIndex = rg.ColorIndex);
}
else
{
GetConnectPLList.ForEach(e => e.ColorIndex = pLColorInex);
}
GetConnectPLList.ForEach(e => e.Layer = rg.Layer);
GetConnectPLList.ForEach(e => newPLList.Add(e));
}
}
return newPLList;
}
#endregion
#region 相连曲线分组
// 扩展方法 ConnectCurves 用于曲线连接,传入曲线列表和允许的最小间隙 gap
public static List<List<Entity>> ConnectCurves(this List<Entity> curList, double gap)
{
// 存储所有分组后的曲线集合
List<List<Entity>> groupedCurves = new List<List<Entity>>();
// 存储未处理的曲线,克隆以避免修改原始数据
List<Entity> unprocessedCurves = curList.Select(curve => (Entity)curve.Clone()).ToList();
// 迭代处理所有未处理的曲线
while (unprocessedCurves.Count > 0)
{
// 当前分组
List<Entity> currentGroup = new List<Entity>();
// 从未处理曲线列表中取出一条曲线开始分组
Entity currentCurve = unprocessedCurves[0];
currentGroup.Add(currentCurve);
unprocessedCurves.RemoveAt(0);
bool curveAdded;
do
{
curveAdded = false;
// 遍历剩余未处理的曲线,尝试连接
for (int i = unprocessedCurves.Count - 1; i >= 0; i--)
{
Entity nextCurve = unprocessedCurves[i];
if (CanConnect(currentCurve, nextCurve, gap))
{
// 将下一条曲线添加到当前分组
currentGroup.Add(nextCurve);
unprocessedCurves.RemoveAt(i);
currentCurve = nextCurve;
curveAdded = true;
break;
}
else if (CanConnect(currentCurve, nextCurve, gap, true))
{
// 如果需要,反转曲线以匹配端点
ReverseCurve(nextCurve);
currentGroup.Add(nextCurve);
unprocessedCurves.RemoveAt(i);
currentCurve = nextCurve;
curveAdded = true;
break;
}
}
} while (curveAdded);
// 将当前分组添加到分组结果中
groupedCurves.Add(currentGroup);
}
return groupedCurves;
}
// 检查两条曲线是否可以连接
private static bool CanConnect(Entity curve1, Entity curve2, double gap, bool allowReverse = false)
{
Point3d endPoint1 = GetEndPoint(curve1);
Point3d startPoint2 = GetStartPoint(curve2);
if (endPoint1.DistanceTo(startPoint2) <= gap)
{
return true;
}
// 检查是否需要反转其中一条曲线
if (allowReverse)
{
Point3d reversedStart2 = GetEndPoint(curve2);
if (endPoint1.DistanceTo(reversedStart2) <= gap)
{
return true;
}
}
return false;
}
// 获取曲线的起点
private static Point3d GetStartPoint(Entity curve)
{
if (curve is Curve c)
{
return c.StartPoint;
}
throw new ArgumentException("实体不是曲线类型");
}
// 获取曲线的终点
private static Point3d GetEndPoint(Entity curve)
{
if (curve is Curve c)
{
return c.EndPoint;
}
throw new ArgumentException("实体不是曲线类型");
}
// 反转曲线的首尾
private static void ReverseCurve(Entity curve)
{
if (curve is Polyline polyline)
{
polyline.ReverseCurve();
}
else if (curve is Spline spline)
{
spline.ReverseCurve();
}
else if (curve is Arc arc)
{
arc.ReverseCurve();
}
else if (curve is Line line)
{
//Line reversedLine = new Line(line.EndPoint, line.StartPoint);
//line = reversedLine;
line.ReverseCurve();
}
}
#endregion
#region 相连曲线生成完整多段线
// 扩展方法:从曲线组创建多段线
public static List<Entity> CreatePLFromCurveGroup(this List<List<Entity>> groupedCurves, double tolerance, bool closedPL)
{
List<Entity> polylines = new List<Entity>();
foreach (var group in groupedCurves)
{
if (group.Count == 1)
{
polylines.Add(group[0].Clone() as Entity);
}
else
{
// 创建一个新的多段线
Polyline polyline = new Polyline();
// 定义当前多段线的顶点索引
int vertexIndex = 0;
foreach (Entity entity in group)
{
if (entity is Line line)
{
// 直线:添加起点和终点
polyline.AddVertexAt(vertexIndex++, To2D(line.StartPoint), 0, 0, 0);
polyline.AddVertexAt(vertexIndex++, To2D(line.EndPoint), 0, 0, 0);
}
else if (entity is Polyline pl)
{
// 多段线:获取所有顶点
for (int i = 0; i < pl.NumberOfVertices; i++)
{
polyline.AddVertexAt(vertexIndex++, pl.GetPoint2dAt(i), pl.GetBulgeAt(i), pl.GetStartWidthAt(i), pl.GetEndWidthAt(i));
}
}
else if (entity is Arc arc)
{
// 圆弧:添加起点和终点,并计算凸度
polyline.AddVertexAt(vertexIndex++, To2D(arc.StartPoint), 0, 0, 0);
polyline.AddVertexAt(vertexIndex++, To2D(arc.EndPoint), GetArcBulge(arc), 0, 0);
}
else if (entity is Spline spline)
{
// 样条曲线:根据公差取样点
var splinePoints = spline.GetSamplePoints(tolerance);
foreach (var point in splinePoints)
{
polyline.AddVertexAt(vertexIndex++, To2D(point), 0, 0, 0);
}
}
}
// 设置多段线是否闭合
polyline.Closed = closedPL;
// 将生成的多段线添加到结果列表中
polylines.Add(polyline);
}
}
return polylines;
}
// 将 3D 点转换为 2D 点
private static Point2d To2D(Point3d point)
{
return new Point2d(point.X, point.Y);
}
// 计算圆弧的凸度
private static double GetArcBulge(Arc arc)
{
double angle = arc.TotalAngle;
return Math.Tan(angle / 4);
}
// 扩展方法:根据样条曲线获取采样点(示例实现)
private static List<Point3d> GetSamplePoints(this Spline spline, double tolerance)
{
// 示例:根据公差获取样条曲线的采样点,实际代码可以更复杂
List<Point3d> samplePoints = new List<Point3d>();
// 样条曲线的起点
samplePoints.Add(spline.StartPoint);
// 使用曲线的长度和公差计算出多个取样点
double length = spline.GetDistAtPoint(spline.EndPoint);
int numPoints = (int)(length / tolerance);
for (int i = 1; i < numPoints; i++)
{
double param = i / (double)numPoints * spline.EndParam;
samplePoints.Add(spline.GetPointAtParameter(param));
}
// 样条曲线的终点
samplePoints.Add(spline.EndPoint);
return samplePoints;
}
#endregion
#endregion