web-dev-qa-db-ja.com

ボロノイ分割からShapelyポリゴンへ

一連のポイントから、 scipy を使用してボロノイ分割を構築しました。

from scipy.spatial import Voronoi
vor = Voronoi(points)

ここで、ボロノイアルゴリズムが作成した領域から Shapelyのポリゴン を作成したいと思います。問題は、Polygonクラスが反時計回りの頂点のリストを必要とすることです。 これらの頂点を並べ替える 方法は知っていますが、これが私の結果であることが多いため、問題を解決できません。

enter image description here

(重なり合うポリゴン)。これはコードです(1つのランダムな例):

def order_vertices(l):
    mlat = sum(x[0] for x in l) / len(l)
    mlng = sum(x[1] for x in l) / len(l)

    # https://stackoverflow.com/questions/1709283/how-can-i-sort-a-coordinate-list-for-a-rectangle-counterclockwise
    def algo(x):
        return (math.atan2(x[0] - mlat, x[1] - mlng) + 2 * math.pi) % 2*math.pi

    l.sort(key=algo)
    return l

a = np.asarray(order_vertices([(9.258054711746084, 45.486245994138976),
 (9.239284166975443, 45.46805963143515),
 (9.271640747003861, 45.48987234571072),
 (9.25828782103321, 45.44377372506324),
 (9.253993275176263, 45.44484395950612),
 (9.250114174032936, 45.48417979682819)]))
plt.plot(a[:,0], a[:,1])

どうすればこの問題を解決できますか?

16
marcodena

ポリゴンのコレクションの直後の場合は、ポリゴンを作成するためにポイントを事前に注文する必要はありません。

scipy.spatial.Voronoiオブジェクトにはridge_vertices属性があり、ボロノイリッジの線を形成する頂点のインデックスが含まれています。インデックスが-1の場合、尾根は無限大になります。

まず、いくつかのランダムなポイントから始めて、ボロノイオブジェクトを作成します。

import numpy as np
from scipy.spatial import Voronoi, voronoi_plot_2d
import shapely.geometry
import shapely.ops

points = np.random.random((10, 2))
vor = Voronoi(points)
voronoi_plot_2d(vor)

Voronoi plot from scipy.spatial

これを使用して、ShapelyLineStringオブジェクトのコレクションを作成できます。

lines = [
    shapely.geometry.LineString(vor.vertices[line])
    for line in vor.ridge_vertices
    if -1 not in line
]

shapely.opsモジュールには polygonize があり、ShapelyPolygonオブジェクトのジェネレーターを返します。

for poly in shapely.ops.polygonize(lines):
    #do something with each polygon

Polygons from Voronoi with some sample points

または、ボロノイ分割で囲まれた領域から形成された単一のポリゴンが必要な場合は、Shapely unary_unionメソッドを使用できます。

shapely.ops.unary_union(list(shapely.ops.polygonize(lines)))

Merged Voronoi tesselation polygon

31
om_henners

ライブラリは座標の順序付きリストを生成できます。提供されているインデックスリストを利用する必要があります。

import numpy as np
from scipy.spatial import Voronoi

...

ids = np.array(my_points_list)
vor = Voronoi(points)
polygons = {}
for id, region_index in enumerate(vor.point_region):
    points = []
    for vertex_index in vor.regions[region_index]:
        if vertex_index != -1:  # the library uses this for infinity
            points.append(list(vor.vertices[vertex_index]))
    points.append(points[0])
    polygons[id]=points

polygons辞書の各ポリゴンはgeojsonにエクスポートするか、形を整えることができ、QGISで適切にレンダリングすることができました

0
alexd