【问题标题】:Convex Hull - Determine order of the pointsConvex Hull - 确定点的顺序
【发布时间】:2012-05-17 20:10:00
【问题描述】:

所以我正在学习 Convex Hull 算法,并编写了从幼稚的 Bruteforce 到 Graham Scan 的所有算法。

这是我的蛮力 O(n^4) 算法。一开始,假设所有点都是船体的一部分。对于每个可能的三角形,消除位于三角形内的所有点。最后,那些没有被淘汰的点将成为船体的一部分。

这是 Java 代码(已修复:使用 Thomash 的解决方案)

public List<Point> naive(List<Point> points) {
    if (points == null)
        return Collections.emptyList();
    if (points.size() <= 3)
        return points;
    boolean[] extremePoints = new boolean[points.size()];
    Arrays.fill(extremePoints, true);
    for (int i = 0, sz = points.size(); i < sz; i++) {
        if (extremePoints[i])
            for (int j = 0; j < sz; j++) {
                if (i != j && extremePoints[j]) {
                    for (int k = 0; k < sz; k++) {
                        if (k != i && k != j) {
                            for (int l = 0; l < sz; l++) {
                                if (extremePoints[l] && l != i && l != j
                                        && l != k) {
                                    // Check if P[l] lies in triangle formed
                                    // by
                                    // P[i],P[j],P[k]

                                    Polygon p = new Polygon();
                                    p.addPoint(points.get(i).x,
                                            points.get(i).y);
                                    p.addPoint(points.get(j).x,
                                            points.get(j).y);
                                    p.addPoint(points.get(k).x,
                                            points.get(k).y);
                                    if (p.contains(points.get(l)))
                                        extremePoints[l] = false;
                                }
                            }
                        }
                    }
                }
            }
    }

    Point centerOfHull = null; // Arbitrary point inside the hull
    // Order?
    for (int i = 0; i < extremePoints.length; i++) {
        if (!extremePoints[i]) {
            centerOfHull = points.get(i);
            break;
        }
    }
    List<Point> convexHull = new ArrayList<Point>();
    for (int i = 0; i < extremePoints.length; i++) {
        if (extremePoints[i]) {
            convexHull.add(points.get(i));
        }
    }
    Collections.sort(convexHull, new PointComp(centerOfHull));
    // or use a heap. still O(nlogn)
    return convexHull;
}

private class PointComp implements Comparator<Point> {

    private Point center;

    public PointComp(Point center) {
        this.center = center;
    }

    @Override
    public int compare(Point o1, Point o2) {
        double angle1 = Math.atan2(o1.y - center.y, o1.x - center.x);
        double angle2 = Math.atan2(o2.y - center.y, o2.x - center.x);
        if (angle1 < angle2)
            return 1;
        else if (angle2 > angle1)
            return -1;
        return 0;
    }
}

我尝试在视觉上看到这些点,它们似乎是正确的,但是我不知道如何建立点的顺序来绘制凸包多边形?任何帮助表示赞赏。

【问题讨论】:

    标签: java algorithm convex-hull convex-polygon


    【解决方案1】:

    在凸包内选择一个点 O 和另一个点 A。对于凸包中的每个 B,计算角度 AÔB 并使用这些角度对点进行排序(如果 AÔB

    【讨论】:

    • 您能详细说明一下吗?我不太明白sort points using these angles
    • 我最终使用了你的方法,使用了一个比较器来测量相对于原点的角度。将编辑我的问题以包含代码。谢谢。 :)
    • 无论如何我可以消除Math.atan2 并只使用斜率吗?我想这会让它更快。 :\
    • @st0le:你应该可以摆脱斜坡,是的。
    【解决方案2】:

    如果你强行找出哪些点是外壳的一部分,你还不如继续做一些丑陋的事情来找出点的顺序。

    1. 从左上角开始。
    2. 计算从该点到所有其他点的角度。
    3. 选择角度最接近 0 度的点。这是围绕船体顺时针方向的下一个点。
    4. 冲洗、起泡、重复。

    您必须在绕船体行驶时调整目标角度,但这很有效(这是您在纸上执行此操作的一种方式。)

    【讨论】:

    • 如果您这样做,则无需先将属于船体一部分的点与其他点分开。
    • @NicolasRepiquet:是的,但如果你已经碰巧在凸包上有一组点,这比从头开始要快。
    • @Li-aungYip,虽然我理解你的方法,但我使用了 Thomash 的方法,因为它在实现中很简单。我已经赞成你的两个解决方案,但会接受他的。再次感谢! :)
    猜你喜欢
    • 2011-10-29
    • 2013-08-29
    • 2015-02-05
    • 2020-08-20
    • 2018-10-15
    • 2016-06-10
    • 2017-07-29
    • 1970-01-01
    • 2019-08-05
    相关资源
    最近更新 更多