比质心更好的“中心点”

时间:2018-05-29 15:27:56

标签: algorithm geometry center computational-geometry centroid

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

然而,一些多边形(香蕉,甜甜圈)显然不会产生预期的结果:在这些情况下,质心多边形区域之外。

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

enter image description here

6 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:3)

要重新评论ChristopheRoussy的评论,我们可能会寻找多边形内部的最大圆圈。

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

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

但它需要创建四个功能:

  1. 圈(顶点,顶点,顶点)
  2. 圈(顶点,顶点,边)
  3. 圈(顶点,边缘)
  4. 圈(边缘,边缘,边缘)
  5. 所有这些都是可能的,但可能需要一些努力。

答案 2 :(得分:2)

我不知道如何为任何可能的形状解决这个问题(并没有做大量的计算),但也许对于你所展示的更简单的形状:

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

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

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

另一种方法可能是根据形状的性质使用多种算法(就像甜甜圈的另一种算法......)。也许还可以依靠衡量“最胖”的方法。第一节?

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

类似:Calculate Centroid WITHIN / INSIDE a SpatialPolygon

类似:How to find two most distant points?

答案 3 :(得分:2)

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

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

这是O(N + K Log K)过程,其中K是交叉点的数量(通常是非常小的偶数)。非常直接的写作。

为了增加漂亮放置的几率,您可以尝试三个横向而不是一个挑选最长的交叉点。

enter image description here

答案 4 :(得分:1)

要获得标记的分数,我将使用伊夫·达乌斯特(Yves Daoust)的方法。

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

如果我有时间进行开发和测试,并且想要良好的性能,那么我将使用一种混合方法:首先使用Yves Daoust的方法来获取一些候选点,然后测试候选者以查看它们是否在多边形内。如果所有候选人均不及格,则退回到较慢的可靠方法(例如GLUtesselator)。

答案 5 :(得分:0)

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附近选择一个点,而不是在// TODO: complete program console.log(calculate(4, "+", 6)); // Must show 10 console.log(calculate(4, "-", 6)); // Must show -2 console.log(calculate(2, "*", 0)); // Must show 0 console.log(calculate(12, "/", 0)); // Must show Infinity 附近选择一个点(这次你不要不需要检查随机点是否在多边形内。