如何在一组线中找到循环?

3 投票
1 回答
115 浏览
提问于 2025-04-13 16:10

我有一个简单的例子可以复现这个问题。

输入数据如下:

coordinates = [(50.0, 50.0, 100.0, 50.0), (70.0, 50.0, 75.0, 40.0, 80.0, 50.0)]

这些数据在图形中形成的样子是这样的:

drawing

任务是找到一个循环,也就是一个封闭的区域,并在终端上显示它们的边界。

在这个例子中,结果应该是这样的(用[(line1), (line2)]表示):

[(70.0, 50.0, 75.0, 40.0), (75.0, 40.0, 80.0, 50.0), (80.0, 50.0, 70.0, 50.0)]

我尝试使用networkx库中的cycle_basic方法。

但是这个方法要求循环的顶点必须接触到其他循环的顶点。而在这里,顶点可以在另一个循环的任何地方接触。

1 个回答

2

如果我理解得没错,你想要的是诱导的 / 无弦循环。如果是这样,这里有一个使用基本方法

points = MultiPoint(list(batched(chain.from_iterable(coordinates), 2)))

lines = [
    line
    for coo in coordinates
    for pop in pairwise(batched(coo, 2))
    for gc in [split(LineString(pop), points)]
    for line in gc.geoms
]

G = gdf_to_nx(
    gpd.GeoDataFrame(geometry=lines), multigraph=False, approach="primal"
)

cycles = [
    [
        tuple(chain.from_iterable(pair))
        for pair in pairwise(cyc)
    ] for cyc in nx.chordless_cycles(G)
    for cyc in [cyc + [cyc[0]]]
]

enter image description here

输出结果(循环, 顺时针):

[
    [ # top/green cycle
        (70.0, 50.0, 80.0, 50.0),
        (80.0, 50.0, 77.5, 45.0),
        (77.5, 45.0, 72.5, 45.0),
        (72.5, 45.0, 70.0, 50.0),
    ],
    [ # bottom/red cycle
        (72.5, 45.0, 77.5, 45.0),
        (77.5, 45.0, 75.0, 40.0),
        (75.0, 40.0, 72.5, 45.0),
    ],
]

使用的输入(坐标):

from itertools import chain, batched, pairwise
import geopandas as gpd
from momepy import gdf_to_nx
import networkx as nx
from shapely import LineString, MultiPoint
from shapely.ops import split

coordinates = [
    (50.0, 50.0, 100.0, 50.0),
    (70.0, 50.0, 75.0, 40.0, 80.0, 50.0),
    (72.5, 45.0, 77.5, 45.0)
]

完整代码
旧答案

撰写回答