Python Voronoi-计算每个区域的精确边界

Python Voronoi-计算每个区域的精确边界,python,numpy,computational-geometry,voronoi,Python,Numpy,Computational Geometry,Voronoi,我试图使用scipy.spatial.Voronoi计算Voronoi图中每个区域的精确边界,当所有点都位于预定义多边形内时 例如,使用文档中的示例 如果我需要用相同的点计算Voroni,但是在一个有以下边界的矩形内,该怎么办 global_boundaries = np.array([[-2, -2], [4, -2], [4, 4], [-2, 4], [-2, -2]]) 我需要计算每个voronoi区域的精确边界,像这样 voronoi_region_1_boundaries = [

我试图使用scipy.spatial.Voronoi计算Voronoi图中每个区域的精确边界,当所有点都位于预定义多边形内时

例如,使用文档中的示例

如果我需要用相同的点计算Voroni,但是在一个有以下边界的矩形内,该怎么办

global_boundaries = np.array([[-2, -2], [4, -2], [4, 4], [-2, 4], [-2, -2]])
我需要计算每个voronoi区域的精确边界,像这样

voronoi_region_1_boundaries = [[-2, -2], [0.5, -2], [0.5, 0.5], [-2, 0-5], [-2, -2]]
voronoi_region_2_boundaries = [[-2, 1.5], [0.5, 1.5], [0.5, 4], [-2, 4], [-2, 1.5]]
voronoi_region_3_boundaries = [[-2, 0.5], [0.5, 0.5], [0.5, 1.5], [-2, 1.5], [-2, 0.5]]
以此类推,适用于所有9个地区,而不是

vor.regions 
[[], [-1, 0], [-1, 1], [1, -1, 0], [3, -1, 2], [-1, 3], [-1, 2], [3, 2, 0, 1], [2, -1, 0], [3, -1, 1]]
如何计算无限脊的缺失端点

我已经尝试过修改这个代码

与这个问题有关

但它只适用于圆形边界。 考虑到半径,我修改了它,使我的区域完全在圆内,然后计算连接点和周长以及边界的线之间的交点。它是有效的,但只适用于第一个点,之后我得到了“GEOMETRYCOLLECTION EMPTY”

direction = np.sign(np.dot(midpoint - center, n)) * n
super_far_point = vor.vertices[v2] + direction * radius
line_0 = LineString([midpoint, super_far_point])
for i in range(0, len(map_boundaries)-1):
    i += 1
    line_i = LineString([(map_boundaries[i-1]), (map_boundaries[i])])
    if line_0.intersection(line_i) != 0:
        far_point = line_0.intersection(line_i)

new_region.append(len(new_vertices))
new_vertices.append(far_point.tolist())
有人解决过类似的问题吗


有人能帮忙吗?

我拿了
voronoi\u plot\u 2d
并修改了它。见下文

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi
from shapely.geometry import Polygon, Point

# Voronoi - Compute exact boundaries of every region


def angle_between(v0, v1):
    return np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1))


def calc_angle(c0, c1, c2):
    return angle_between(np.array(c1) - np.array(c0), np.array(c2) - np.array(c1))


def is_convex(polygon):
    temp_coords = np.array(polygon.exterior.coords)
    temp_coords = np.vstack([temp_coords, temp_coords[1, :]])

    for i, (c0, c1, c2) in enumerate(zip(temp_coords, temp_coords[1:], temp_coords[2:])):
        if i == 0:
            first_angle_crit = calc_angle(c0, c1, c2) > 0
        elif (calc_angle(c0, c1, c2) > 0) != first_angle_crit:
            return False
    return True


def infinite_segments(vor_):
    line_segments = []
    center = vor_.points.mean(axis=0)
    for pointidx, simplex in zip(vor_.ridge_points, vor_.ridge_vertices):
        simplex = np.asarray(simplex)
        if np.any(simplex < 0):
            i = simplex[simplex >= 0][0]  # finite end Voronoi vertex

            t = vor_.points[pointidx[1]] - vor_.points[pointidx[0]]  # tangent
            t /= np.linalg.norm(t)
            n = np.array([-t[1], t[0]])  # normal

            midpoint = vor_.points[pointidx].mean(axis=0)
            direction = np.sign(np.dot(midpoint - center, n)) * n

            line_segments.append([(vor_.vertices[i, 0], vor_.vertices[i, 1]),
                                  (direction[0], direction[1])])
    return line_segments


