頂点の座標のリスト= [(x1、y1)、(x2、y2)、(x3、y3)、...]とpoint(x、y)を持つポリラインがあります。 Shapelyでは、geometry1.distance(geometry2)
は2つのジオメトリ間の最短距離を返します。
_>>> from shapely.geometry import LineString, Point
>>> line = LineString([(0, 0), (5, 7), (12, 6)]) # geometry2
>>> list(line.coords)
[(0.0, 0.0), (5.0, 7.0), (12.0, 6.0)]
>>> p = Point(4,8) # geometry1
>>> list(p.coords)
[(4.0, 8.0)]
>>> p.distance(line)
1.4142135623730951
_
しかし、point(x、y)に最も近いライン上のポイントの座標も見つける必要があります。上記の例では、これはLineString
オブジェクト上のポイントの座標であり、Point(4,8)
から1.4142135623730951単位離れています。 distance()
メソッドは、距離を計算するときに座標を持つ必要があります。このメソッドから返されるようにする方法はありますか?
あなたが説明しているGIS用語は 線形参照 であり、 Shapelyにはこれらのメソッドがあります です。
# Length along line that is closest to the point
print(line.project(p))
# Now combine with interpolated point on line
np = line.interpolate(line.project(p))
print(np) # POINT (5 7)
別の方法は nearest_points
:
from shapely.ops import nearest_points
np = nearest_points(line, p)[0]
print(np) # POINT (5 7)
これは、線形参照手法と同じ答えを提供しますが、2つのポリゴンなどのより複雑なジオメトリ入力から最も近いポイントのペアを決定できます。
セグメントのリストではなく、単一のセグメント(例:タイトルを参照する行)がある場合、ここに私がやったことと、合格したテストケースがあります。このページの一部のユーザーは、Google検索からタイトルを見て、それだけを求めていると考えてください。
def sq_shortest_dist_to_point(self, other_point):
dx = self.b.x - self.a.x
dy = self.b.y - self.a.y
dr2 = float(dx ** 2 + dy ** 2)
lerp = ((other_point.x - self.a.x) * dx + (other_point.y - self.a.y) * dy) / dr2
if lerp < 0:
lerp = 0
Elif lerp > 1:
lerp = 1
x = lerp * dx + self.a.x
y = lerp * dy + self.a.y
_dx = x - other_point.x
_dy = y - other_point.y
square_dist = _dx ** 2 + _dy ** 2
return square_dist
def shortest_dist_to_point(self, other_point):
return math.sqrt(self.sq_shortest_dist_to_point(other_point))
def test_distance_to_other_point(self):
# Parametrize test with multiple cases:
segments_and_point_and_answer = [
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
[Segment(Point(0.0, 0.0), Point(0.0, 3.0)), Point(1.0, 1.0), 1.0],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3.0, -4.0), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-4.0, -3.0), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(1, 2), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(2, 1), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3, -1), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-1, -3), math.sqrt(2.0)],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)]
]
for i, (segment, point, answer) in enumerate(segments_and_point_and_answer):
result = segment.shortest_dist_to_point(point)
self.assertAlmostEqual(result, answer, delta=0.001, msg=str((i, segment, point, answer)))
注:この関数はSegment
クラス内にあると想定しています。行が無限の場合は、lerp
を0から1に制限しないでください。ただし、少なくとも2つの異なるa
およびb
ポイントを指定してください。