63 lines
1.6 KiB
Python
63 lines
1.6 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import sys
|
||
|
import rtree
|
||
|
import os
|
||
|
from osgeo import ogr
|
||
|
|
||
|
def main():
|
||
|
infile = sys.argv[1]
|
||
|
driver = ogr.GetDriverByName('gpkg')
|
||
|
inDataSource = driver.Open(infile, 0)
|
||
|
inLayer = inDataSource.GetLayer()
|
||
|
srs = inLayer.GetSpatialRef()
|
||
|
|
||
|
points = get_points(inLayer)
|
||
|
path = greedy_path(points)
|
||
|
|
||
|
outDataSource = driver.CreateDataSource(sys.argv[2])
|
||
|
outLayerName, _ = os.path.splitext(os.path.basename(sys.argv[2]))
|
||
|
outLayer = outDataSource.CreateLayer(outLayerName, srs, geom_type=ogr.wkbLineString)
|
||
|
|
||
|
line = ogr.Geometry(ogr.wkbLineString)
|
||
|
for point in path:
|
||
|
line.AddPoint(point[0], point[1])
|
||
|
|
||
|
outFeature = ogr.Feature(outLayer.GetLayerDefn())
|
||
|
outFeature.SetGeometry(line)
|
||
|
outLayer.CreateFeature(outFeature)
|
||
|
|
||
|
inDataSource.Destroy()
|
||
|
outFeature.Destroy()
|
||
|
outDataSource.Destroy()
|
||
|
|
||
|
def get_points(layer):
|
||
|
points = {}
|
||
|
for (i, pt) in enumerate(layer):
|
||
|
p = pt.GetGeometryRef().GetPoint()
|
||
|
points[i] = (p[0], p[1])
|
||
|
return points
|
||
|
|
||
|
def greedy_path(points):
|
||
|
"Given a dict of points, return a localized short path between them."
|
||
|
idx = rtree.index.Index(interleaved = False)
|
||
|
for (i, pt) in points.items():
|
||
|
idx.insert(i, pt)
|
||
|
|
||
|
def _bounds(_pts):
|
||
|
return (_pts[0], _pts[0], _pts[1], _pts[1])
|
||
|
|
||
|
ret = [0]
|
||
|
idx.delete(0, _bounds(points[0]))
|
||
|
while len(ret) < len(points):
|
||
|
pt = _bounds(points[ret[-1]])
|
||
|
nearest = next(idx.nearest(pt))
|
||
|
ret.append(nearest)
|
||
|
idx.delete(nearest, _bounds(points[nearest]))
|
||
|
ret.append(0)
|
||
|
return [points[point] for point in ret]
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|