forked from OpenPDU/openpdu
first mockup in go
This commit is contained in:
205
static/bower_components/jvectormap/converter/simplifier.py
vendored
Normal file
205
static/bower_components/jvectormap/converter/simplifier.py
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
from osgeo import ogr
|
||||
from osgeo import osr
|
||||
import anyjson
|
||||
import shapely.geometry
|
||||
import shapely.ops
|
||||
import codecs
|
||||
import time
|
||||
|
||||
|
||||
format = '%.8f %.8f'
|
||||
tolerance = 0.01
|
||||
infile = '/Users/kirilllebedev/Maps/50m-admin-0-countries/ne_50m_admin_0_countries.shp'
|
||||
outfile = 'map.shp'
|
||||
|
||||
# Open the datasource to operate on.
|
||||
in_ds = ogr.Open( infile, update = 0 )
|
||||
in_layer = in_ds.GetLayer( 0 )
|
||||
in_defn = in_layer.GetLayerDefn()
|
||||
|
||||
|
||||
# Create output file with similar information.
|
||||
shp_driver = ogr.GetDriverByName( 'ESRI Shapefile' )
|
||||
if os.path.exists('map.shp'):
|
||||
shp_driver.DeleteDataSource( outfile )
|
||||
shp_ds = shp_driver.CreateDataSource( outfile )
|
||||
shp_layer = shp_ds.CreateLayer( in_defn.GetName(),
|
||||
geom_type = in_defn.GetGeomType(),
|
||||
srs = in_layer.GetSpatialRef() )
|
||||
|
||||
in_field_count = in_defn.GetFieldCount()
|
||||
for fld_index in range(in_field_count):
|
||||
src_fd = in_defn.GetFieldDefn( fld_index )
|
||||
fd = ogr.FieldDefn( src_fd.GetName(), src_fd.GetType() )
|
||||
fd.SetWidth( src_fd.GetWidth() )
|
||||
fd.SetPrecision( src_fd.GetPrecision() )
|
||||
shp_layer.CreateField( fd )
|
||||
|
||||
|
||||
# Load geometries
|
||||
geometries = []
|
||||
for feature in in_layer:
|
||||
geometry = feature.GetGeometryRef()
|
||||
geometryType = geometry.GetGeometryType()
|
||||
|
||||
if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon:
|
||||
shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() )
|
||||
#if not shapelyGeometry.is_valid:
|
||||
#buffer to fix selfcrosses
|
||||
#shapelyGeometry = shapelyGeometry.buffer(0)
|
||||
if shapelyGeometry:
|
||||
geometries.append(shapelyGeometry)
|
||||
in_layer.ResetReading()
|
||||
|
||||
start = int(round(time.time() * 1000))
|
||||
# Simplification
|
||||
points = []
|
||||
connections = {}
|
||||
counter = 0
|
||||
for geom in geometries:
|
||||
counter += 1
|
||||
polygons = []
|
||||
|
||||
if isinstance(geom, shapely.geometry.Polygon):
|
||||
polygons.append(geom)
|
||||
else:
|
||||
for polygon in geom:
|
||||
polygons.append(polygon)
|
||||
|
||||
for polygon in polygons:
|
||||
if polygon.area > 0:
|
||||
lines = []
|
||||
lines.append(polygon.exterior)
|
||||
for line in polygon.interiors:
|
||||
lines.append(line)
|
||||
|
||||
for line in lines:
|
||||
for i in range(len(line.coords)-1):
|
||||
indexFrom = i
|
||||
indexTo = i+1
|
||||
pointFrom = format % line.coords[indexFrom]
|
||||
pointTo = format % line.coords[indexTo]
|
||||
if pointFrom == pointTo:
|
||||
continue
|
||||
if not (pointFrom in connections):
|
||||
connections[pointFrom] = {}
|
||||
connections[pointFrom][pointTo] = 1
|
||||
if not (pointTo in connections):
|
||||
connections[pointTo] = {}
|
||||
connections[pointTo][pointFrom] = 1
|
||||
print int(round(time.time() * 1000)) - start
|
||||
|
||||
simplifiedLines = {}
|
||||
pivotPoints = {}
|
||||
def simplifyRing(ring):
|
||||
coords = list(ring.coords)[0:-1]
|
||||
simpleCoords = []
|
||||
|
||||
isPivot = False
|
||||
pointIndex = 0
|
||||
while not isPivot and pointIndex < len(coords):
|
||||
pointStr = format % coords[pointIndex]
|
||||
pointIndex += 1
|
||||
isPivot = ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints))
|
||||
pointIndex = pointIndex - 1
|
||||
|
||||
if not isPivot:
|
||||
simpleRing = shapely.geometry.LineString(coords).simplify(tolerance)
|
||||
if len(simpleRing.coords) <= 2:
|
||||
return None
|
||||
else:
|
||||
pivotPoints[format % coords[0]] = True
|
||||
pivotPoints[format % coords[-1]] = True
|
||||
simpleLineKey = format % coords[0]+':'+format % coords[1]+':'+format % coords[-1]
|
||||
simplifiedLines[simpleLineKey] = simpleRing.coords
|
||||
return simpleRing
|
||||
else:
|
||||
points = coords[pointIndex:len(coords)]
|
||||
points.extend(coords[0:pointIndex+1])
|
||||
iFrom = 0
|
||||
for i in range(1, len(points)):
|
||||
pointStr = format % points[i]
|
||||
if ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints)):
|
||||
line = points[iFrom:i+1]
|
||||
lineKey = format % line[-1]+':'+format % line[-2]+':'+format % line[0]
|
||||
if lineKey in simplifiedLines:
|
||||
simpleLine = simplifiedLines[lineKey]
|
||||
simpleLine = list(reversed(simpleLine))
|
||||
else:
|
||||
simpleLine = shapely.geometry.LineString(line).simplify(tolerance).coords
|
||||
lineKey = format % line[0]+':'+format % line[1]+':'+format % line[-1]
|
||||
simplifiedLines[lineKey] = simpleLine
|
||||
simpleCoords.extend( simpleLine[0:-1] )
|
||||
iFrom = i
|
||||
if len(simpleCoords) <= 2:
|
||||
return None
|
||||
else:
|
||||
return shapely.geometry.LineString(simpleCoords)
|
||||
|
||||
|
||||
def simplifyPolygon(polygon):
|
||||
simpleExtRing = simplifyRing(polygon.exterior)
|
||||
if simpleExtRing is None:
|
||||
return None
|
||||
simpleIntRings = []
|
||||
for ring in polygon.interiors:
|
||||
simpleIntRing = simplifyRing(ring)
|
||||
if simpleIntRing is not None:
|
||||
simpleIntRings.append(simpleIntRing)
|
||||
return shapely.geometry.Polygon(simpleExtRing, simpleIntRings)
|
||||
|
||||
|
||||
results = []
|
||||
for geom in geometries:
|
||||
polygons = []
|
||||
simplePolygons = []
|
||||
|
||||
if isinstance(geom, shapely.geometry.Polygon):
|
||||
polygons.append(geom)
|
||||
else:
|
||||
for polygon in geom:
|
||||
polygons.append(polygon)
|
||||
|
||||
for polygon in polygons:
|
||||
simplePolygon = simplifyPolygon(polygon)
|
||||
if not (simplePolygon is None or simplePolygon._geom is None):
|
||||
simplePolygons.append(simplePolygon)
|
||||
|
||||
if len(simplePolygons) > 0:
|
||||
results.append(shapely.geometry.MultiPolygon(simplePolygons))
|
||||
else:
|
||||
results.append(None)
|
||||
|
||||
|
||||
# Process all features in input layer.
|
||||
in_feat = in_layer.GetNextFeature()
|
||||
counter = 0
|
||||
while in_feat is not None:
|
||||
if results[counter] is not None:
|
||||
out_feat = ogr.Feature( feature_def = shp_layer.GetLayerDefn() )
|
||||
out_feat.SetFrom( in_feat )
|
||||
out_feat.SetGeometryDirectly(
|
||||
ogr.CreateGeometryFromWkb(
|
||||
shapely.wkb.dumps(
|
||||
results[counter]
|
||||
)
|
||||
)
|
||||
)
|
||||
shp_layer.CreateFeature( out_feat )
|
||||
out_feat.Destroy()
|
||||
else:
|
||||
print 'geometry is too small: '+in_feat.GetField(16)
|
||||
|
||||
in_feat.Destroy()
|
||||
in_feat = in_layer.GetNextFeature()
|
||||
counter += 1
|
||||
|
||||
|
||||
# Cleanup
|
||||
shp_ds.Destroy()
|
||||
in_ds.Destroy()
|
||||
|
||||
print int(round(time.time() * 1000)) - start
|
||||
Reference in New Issue
Block a user