class NotConvexException(Exception):
    def __str__(self):
        return 'The Polygon is not Convex!!!'


class NotAllPointsAreInException(Exception):
    def __str__(self):
        return 'Not all points are in the polygon!!!'


def intersect(p0, u, q0, q1):
    v = (q1 - q0)[np.newaxis].T
    A = np.hstack([u, -v])
    b = q0 - p0
    try:
        inv_A = np.linalg.inv(A)
    except np.linalg.LinAlgError:
        return np.nan, np.nan
    return np.dot(inv_A, b)


def _adjust_bounds(ax__, points_):
    ptp_bound = points_.ptp(axis=0)
    ax__.set_xlim(points_[:, 0].min() - 0.1*ptp_bound[0], points_[:, 0].max() + 0.1*ptp_bound[0])
    ax__.set_ylim(points_[:, 1].min() - 0.1*ptp_bound[1], points_[:, 1].max() + 0.1*ptp_bound[1])


def in_polygon(polygon, points_):
    return [polygon.contains(Point(x)) for x in points_]


def voronoi_plot_2d_inside_convex_polygon(vor_, polygon, ax__=None, **kw):
    from matplotlib.collections import LineCollection

    if not all(in_polygon(polygon, vor_.points_)):
        raise NotAllPointsAreInException()

    if not is_convex(polygon):
        raise NotConvexException()

    if vor_.points.shape[1] != 2:
        raise ValueError("Voronoi diagram is not 2-D")

    vor_inside_ind = np.array([i for i, x in enumerate(vor_.vertices) if polygon.contains(Point(x))])
    vor_outside_ind = np.array([i for i, x in enumerate(vor_.vertices) if not polygon.contains(Point(x))])
    ax__.plot(vor_.points[:, 0], vor_.points[:, 1], '.')
    if kw.get('show_vertices', True):
        ax__.plot(vor_.vertices[vor_inside_ind, 0], vor_.vertices[vor_inside_ind, 1], 'o')

    temp_coords = np.array(polygon.exterior.coords)
    line_segments = []
    for t0, t1 in zip(temp_coords, temp_coords[1:]):
        line_segments.append([t0, t1])
    ax__.add_collection(LineCollection(line_segments, colors='b', linestyle='solid'))
    line_segments = []
    for simplex in vor_.ridge_vertices:
        simplex = np.asarray(simplex)
        if np.all(simplex >= 0):
            if not all(in_polygon(polygon, vor_.vertices[simplex])):
                continue
            line_segments.append([(x, y) for x, y in vor_.vertices[simplex]])

    ax__.add_collection(LineCollection(line_segments, colors='k', linestyle='solid'))

    line_segments = infinite_segments(vor_)
    from_inside = np.array([x for x in line_segments if polygon.contains(Point(x[0]))])

    line_segments = []

    for f in from_inside:
        for coord0, coord1 in zip(temp_coords, temp_coords[1:]):
            s, t = intersect(f[0], f[1][np.newaxis].T, coord0, coord1)
            if 0 < t < 1 and s > 0:
                line_segments.append([f[0], f[0] + s * f[1]])
                break

    ax__.add_collection(LineCollection(np.array(line_segments), colors='k', linestyle='dashed'))

    line_segments = []

    for v_o_ind in vor_outside_ind:
        for simplex in vor_.ridge_vertices:
            simplex = np.asarray(simplex)
            if np.any(simplex < 0):
                continue
            if np.any(simplex == v_o_ind):
                i = simplex[simplex != v_o_ind][0]
                for coord0, coord1 in zip(temp_coords, temp_coords[1:]):
                    s, t = intersect(
                        vor_.vertices[i],
                        (vor_.vertices[v_o_ind] - vor_.vertices[i])[np.newaxis].T,
                        coord0,
                        coord1
                    )
                    if 0 < t < 1 and 0 < s < 1:
                        line_segments.append([
                            vor_.vertices[i],
                            vor_.vertices[i] + s * (vor_.vertices[v_o_ind] - vor_.vertices[i])
                        ])
                        break

    ax__.add_collection(LineCollection(np.array(line_segments), colors='r', linestyle='dashed'))

    _adjust_bounds(ax__, temp_coords)

    return ax__.figure

points = np.array([[0.1, -0.4], [0, 1.5], [0, 2.25], [1, 0], [1, 1], [1, 2],
                   [2, 0], [2.5, 1], [2, 2], [2.3, 2.3], [-0.5, -1.3], [-1.5, 3]])

