Created
March 24, 2016 21:24
-
-
Save dotdoom/d0df396f99630a4d6e84 to your computer and use it in GitHub Desktop.
ZVV Tarifzonen KML (Google Maps)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Fetch ZVV Tarifzonen map in SVG and convert to KML. | |
# You can save the output and import into Google Maps. | |
# Use at your own risk. The API used is not publicly disclosed, | |
# improper use may lead to lawsuits. | |
import sys | |
import urllib2 | |
import xml.etree.ElementTree as ET | |
minLat = 47.1417 | |
maxLat = 47.7124 | |
minLon = 8.15723 | |
maxLon = 9.03749 | |
width = 2000 | |
height = 2000 | |
url = 'http://wms.zh.ch/ZVVZHWMS?version=1.3.0&service=WMS&request=GetMap&' \ | |
'LAYERS=tarifzonen&format=image/svg%%2Bxml&CRS=EPSG:4326&BBOX=' \ | |
'%.5f,%.5f,%.5f,%.5f&WIDTH=%d&HEIGHT=%d' % ( | |
minLat, minLon, maxLat, maxLon, width, height) | |
root = ET.fromstring(urllib2.urlopen(url).read()) | |
def ParseColor(s): | |
if s.startswith('rgb'): | |
return ''.join( | |
'%.2x' % (float(percent[:-1]) * 0xff / 100) | |
for percent in reversed(s[4:-1].split(','))) | |
return '000000' | |
def ParseData(s): | |
pipeline = s.split(' ') | |
moveto = None | |
for i in xrange(0, len(pipeline), 3): | |
command, x, y = pipeline[i:i+3] | |
if command == 'L': | |
if moveto: | |
yield moveto | |
moveto = None | |
yield (x, y) | |
elif command == 'M': | |
moveto = (x, y) | |
elif command == 'Z': | |
return | |
else: | |
raise Exception('Unknown command: %s' % command) | |
def Map(value, low, high, newLow, newHigh): | |
return (value - low) / (high - low) * (newHigh - newLow) + newLow | |
def AddStyle(doc, styleId, fill): | |
style = ET.SubElement(doc, 'Style', id=styleId) | |
poly = ET.SubElement(style, 'PolyStyle') | |
ET.SubElement(poly, 'color').text = fill | |
ET.SubElement(poly, 'fill').text = '1' | |
ET.SubElement(poly, 'outline').text = '1' | |
kml = ET.Element('kml', xmlns='http://www.opengis.net/kml/2.2') | |
doc = ET.SubElement(kml, 'Document') | |
ET.SubElement(doc, 'name').text='Tarifzonen' | |
for i, path in enumerate(root.iter('{http://www.w3.org/2000/svg}path')): | |
styles = dict( | |
style.split(':') | |
for style in path.attrib['style'].split(';') | |
if len(style)) | |
if (styles.get('fill') == 'none') or (styles.get('fill-opacity') == '1'): | |
# These are numbers, we don't have curve support so don't even try | |
continue | |
pm = ET.SubElement(doc, 'Placemark') | |
ET.SubElement(pm, 'name').text = str(i) | |
ET.SubElement(pm, 'styleUrl').text = '#poly-%d' % i | |
ring = ET.SubElement( | |
ET.SubElement( | |
ET.SubElement(pm, 'Polygon'), | |
'outerBoundaryIs'), | |
'LinearRing') | |
ET.SubElement(ring, 'tessellate').text = '1' | |
try: | |
coordinates = [ | |
(Map(float(x), 0, width, minLon, maxLon), | |
Map(float(y), 0, height, maxLat, minLat)) | |
for x, y in ParseData(path.attrib['d'])] | |
except: | |
continue | |
ET.SubElement(ring, 'coordinates').text = ' '.join('%.8f,%.8f,0.0' % (x, y) | |
for x, y in coordinates) | |
# fill is AABBGGRR, where AA is alpha-channel (transparency) | |
fill = '%.2x%s' % ( | |
int(float(styles.get('fill-opacity', 1)) * 0xff), | |
ParseColor(styles['fill'])) | |
AddStyle(doc, 'poly-%d' % i, fill) | |
ET.ElementTree(kml).write(sys.stdout, encoding='utf-8', xml_declaration=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment