/// <summary> /// Compare the vector and if value locate right of original , return true , else false /// In the upper hull and lower hull , the vector dot angle will -90 ~ 0 /// </summary> /// <param name="original"></param> /// <param name="value"></param> /// <returns></returns> public bool IsRight(XYZ original, XYZ value) { //Dot Product var angleValue = original.CrossProduct(value); //90° if (angleValue.Z >= 0) return true; return false; }
创建遍历的函数,此处放上书中的伪代码与c#代码解释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
算法 CONVEXHULL(P) 输入:平面点集P 输出:由CH(P)的所有顶点沿顺时针方向组成的一个列表 1. 根据x-坐标,对所有点进行排序,得到序列p1, …, pn 2. 在Lupper 中加入p1 和p2(p1 在前) 3. for (i← 3 to n) 4. do 在Lupper 中加入pi 5. while (Lupper 中至少还有三个点,而且最末尾的三个点所构成的不是一个右拐) 6. do 将倒数第二个顶点从Lupper 中删去 7. 在Llower 中加入pn 和pn-1(pn 在前) 8. for (i← n-2 downto 1) 9. do 在Llower 中加入pi 10. while (Llower 中至少还有三个点,而且最末尾的三个点所构成的不是一个右拐) 11. do 将倒数第二个顶点从Llower 中删去 12. 将第一个和最后一个点从Llower 中删去 (以免在上凸包与下凸包联接之后,出现重复顶点) 13. 将Llower 联接到Lupper 后面(将由此得到的列表记为L) 14. return(L)
private List<XYZ> GetHullVertices(bool isUp = true) { var vertices = new List<XYZ>(); vertices.AddRange(_vertices); if (!isUp) { vertices = vertices.OrderByDescending(x=>x.X).ToList(); } var theLeft = vertices.First(); vertices.Remove(theLeft); var theLast = vertices.Last(); var fakeDir = (theLast - theLeft).Normalize(); var upHullVertices = new List<XYZ>(){theLeft}; var fakeIndex = 1; while (true) { if (theLeft.IsAlmostEqualWithoutZ(theLast)) { //upHullVertices.Add(theLast); break; } var fakePoint = XYZ.Zero; for (int i = 0; i < vertices.Count ; i++) { var point = vertices[i]; var dir = (point - theLeft).Normalize(); //if is dir right to fakeDir , replace value to dir and fakePoint if (IsRight(fakeDir, dir)) { fakeDir = dir; fakePoint = point; } } //remove the theLeft point and replace theLeft to new Point; theLeft = fakePoint; if (vertices.Remove(theLeft)) { upHullVertices.Add(theLeft); fakeDir = (theLast - theLeft).Normalize(); } fakeIndex++; }