【问题标题】:Better "centerpoint" than centroid比质心更好的“中心点”
【发布时间】:2018-11-08 07:47:34
【问题描述】:

我正在使用多边形的质心在地图应用程序中附加标记。这对于凸多边形绝对适用,并且对于许多凹多边形非常好。

但是,某些多边形(香蕉、甜甜圈)显然不会产生所需的结果:在这些情况下,质心位于多边形区域之外

有没有人知道更好的方法来在任何多边形区域(可能包含孔!)找到合适的点来附加标记?

【问题讨论】:

  • 一些应用程序在找到质心后会做一个多边形内的点。如果它在外面,则根据与多边形相交的射线的中点计算新的 x 或 y。
  • 我认为你可以通过三角测量来做到这一点。例如,在第一步,对多边形进行三角剖分,然后尝试找到一个三角形,该三角形似乎是所需标准中的中心三角形并返回它的质心。
  • 我会将凹多边形分割成凸部分(也许已经如此表示),取其中“最丰满”的部分(绝对直径大,最大直径/最小直径之比接近 1 ),并将点放在该部分的中心。不过,这可能需要大量的计算,所以我会考虑缓存结果,或者将它们与多边形一起存储。
  • 您似乎在寻找离任何边界最远的点。在数学论坛上提问。
  • @ChristopheRoussy:没错!

标签: algorithm geometry center computational-geometry centroid


【解决方案1】:

我不知道如何为任何可能的形状解决这个问题(并且不进行大量计算),但也许对于像你展示的那些更简单的形状:

https://en.wikipedia.org/wiki/Force-directed_graph_drawing

启发式:这可能会在一段时间后收敛到合理的近似值

  • 将形状边框转换为许多点(更多 = 更精确)
  • 从多边形内的许多随机点开始
  • 推动它们直到它们离边界点最远,或者只计算距离......(可以并行完成)
  • 取最佳点

另一种方法可能是根据形状的性质使用多种算法(如甜甜圈的另一种算法......)。也可能首先依靠测量“最胖”的部分?

恕我直言,会在数学论坛上问这个问题。

类似:Calculate Centroid WITHIN / INSIDE a SpatialPolygon

类似:How to find two most distant points?

【讨论】:

    【解决方案2】:
    for (int i = 0; i < n; /*++i*/) {
        p = RandomPointInsideConvexHull();
        if (IsInsidePolygon(p)) {
            ++i;
            d = DistanceToClosestEdge(p);
            if (d > bestD) {
                bestP = p;
            }
        }
    }
    

    运行此循环后,您将通过bestP 近似解。 n 是要选择的参数。如果您想要更准确的结果,您可以重新开始搜索,但现在您可以在bestP 附近选择一个点,而不是在多边形的凸包内选择一个点,比如不超过bestD / 5(这次您不需要检查随机点是否在多边形内)。

    【讨论】:

    • 该算法不适用于具有许多顶点但面积较小的多边形,例如蜿蜒穿过山脉的细轨道/道路的轮廓。问题是凸包内随机选择的点很可能在多边形之外。在某些情况下,所有点可能在多边形之外。
    • @AdamGawne-Cain 请检查i 递增的条件。尽管对于您提到的那种多边形来说,这不是最有效的算法。
    • 你的方法的好处是它可以在许多多边形中找到一个不错的点。但是OP想要“任何多边形”的方法。如果输入多边形是退化的(例如,面积为 0 的 L 形,例如 {0 0, 1 0, 1 1, 1 0, 0 0}),您的代码将永远运行。
    • @AdamGawne-Cain Hm... 对,但是面积为零的多边形没有严格多边形内的点;)
    【解决方案3】:

    一种方法是生成并优化多边形的skeleton,然后使用骨架的中点放置标记(如果是文本,则正确定位文本)。这适用于大多数形状,包括带孔的形状,以及香蕉形或蝌蚪形的新月形。

    CGAL 库有一个 2D Straight Skeleton and Polygon Offsetting 模块,或者您可以 use PostGIS,例如。

    【讨论】:

    • 所以,如果连续收缩过程中的每个轮廓都被赋予一个递增的高度,则取最高点。
    • @Will - 这是一种方法(并且会为您提供离任何边缘最远的点)。对于哑铃形多边形,您可能希望算法在“条”上选择一个点 - 在这种情况下,您应该更喜欢沿骨架脊柱的(可能加权的)平均位置。
    【解决方案4】:

    为了改写 ChristopheRoussy 的评论,我们可以在多边形内寻找最大的圆。

    最大的圆是不能再增长的圆,因为它接触了三个顶点或边(如果它只接触两个,它可以变大或移动到第三个为止)。

    因此,如果您的顶点很少,您可以枚举所有可能的顶点/边三元组,为每个顶点/边找到一个圆圈,然后选择最大的一个。

    但这需要创建四个函数:

    1. 圆(顶点,顶点,顶点)
    2. 圆(顶点、顶点、边)
    3. 圆(顶点、边、边)
    4. 圆(边、边、边)

    所有这些都是可能的,但可能需要一些努力。

    【讨论】:

      【解决方案5】:

      找到极坐标并在中间画一条水平线。保证穿过多边形。

      找到与边的交点并通过增加横坐标对它们进行排序。在两个交叉点的中间选择一个点。

      这是一个 O(N + K Log K) 过程,其中 K 是交叉点的数量(通常是非常小的偶数)。写起来很简单。

      为了增加良好放置的机会,您可以尝试三个水平线而不是一个,然后选择最长的交叉点。

      【讨论】:

      • 如果多边形内部不连通且水平线与多边形的交点位于多边形的自交点上,此方法可能会失败。例如,多边形可以是数字 8,水平线可以穿过 8 的腰部。
      • @AdamGawne-Cain:不,这行得通。你会得到两个重叠的交点,定义一个退化的段。
      • 我同意你会得到一个点,但它不会按照 OP 的要求严格多边形内。实际上,我认为您的方法适合获取标记点,因为标记可能大于点并且可能大于多边形内的所有空间。
      【解决方案6】:

      要获得标记点,我会使用 Yves Daoust 的方法。

      为了得到一个可靠的“在任何带孔的多边形内”的点,我会使用可靠的库(例如 OpenGL 的 GLUtessellator)将多边形分割成三角形,然后得到面积最大的三角形的质心。

      如果我有时间进行开发和测试,并且我想要良好的性能,那么我会使用混合方法:首先使用 Yves Daoust 的方法获取一些候选点,然后测试候选点是否在多边形内。如果所有候选者都失败了,则回退到速度较慢的可靠方法(例如 GLUtesselator)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-14
        • 2020-02-09
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-19
        • 1970-01-01
        相关资源
        最近更新 更多