我这里有一些Python代码,可以实现你想要的功能。
首先,构建alpha形状(参见我的上一个答案):
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:
assert (j, i) in edges, "Can't go twice over same directed edge right?"
if only_outer:
edges.remove((j, i))
return
edges.add((i, j))
tri = Delaunay(points)
edges = set()
for ia, ib, ic in tri.vertices:
pa = points[ia]
pb = points[ib]
pc = points[ic]
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)
现在,在计算了点集的alpha形状的外边界的边缘之后,以下函数将确定一个点(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]
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](https://istack.dev59.com/CHCxN.webp)
在上图所示的输入中(摘自我之前的
答案),调用
is_inside(1.5, 0.0, points, edges)
将返回
True
,而
is_inside(1.5, 3.0, points, edges)
将返回
False
。
请注意,上面的
is_inside
函数不处理退化情况。我添加了两个断言来检测这种情况(您可以定义适合您应用程序的任何epsilon值)。在许多应用程序中,这已经足够了,但如果没有遇到这些边缘情况,它们需要单独处理。
例如,请参见
此处有关实现几何算法时鲁棒性和精度问题的信息。
polygon
包中的算法。 - Prune