Revit二次開發-曲線三連:對curves進行排序

哀家爆發表於2020-10-17

日常開發工作中,經常會遇到這樣的場景:

通過手動選擇(或其他手段),獲取到了一些頭尾相連的曲線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;
        }

 

相關文章