簡體   English   中英

確定沿着 Shapely 中的一條線進一步產生哪個交點

[英]Determine which intersection result further along a line in Shapely

語境

(最后的最小工作示例代碼)

我正在嘗試創建一個線平滑算法:從第一條線的頂點,創建一個指定半徑的圓,這個圓與線 (LineString) 相交。 這導致 1 到多個交集結果(點)。 然后取沿線最遠的交點,創建一個新圓,與線相交,依此類推,直到接近線端點。

具有奇怪傳遞參數的可視化結果如下圖所示。 藍線是輸入,綠線是平滑后的結果。 這條線在 UTM 投影中,但沒關系。

在此處輸入圖片說明

問題

現在我大致知道如何設計大部分算法(如果成功,我可以在這里完整地傳遞它)。

我不知道的是如何始終從當前交點結果中選擇沿線最遠的交點 在這種情況下,Shapely 使用 Point 或 MultiPoint 作為 interserciton 結果。 如果我通過geoms到達 MultiPoint 部件,它們可能按升序x coordinate排序(雖然不確定)。

嘗試的解決方案

我首先想到我總是從circle_intersections.geoms取出最后一個成員。 正如您可能猜到的那樣,如果我將其應用於算法,一旦該線相對於上升的x coordinate改變其方向,這將不起作用。 然后,我需要的交點通常是列表中的第一個(或其他)。 因此,它進入無限循環,通過兩個圓之間的交點。

在上圖中,它之所以起作用,只是因為設置了radius ,使得搜索的交點始終在x coordinate更遠。

其次,我嘗試遍歷這條線並過濾掉splits條線splits得最遠的交點。 在這里,我一定犯了一些我沒有看到的錯誤。

您可以在find_farthest_intersection函數中找到這兩種嘗試。

代碼

進口:

import shapely
from shapely.geometry import Point, LineString
from shapely.ops import split
import matplotlib.pyplot as plt

算法:

def smooth(point, geometry, r, first_pass=True):
    circle = point.buffer(r)
    circle_intersections = geometry.intersection(circle.exterior)

    # It's always a single point at the first iteration
    if isinstance(circle_intersections, Point):
        next_point = circle_intersections
    else:
        next_point = find_farthest_intersection(
            geometry,
            circle_intersections
        )

    # If you want to visualize in Jupyter
    # plt.plot(
    #     *point.buffer(6).exterior.xy,
    #     *circle.exterior.xy,
    #     *next_point.buffer(5).exterior.xy,
    # )

    if not first_pass and Point(geometry.coords[-1]).within(circle):
        return [geometry.coords[-1]]

    return [point.coords[0]] + smooth(
        next_point,
        geometry,
        r,
        first_pass=False
    )


def find_farthest_intersection(geometry, intersections):
    # How to return the right intersection furthest along the line?

    # Naive and wrong solution
    # When the line heads against X this becomes the opposite point than I want
    # return circle_intersections.geoms[-1]

    # Other attempted solution
    # Not working, results in the same problem as with the solution above.

    # Find each intersection point's distance from the
    # line beginning
    intersection_pnt_dsts_from_line_start = [
        split(geometry, point).geoms[0].length
        for point in intersections.geoms
    ]

    # Return the intersection point with the maximum
    # distance from the line beginning
    return max(
        zip(
            intersection_pnt_dsts_from_line_start,
            intersections.geoms
        ),
        key=lambda item: item[0]
    )[1]

如果你想在例如可視化。 Jupyter(也在smooth函數中取消注釋 pyplots)。

# it's in UTM btw
line = shapely.wkt.loads('LINESTRING (478098.5964211893 5442495.543688663, 478229.0423690955 5442525.981076508, 478242.0869638861 5442558.592563484, 478198.6049812507 5442595.552248725, 478129.033809034 5442649.904727018, 478168.1675934059 5442691.212610522, 478209.4754769095 5442665.123420941, 478209.4754769095 5442628.163735701, 478213.8236751731 5442615.11914091, 478231.2164682273 5442599.900446988, 478252.957459545 5442593.378149592, 478305.1358387075 5442602.07454612, 478322.5286317617 5442652.078826151, 478329.0509291569 5442732.520494026, 478383.4034074512 5442762.957881871, 478353.5095443893 5442726.541721413, 478421.4501422573 5442696.37609596, 478471.7261846794 5442718.117087278, 478434.7664994393 5442728.987582936, 478399.9809133308 5442732.248731634, 478458.6815898888 5442757.250871649, 478526.0786629738 5442780.078912533, 478532.6009603692 5442848.563035184, 478579.3440917023 5442883.348621292)')

r = 100  # radius parameter

plt.plot(*line.xy)

result = smooth(
    Point(line.coords[0]),  # first time it's the first line node
    line,
    r # smaller number or more complicated lines cause fail
)

# Would then do
# plt.plot(*LineString(result).xy)

所以我玩了更多幾何運算,並在#50194077 的幫助下發現解決方案相當簡單。 我可以通過每個交點分割線並測量從第一個分割結果的線開始處的距離。 最長的距離指向最遠的交點,即我想要的交點。

方便分割的關鍵是創建交點的緩沖區。 它的大小應該解決勻稱的精度問題並且盡可能小(例如1Oe-9 )。

修訂功能:

def find_farthest_intersection(geometry, intersection_points):
    intersection_points_from_geom_distance = []

    for intersection_point in intersection_points:
        # Create a little buffer
        precision_buffer = intersection_point.buffer(10e-9)

        # Split line on buffer and take the first line fragment
        intersection_points_from_geom_distance.append([
            intersection_point,
            split(line, precision_buffer)[0].length]
        )

    # Return the intersection point with the maximum
    # distance from the line beginning
    return max(
        intersection_points_from_geom_distance,
        key=lambda item: item[1]
    )[0]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM