我認爲,在「表現良好」(小缺口,不太不規則的形狀等)情況下,可能會採取以下方法。這個想法是假定解決方案(特定的輸入線段的置換,然後假定用直線連接)使得到的MultiLineString的長度最小化,定義了感興趣的多邊形的邊界。
要解決這個問題,下面的實現使用2-opt啓發式來解決旅行商問題。它前進在以下步驟:
- 頂點集被定義爲所有輸入的線段的端點的並集
- 它試圖這些點,以便下,以最小化得到的MULTILINESTRING的總長度連接屬於相同輸入線段的點總是連接的限制(即,,2-opt算法僅允許分割連接不同線段的邊緣 - 這是由主雙
for
-loop中額外的if
條件處理的。
所以,結果是:
import logging
import random
import sys
from shapely.geometry import LineString, Polygon
from shapely.ops import polygonize, linemerge
#prevent shapely from showing an error message on is_valid tests
logger = logging.getLogger()
logger.setLevel(logging.ERROR)
#input lines (LineStrings)
lines = [
[(3.15,3.94), (4.06,3.91), (4.27,3.49)],
[(0.84,2.99), (0.97,3.67), (1.68,3.91), (2.68,3.92)],
[(4.46,3.23), (5.12,2.97), (4.60,2.00)],
[(4.13,1.44), (4.41,0.68), (1.14,1.99)]
]
random.shuffle(lines)
N, pnts = 0, []
pnt2line = {}
for line_id, line in enumerate(lines):
#for each line, save its endpoints and remember
#to which line each point belongs
for pnt in [line[0], line[-1]]:
pnt2line[N] = line_id
pnts.append(pnt)
N += 1
#as initial guess, try to connect these points sequentially
route = [i for i in range(0, N)]
def nrm_idx(N, idx):
return (N + idx) % N
def get_polygon(route):
#for given route, attempt to construct the resulting polygon
segments = []
m = len(route)
for idx in range(0, m):
i, j = route[idx], route[nrm_idx(m, idx+1)]
if pnt2line[i] == pnt2line[j]:
#if two consecutive points belong to the same line, consider this line
segments.append(lines[pnt2line[i]])
else:
#otherwise, connect these points with a straight line
segments.append([pnts[i], pnts[j]])
return Polygon(linemerge(segments))
def get_weight(route):
P = get_polygon(route)
return P.length if P.is_valid else sys.maxsize
def edge_is_fixed(pnt_i, pnt_j):
#check if an edge specified by point pnt_i/pnt_j can be dissected or not
#in the latter case, the points belong to the same line/line segment
return (pnt2line[pnt_i] == pnt2line[pnt_j])
def opt_swap(route, i, k):
#perform 2-opt swap
return route[0:i] + route[i:k+1][::-1] + route[k+1:]
flag = True
while flag:
flag = False
best_weight = get_weight(route)
for i in range(0, N-1):
for k in range(i+1, N):
if edge_is_fixed(route[nrm_idx(N, i-1)], route[i]) or edge_is_fixed(route[k], route[nrm_idx(N, k+1)]):
continue
new_route = opt_swap(route, i, k)
weight = get_weight(new_route)
if weight < best_weight:
route = new_route[:]
best_weight = weight
flag = True
P = get_polygon(route)
for x, y in P.exterior.coords:
print(x, y)
您的輸入(近似),然後將結果確實: 
只有採用開放點之間的單一直線? – danyamachine
是的。只有一條直線。將其添加到問題 – MaPY