未能找到解决方案,我最终编写了这个算法。它可以完成这项工作,但可以更好地处理分支,即。选择会产生最长连续路径的分支。现在它只是坚持第一条线段并从那里开始。
给定一个 GeoJSON MultiLineString 几何,该算法将线段排序为连续路径并返回一个新几何。
代码已根据 Do What The F*ck You Want To Public License 获得许可。
import math
from collections import namedtuple
from operator import attrgetter
from copy import deepcopy
def arrange_geometry(original_geometry):
def distance(coords1, coords2):
return math.sqrt(math.pow(coords1[0] - coords2[0], 2) + math.pow(coords1[1] - coords2[1], 2))
MinDistance = namedtuple('MinDistance', 'target distance offset reverse_target')
geometry = deepcopy(original_geometry)
if geometry['type'] == 'MultiLineString':
lines = geometry['coordinates']
sorted_multistring = [lines.pop(0)]
while lines:
min_distances = []
for line in lines:
source_a = sorted_multistring[0][0]
source_b = sorted_multistring[-1][-1]
target_a = line[0]
target_b = line[-1]
distances = [
MinDistance(target=line, distance=distance(source_b, target_a), offset=1, reverse_target=False),
MinDistance(target=line, distance=distance(source_a, target_a), offset=-1, reverse_target=True),
MinDistance(target=line, distance=distance(source_b, target_b), offset=1, reverse_target=True),
MinDistance(target=line, distance=distance(source_a, target_b), offset=-1, reverse_target=False)
]
min_distance = min(distances, key=attrgetter('distance'))
min_distances.append(min_distance)
min_distance = min(min_distances, key=attrgetter('distance'))
target = min_distance.target
if min_distance.reverse_target:
target.reverse()
if min_distance.offset == 1:
sorted_multistring.append(target)
else:
sorted_multistring.insert(0, target)
lines.remove(target)
geometry['coordinates'] = sorted_multistring
return geometry