[英]Split self-intersecting linestring into non-self-intersecting linestrings
我有一个坐标列表,定义了一个可能与自身相交的线串:
coordinates = [
[0, 3],
[0, 5],
[4, 5],
[4, 0],
[0, 0],
[0, 5],
[2, 5]
]
如何将线串拆分成更小的线串,使所有线串都不与自身相交?
在这种情况下,期望的结果是:
line0 = [
[0, 3],
[0, 5],
[4, 5],
[4, 0]
]
line1 = [
[4, 0],
[0, 0],
[0, 5],
[2, 5]
]
到目前为止,在我的尝试中,我使用 Shapely Linestrings 构造了一个交集矩阵来查找交点:
from shapely.geometry import LineString
from itertools import product, zip_longest
import numpy as np
def get_intersection_matrix(coordinates):
linestrings = [
(ix, LineString([c0, c1]))
for ix, (c0, c1) in enumerate(zip(coordinates[:-1], coordinates[1:]))
]
M = np.zeros((len(linestrings), len(linestrings)))
for (ix0, ls0), (ix1, ls1) in combinations(linestrings, 2):
if abs(ix0 - ix1) == 1: # ignore connecting segments
continue
if ls0.intersects(ls1):
M[ix0, ix1], M[ix1, ix0] = 1, 1
return M
它输出我所说的“交集矩阵”:
>> get_intersection_matrix(coordinates)
array([[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0]])
你可以读作:
还; 我认为“交叉点簇”的数量表示线串的数量: no_clusters + 1
我现在如何解决它......我改变了我的交叉点矩阵,所以在没有交叉点的情况下值为 1,在任何交叉点处的值为 0。
def get_intersection_matrix(coordinates):
linestrings = [
(ix, LineString([c0, c1]))
for ix, (c0, c1) in enumerate(zip(coordinates[:-1], coordinates[1:]))
]
M = np.ones((len(linestrings), len(linestrings)))
for (ix0, ls0), (ix1, ls1) in combinations(linestrings, 2):
if abs(ix0 - ix1) == 1: # ignore connecting segments
continue
if ls0.intersects(ls1):
M[ix0, ix1], M[ix1, ix0] = 0, 0
return M
>> M = get_intersection_matrix(coordinates)
>> M
array([[1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1.]])
itertools.combinations(range(1, len(M)), nr_split_ixs)
其中ix1 < ix2 <... < ixn
在一个分割索引处,您会得到两个不应包含任何 0 的方块,并且这些方块可以通过最小和进行优化!
这是一个合法的(但不是最好的)拆分, split_ix = 4
,两个框的总和为 16+4 = 20。
这是一个更好的合法(无零)拆分,其中两个框的总和为 9+9=18
得分分割指数的计算方法:
def get_scored_split_ixs_combination(M, nr_split_ixs):
ixs_scores = []
for ixs in combinations(range(1, len(M)), nr_split_ixs):
splitted_matrix = [
M[i0:i1, i0:i1] for i0, i1 in zip((0, *ixs), (*ixs, len(M)))
]
# check if no matrices have zeros
if not all([(m > 0).all() for m in splitted_matrix]):
# ilegal ixs combination
continue
ixs_scores.append((ixs, sum([m.sum() for m in splitted_matrix])))
return ixs_scores
如果返回为空,则没有合法选项,您应该增加拆分次数。
现在通过增加拆分次数返回最佳拆分选项:
def get_best_split_ixs_combination(M):
nr_split_ixs = 0
while True:
ixs_scores = get_scored_split_ixs_combination(M, nr_split_ixs)
if ixs_scores:
return min(ixs_scores, key=lambda x: x[1])[0]
nr_split_ixs +=1
>> get_best_split_ixs_combination(M)
(3,)
最后把它们包起来:
def get_non_intersecting_linestrings(coordinates):
M = get_intersection_matrix(coordinates)
split_indexes = get_best_split_ixs_combination(M)
return [
coordinates[i1:i2]
for i1, i2 in zip([0] + split_indexes, split_indexes + [len(coordinates)])
]
>> get_non_intersecting_linestrings(coordinates)
[[[0, 3], [0, 5], [4, 5]], [[4, 0], [0, 0], [0, 5], [2, 5]]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.