c++ - 实现格雷厄姆扫描以找到凸包

标签 c++ algorithm qt math computational-geometry

我正在尝试实现 Graham Scan在 C++ 中,但它不起作用,我找不到原因。任何线索将不胜感激。经过一些尝试后,似乎我总是有 m_M = 2 并且这 2 个点是最高的 y 点,如果有帮助的话。

通过叉积判断是右转还是左转。

qreal Interpolation::ccw(QPointF pt1, QPointF pt2, QPointF pt3)
{
    return (pt2.x()-pt1.x())*(pt3.y()-pt1.y()) - (pt2.y()-pt1.y())*(pt3.x()-pt1.x());
}

点积除以范数得到 cos,因为对角度排序与对 [0, Pi] 中的 cos 排序相同。

qreal Interpolation::dp(QPointF pt1, QPointF pt2)
{
    return (pt2.x()-pt1.x())/qSqrt((pt2.x()-pt1.x())*(pt2.x()-pt1.x()) + (pt2.y()-pt1.y())*(pt2.y()-pt1.y()));
}

主要功能:

void Interpolation::ConvexHull()
{
    QPointF points[m_N+1]; // My number of points
    QPointF pt_temp(m_pt[0]);
    qreal angle_temp(0);
    int k_temp(0);

points[1] 作为 lower-y 点填充数组点:

    for (int i(1); i < m_N; ++i)
    {
        if (m_pt[i].y() < pt_temp.y())
        {
            points[i+1] = pt_temp;
            pt_temp = m_pt[i];
        }
        else
        {
            points[i+1] = m_pt[i];
        }
    }
    points[1] = pt_temp;

按角度对点数组进行排序并执行 points[m_N] = points[0]

    for (int i(2); i <= m_N; ++i)
    {
        pt_temp = points[i];
        angle_temp = dp(points[1], pt_temp);
        k_temp = i;
        for (int j(1); j <= m_N-i; ++j)
        {
            if (dp(points[1], points[i+j]) < angle_temp)
            {
                pt_temp = points[i+j];
                angle_temp = dp(points[1], points[i+j]);
                k_temp = i+j;
            }
        }
        points[k_temp] = points[i];
        points[i] = pt_temp;
    }
    points[0] = points[m_N];

执行格雷厄姆扫描

    m_M = 1; // Number of points on the convex hull.

    for (int i(2); i <= m_N; ++i)
    {
        while (ccw(points[m_M-1], points[m_M], points[i]) <= 0)
        {
            if (m_M > 1)
            {
                m_M -= 1;
            }
            else if (i == m_N)
            {
                break;
            }
            else
            {
                i += 1;
            }
        }
        m_M += 1;
        pt_temp = points[m_M];
        points[m_M] = points[i];
        points[i] = points[m_M];
    }

将点保存到 m_convexHull,它应该是具有 ConvexHull[m_M]=[ConvexHull[0] 的船体上的点列表

    for (int i(0); i < m_M; ++i)
    {
        m_convexHull.push_back(points[i+1]);
    }
    m_convexHull.push_back(points[1]);
}

最佳答案

我发现了问题。它在于句子:

Dot product divided by the norm to have the cos because sorting the angle is the same as sorting the cos in [0, Pi].

角度越低,cos越高,所以我只需要更改这行代码:

            if (dp(points[1], points[i+j]) < angle_temp)

到:

            if (dp(points[1], points[i+j]) > angle_temp)

现在它完美运行了!

关于c++ - 实现格雷厄姆扫描以找到凸包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11107687/

相关文章:

javascript - 匹配一个词,其中候选者可以跨越连续的组(跨度)

c++ - 带动画的 QStateMachine 事件循环

c++ - Qt Creator 需要一个编译器设置来构建

c++ - 不能包含为 <QtCore/QString>

C++ - 在初始化类成员之前运行一个函数

c++ - 为什么要编译 class::class::class::static Class Member()(在 C++ 中)?

C++ 在一组区间内有效搜索值

algorithm - 使用 HiLo 后,如果更改容量(最大 Lo)会发生什么情况?

c++ - 如何将 Double Date 转换为 std::string

c++ - 使用递归时如何摆脱这个全局变量?