【问题标题】:Merging two convex hulls合并两个凸包
【发布时间】:2012-11-09 02:46:22
【问题描述】:

我目前正在编写 Convex Hull 算法的分而治之版本,它非常接近工作,但在合并两个凸包(以形成整体凸包)时遇到了麻烦。

我正在合并:

  • 计算每个输入船体 A 和 B 的上船体和下船体
  • 通过确保右转找到组合的上层船体
  • 通过确保左转找到组合的下部船体
  • 计算 2 个组合船体的并集

我不能 100% 确定这是否是正确的方法 - 任何用于查找组合的上/下船体的指导或伪代码?

【问题讨论】:

    标签: java algorithm convex-hull


    【解决方案1】:

    【讨论】:

    【解决方案2】:

    虽然这是使用 XNA 库,但您绝对可以将其移植到 Java:

    public static class PolygonUnion
    {
            public static bool PolyUnion(Vector2[] polya, Vector2[] polyb, out Vector2[] union, out Vector2[] intersection)
            {
                if (!Intersects(polya, polyb))
                {
                    union = polya;
                    intersection = polyb;
                    return false;
                }
    
                LList a = new LList(polya), b = new LList(polyb);
                List<Intersection> intersections = new List<Intersection>();
    
                Vector2 vert;
                VNode aNode = a.First, bNode = b.First;
                //Find intersection points between the polygons
                do
                {
                    do
                    {
                        if (EdgeIntersects(aNode.Value, (aNode.Next == null) ? a.First.Value : aNode.Next.Value, bNode.Value,
    (bNode.Next == null) ? b.First.Value : bNode.Next.Value, out vert))
                        {
                            //An intersection point has been found!
                            intersections.Add(new Intersection(vert, aNode, bNode, (aNode.Next == null) ? a.First : aNode.Next,
    (bNode.Next == null) ? b.First : bNode.Next));
                        }
                        bNode = bNode.Next;
                    }
                    while (bNode != null);
                    bNode = b.First;
                    aNode = aNode.Next;
                }
                while (aNode != null);
                //Perform surgery on these intersections
                Intersection i;
                for (int j = 0; j < intersections.Count; j++)
                {
                    i = intersections[j];
                    i.aIn.Next = new VNode(i.Position, i.bOut, i.aIn);
                    i.bOut.Prev = i.aIn.Next;
    
                    i.bIn.Next = new VNode(i.Position, i.aOut, i.bIn);
                    i.aOut.Prev = i.bIn.Next;
                }
                //Decompose and simplify polygons into arrays
                union = a.ToArray();
                intersection = b.ToArray();
    
                //Find exterior polygon
                if (union.Length < intersection.Length)
                {
                    //Polygons need swapping!
                    Vector2[] u = union;
                    union = intersection;
                    intersection = u;
                }
                return true;
            }
    
            private class Intersection
            {
                public Intersection(Vector2 position, VNode aIn, VNode bIn, VNode aOut, VNode bOut)
                {
                    this.aIn = aIn;
                    this.bIn = bIn;
                    this.aOut = aOut;
                    this.bOut = bOut;
                    this.Position = position;
                }
    
                public VNode aIn, bIn, aOut, bOut;
                public Vector2 Position;
            }
    
            private class LList
            {
                public LList(Vector2[] poly)
                {
                    First = new VNode(poly[0], null, null);
    
                    current = First;
                    for (int i = 1; i < poly.Length; i++)
                    {
                        Add(current, poly[i]);
                        current = current.Next;
                    }
                    current = First;
                }
    
                private void Add(VNode prev, Vector2 pos)
                {
                    prev.Next = new VNode(pos, null, prev);
                }
    
                public VNode First;
                private VNode current;
    
                public Vector2[] ToArray()
                {
                    List<Vector2> ret = new List<Vector2>();
                    current = First;
                    int timeout = 1000;
                    bool starting = true;
    
                    while (current != null)
                    {
                        if (current.Prev != null && current.Value == current.Prev.Value)
                        {
                            current = current.Next;
                            if (current.Value == current.Next.Value && current.Value == current.Prev.Value) break;
                            continue;
                        }
                        if (!starting && current.Value == First.Value) break;
                        starting = false;
    
                        ret.Add(current.Value);
                        current = current.Next;
    
                        timeout--;
                        if (timeout <= 0) break;
                    }
                    return Simplify(ret.ToArray());
                }
            }
    
            private class VNode
            {
                public VNode(Vector2 value, VNode next, VNode prev)
                {
                    Value = value;
                    Next = next;
                    Prev = prev;
                }
    
                public VNode Next;
                public VNode Prev;
                public Vector2 Value;
    
                public override string ToString()
                {
                    return Value.ToString();
                }
            }
    
            private static Vector2[] Simplify(Vector2[] poly)
            {
                const float tolerance = 25f;//5 pixels tolerance. (5^2 to save sqrt)
                if (poly.Length == 0) return poly;
    
                List<Vector2> ret = new List<Vector2>(1);
                ret.Add(poly[0]);
                float dist;
    
                for (int i = 1; i < poly.Length; i++)
                {
                    dist = (poly[ret.Count - 1] - poly[i]).LengthSquared();
                    if (dist < tolerance) continue;
                    if (ret.Contains(poly[i])) continue;
    
                    ret.Add(poly[i]);
                }
                return ret.ToArray();
            }
    
            /// <summary>
            /// Checks if the line segments intersect.
            /// </summary>
            private static bool EdgeIntersects(Vector2 x, Vector2 y, Vector2 a, Vector2 b, out Vector2 i)
            {
                i = Vector2.Zero;
                float dx, dy, da, db, t, s;
    
                dx = y.X - x.X;
                dy = y.Y - x.Y;
                da = b.X - a.X;
                db = b.Y - a.Y;
                if ((da * dy - db * dx) == 0) return false;
    
                s = (dx * (a.Y - x.Y) + dy * (x.X - a.X)) / (da * dy - db * dx);
                t = (da * (x.Y - a.Y) + db * (a.X - x.X)) / (db * dx - da * dy);
                i = new Vector2(x.X + t * dx, x.Y + t * dy);
                return (bool)(s >= 0 && s <= 1 && t >= 0 && t <= 1);
            }
    
            #region Intersection Test
            /// <summary>
            /// Checks if two polygons intersect.
            /// </summary>
            public static bool Intersects(Vector2[] aPoints, Vector2[] bPoints)
            {
                Vector2 edge, axis;
                float minA, maxA, minB, maxB, overlap;
                //Loop through all edges until a seperating axis is found
                for (int x = 0; x < aPoints.Length + bPoints.Length; x++)
                {
                    //Calculate the current edge
                    if (x < aPoints.Length) edge = aPoints[(x == aPoints.Length - 1 ? 0 : x + 1)] - aPoints[x];
                    else
                    {
                        x -= aPoints.Length;
                        edge = bPoints[(x == bPoints.Length - 1 ? 0 : x + 1)] - bPoints[x];
                        x += aPoints.Length;
                    }
                    //Find the axis perpendicular to current edge
                    axis = new Vector2(-edge.Y, edge.X);
                    axis.Normalize();
                    //Project the two shapes onto this axis
                    //Project this
                    ProjectPoly(aPoints, axis, out maxA, out minA);
                    ProjectPoly(bPoints, axis, out maxB, out minB);
                    //Find the overlap between them
                    if (minA < minB) overlap = minB - maxA;
                    else overlap = minA - maxB;
                    //If the overlap is negative then they are overlapping and the smallest
                    //overlap must be found to find the minumum translation.
                    //If it is bigger than 0 then they won't overlap at all.
                    if (overlap < 0) return true;
                }
                return false;
            }
            /// <summary>
            /// Projects a polygon onto the axis, giving the maximum and minimum positions.
            /// </summary>
            /// <param name="points">Points that are in world space with origin at the centre</param>
            private static void ProjectPoly(Vector2[] points, Vector2 axis, out float max, out float min)
            {
                //Projecting a point onto an axis uses a dot product.
                float dotProduct = Vector2.Dot(axis, points[0]);
                min = dotProduct;
                max = dotProduct;
                //Now project the rest of the polygon...
                for (int i = 1; i < points.Length; i++)
                {
                    dotProduct = Vector2.Dot(axis, points[i]);
                    if (dotProduct < min) min = dotProduct;
                    else if (dotProduct > max) max = dotProduct;
                }
            }
            #endregion
    }
    

    【讨论】:

      【解决方案3】:

      我不确定你所说的低和高是什么意思,最好指定它是 2D 还是 3D。

      对于 2D 凸包。我做了一个算法,根据我的测试,它是最快的(至少是 Chan 的两倍),并且两者都在 O(n log h) 中。

      但我的另一个不同之处在于,它支持“在线”喂食。我的意思是您可以一次动态地添加一个点(尚不支持删除)。每一点都保持在 O (log h) 内,这实际上是您可以获得的最快速度。我认为,它也是唯一一个在线并在该性能范围内的。

      关于凸包的文章是:Fast and improved 2D Convex Hull algorithm and its implementation in O(n log h)。但是“在线”部分尚未记录。我今天才完成(2018-01-25)。但是所有代码都可以在GitHub 访问。

      为简单起见,您只能使用在线部分将任何内容与此代码动态合并(您可以添加凸包点或任何点):

      OuelletConvexHullAvl2Online.ConvexHullOnline convexHullOnline = new OuelletConvexHullAvl2Online.ConvexHullOnline();
                          foreach (Point pt in points)
                          {
                              convexHullOnline.DynamicallyAddAnotherPointToConvexHullIfAppropriate(pt);
                          }
      
                          return convexHullOnline.GetResultsAsArrayOfPoint();
      

      【讨论】:

        猜你喜欢
        • 2021-11-26
        • 2013-05-06
        • 2012-05-07
        • 1970-01-01
        • 1970-01-01
        • 2013-10-09
        • 2017-05-01
        • 2018-10-30
        • 2013-07-28
        相关资源
        最近更新 更多