Skip to content

Instantly share code, notes, and snippets.

@ckhung
Last active September 19, 2015 01:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ckhung/8411f3222c89761005bd to your computer and use it in GitHub Desktop.
Save ckhung/8411f3222c89761005bd to your computer and use it in GitHub Desktop.
本程式把鄉鎮縣市的 geojson 檔裡面的 MultiPolygon 當中面積最大的一塊抓出來, 變成一個單獨的 Polygon, 就可以上傳至 umap 了。
#!/usr/bin/python
# -*- coding: utf-8 -*-
# http://newtoypia.blogspot.tw/2015/08/admin-boundary.html
# 「臺灣各級行政區域(縣市/鄉鎮/村里)邊界座標檔, 自選解析度、 存成 csv、 畫成 svg 」
import json, argparse, sys, math, warnings
def area(coords):
n = len(coords)
if n < 3:
return 0
o = [ (coords[0][0]+coords[n/3][0]+coords[n*2/3][0]) / 3,
(coords[0][1]+coords[n/3][1]+coords[n*2/3][1]) / 3 ]
a = 0
for i in range(len(coords)):
p = [coords[i][0]-o[0], coords[i][1]-o[1]]
q = [coords[(i+1)%n][0]-o[0], coords[(i+1)%n][1]-o[1]]
a += p[0]*q[1] - p[1]*q[0]
c = math.cos(o[1]/180*math.pi)
# warnings.warn('# cos({0:8f} deg) == {1:8f}'.format(o[1], c))
return abs(a*c)
def largest_piece(coords):
if isinstance(coords[0], list):
if isinstance(coords[0][0], (int, long, float)) and len(coords[0])==2:
return { 'area': area(coords), 'coords': coords }
else:
pieces = map(largest_piece, coords)
m = pieces[0]
for p in pieces:
if p['area'] > m['area']:
m = p
return m
else:
assert False, "input data dose not look like geometry coordinates"
def multi2maxpolygon(gjdata):
if isinstance(gjdata, dict):
if gjdata['type'] == 'FeatureCollection':
gjdata['features'] = map(multi2maxpolygon, gjdata['features'])
elif gjdata['type'] != 'Feature':
warnings.warn('ignoring something with type=="' + gjdata['type'] + '"')
elif not ('geometry' in gjdata):
warnings.warn('ignoring a feature without geometry: ' + json.dumps(gjdata,indent=2,ensure_ascii=False).encode('utf8'))
elif gjdata['geometry'] is None:
warnings.warn('ignoring a feature with null geometry: ' + json.dumps(gjdata,indent=2,ensure_ascii=False).encode('utf8'))
else:
if len(args.name_field) > 0:
gjdata['properties']['name'] = gjdata['properties'][args.name_field]
if gjdata['geometry']['type'] == 'MultiPolygon':
gjdata['geometry']['coordinates'] = [largest_piece(gjdata['geometry']['coordinates'])['coords']]
gjdata['geometry']['type'] = 'Polygon'
return gjdata
elif isinstance(gjdata, list):
return map(multi2maxpolygon, gjdata)
parser = argparse.ArgumentParser(description='pick the largest piece of a multipolygon in geojson files',formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-n', '--name_field', type=str,
default='', help='which subfield of "properties" to use as "name"?')
parser.add_argument('gjf', nargs='*', default='-', help='path to geojson files')
args = parser.parse_args()
for fn in args.gjf:
gjfile = sys.stdin if fn == '-' else open(fn)
gjdata = json.load(gjfile)
print json.dumps(multi2maxpolygon(gjdata),indent=2,ensure_ascii=False).encode('utf8')
# https://stackoverflow.com/questions/18337407/saving-utf-8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence
if gjfile is not sys.stdin:
gjfile.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment