日常开发工作中,经常会遇到这样的场景:
通过手动选择(或其他手段),获取到了一些头尾相连的曲线List<Curves> curves(只限于Line和Arc),现在只知道它们是相连的,但是不知是否沿着一个方向,在集合中是否是按顺序排列?
可以根据以下方式对其进行排序,达到真正的首尾相连的结果:
1.首先我们找到第一根线L1,满足要求:有一端是没有其他线与其相重合的。并记录L1与其他线重合的那个端点PL1。
2.然后找下一根线,满足要求:有一端点与PL1重合,并记录另一端点P2;
3.重复第二步,直至最后一根线。
如此我们就可以保证所有曲线都是按照次序一根接着一根的。
贴代码(经测试,应该没问题,但很多地方可能有重复过程):
/// <summary>
/// 对目标曲线进行排序(只改变curves的顺序)
/// </summary>
/// <param name="curves"></param>
/// <returns></returns>
private List<Curve> OrderCurves(List<Curve> curves)
{
//如果只有1根或者2根,那么不需要排序
if (curves.Count < 3)
{
return curves;
}
//首先找到第一根线
Curve firstCurve = null;
foreach (var curve in curves)
{
if (IsCurveJoinedBothPoints(curve, curves) == false)
{
firstCurve = curve;
break;
}
}
var orderedCurves = new List<Curve> { firstCurve };
//然后从第二个元素开始,找与第一个元素首尾相连的对象
for (int i = 0; i < orderedCurves.Count; i++)
{
foreach (var item in curves)
{
//首先保证item并不在orderedCurves中
if (orderedCurves.Contains(item) == false)
{
//如果curves存在一根线与orderedCurves[i]的端点重合
if (IsPointJoinedWithCurve(orderedCurves[i].GetEndPoint(0), item, out _)
|| IsPointJoinedWithCurve(orderedCurves[i].GetEndPoint(1), item, out _))
{
orderedCurves.Add(item);
}
}
}
}
return orderedCurves;
}
/// <summary>
/// 判断这根线的两个端点,是否与目标curves中的线都相连接
/// </summary>
/// <param name="curve"></param>
/// <param name="curves"></param>
/// <returns></returns>
private bool IsCurveJoinedBothPoints(Curve curve, List<Curve> curves)
{
if (curves.Exists(
x => x.GetHashCode() != curve.GetHashCode()//不是同一根线
&& IsPointJoinedWithCurve(curve.GetEndPoint(0), x, out _)//有线与curve的起点重合
))
{
if (curves.Exists(
y => y.GetHashCode() != curve.GetHashCode()//不是同一根线
&& IsPointJoinedWithCurve(curve.GetEndPoint(1), y, out _)//也有线与curve的终点重合
))
{
//即如果即有与curve起点重合的线,又有与curve重点重合的线
//就判定这跟线收尾都有与之相邻的线
return true;
}
}
return false;
}
/// <summary>
/// 判断一个点和一根线的起始点是否重合
/// </summary>
/// <param name="point"></param>
/// <param name="curve"></param>
/// <param name="p">0代表curve与point的起点重合,1代表curve与point的终点重合</param>
/// <returns></returns>
private bool IsPointJoinedWithCurve(XYZ point, Curve curve, out int p)
{
if (curve.GetEndPoint(0).DistanceTo(point)<_presion)
{
p = 0;
return true;
}
else if (curve.GetEndPoint(1).DistanceTo(point) < _presion)
{
p = 1;
return true;
}
p = -1;
return false;
}
/// <summary>
/// 对orderedCurves的第一条线做变向处理,使其开放端为起点
/// </summary>
/// <param name="curves"></param>
private List<Curve> ChangeFirstCurveOrientation(List<Curve> curves)
{
var firstCurve = curves[0];
//如果第一条线的起点,有其他线与之重合,则将第一条线的方向改一下
if (curves.Exists(x=> x.GetHashCode()!= firstCurve.GetHashCode()&&
IsPointJoinedWithCurve(firstCurve.GetEndPoint(0),x,out int _)))
{
var newCurve = firstCurve.CreateReversed();
curves.Remove(firstCurve);
curves.Insert(0, newCurve);
}
return curves;
}
/// <summary>
/// 改变曲线的方向,使其首尾相连
/// </summary>
/// <param name="curves"></param>
/// <returns></returns>
private List<Curve> ChangeOriention(List<Curve> curves)
{
if (curves.Count < 2)
{
return curves;
}
var output = new List<Curve>() { curves[0] };
for (int i = 1; i <curves.Count; i++)
{
var p0 = output[i - 1].GetEndPoint(0);
var p1 = output[i - 1].GetEndPoint(1);
var p10 = curves[i].GetEndPoint(0);
var p11 = curves[i].GetEndPoint(1);
//否则,就是起点与起点重合,终点与终点重合,需要改变其方向
if (p0.DistanceTo(p10) < _presion || p1.DistanceTo(p11) < _presion)
{
var curve = curves[i].CreateReversed();
output.Add(curve);
}
//如果下一根线与上一根线是起点与终点重合,或者终点与起点重合,说明方向一样
//那就原封不动放进去
else
{
output.Add(curves[i]);
}
}
return output;
}