global_boundaries = Polygon([[-5, -2], [3.4, -2], [4.7, 4], [2.7, 5.7], [-1, 4]])
fig = plt.figure()
ax = fig.add_subplot(111)

vor = Voronoi(points)
voronoi_plot_2d_inside_convex_polygon(vor, global_boundaries, ax_=ax)
plt.show()
将numpy导入为np
将matplotlib.pyplot作为plt导入
来自scipy.Voronoi
从shapely.geometry导入多边形,点
#Voronoi-计算每个区域的精确边界
(v0,v1)之间的def角度_:
返回np.math.atan2(np.linalg.det([v0,v1]),np.dot(v0,v1))
def校准角度(c0、c1、c2):
(np.阵列(c1)-np.阵列(c0),np.阵列(c2)-np.阵列(c1))之间的返回角_
def是凸的(多边形):
temp_coords=np.array(polygon.external.coords)
temp_coords=np.vstack([temp_coords,temp_coords[1,:]))
对于枚举中的i,(c0,c1,c2)(zip(temp_-coords,temp_-coords[1:],temp_-coords[2:]):
如果i==0:
第一个角临界值=计算角(c0、c1、c2)>0
elif(计算角(c0、c1、c2)>0)!=第一个角度临界值:
返回错误
返回真值
def无限_段(vor_u):
直线段=[]
中心=中心点平均值(轴=0)
对于pointidx,zip中的单纯形(vor_.ridge_点,vor_.ridge_顶点):
单工=np.asarray(单工)
如果np.有(单纯形<0):
i=simplex[simplex>=0][0]#有限端Voronoi顶点
t=vor_ux.点[pointidx[1]]-vor_ux.点[pointidx[0]]35;切线
t/=np.linalg.norm(t)
n=np.数组([-t[1],t[0]])#正常
中点=垂直点[pointidx]。平均值(轴=0)
方向=np.符号(np.点(中点-中心,n))*n
线段追加([(vor顶点[i,0],vor顶点[i,1]),
(方向[0],方向[1]))
返回直线段
类NotConvexException(异常):
定义(自我):
返回“多边形不是凸的!!!”
类NOTALLPOINTSAREINEException(异常):
定义(自我):
return“并非所有点都在多边形中!!!”
def相交(p0、u、q0、q1):
v=(q1-q0)[np.newaxis].T
A=np.hstack([u,-v])
b=q0-p0
尝试:
库存A=np.linalg.inv(A)
除np.linalg.LINALGER外:
返回np.nan,np.nan
返回np.dot(库存A、b)
定义调整界限(顶点、点):
ptp_边界=点_u.ptp(轴=0)
ax\uuuuu.set\uxlim(points\u[:,0].min()-0.1*ptp\u-bound[0],points\u[:,0].max()+0.1*ptp\u-bound[0])
ax_uuuuu.set_ylim(points_u[:,1].min()-0.1*ptp_绑定[1],points_[:,1].max()+0.1*ptp_绑定[1])
多边形中的定义(多边形、点):
返回点中x的[polygon.contains(点(x))]
def voronoi_plot_2d_in_凸多边形(vor_,多边形,ax_=无,**kw):
从matplotlib.collections导入LineCollection
如果不是全部(在多边形(多边形,vor_u.点)中):
提出NotallPointsRaineException()
如果不是凸的(多边形):
引发NotConvexException()
如果vor_.指向.shape[1]!=2:
提升值错误(“Voronoi图不是二维的”)
vor_inside_ind=np.数组([i表示i,如果多边形包含(点(x)),则枚举(vor_.顶点)中的x])
vor_outside_ind=np.数组([i表示i,x表示枚举(vor_.顶点),如果不是多边形包含(点(x))]))
轴图(vor点[:,0],vor点[:,1],'。)
如果kw.get('show_vertices',True):
轴图(vor顶点[vor\u内部索引,0],vor\u顶点[vor\u内部索引,1],'o')
temp_coords=np.array(polygon.external.coords)
直线段=[]
对于t0,t1在zip中(临时坐标,临时坐标[1:]):
直线段。追加([t0,t1])
ax_uuu.add_u集合(LineCollection(线段、颜色='b',线型='solid'))
直线段=[]
对于垂直脊顶点中的单纯形:
单工=np.asarray(单工)
如果np.all(单纯形>=0):
如果不是全部(在多边形中(多边形,顶点[单纯形]):
持续
直线段追加([(x,y)表示顶点[simplex]中的x,y])
ax_uuu.add_u集合(线条集合(线段、颜色为k、线条样式为实心))
直线段=无限段(vor)
from_inside=np.array([x表示直线段中的x,如果多边形包含(点(x[0]))]))
直线段=[]
对于f in,从_in开始:
对于coord0,zip中的coord1(temp_coords,temp_coords[1:]):
s、 t=intersect(f[0],f[1][np.newaxis].t,coord0,coord1)
如果00:
直线段。追加([f[0],f[0]+s*f[1]])
打破
ax\uuu.add\u集合(LineCollection(np.array(直线段),colors='k',linestyle='虚线'))
直线段=[]
对于v\u o\u ind in vor\u out\u ind:
对于垂直脊顶点中的单纯形:
单工=np.asarray(单工)
如果np.有(单纯形<0):
持续
如果np.any(单纯形==v_o_______________________________
i=simplex[simplex!=v_o___ind][0]
对于coord0,zip中的coord1(temp_coords,temp_coords[1:]):
s、 t=相交(
v.顶点[i],
from collections import defaultdict

from shapely.geometry import Polygon

def voronoi_polygons(voronoi, diameter):
    """Generate shapely.geometry.Polygon objects corresponding to the
    regions of a scipy.spatial.Voronoi object, in the order of the
    input points. The polygons for the infinite regions are large
    enough that all points within a distance 'diameter' of a Voronoi
    vertex are contained in one of the infinite polygons.

    """
    centroid = voronoi.points.mean(axis=0)

    # Mapping from (input point index, Voronoi point index) to list of
    # unit vectors in the directions of the infinite ridges starting
    # at the Voronoi point and neighbouring the input point.
    ridge_direction = defaultdict(list)
    for (p, q), rv in zip(voronoi.ridge_points, voronoi.ridge_vertices):
        u, v = sorted(rv)
        if u == -1:
            # Infinite ridge starting at ridge point with index v,
            # equidistant from input points with indexes p and q.
            t = voronoi.points[q] - voronoi.points[p] # tangent
            n = np.array([-t[1], t[0]]) / np.linalg.norm(t) # normal
            midpoint = voronoi.points[[p, q]].mean(axis=0)
            direction = np.sign(np.dot(midpoint - centroid, n)) * n
            ridge_direction[p, v].append(direction)
            ridge_direction[q, v].append(direction)

    for i, r in enumerate(voronoi.point_region):
        region = voronoi.regions[r]
        if -1 not in region:
            # Finite region.
            yield Polygon(voronoi.vertices[region])
            continue
        # Infinite region.
        inf = region.index(-1)              # Index of vertex at infinity.
        j = region[(inf - 1) % len(region)] # Index of previous vertex.
        k = region[(inf + 1) % len(region)] # Index of next vertex.
        if j == k:
            # Region has one Voronoi vertex with two ridges.
            dir_j, dir_k = ridge_direction[i, j]
        else:
            # Region has two Voronoi vertices, each with one ridge.
            dir_j, = ridge_direction[i, j]
            dir_k, = ridge_direction[i, k]

        # Length of ridges needed for the extra edge to lie at least
        # 'diameter' away from all Voronoi vertices.
        length = 2 * diameter / np.linalg.norm(dir_j + dir_k)

        # Polygon consists of finite part plus an extra edge.
        finite_part = voronoi.vertices[region[inf + 1:] + region[:inf]]
        extra_edge = [voronoi.vertices[j] + dir_j * length,
                      voronoi.vertices[k] + dir_k * length]
        yield Polygon(np.concatenate((finite_part, extra_edge)))
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi

points = np.array([[0.1, -0.4], [0, 1.5], [0, 2.25], [1, 0], [1, 1], [1, 2],
                   [2, 0], [2.5, 1], [2, 2], [2.3, 2.3], [-0.5, -1.3], [-1.5, 3]])
boundary = np.array([[-5, -2], [3.4, -2], [4.7, 4], [2.7, 5.7], [-1, 4]])

x, y = boundary.T
plt.xlim(round(x.min() - 1), round(x.max() + 1))
plt.ylim(round(y.min() - 1), round(y.max() + 1))
plt.plot(*points.T, 'b.')

diameter = np.linalg.norm(boundary.ptp(axis=0))
boundary_polygon = Polygon(boundary)
for p in voronoi_polygons(Voronoi(points), diameter):
    x, y = zip(*p.intersection(boundary_polygon).exterior.coords)
    plt.plot(x, y, 'r-')

plt.show()