给定一组点,
points = np.random.randn(...) # n 3d points
我希望能将一个由一组三维点列表(形如nx3
的np.array)定义的凸包体积均匀填充。
我可以通过以下方式获取凸包:
hull = scipy.spatial.ConvexHull(points)
如何以最快的方式获取一个点列表,使这些点均匀地填充该凸壳的体积?
给定一组点,
points = np.random.randn(...) # n 3d points
我希望能将一个由一组三维点列表(形如nx3
的np.array)定义的凸包体积均匀填充。
我可以通过以下方式获取凸包:
hull = scipy.spatial.ConvexHull(points)
如何以最快的方式获取一个点列表,使这些点均匀地填充该凸壳的体积?
Find delaunay simplices of the hull
randomly sample the simplices based on their area
for each simplex, find uniform distribution of sampled points using dirichelet
distribution
multiply the distributions with the simplices to find final points.
import numpy as np
from numpy.linalg import det
from scipy.stats import dirichlet
def dist_in_hull(points, n):
dims = points.shape[-1]
hull = points[ConvexHull(points).vertices]
deln = hull[Delaunay(hull).simplices]
vols = np.abs(det(deln[:, :dims, :] - deln[:, dims:, :])) / np.math.factorial(dims)
sample = np.random.choice(len(vols), size = n, p = vols / vols.sum())
return np.einsum('ijk, ij -> ik', deln[sample], dirichlet.rvs([1]*(dims + 1), size = n))
编辑:功能化并扩展到更高的维度(警告:ConvexHull
仅适用于9D以下)
如果有人需要帮助,这里是实现Yves答案的代码:
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import ConvexHull
from matplotlib.patches import Rectangle
from matplotlib.path import Path
#Initial positions
pos = np.random.uniform(-30, 10, (20, 2))
#Convex hull of initial positions
hull = ConvexHull( pos )
#Bounding box
bbox = [hull.min_bound, hull.max_bound]
#Hull path
hull_path = Path( hull.points[hull.vertices] )
#Draw n random points inside the convex hull
n = 10**3
rand_points = np.empty((n, 2))
for i in range(n):
#Draw a random point in the bounding box of the convex hull
rand_points[i] = np.array([np.random.uniform(bbox[0][0], bbox[1][0]), np.random.uniform(bbox[0][1], bbox[1][1])])
#We check if the random point is inside the convex hull, otherwise we draw it again
while hull_path.contains_point(rand_points[i]) == False:
rand_points[i] = np.array([np.random.uniform(bbox[0][0], bbox[1][0]), np.random.uniform(bbox[0][1], bbox[1][1])])
#Plot
plt.scatter(pos[:, 0],pos[:, 1], marker='o', c='blue', alpha = 1, label ='Initial points')
for simplex in hull.simplices:
plt.plot(hull.points[simplex, 0], hull.points[simplex, 1], '-k')
plt.gca().add_patch(Rectangle((bbox[0][0], bbox[0][1]), bbox[1][0] - bbox[0][0], bbox[1][1] - bbox[0][1],facecolor = 'None', edgecolor = 'cyan'))
plt.scatter(rand_points[:, 0],rand_points[:, 1], marker='o', c='red', alpha = 0.31, label ='Random points inside hull')
plt.legend()
plt.savefig("fig.png", dpi = 300)