#!/usr/bin/python3.4 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 class MultiGeo(IntEnum): """Formats multiple coordinates, even in multiple lines to [(latitude, longitude, elevation), ...] or [(latitude, longitude, None), ...] tuples.""" # Valid for input_format FORMAT_GUESS = 0 # guesses the input format; default for input_format FORMAT_NONE = -1 # indicates missing formats # 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. "1090.57" 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( '%.2f' % (latitude, longitude, height)) else: result.append('' % (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_genshi_template('coordtool.html', c=c) def convert(self): 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_for('coordtool_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 = 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_genshi_template('coordtool.html', c=c)