2013-02-03 54 views
6

我是C#的新手,並且很難計算凸包。 C#是否有這樣的數學庫?如果不是,那麼我想我只需要實現我自己的。凸面船體庫

+0

在谷歌的第一個命中'C#凸包' - http://www.codeproject.com/Articles/29275/Convex-Hull。你有做過什麼研究嗎? –

+1

是的,我已經看到了。我的問題是,如果C#有一個現有的內置庫... – Owen

回答

3

下面是我用Monotone Chain算法a.k.a. Andrew的算法編寫的2D凸包算法。

public static IListSource<Point> ComputeConvexHull(List<Point> points, bool sortInPlace = false) 
{ 
    if (!sortInPlace) 
     points = new List<Point>(points); 
    points.Sort((a, b) => 
     a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); 

    // Importantly, DList provides O(1) insertion at beginning and end 
    DList<Point> hull = new DList<Point>(); 
    int L = 0, U = 0; // size of lower and upper hulls 

    // Builds a hull such that the output polygon starts at the leftmost point. 
    for (int i = points.Count - 1; i >= 0 ; i--) 
    { 
     Point p = points[i], p1; 

     // build lower hull (at end of output list) 
     while (L >= 2 && (p1 = hull.Last).Sub(hull[hull.Count-2]).Cross(p.Sub(p1)) >= 0) { 
      hull.RemoveAt(hull.Count-1); 
      L--; 
     } 
     hull.PushLast(p); 
     L++; 

     // build upper hull (at beginning of output list) 
     while (U >= 2 && (p1 = hull.First).Sub(hull[1]).Cross(p.Sub(p1)) <= 0) 
     { 
      hull.RemoveAt(0); 
      U--; 
     } 
     if (U != 0) // when U=0, share the point added above 
      hull.PushFirst(p); 
     U++; 
     Debug.Assert(U + L == hull.Count + 1); 
    } 
    hull.RemoveAt(hull.Count - 1); 
    return hull; 
} 

它依賴於一些假定存在的事情,詳見我的blog post

1

下面是對Qwertie答案中使用的相同Java源代碼的C#的音譯,但沒有依賴於具有雙字段的Point類之外的非標準類。

class ConvexHull 
{ 
    public static double cross(Point O, Point A, Point B) 
    { 
     return (A.X - O.X) * (B.Y - O.Y) - (A.Y - O.Y) * (B.X - O.X); 
    } 

    public static List<Point> GetConvexHull(List<Point> points) 
    { 
     if (points == null) 
      return null; 

     if (points.Count() <= 1) 
      return points; 

     int n = points.Count(), k = 0; 
     List<Point> H = new List<Point>(new Point[2 * n]); 

     points.Sort((a, b) => 
      a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); 

     // Build lower hull 
     for (int i = 0; i < n; ++i) 
     { 
      while (k >= 2 && cross(H[k - 2], H[k - 1], points[i]) <= 0) 
       k--; 
      H[k++] = points[i]; 
     } 

     // Build upper hull 
     for (int i = n - 2, t = k + 1; i >= 0; i--) 
     { 
      while (k >= t && cross(H[k - 2], H[k - 1], points[i]) <= 0) 
       k--; 
      H[k++] = points[i]; 
     } 

     return H.Take(k - 1).ToList(); 
    } 
} 
1

我比較了許多Convex Hull算法/實現與所有提供的代碼。一切都包含在CodeProject文章中。

算法相比:

  • 單調鏈
  • MiConvexHull(Delaunay三角和沃羅諾伊目)
  • 格雷厄姆掃描
  • Ouellet的(礦)

文章:

+0

@ephraim,非常感謝您向我彙報。我目前正在看這種情況! –

+0

@ephraim,你在哪裏有錯誤,在哪篇文章?我無法用我最新文章的代碼重現它?你有什麼暗示我可以自己看到錯誤嗎? 1 000 000個測試用4個點(這應該導致1個象限,偶爾有1個點),所有的Ouellet公司都沒有錯誤/異常? –

+0

@ephraim,找到了Bug!十分感謝!這只是在第一篇文章。有更正的文章應該很快就可以使用(將在15分鐘內完成,並且在CodeProject批准的時候可以使用〜大概今天) –