连续排列线段以形成多边形

时间:2017-04-30 03:57:11

标签: python polygons segments

我试图安排线段以使用python创建一个闭合的多边形。目前我已经设法解决了这个问题,但是当细分数量增加时(它就像一个泡泡排序,但是对于细分的终点)来说真的很慢。我附加了一个sample file坐标(真正的坐标非常复杂,但对于测试目的很有用)。该文件包含两个separetes闭合多边形的段的坐标。下面的图片是我附上的坐标的结果。

enter image description here 这是我加入细分的代码。 “Curve”文件位于上面的保管箱链接中:

from ast import literal_eval as make_tuple
from random import shuffle
from Curve import Point, Curve, Segment

def loadFile():
    print 'Loading File'
    file = open('myFiles/coordinates.txt','r')
    for line in file:
        pairs.append(make_tuple(line))
    file.close()

def sortSegment(segPairs):
    polygons = []
    segments = segPairs

    while (len(segments) > 0):
        counter = 0
        closedCurve = Curve(Point(segments[0][0][0], segments[0][0][1]), Point(segments[0][1][0], segments[0][1][1]))
        segments.remove(segments[0])
        still = True

        while (still):
            startpnt = Point(segments[counter][0][0], segments[counter][0][1])
            endpnt = Point(segments[counter][1][0], segments[counter][1][1])
            seg = Segment(startpnt, endpnt)
            val= closedCurve.isAppendable(seg)

            if(closedCurve.isAppendable(seg)):

                if(closedCurve.isClosed(seg)):
                    still =False
                    polygons.append(closedCurve.vertex)
                    segments.remove(segments[counter])

                else:
                    closedCurve.appendSegment(Segment(Point(segments[counter][0][0], segments[counter][0][1]), Point(segments[counter][1][0], segments[counter][1][1])))
                    segments.remove(segments[counter])
                    counter = 0

            else:
                counter+=1
                if(len(segments)<=counter):
                    counter = 0

    return polygons

def toTupleList(list):
    curveList = []
    for curve in list:
        pointList = []
        for point in curve:
            pointList.append((point.x,point.y))
        curveList.append(pointList)

    return curveList

def convertPolyToPath(polyList):
    path = []
    for curves in polyList:
        curves.insert(1, 'L')
        curves.insert(0, 'M')
        curves.append('z')
        path = path + curves
    return path

if __name__ == '__main__':

    pairs =[]
    loadFile();


    polygons = sortSegment(pairs)
    polygons = toTupleList(polygons)
    polygons = convertPolyToPath(polygons)

2 个答案:

答案 0 :(得分:2)

假设您只是在寻找方法,而不是代码,我会尝试这样做。

当您从文件中读取片段坐标时,请继续将坐标添加到字典中,其中片段的一个坐标(字符串形式)作为键,另一个坐标作为值。最后,它应该是这样的:

{
    '5,-1': '5,-2',
    '4,-2': '4,-3',
    '5,-2': '4,-2',
    ...
}

现在从这本词典中选择任何一个键值对。接下来,从字典中选择键值对,其中键与前一个键值对中的值相同。因此,如果第一个键值对为'5,-1': '5,-2',则下次查找键'5,-2',您将获得'5,-2': '4,-2'。接下来查找键'4,-2'等等。

继续从字典中删除键值对,这样一旦完成一个多边形,就可以检查是否还有任何元素,这意味着可能有更多的多边形。

如果您还需要代码,请告诉我。

答案 1 :(得分:2)

我不得不做类似的事情。我需要将海岸线线段(未正确排序)转换为多边形。我使用NetworkX将分段排列成连接的组件,并使用this function对其进行排序。

事实证明,我的代码也适用于此示例。我使用geopandas来显示结果,但是该依赖性对于此处的原始问题是可选的。我还使用shapely将线段列表转换为多边形,但是您可以只使用CoastLine.rings来获取线段列表。

我计划将此代码包含在下一版PyRiv中。

from shapely.geometry import Polygon
import geopandas as gpd
import networkx as nx

class CoastLine(nx.Graph):
    def __init__(self, *args, **kwargs):
        """
        Build a CoastLine object.

        Parameters
        ----------

        Returns
        -------
          A CoastLine object
        """
        self = super(CoastLine, self).__init__(*args, **kwargs)

    @classmethod
    def read_shp(cls, shp_fn):
        """
        Construct a CoastLine object from a shapefile.
        """
        dig = nx.read_shp(shp_fn, simplify=False)
        return cls(dig)

    def connected_subgraphs(self):
        """
        Get the connected component subgraphs. See the NetworkX
        documentation for `connected_component_subgraphs` for more
        information.
        """
        return nx.connected_component_subgraphs(self)

    def rings(self):
        """
        Return a list of rings. Each ring is a list of nodes. Each
        node is a coordinate pair.
        """
        rings = [list(nx.dfs_preorder_nodes(sg)) for sg in self.connected_subgraphs()]
        return rings

    def polygons(self):
        """
        Return a list of `shapely.Polygon`s representing each ring.
        """
        return [Polygon(r) for r in self.rings()]

    def poly_geodataframe(self):
        """
        Return a `geopandas.GeoDataFrame` of polygons.
        """
        return gpd.GeoDataFrame({'geometry': self.polygons()})

使用此类,可以解决原始问题:

edge_list = [
    ((5, -1), (5, -2)),
    ((6, -1), (5, -1)),
    ((1, 0), (1, 1)),
    ((4, -3), (2, -3)),
    ((2, -2), (1, -2)),
    ((9, 0), (9, 1)),
    ((2, 1), (2, 2)),
    ((0, -1), (0, 0)),
    ((5, 0), (6, 0)),
    ((2, -3), (2, -2)),
    ((6, 0), (6, -1)),
    ((4, 1), (5, 1)),
    ((10, -1), (8, -1)),
    ((10, 1), (10, -1)),
    ((2, 2), (4, 2)),
    ((5, 1), (5, 0)),
    ((8, -1), (8, 0)),
    ((9, 1), (10, 1)),
    ((8, 0), (9, 0)),
    ((1, -2), (1, -1)),
    ((1, 1), (2, 1)),
    ((5, -2), (4, -2)),
    ((4, 2), (4, 1)),
    ((4, -2), (4, -3)),
    ((1, -1), (0, -1)),
    ((0, 0), (1, 0)) ]

eG = CoastLine()

for e in edge_list:
    eG.add_edge(*e)

eG.poly_geodataframe().plot()

这将是结果:

Polygon plot