1. 程式人生 > 其它 >cad.net 判斷四個點是否構成矩形(帶旋轉)測試時間篇

cad.net 判斷四個點是否構成矩形(帶旋轉)測試時間篇

說明

測試命令

namespace JoinBox
{
    public partial class CmdTest
    {
        [CommandMethod("CmdTest_IsRect")]
        public void CmdTest_IsRect()
        {
            var dm = Acap.DocumentManager;
            var doc = dm.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            ed.WriteMessage("\n判斷四個點是否構成矩形(帶旋轉)");

            PromptEntityOptions peo = new("\n選擇多段線:");
            peo.SetRejectMessage("\n必須是多段線!");
            peo.AddAllowedClass(typeof(Polyline), false);
            var per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            db.Action(tr => {
                var pwl = per.ObjectId.ToEntity(tr) as Polyline;
                if (pwl == null)
                    return;
                var lst = new List<PointV>();
                var pts = pwl.GetEntityPoint3ds();
                pts.ForEach(a => lst.Add(a));

                var t1 = TimeHelper.RunTime(() => {
                    for (int i = 0; i < 100_0000; i++)//一百萬次
                        RectHelper.IsRect(lst);
                });

                var t2 = TimeHelper.RunTime(() => {
                    for (int i = 0; i < 100_0000; i++)//一百萬次
                        RectHelper.IsRect2(lst);
                });

                ed.WriteMessage("\n 點乘時間:" + t1);
                ed.WriteMessage("\n 山人時間:" + t2);
            });
        }
    }
}

函式

namespace JoinBox
{
    public static class RectHelper
    {
        /// <summary>
        /// 是否矩形(帶角度)
        /// </summary>
        /// <param name="ptList"></param>
        /// <returns></returns>
        public static bool IsRect(List<PointV>? ptList)
        {
            if (ptList == null)
                throw new ArgumentNullException(nameof(ptList));
            var pts = ptList.ToList();
            if (ptList.Count == 5)
            {
                //首尾點相同移除最後
                if (pts[0].IsEqualTo(pts[pts.Count - 1], 1e-6))
                    pts.RemoveAt(pts.Count - 1);
            }
            if (pts.Count != 4)
                return false;
#if true
            //利用點乘:90度的話,點乘ABD==A;若BC斜邊,導致前面點乘不足,則再點乘BCA==B
            //時間上面:點乘內部用了"求距離"求GetUnitNormal(牛頓迭代),兩次則*2了.
            //點乘會產生一個點
            var P1 = pts[0].DotProduct(pts[1], pts[3]);
            var P2 = pts[1].DotProduct(pts[2], pts[0]);
            return P1.IsEqualTo(pts[0], 1e-10) && P2.IsEqualTo(pts[1], 1e-10);
#else
#endif
        }


        /// <summary>
        /// 是否矩形(帶角度)
        /// </summary>
        /// <param name="ptList"></param>
        /// <returns></returns>
        public static bool IsRect2(List<PointV>? ptList)
        {
            if (ptList == null)
                throw new ArgumentNullException(nameof(ptList));
            var pts = ptList.ToList();
            if (ptList.Count == 5)
            {
                //首尾點相同移除最後
                if (pts[0].IsEqualTo(pts[pts.Count - 1], 1e-6))
                    pts.RemoveAt(pts.Count - 1);
            }
            if (pts.Count != 4)
                return false;
#if true2
#else
            //山人方案:對角線等長及一個角90度
            //對角長度相等(矩形/梯形(有第二個解,因此需要90度))
            var length1 = pts[0].GetDistanceTo(pts[2]);
            var length2 = pts[1].GetDistanceTo(pts[3]);
            if (Math.Abs(length1 - length2) < 1e-10)
            {
                var v1 = pts[0].GetVectorTo(pts[1]);
                var v2 = pts[0].GetVectorTo(pts[3]);
                return Math.Abs(v1.GetAngleTo(v2) - Constant.PiHalf) < 1e-10;
            }
            return false;
#endif
        }
    }
}

結果

(完)