Skip to content

Instantly share code, notes, and snippets.

@dotdoom
Created March 24, 2016 21:24
Show Gist options
  • Save dotdoom/d0df396f99630a4d6e84 to your computer and use it in GitHub Desktop.
Save dotdoom/d0df396f99630a4d6e84 to your computer and use it in GitHub Desktop.
ZVV Tarifzonen KML (Google Maps)
#!/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