在 Sympy 中迭代相交线段......有更好的方法吗?

iteratively intersecting line segments in Sympy... is there a better way?

好的。我有构成多边形边界的点。我想 (a) 使用 Sympy 的几何模块来确定,从任何一对点之间的所有可能的线段,哪些线段不穿过周边。此结果将是 "edges" 允许在 (b) Networkx 中的 shortest_distance 分析中使用。我的最终目标是通过许多形状重复这个过程,但我在这个例子中只对 1 个形状的坐标进行了硬编码。

import numpy
import networkx as nx
from sympy import geometry
from itertools import combinations
from matplotlib import pyplot as plot
arr_bou = numpy.array([[-542.62545014,  961.34455209],
   [-544.45425379,  961.34455209],
   [-544.45425379,  962.25895392],
   [-547.19745928,  962.25895392],
   [-547.19745928,  963.17335575],
   [-549.02626294,  963.17335575],
   [-549.02626294,  964.08775758],
   [-550.85506659,  964.08775758],
   [-550.85506659,  961.34455209],
   [-552.68387025,  961.34455209],
   [-552.68387025,  962.25895392],
   [-553.59827208,  962.25895392],
   [-553.59827208,  965.91656123],
   [-552.68387025,  965.91656123],
   [-552.68387025,  967.7453649 ],
   [-551.76946842,  967.7453649 ],
   [-551.76946842,  968.65976672],
   [-550.85506659,  968.65976672],
   [-550.85506659,  967.7453649 ],
   [-548.11186111,  967.7453649 ],
   [-548.11186111,  965.91656123],
   [-547.19745928,  965.91656123],
   [-547.19745928,  964.08775758],
   [-546.28305745,  964.08775758],
   [-546.28305745,  965.00215941],
   [-543.53985197,  965.00215941],
   [-543.53985197,  963.17335575],
   [-542.62545014,  963.17335575],
   [-542.62545014,  964.08775758],
   [-540.79664648,  964.08775758],
   [-540.79664648,  963.17335575],
   [-539.88224465,  963.17335575],
   [-539.88224465,  962.25895392],
   [-542.62545014,  962.25895392],
   [-542.62545014,  961.34455209]])

boundXY = []
for i in arr_bou:
    boundXY.append((i[0],i[1]))

points     = [geometry.Point(i) for i in boundXY]
poly       = geometry.Polygon(*points) # use the * first to unpack the points (necessary to avoid errors)


G          = nx.Graph()
positions  = {}                                  # build a dictionary
for i in xrange(len(boundXY)):                   # that contains coordinates
    positions[i] = boundXY[i]                    # of each node on the graph's perimeter
G.add_path(positions.keys())# add nodes to graph w/ boundary edges
G.add_path([min(G.nodes()),max(G.nodes())])    combos_o   = list(combinations(positions.keys(),2))
combos     = [i for i in combos_o if i not in G.edges()]

keepcombos = []
for combo in combos:
    pt1 = positions[combo[0]]
    pt2 = positions[combo[1]]
    line = geometry.Polygon(pt1,pt2)
    # there are 4 polygon sides that do not count as intersections
    # because 2 sides will intersect a point on each end
    test = True
    for side in poly.sides:
        if side.p1 != geometry.Point(pt1) and side.p1 != geometry.Point(pt2):
            if side.p2 != geometry.Point(pt1) and side.p2 != geometry.Point(pt2):
                if geometry.intersection(line,side):
                    test = False
                    break
                else:
                    try:
                        if poly.encloses(line.midpoint):
                            pass
                        else:
                            test = False
                            break
                    except NotImplementedError:
                        pass
    if test == True:
        keepcombos.append(combo)
G.add_edges_from(keepcombos)

我已经将它用于小多边形(14 个顶点),但这需要永远,即使只有 35 个顶点,其他多边形仍然会比这更大。

是否有更有效的方法来查找多边形内的所有节点对?

谢谢!!

如果凸包是定义包含所有其他凸多边形的点集

>>> coords = [[-542.62545014,  961.34455209],
...    [-544.45425379,  961.34455209],
...    [-544.45425379,  962.25895392],
...    [-547.19745928,  962.25895392],

...    [-542.62545014,  962.25895392],
...    [-542.62545014,  961.34455209]]
>>> from sympy import *
>>> pts = [Point(*i) for i in coords]
>>> h = convex_hull(*pts)

那么你只对不在周界上的所有点感兴趣吗?知道这些点后,您是否只想生成这些点的所有成对组合?

inside = [p for p in pts if p not in h.vertices]
from sympy.utilities.iterables import combinations
pairs = combinations(inside, 2)

查看 https://www.desmos.com/calculator/up4k2qkxy9 我发现有几个点似乎落在边缘上,因此也许它们不应包含在 "inside" 点中。但希望您能理解我的回答要点。

我找到了一个解决方案,该解决方案将处理速度提高了大约 13 倍(对于具有 35 个点的多边形(如上面列出的数据),问题代码中的旧方法花了大约 4 小时才能找到其中的所有线段多边形。这个新方法用了 18 分钟。)

上面我遍历了点,并且在每次迭代中分别查看每个边界 ("side") 以查看线条是否相交。我将其更改为将线与整个多边形相交。如果它在里面或在边缘上,它相交的地方应该只有2个点,所以如果相交的长度>2,我把组合扔掉

for combo in combos:
    pt1  = geometry.Point(positions[combo[0]],evaluate=False)
    pt2  = geometry.Point(positions[combo[1]],evaluate=False)
    line = geometry.Polygon(pt1,pt2)
    try:
        if poly.encloses(line.midpoint):
            pass
        else:
            continue
    except NotImplementedError:
        continue
    intersect = geometry.intersection(line,poly)
    if len(intersect)>2:
        continue
    keepcombos.append(combo)

此列表 "keepcombos" 现在包含我希望包含在 Dijkstra 路径分析中的所有行(或 networkx "edges")