web-dev-qa-db-ja.com

Shapelyでポリゴン上の最も近い点の座標を見つける

次のポリゴンとポイントがあるとします。

_>>> poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
>>> point = Point(12, 4)
_

enter image description here

ポイントからポリゴンまでの距離を計算できます...

_>>> dist = point.distance(poly)
>>> print(dist)
2.49136439561
_

...しかし、その最短距離が測定されるポリゴン境界上のポイントの座標を知りたいのですが。

私の最初のアプローチは、ポリゴンまでの距離によってポイントをバッファリングし、その円がポリゴンに接するポイントを見つけることです。

_>>> buff = point.buffer(dist) 
_

enter image description here ただし、そのポイントの計算方法はわかりません。 2つのポリゴンは交差しないので、list(poly.intersection(buff))はそのポイントを与えません。

私はこれで正しい軌道に乗っていますか?より簡単な方法はありますか?

21
AJG519

Shapely関数に依存してこれを行う簡単な方法があります。まず、ポリゴンの外部リングを取得し、ポイントをリングに投影する必要があります。ポリゴンには投影関数がないため、LinearRingとして外部を取得する必要があります。直感とは対照的に、これは距離を示します。これは、リングの最初のポイントから、指定されたポイントに最も近いリングのポイントまでの距離です。次に、その距離を使用して、補間関数でポイントを取得します。以下のコードを参照してください。

from shapely.geometry import Polygon, Point, LinearRing

poly = Polygon([(0, 0), (2,8), (14, 10), (6, 1)])
point = Point(12, 4)

pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
closest_point_coords = list(p.coords)[0]

この方法は、ポイントがポリゴンの外側にあることがわかっている場合にのみ機能することに注意してください。ポイントがその内部リングの1つの内側にある場合は、その状況に合わせてコードを調整する必要があります。

ポリゴンに内部リングがない場合、コードはポリゴン内のポイントでも機能します。これは、実際には外部リングをラインストリングとして使用しており、ラインストリングがポリゴンからのものであるかどうかを無視しているためです。

このコードを、ポリゴン境界内の最も近いポイントまでの任意のポイント(ポリゴンの内側または外側)の距離を計算する一般的なケースに拡張するのは簡単です。ポイントからすべてのラインリング(ポリゴンの外部リングおよび各内部リング)までの最も近いポイント(および距離)を計算するだけで済みます。次に、それらの最小値を維持します。

enter image description here

30
eguaio

eguaio が答えを出しますが、- shapely.ops.nearest_points 関数:

from shapely.geometry import Point, Polygon
from shapely.ops import nearest_points

poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
point = Point(12, 4)
# The points are returned in the same order as the input geometries:
p1, p2 = nearest_points(poly, point)
print(p1.wkt)
# POINT (10.13793103448276 5.655172413793103)

結果は他の答えと同じです:

from shapely.geometry import LinearRing
pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
print(p.wkt)
# POINT (10.13793103448276 5.655172413793103)
print(p.equals(p1))
# True
16
Georgy

2つのケースが2つ考えられます。(1)最も近い点はエッジ上にあり、(2)最も近い点は頂点です。ケース(2)は簡単に確認できます。各頂点までの距離を取り、最小値を見つけるだけです。ケース(1)にはもう少し数学が含まれますが、それでもそれほど悪くはありません。 (1)の場合、2つのことを実行する必要があります:(a)ポイントからエッジへの法線がエッジと交差する場所を見つけ、(b)それがラインセグメント内にあることを確認します(終了)。ラインセグメント上にない場合は無視してください(頂点の1つがそのエッジ上の最も近い点になります)。

0
Tom Karzes