非凸多边形内最大的圆

发布于 2024-10-04 01:57:57 字数 66 浏览 2 评论 0 原文

如何找到可以容纳在凹多边形内的最大圆?

只要能够实时处理具有约 50 个顶点的多边形,暴力算法就可以。

How can I find the largest circle that can fit inside a concave polygon?

A brute force algorithm is OK as long as it can handle polygons with ~50 vertices in real-time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

乜一 2024-10-11 01:57:57

解决这个问题的关键是首先进行观察:适合任意多边形的最大圆的中心是以下点:

  1. 在多边形内; 。
  2. 距离多边形边缘上的任意点最远

为什么?因为圆的边缘上的每个点到圆心的距离都相等。根据定义,最大的圆将具有最大的半径,并且至少在两个点上接触多边形,因此如果您找到距离多边形最远的点,您就找到了圆的中心。

这个问题出现在地理学中,并且可以以任意精度迭代解决。它被称为“难以到达的极点”问题。请参阅难以到达的极点:地球上最偏远地点的计算算法

基本算法的工作原理如下:

  1. 将 R 定义为从 (xmin,ymin) 到 (xmax,y 的直线区域>最大);
  2. 将 R 分成任意数量的点。论文使用 21 作为启发式(意味着高度和宽度除以 20);
  3. 裁剪多边形外部的任何点;
  4. 对于余数,找到距离边缘上任意点最远的点;
  5. 从那时起,定义一个具有较小间隔和界限的新 R,并重复步骤 2 以获得任意精度答案。论文将 R 减小了 2 的平方根。

需要注意的是,如何测试一个点是否在多边形内部:这部分问题的最简单解决方案是将一条射线投射到该点的右侧。如果它穿过奇数条边,则它在多边形内。如果是偶数,则在外面。

此外,就测试到任何边的距离而言,您需要考虑两种情况:

  1. 该点垂直于该边上的点(在两个顶点的边界内);或者
  2. 它不是。

(2)很容易。到边缘的距离是到两个顶点的距离中的最小值。对于 (1),该边缘上最近的点将是从您正在测试的点开始与边缘以 90 度角相交的点。请参阅点到射线或线段的距离

The key to solving this problem is first making an observation: the center of the largest circle that will fit inside an arbitrary polygon is the point that is:

  1. Inside the polygon; and
  2. Furthest from any point on the edges of the polygon.

Why? Because every point on the edge of a circle is equidistant from that center. By definition, the largest circle will have the largest radius and will touch the polygon on at least two points so if you find the point inside furthest from the polygon you've found the center of the circle.

This problem appears in geography and is solved iteratively to any arbitrary precision. Its called the Poles of Inaccessibility problem. See Poles of Inaccessibility: A Calculation Algorithm for the Remotest Places on Earth.

The basic algorithm works like this:

  1. Define R as a rectilinear region from (xmin,ymin) to (xmax,ymax);
  2. Divide R into an arbitrary number of points. The paper uses 21 as a heuristic (meaning divide the height and width by 20);
  3. Clip any points that are outside the polygon;
  4. For the remainder find the point that is furthest from any point on the edge;
  5. From that point define a new R with smaller intervals and bounds and repeat from step 2 to get to any arbitrary precision answer. The paper reduces R by a factor of the square root of 2.

One note, How to test if a point is inside the polygon or not: The simplest solution to this part of the problem is to cast a ray to the right of the point. If it crosses an odd number of edges, it's within the polygon. If it's an even number, it's outside.

Also, as far as testing the distance to any edge there are two cases you need to consider:

  1. The point is perpendicular to a point on that edge (within the bounds of the two vertices); or
  2. It isn't.

(2) is easy. The distance to the edge is the minimum of the distances to the two vertices. For (1), the closest point on that edge will be the point that intersects the edge at a 90 degree angle starting from the point you're testing. See Distance of a Point to a Ray or Segment.

幻梦 2024-10-11 01:57:57

如果有人正在寻找实际的实现,我设计了一种更快的算法,可以在给定的精度下解决这个问题,并将其作为一个 JavaScript 库。它类似于@cletus描述的迭代网格算法,但它保证获得全局最优,并且在实践中也快了20-40倍。

看看: https://github.com/mapbox/polylabel

In case anyone is looking for a practical implementation, I designed a faster algorithm that solves this problem for a given precision and made it a JavaScript library. It's similar to the iterative grid algorithm described by @cletus, but it's guaranteed to obtain global optimum, and is also 20-40 times faster in practice.

Check it out: https://github.com/mapbox/polylabel

记忆里有你的影子 2024-10-11 01:57:57

摘要:理论上,这可以在 O(n) 时间内完成。实际上,您可以在 O(n log n) 时间内完成。

广义 Voronoi 图。

如果您将多边形的顶点和边视为一组位点,并将内部细分为“最近邻单元”,那么您将得到所谓的(广义)Voronoi 图。 Voronoi 图由节点和连接节点的边组成。节点的间隙是到其定义的多边形面的距离。

