【问题标题】:Finding the centroid of a polygon寻找多边形的质心
【发布时间】:2017-06-04 16:45:00
【问题描述】:

我使用下面的代码来查找多边形的质心(代码不是我写的,来自另一个问题)。

Point compute2DPolygonCentroid(const std::vector<Point> vertices) {
    Point centroid;
    double signedArea = 0.0;
    double x0 = 0.0; // Current vertex X
    double y0 = 0.0; // Current vertex Y
    double x1 = 0.0; // Next vertex X
    double y1 = 0.0; // Next vertex Y
    double a = 0.0;  // Partial signed area

    // For all vertices except last
    for (int i = 0; i < vertices.size() - 1; ++i) {

        x0 = vertices[i].x;
        y0 = vertices[i].y;
        x1 = vertices[i + 1].x;
        y1 = vertices[i + 1].y;
        a = x0 * y1 - x1 * y0;
        signedArea += a;
        centroid.x += (x0 + x1) * a;
        centroid.y += (y0 + y1) * a;

    }

    // Do last vertex separately to avoid performing an expensive
    // modulus operation in each iteration.
    x0 = vertices.back().x;
    y0 = vertices.back().y;
    x1 = vertices.front().x;
    y1 = vertices.front().y;
    a = x0 * y1 - x1 * y0;
    signedArea += a;
    centroid.x += (x0 + x1) * a;
    centroid.y += (y0 + y1) * a;

    signedArea *= 0.5;
    centroid.x /= (6.0 * signedArea);
    centroid.y /= (6.0 * signedArea);

    return centroid;
}

问题在于它仅在输入向量vertices 中的点按顺时针顺序时才有效。当点按逆时针顺序排列时,它不起作用。这是我所说的 cw && ccw order 的图片:

我不明白为什么当点的顺序改变但点仍然相同时它不起作用。

【问题讨论】:

  • 作为一个小的代码清晰度更改,您可以将第一个顶点的副本推送到向量的背面,因此您不需要特殊情况下最后一个操作。
  • 我现在没有办法测试代码,但我相当肯定这个算法应该以任意顺序处理点(尽管计算的面积将为负数)。在这种情况下,“它不起作用”是什么意思?质心位置完全错误?
  • @Rook 是的,在 ccw 顺序的情况下,我得到多边形外部的质心(完全磨损)。
  • 我刚刚测试了你的代码,发现如果我颠倒顶点的顺序,质心计算的结果是完全一样的,正如我所期望的那样。你能提供一些证明问题的测试数据吗?

标签: c++ 2d polygon centroid


【解决方案1】:

事实证明,问题在于Point 有未签名的成员。还有一个潜在的次要问题,即浮点舍入问题。

在这个算法中,如果风的顺序是错误的,计算的面积将是负数,当你做类似的事情时

centroid.x += (x0 + x1) * a;

你会得到一个不正确的值,因为a 是负数,而centroid.x 是无符号的。

您应该将中间质心值存储为某种浮点数,以便 a) 您不会得到这些有符号/无符号问题 b) 这样您就不会在每个顶点上都出现舍入错误;我不确定这些错误最终是否会大到足以给您带来问题,但是当它可以很容易地避免时,冒这个风险似乎很愚蠢。返回时,您应该在最后转换为 unsigned int (或其他)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多