cad.net 判斷四個點是否構成矩形(帶旋轉)測試時間篇
阿新 • • 發佈:2022-03-27
說明
測試命令
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 } } }
結果
(完)