多边形的沃罗诺伊图
(这里的多边形即使有孔,原理仍然有效。)

现在的关键观察是最大内切圆的中心接触多边形的三个面(顶点或边),并且没有其他面可以更接近。因此中心必须位于 Voronoi 节点上,即间隙最大的节点。

在上面的示例中,标记最大内切圆中心的节点接触多边形的两条边和一个顶点。

顺便说一句,中轴是 Voronoi 图,其中删除了从反射顶点发出的 Voronoi 边。因此,最大内接圆的中心也位于中轴上。

来源:我的一篇博客文章,涉及概括某点的最大内切圆。在那里您可以找到有关 Voronoi 图及其与最大内切圆的关系的更多信息。

算法与

您实际上可以计算 Voronoi 图。 Fortune 给出了点和线段的最坏情况 O(n log n) 算法,Voronoi 图的扫描线算法,SoCG'86。 Held 发布了软件包 Vroni,预期为 O (n log n) 时间复杂度,实际上也计算最大内切圆。 boost 中似乎有一个实现, 也。

对于简单多边形(即没有孔),Chin 等人提出了一种在 O(n) 时间内运行的时间最优算法,在线性时间内查找简单多边形的中轴,1999。

蛮力。

但是,正如您所说,您是使用暴力算法就可以了:简单地尝试所有三元组(顶点和边)怎么样?对于每个三元组,您找到候选 Voronoi 节点,即到三个位点的等距位点,并检查是否有任何其他位点与候选最大内切圆相交。如果存在交叉点,您将解雇该候选人。从所有三胞胎中找出最大的一个。

请参阅我的硕士论文中的第 3 章,了解有关计算等距位点的更多详细信息三个站点。

Summary: In theory, this can be done in O(n) time. In practice you can do it in O(n log n) time.

Generalized Voronoi diagrams.

If you consider the vertices and edges of the polygon as a set of sites and tessellate the interior into the "nearest neighbor cells" then you get the so-called (generalized) Voronoi diagram. The Voronoi diagram consists of nodes and edges connecting them. The clearance of a node is the distance to its defining polygon faces.

Voronoi diagram of a polygon
(Here the polygon even has holes; the principle still works.)

The key observation now is that the center of the maximum inscribed circle touches three faces (vertices or edges) of the polygon, and no other face can be closer. So the center has to lie on a Voronoi node, i.e, the node with the largest clearance.

In the example above the node that marks the center of the maximum inscribed circle touches two edges and a vertex of the polygon.

The medial axis, by the way, is the Voronoi diagram with those Voronoi edges removed that emanate from reflex vertices. Hence, the center of the maximum inscribed circle also lies on the medial axis.

Source: A blog article of mine that deals with generalizations of maximum inscribed circles at some point. There you can find more on Voronoi diagrams and their relation to maximum inscribed circles.

Algorithms & implementations.

You could actually compute the Voronoi diagram. A worst-case O(n log n) algorithm for points and segments is given by Fortune, A sweepline algorithm for Voronoi diagrams, SoCG'86. Held published the software package Vroni with an expected O(n log n) time complexity, which actually computes the maximum inscribed circle, too. And there seems to be an implementation in boost, too.

For simple polygons (i.e., without holes) a time-optimal algorithm that runs in O(n) time is due to Chin et al., Finding the Medial Axis of a Simple Polygon in Linear Time, 1999.

Brute force.

However, as you stated that you are fine with a brute-force algorithm: What about simply trying out all triplets of sites (vertices and edges). For each triplet you find candidate Voronoi nodes, i.e., equidistant loci to the three sites and check whether any other site would intersect the candidate maximum inscribed circle. If there is an intersection you dismiss the candidate. Take the greatest you can find over all triplets.

See chapter 3 in my Master thesis about more details on computing equidistant loci for three sites.

我很坚强 2024-10-11 01:57:57

O(n log(n)) 算法:

  1. 构造 P 中边的 Voronoi 图。例如,这可以通过 Fortunes 算法 来完成。
  2. 对于 P 内的 Voronoi 节点(与三个或更多边等距的点);
  3. 找到 P 中到边的距离最大的节点。该节点是最大内切圆的圆心。

An O(n log(n)) algorithm:

  1. Construct the Voronoi Diagram of the edges in P. This can be done with, for example, Fortunes algorithm.
  2. For Voronoi nodes (points equidistant to three or more edges) inside P;
  3. Find the node with the maximum distance to edges in P. This node is the centre of the maximum inscribed circle.
寄与心 2024-10-11 01:57:57

我实现了一段基于cv2的python代码,以获取掩模/多边形/轮廓内的最大/最大内切圆。它支持非凸/空心形状。

