如何使用 scipy 的 Delaunay 找到两个不同集合中点的 Delaunay 邻居?
How to find the Delaunay neighbours of points in two different sets using scipy's Delaunay?
见https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.Delaunay.html
考虑两组点。对于 X_ 中的每个点,我想在“点”中找到最近的 delaunay 邻居。我认为一种缓慢的方法是形成 points
的 Delaunay 三角剖分加上 X_
中的一个点,然后以某种方式进行邻居查找。使用 scipy(或其他工具)是否有更有效的方法?
from pylab import *
from scipy.spatial import Delaunay
np.random.seed(1)
points = np.random.randn(10, 2)
X_ = np.random.randn(4, 2)
tri = Delaunay(points, incremental=True)
plt.triplot(points[:,0], points[:,1], tri.simplices, alpha=0.5)
plot(X_[:, 0], X_[:, 1], 'ro', alpha=0.5)
for i, (x, y) in enumerate(points):
text(x, y, i)
for i, (x, y) in enumerate(X_):
text(x, y, i, color='g')
tri.points, tri.points.shape
理想情况下,最简单的解决方案可能如下所示:
Generate the Delaunay triangulation of "points"
For each point X in X_
Add point X to the triangulation
Get the neighbors of X in the augmented triangulation
Remove point X from triangulation
使用 scipy.spatial.Delaunay
,您可以 incrementally add points 进行三角测量,但这不是删除它们的机制。所以这种方法不能直接应用。
我们可以避免将新点实际添加到三角剖分中,而只是确定它将连接到哪些点而不实际更改三角剖分。基本上,我们需要识别 Bowyer-Watson algorithm 中的空腔并收集空腔中三角形的顶点。如果建议的点位于其外接圆内,则 Delaunay 三角形是空腔的一部分。这可以从包含点的三角形开始增量/局部构建,然后只测试相邻的三角形。
此处是执行此算法的代码(针对单个测试点)。
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
num_tri_points = 50
rng = np.random.default_rng(1)
# points in the Delaunay triangulation
points = rng.random((num_tri_points, 2))
# test point for identifying neighbors in the combined triangulation
X = rng.random((1, 2))*.8 + .1
tri = Delaunay(points)
# determine if point lies in the circumcircle of simplex of Delaunay triangulation tri...
# note: this code is not robust to numerical errors and could be improved with exact predicates
def in_circumcircle(tri, simplex, point):
coords = tri.points[tri.simplices[simplex]]
ax = coords[0][0]
ay = coords[0][1]
bx = coords[1][0]
by = coords[1][1]
cx = coords[2][0]
cy = coords[2][1]
d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by))
ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d
uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d
rad_sq = (ax-ux)*(ax-ux)+(ay-uy)*(ay-uy)
point_dist_sq = (point[0]-ux)*(point[0]-ux)+(point[1]-uy)*(point[1]-uy)
return point_dist_sq < rad_sq
# find the triangle containing point X
starting_tri = tri.find_simplex(X)
# remember triangles that have been tested so we don't repeat
tris_tested = set()
# collect the set of neighboring vertices in the potential combined triangulation
neighbor_vertices = set()
# queue triangles for performing the incircle check
tris_to_process = [ starting_tri[0] ]
while len(tris_to_process):
# get the next triangle
tri_to_process = tris_to_process.pop()
# remember that we have checked this triangle
tris_tested.add(tri_to_process)
# is the proposed point inside the circumcircle of the triangle
if in_circumcircle(tri, tri_to_process, X[0,:]):
# if so, add the vertices of this triangle as neighbors in the combined triangulation
neighbor_vertices.update(tri.simplices[tri_to_process].flatten())
# queue the neighboring triangles for processing
for nbr in tri.neighbors[tri_to_process]:
if nbr not in tris_tested:
tris_to_process.append(nbr)
# plot the results
plt.triplot(points[:,0], points[:,1], tri.simplices, alpha=0.7)
plt.plot(X[0, 0], X[0, 1], 'ro', alpha=0.5)
plt.plot(tri.points[list(neighbor_vertices)][:,0], tri.points[list(neighbor_vertices)][:,1], 'bo', alpha=0.7)
plt.show()
运行 代码给出了以下图,其中包含原始三角剖分、测试点(红色)和已识别的相邻顶点(蓝色)。
见https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.Delaunay.html
考虑两组点。对于 X_ 中的每个点,我想在“点”中找到最近的 delaunay 邻居。我认为一种缓慢的方法是形成 points
的 Delaunay 三角剖分加上 X_
中的一个点,然后以某种方式进行邻居查找。使用 scipy(或其他工具)是否有更有效的方法?
from pylab import *
from scipy.spatial import Delaunay
np.random.seed(1)
points = np.random.randn(10, 2)
X_ = np.random.randn(4, 2)
tri = Delaunay(points, incremental=True)
plt.triplot(points[:,0], points[:,1], tri.simplices, alpha=0.5)
plot(X_[:, 0], X_[:, 1], 'ro', alpha=0.5)
for i, (x, y) in enumerate(points):
text(x, y, i)
for i, (x, y) in enumerate(X_):
text(x, y, i, color='g')
tri.points, tri.points.shape
理想情况下,最简单的解决方案可能如下所示:
Generate the Delaunay triangulation of "points"
For each point X in X_
Add point X to the triangulation
Get the neighbors of X in the augmented triangulation
Remove point X from triangulation
使用 scipy.spatial.Delaunay
,您可以 incrementally add points 进行三角测量,但这不是删除它们的机制。所以这种方法不能直接应用。
我们可以避免将新点实际添加到三角剖分中,而只是确定它将连接到哪些点而不实际更改三角剖分。基本上,我们需要识别 Bowyer-Watson algorithm 中的空腔并收集空腔中三角形的顶点。如果建议的点位于其外接圆内,则 Delaunay 三角形是空腔的一部分。这可以从包含点的三角形开始增量/局部构建,然后只测试相邻的三角形。
此处是执行此算法的代码(针对单个测试点)。
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
num_tri_points = 50
rng = np.random.default_rng(1)
# points in the Delaunay triangulation
points = rng.random((num_tri_points, 2))
# test point for identifying neighbors in the combined triangulation
X = rng.random((1, 2))*.8 + .1
tri = Delaunay(points)
# determine if point lies in the circumcircle of simplex of Delaunay triangulation tri...
# note: this code is not robust to numerical errors and could be improved with exact predicates
def in_circumcircle(tri, simplex, point):
coords = tri.points[tri.simplices[simplex]]
ax = coords[0][0]
ay = coords[0][1]
bx = coords[1][0]
by = coords[1][1]
cx = coords[2][0]
cy = coords[2][1]
d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by))
ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d
uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d
rad_sq = (ax-ux)*(ax-ux)+(ay-uy)*(ay-uy)
point_dist_sq = (point[0]-ux)*(point[0]-ux)+(point[1]-uy)*(point[1]-uy)
return point_dist_sq < rad_sq
# find the triangle containing point X
starting_tri = tri.find_simplex(X)
# remember triangles that have been tested so we don't repeat
tris_tested = set()
# collect the set of neighboring vertices in the potential combined triangulation
neighbor_vertices = set()
# queue triangles for performing the incircle check
tris_to_process = [ starting_tri[0] ]
while len(tris_to_process):
# get the next triangle
tri_to_process = tris_to_process.pop()
# remember that we have checked this triangle
tris_tested.add(tri_to_process)
# is the proposed point inside the circumcircle of the triangle
if in_circumcircle(tri, tri_to_process, X[0,:]):
# if so, add the vertices of this triangle as neighbors in the combined triangulation
neighbor_vertices.update(tri.simplices[tri_to_process].flatten())
# queue the neighboring triangles for processing
for nbr in tri.neighbors[tri_to_process]:
if nbr not in tris_tested:
tris_to_process.append(nbr)
# plot the results
plt.triplot(points[:,0], points[:,1], tri.simplices, alpha=0.7)
plt.plot(X[0, 0], X[0, 1], 'ro', alpha=0.5)
plt.plot(tri.points[list(neighbor_vertices)][:,0], tri.points[list(neighbor_vertices)][:,1], 'bo', alpha=0.7)
plt.show()
运行 代码给出了以下图,其中包含原始三角剖分、测试点(红色)和已识别的相邻顶点(蓝色)。