Voronoi细胞体积(python)

Chr*_*s H 7 voronoi scipy python-2.7 qhull

我在Python 2.7中使用Scipy 0.13.0来计算3d中的一组Voronoi单元.我需要获得每个单元的体积以(de)加权专有模拟的输出.有没有简单的方法这样做 - 当然这是一个常见的问题或Voronoi细胞的常见用途,但我找不到任何东西.运行以下代码,并转储scipy.spatial.Voronoi手册所知道的所有内容.

from scipy.spatial import Voronoi
x=[0,1,0,1,0,1,0,1,0,1]
y=[0,0,1,1,2,2,3,3.5,4,4.5]
z=[0,0,0,0,0,1,1,1,1,1]
points=zip(x,y,z)
print points
vor=Voronoi(points)
print vor.regions
print vor.vertices
print vor.ridge_points
print vor.ridge_vertices
print vor.points
print vor.point_region
Run Code Online (Sandbox Code Playgroud)

ybe*_*kov 6

如评论中所述,您可以计算每个Voronoi单元的ConvexHull。由于Voronoi细胞是凸的,您将获得适当的体积。

def voronoi_volumes(points):
    v = Voronoi(points)
    vol = np.zeros(v.npoints)
    for i, reg_num in enumerate(v.point_region):
        indices = v.regions[reg_num]
        if -1 in indices: # some regions can be opened
            vol[i] = np.inf
        else:
            vol[i] = ConvexHull(v.vertices[indices]).volume
    return vol
Run Code Online (Sandbox Code Playgroud)

此方法适用于任何尺寸


Chr*_*s H 5

我已经破解了它。我的方法如下:

  • 对于 Voronoi 图的每个区域
  • 对区域的顶点执行 Delaunay 三角剖分
    • 这将返回一组填充该区域的不规则四面体
  • 四面体的体积可以轻松计算(维基百科)
    • 将这些体积相加即可得到该区域的体积。

我确信会有错误和糟糕的编码 - 我将寻找前者,欢迎对后者发表评论 - 特别是因为我对 Python 还很陌生。我仍在检查一些事情 - 有时给出 -1 的顶点索引,根据 scipy 手册“指示 Voronoi 图之外的顶点”,此外,生成的顶点的坐标远远超出原始数据(插入numpy.random.seed(42)并检查点7的区域坐标,它们转到~(7,-14,6),点49类似。所以我需要弄清楚为什么有时会发生这种情况,有时我得到索引-1。

from scipy.spatial import Voronoi,Delaunay
import numpy as np
import matplotlib.pyplot as plt

def tetravol(a,b,c,d):
 '''Calculates the volume of a tetrahedron, given vertices a,b,c and d (triplets)'''
 tetravol=abs(np.dot((a-d),np.cross((b-d),(c-d))))/6
 return tetravol

def vol(vor,p):
 '''Calculate volume of 3d Voronoi cell based on point p. Voronoi diagram is passed in v.'''
 dpoints=[]
 vol=0
 for v in vor.regions[vor.point_region[p]]:
  dpoints.append(list(vor.vertices[v]))
 tri=Delaunay(np.array(dpoints))
 for simplex in tri.simplices:
  vol+=tetravol(np.array(dpoints[simplex[0]]),np.array(dpoints[simplex[1]]),np.array(dpoints[simplex[2]]),np.array(dpoints[simplex[3]]))
 return vol

x= [np.random.random() for i in xrange(50)]
y= [np.random.random() for i in xrange(50)]
z= [np.random.random() for i in xrange(50)]
dpoints=[]
points=zip(x,y,z)
vor=Voronoi(points)
vtot=0


for i,p in enumerate(vor.points):
 out=False
 for v in vor.regions[vor.point_region[i]]:
  if v<=-1: #a point index of -1 is returned if the vertex is outside the Vornoi diagram, in this application these should be ignorable edge-cases
   out=True
  else:
 if not out:
  pvol=vol(vor,i)
  vtot+=pvol
  print "point "+str(i)+" with coordinates "+str(p)+" has volume "+str(pvol)

print "total volume= "+str(vtot)

#oddly, some vertices outside the boundary of the original data are returned, meaning that the total volume can be greater than the volume of the original.
Run Code Online (Sandbox Code Playgroud)