import cv2
import numpy as np
def get_test_mask():
    # Create an image
    r = 100
    mask = np.zeros((4 * r, 4 * r), dtype=np.uint8)

    # Create a sequence of points to make a contour
    vert = [None] * 6
    vert[0] = (3 * r // 2, int(1.34 * r))
    vert[1] = (1 * r, 2 * r)
    vert[2] = (3 * r // 2, int(2.866 * r))
    vert[3] = (5 * r // 2, int(2.866 * r))
    vert[4] = (3 * r, 2 * r)
    vert[5] = (5 * r // 2, int(1.34 * r))
    # Draw it in mask
    for i in range(6):
        cv2.line(mask, vert[i], vert[(i + 1) % 6], (255), 63)
    return mask


mask = get_test_mask()

"""
Get the maximum/largest inscribed circle inside mask/polygon/contours.
Support non-convex/hollow shape
"""
dist_map = cv2.distanceTransform(mask, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
_, radius, _, center = cv2.minMaxLoc(dist_map)

result = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
cv2.circle(result, tuple(center), int(radius), (0, 0, 255), 2, cv2.LINE_8, 0)

# minEnclosingCircle directly by cv2
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
center2, radius2 = cv2.minEnclosingCircle(np.concatenate(contours, 0))
cv2.circle(result, (int(center2[0]), int(center2[1])), int(radius2), (0, 255, 0,), 2)

cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)

输入图片此处描述
红色圆圈是最大内切圆

来源:https://gist.github.com/DIYer22/f82dc329b27c2766b21bec4a563703cc

I implemented a piece of python code based on cv2 to get the maximum/largest inscribed circle inside mask/polygon/contours. It supports non-convex/hollow shape.

import cv2
import numpy as np
def get_test_mask():
    # Create an image
    r = 100
    mask = np.zeros((4 * r, 4 * r), dtype=np.uint8)

    # Create a sequence of points to make a contour
    vert = [None] * 6
    vert[0] = (3 * r // 2, int(1.34 * r))
    vert[1] = (1 * r, 2 * r)
    vert[2] = (3 * r // 2, int(2.866 * r))
    vert[3] = (5 * r // 2, int(2.866 * r))
    vert[4] = (3 * r, 2 * r)
    vert[5] = (5 * r // 2, int(1.34 * r))
    # Draw it in mask
    for i in range(6):
        cv2.line(mask, vert[i], vert[(i + 1) % 6], (255), 63)
    return mask


mask = get_test_mask()

"""
Get the maximum/largest inscribed circle inside mask/polygon/contours.
Support non-convex/hollow shape
"""
dist_map = cv2.distanceTransform(mask, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
_, radius, _, center = cv2.minMaxLoc(dist_map)

result = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
cv2.circle(result, tuple(center), int(radius), (0, 0, 255), 2, cv2.LINE_8, 0)

# minEnclosingCircle directly by cv2
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
center2, radius2 = cv2.minEnclosingCircle(np.concatenate(contours, 0))
cv2.circle(result, (int(center2[0]), int(center2[1])), int(radius2), (0, 255, 0,), 2)

cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)

enter image description here
Red circle is max inscribed circle

Source: https://gist.github.com/DIYer22/f82dc329b27c2766b21bec4a563703cc

岁月流歌 2024-10-11 01:57:57

我使用直骨架将图像放置在多边形内,分三个步骤:

  1. 使用直骨架算法找到直骨架(图​​ 1)
  2. 在直骨架的基础上,找到最大的圆(图 2)
  3. 在该圆内绘制图像(图 2 ) 3)

尝试一下:https://smartdiagram.com/simple-infographics-3d -charts-2/

使用直骨架算法找到直骨架
基于直骨架,找到最大的圆
绘制该圆圈内的图像

I used Straight Skeletons to place an image inside a polygon with three steps:

  1. Find the straight skeleton using the Straight Skeleton algorithm (pic 1)
  2. Base on the straight skeleton, find the largest circle (pic 2)
  3. Draw the image inside that circle (pic 3)

Try it at: https://smartdiagram.com/simple-infographics-3d-charts-2/

Find the straight skeleton using the Straight Skeleton algorithm
Base on the straight skeleton, find the largest circle
Draw the image inside that circle

默嘫て 2024-10-11 01:57:57

O(n log X) 算法,其中 X 取决于您想要的精度。

对圆的最大半径 R 进行二分搜索:

在每次迭代中,对于给定的半径 r,将每条边 E“向内”推 R,以获得 E'。对于每条边 E',将半平面 H 定义为多边形“内部”的所有点的集合(使用 E' 作为边界)。现在,计算所有这些半平面 E' 的交集,这可以在 O(n) 时间内完成。如果交点非空,那么如果以交点中的任意点为圆心绘制半径为 r 的圆,则该圆将位于给定多边形内。

An O(n log X) algorithm, where X depends on the precision you want.

Binary search for largest radius R for a circle:

At each iteration, for a given radius r, push each edge E, "inward" by R, to get E'. For each edge E', define half-plane H as the set of all points "inside" the the polygon (using E' as the boundary). Now, compute the intersection of all these half-planes E', which could be done in O(n) time. If the intersection is non-empty, then if you draw a circle with radius r using any point in the intersection as the center, it will be inside the given polygon.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文