gpt4 book ai didi

algorithm - 对具有凹域的一组点进行三角剖分

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:37:41 54 4
gpt4 key购买 nike

设置

给定凸包内的一组节点,假设域包含一个或多个凹区域:

point distribution with concave areas

其中蓝点表示点,黑线表示域。假设点被保存为长度为 n 的二维数组 points,其中 n 是点对的数量。

然后让我们使用 scipy.spatial 中的 Delaunay 方法对这些点进行三角测量:

triangulation within domain

如您所见,人们可能会体验到跨越域的三角形的创建。

问题

什么是删除跨越域外的任何三角形的好算法方法?理想情况下但不一定,单纯形边缘仍然保留域形状(即,没有删除三角形的主要间隙)。


由于我的问题似乎继续得到相当多的事件,我想跟进我当前使用的应用程序。

假设您定义了边界,您可以使用 ray casting algorithm以确定多边形是否在域内。

为此:

  1. 取每个多边形的质心为C_i = (x_i,y_i)
  2. 然后,想象一条线 L = [C_i,(+inf,y_i)]:也就是说,一条线向东跨越您域的末端。
  3. 对于边界 S 中的每个边界段 s_i,检查与 L 的交点。如果是,将 +1 添加到内部计数器 intersection_count;否则,什么都不加。
  4. 计算完 Ls_i for i=1..N 之间的所有交点数后:

    if intersection_count % 2 == 0:
    return True # triangle outside convex hull
    else:
    return False # triangle inside convex hull

如果您的边界未明确定义,我发现将形状“映射”到 bool 数组并使用 neighbor tracing algorithm 会很有帮助来定义它。请注意,此方法假定一个实体域,您将需要对其中有“漏洞”的域使用更复杂的算法。

最佳答案

这里有一些 Python 代码可以满足您的需求。

首先,构建 alpha 形状(参见 my previous answer ):

def alpha_shape(points, alpha, only_outer=True):
"""
Compute the alpha shape (concave hull) of a set of points.
:param points: np.array of shape (n,2) points.
:param alpha: alpha value.
:param only_outer: boolean value to specify if we keep only the outer border or also inner edges.
:return: set of (i,j) pairs representing edges of the alpha-shape. (i,j) are the indices in the points array.
"""
assert points.shape[0] > 3, "Need at least four points"

def add_edge(edges, i, j):
"""
Add a line between the i-th and j-th points,
if not in the list already
"""
if (i, j) in edges or (j, i) in edges:
# already added
assert (j, i) in edges, "Can't go twice over same directed edge right?"
if only_outer:
# if both neighboring triangles are in shape, it's not a boundary edge
edges.remove((j, i))
return
edges.add((i, j))

tri = Delaunay(points)
edges = set()
# Loop over triangles:
# ia, ib, ic = indices of corner points of the triangle
for ia, ib, ic in tri.vertices:
pa = points[ia]
pb = points[ib]
pc = points[ic]
# Computing radius of triangle circumcircle
# www.mathalino.com/reviewer/derivation-of-formulas/derivation-of-formula-for-radius-of-circumcircle
a = np.sqrt((pa[0] - pb[0]) ** 2 + (pa[1] - pb[1]) ** 2)
b = np.sqrt((pb[0] - pc[0]) ** 2 + (pb[1] - pc[1]) ** 2)
c = np.sqrt((pc[0] - pa[0]) ** 2 + (pc[1] - pa[1]) ** 2)
s = (a + b + c) / 2.0
area = np.sqrt(s * (s - a) * (s - b) * (s - c))
circum_r = a * b * c / (4.0 * area)
if circum_r < alpha:
add_edge(edges, ia, ib)
add_edge(edges, ib, ic)
add_edge(edges, ic, ia)
return edges

要计算 alpha 形状外边界的边缘,请使用以下示例调用:

edges = alpha_shape(points, alpha=alpha_value, only_outer=True)

现在,在计算出 points 的 alpha 形状外边界的 edges 之后,以下函数将确定点 (x ,y) 在外边界内。

def is_inside(x, y, points, edges, eps=1.0e-10):
intersection_counter = 0
for i, j in edges:
assert abs((points[i,1]-y)*(points[j,1]-y)) > eps, 'Need to handle these end cases separately'
y_in_edge_domain = ((points[i,1]-y)*(points[j,1]-y) < 0)
if y_in_edge_domain:
upper_ind, lower_ind = (i,j) if (points[i,1]-y) > 0 else (j,i)
upper_x = points[upper_ind, 0]
upper_y = points[upper_ind, 1]
lower_x = points[lower_ind, 0]
lower_y = points[lower_ind, 1]

# is_left_turn predicate is evaluated with: sign(cross_product(upper-lower, p-lower))
cross_prod = (upper_x - lower_x)*(y-lower_y) - (upper_y - lower_y)*(x-lower_x)
assert abs(cross_prod) > eps, 'Need to handle these end cases separately'
point_is_left_of_segment = (cross_prod > 0.0)
if point_is_left_of_segment:
intersection_counter = intersection_counter + 1
return (intersection_counter % 2) != 0

enter image description here

在上图中显示的输入(取 self 之前的 answer )调用 is_inside(1.5, 0.0, points, edges) 将返回 True,而 is_inside(1.5, 3.0, points, edges) 将返回 False

请注意,上面的 is_inside 函数不处理退化情况。我添加了两个断言来检测此类情况(您可以定义适合您的应用程序的任何 epsilon 值)。在许多应用程序中,这就足够了,但如果没有,并且您遇到了这些最​​终情况,则需要单独处理它们。参见,例如,here实现几何算法时的稳健性和精度问题。

关于algorithm - 对具有凹域的一组点进行三角剖分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45226931/

54 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com