#!/usr/bin/python3.4
-import logging
+import re
+import xml.dom.minidom as minidom
+from xml.parsers.expat import ExpatError
+from enum import IntEnum
+from flask import request, redirect, url_for, flash
+from wradmin.genshi import render_genshi_template, TemplateContext
-from pylons import request, response, session, url, tmpl_context as c
-from pylons.controllers.util import abort, redirect
-import formencode
-from wradmin.lib.base import BaseController, render
-import wrpylib.wrvalidators
+class MultiGeo(IntEnum):
+ """Formats multiple coordinates, even in multiple lines to [(latitude, longitude, elevation), ...]
+ or [(latitude, longitude, None), ...] tuples."""
-log = logging.getLogger(__name__)
+ # Valid for input_format
+ FORMAT_GUESS = 0 # guesses the input format; default for input_format
+ FORMAT_NONE = -1 # indicates missing formats
-class CoordtoolController(BaseController):
+ # Valid for input_format and output_format
+ FORMAT_GEOCACHING = 1 # e.g. "N 47° 13.692 E 011° 25.535"
+ FORMAT_WINTERRODELN = 2 # e.g. "47.222134 N 11.467211 E"
+ FORMAT_GMAPPLUGIN = 3 # e.g. "47.232922, 11.452239"
+ FORMAT_GPX = 4 # e.g. "<trkpt lat="47.181289" lon="11.408827"><ele>1090.57</ele></trkpt>"
+
+
+def multigeo_from_string(value, input_format):
+ assert input_format in [MultiGeo.FORMAT_GUESS, MultiGeo.FORMAT_GEOCACHING, MultiGeo.FORMAT_WINTERRODELN,
+ MultiGeo.FORMAT_GMAPPLUGIN, MultiGeo.FORMAT_GPX], "input_format %d is not recognized"
+ lines = [line.strip() for line in value.split("\n") if len(line.strip()) > 0]
+
+ result = []
+ for line in lines:
+ if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GEOCACHING:
+ r = re.match('N ?(\d+)° ?(\d+\.\d+) +E ?(\d+)° ?(\d+\.\d+)', line)
+ if r is not None:
+ g = r.groups()
+ result.append((float(g[0]) + float(g[1]) / 60, float(g[2]) + float(g[3]) / 60, None))
+ continue
+
+ if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_WINTERRODELN:
+ r = re.match('(\d+\.\d+) N (\d+\.\d+) E', line)
+ if not r is None:
+ result.append((float(r.groups()[0]), float(r.groups()[1]), None))
+ continue
+
+ if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GMAPPLUGIN:
+ r = re.match('(\d+\.\d+), ?(\d+\.\d+)', line)
+ if r is not None:
+ result.append((float(r.groups()[0]), float(r.groups()[1]), None))
+ continue
+
+ if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GPX:
+ try:
+ xml = minidom.parseString(line)
+ coord = xml.documentElement
+ lat = float(coord.getAttribute('lat'))
+ lon = float(coord.getAttribute('lon'))
+ try:
+ ele = float(coord.childNodes[0].childNodes[0].nodeValue)
+ except (IndexError, ValueError):
+ ele = None
+ result.append((lat, lon, ele))
+ continue
+ except (ExpatError, IndexError, ValueError):
+ pass
+
+ raise ValueError("Coordinates '%s' have no known format" % line, value)
+ return result
+
+
+def multigeo_to_string(value, output_format):
+ result = []
+ for latitude, longitude, height in value:
+ if output_format == MultiGeo.FORMAT_GEOCACHING:
+ result.append(
+ 'N %02d° %02.3f E %03d° %02.3f' % (latitude, latitude % 1 * 60, longitude, longitude % 1 * 60))
+
+ elif output_format == MultiGeo.FORMAT_WINTERRODELN:
+ result.append('%.6f N %.6f E' % (latitude, longitude))
+
+ elif output_format == MultiGeo.FORMAT_GMAPPLUGIN:
+ result.append('%.6f, %.6f' % (latitude, longitude))
+
+ elif output_format == MultiGeo.FORMAT_GPX:
+ if not height is None:
+ result.append(
+ '<trkpt lat="%.6f" lon="%.6f"><ele>%.2f</ele></trkpt>' % (latitude, longitude, height))
+ else:
+ result.append('<trkpt lat="%.6f" lon="%.6f"/>' % (latitude, longitude))
+
+ else:
+ raise ValueError("output_format %d is not recognized" % output_format, value)
+
+ return "\n".join(result)
+
+
+class CoordtoolController:
def index(self):
+ c = TemplateContext()
c.result = None
- return render('coordtool.html')
-
+ return render_genshi_template('coordtool.html', c=c)
def convert(self):
- input = request.POST['input']
- no_elevation = 'no_elevation' in request.POST
- simplify = 'simplify' in request.POST
- swap_latlon = 'swap_latlon' in request.POST
- c.no_geoformat = 'no_geoformat' in request.POST
- c.no_gpxformat = 'no_gpxformat' in request.POST
- c.no_gmapsformat = 'no_gmapsformat' in request.POST
- c.no_geocachingformat = 'no_geocachingformat' in request.POST
+ c = TemplateContext()
+ assert request.method == 'POST'
+ input = request.form['input']
+ no_elevation = 'no_elevation' in request.form
+ simplify = 'simplify' in request.form
+ swap_latlon = 'swap_latlon' in request.form
+ c.no_geoformat = 'no_geoformat' in request.form
+ c.no_gpxformat = 'no_gpxformat' in request.form
+ c.no_gmapsformat = 'no_gmapsformat' in request.form
+ c.no_geocachingformat = 'no_geocachingformat' in request.form
if input is None or len(input.strip()) == 0:
c.result = None
- return redirect(url(controller='coordtool', action='index'))
+ return redirect(url_for('coordtool_index'))
- geo = wrpylib.wrvalidators.MultiGeo()
- try: c.result = geo.to_python(input)
- except formencode.Invalid as e:
- session['flash'] = str(e)
- session.save()
- return redirect(url(controller='coordtool', action='index'))
+ try:
+ c.result = multigeo_from_string(input, MultiGeo.FORMAT_GUESS)
+ except ValueError as e:
+ flash(str(e))
+ return redirect(url_for('coordtool_index'))
if swap_latlon:
c.result = [(latitude, longitude, elevation) for (longitude, latitude, elevation) in c.result]
if no_elevation:
c.result = [(longitude, latitude, None) for (longitude, latitude, elevation) in c.result]
- c.geo_winterrodeln = wrpylib.wrvalidators.MultiGeo(output_format = geo.FORMAT_WINTERRODELN)
- c.geo_gmapplugin = wrpylib.wrvalidators.MultiGeo(output_format = geo.FORMAT_GMAPPLUGIN)
- c.geo_gpx = wrpylib.wrvalidators.MultiGeo(output_format = geo.FORMAT_GPX)
- c.geo_geocaching = wrpylib.wrvalidators.MultiGeo(output_format = geo.FORMAT_GEOCACHING)
+ c.geo_winterrodeln = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_WINTERRODELN)
+ c.geo_gmapplugin = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GMAPPLUGIN)
+ c.geo_gpx = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GPX)
+ c.geo_geocaching = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GEOCACHING)
- return render('coordtool.html')
+ return render_genshi_template('coordtool.html', c=c)