]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blob - wradmin/controllers/coordtool.py
9dda22b248977a92c80560a06c99c5f97ae489dc
[philipp/winterrodeln/wradmin.git] / wradmin / controllers / coordtool.py
1 #!/usr/bin/python3.4
2 import re
3 import xml.dom.minidom as minidom
4 from xml.parsers.expat import ExpatError
5 from enum import IntEnum
6 from flask import request, redirect, url_for, flash, render_template
7
8
9 class MultiGeo(IntEnum):
10     """Formats multiple coordinates, even in multiple lines to [(latitude, longitude, elevation), ...] 
11     or [(latitude, longitude, None), ...] tuples."""
12
13     # Valid for input_format
14     FORMAT_GUESS = 0  # guesses the input format; default for input_format
15     FORMAT_NONE = -1  # indicates missing formats
16
17     # Valid for input_format and output_format
18     FORMAT_GEOCACHING = 1  # e.g. "N 47° 13.692 E 011° 25.535"
19     FORMAT_WINTERRODELN = 2  # e.g. "47.222134 N 11.467211 E"
20     FORMAT_GMAPPLUGIN = 3  # e.g. "47.232922, 11.452239"
21     FORMAT_GPX = 4  # e.g. "<trkpt lat="47.181289" lon="11.408827"><ele>1090.57</ele></trkpt>"
22
23
24 def multigeo_from_string(value, input_format):
25     assert input_format in [MultiGeo.FORMAT_GUESS, MultiGeo.FORMAT_GEOCACHING, MultiGeo.FORMAT_WINTERRODELN,
26                             MultiGeo.FORMAT_GMAPPLUGIN, MultiGeo.FORMAT_GPX], "input_format %d is not recognized"
27     lines = [line.strip() for line in value.split("\n") if len(line.strip()) > 0]
28
29     result = []
30     for line in lines:
31         if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GEOCACHING:
32             r = re.match('N ?(\d+)° ?(\d+\.\d+) +E ?(\d+)° ?(\d+\.\d+)', line)
33             if r is not None:
34                 g = r.groups()
35                 result.append((float(g[0]) + float(g[1]) / 60, float(g[2]) + float(g[3]) / 60, None))
36                 continue
37
38         if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_WINTERRODELN:
39             r = re.match('(\d+\.\d+) N (\d+\.\d+) E', line)
40             if not r is None:
41                 result.append((float(r.groups()[0]), float(r.groups()[1]), None))
42                 continue
43
44         if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GMAPPLUGIN:
45             r = re.match('(\d+\.\d+), ?(\d+\.\d+)', line)
46             if r is not None:
47                 result.append((float(r.groups()[0]), float(r.groups()[1]), None))
48                 continue
49
50         if input_format == MultiGeo.FORMAT_GUESS or input_format == MultiGeo.FORMAT_GPX:
51             try:
52                 xml = minidom.parseString(line)
53                 coord = xml.documentElement
54                 lat = float(coord.getAttribute('lat'))
55                 lon = float(coord.getAttribute('lon'))
56                 try:
57                     ele = float(coord.childNodes[0].childNodes[0].nodeValue)
58                 except (IndexError, ValueError):
59                     ele = None
60                 result.append((lat, lon, ele))
61                 continue
62             except (ExpatError, IndexError, ValueError):
63                 pass
64
65         raise ValueError("Coordinates '%s' have no known format" % line, value)
66     return result
67
68
69 def multigeo_to_string(value, output_format):
70     result = []
71     for latitude, longitude, height in value:
72         if output_format == MultiGeo.FORMAT_GEOCACHING:
73             result.append(
74                 'N %02d° %02.3f E %03d° %02.3f' % (latitude, latitude % 1 * 60, longitude, longitude % 1 * 60))
75
76         elif output_format == MultiGeo.FORMAT_WINTERRODELN:
77             result.append('%.6f N %.6f E' % (latitude, longitude))
78
79         elif output_format == MultiGeo.FORMAT_GMAPPLUGIN:
80             result.append('%.6f, %.6f' % (latitude, longitude))
81
82         elif output_format == MultiGeo.FORMAT_GPX:
83             if not height is None:
84                 result.append(
85                     '<trkpt lat="%.6f" lon="%.6f"><ele>%.2f</ele></trkpt>' % (latitude, longitude, height))
86             else:
87                 result.append('<trkpt lat="%.6f" lon="%.6f"/>' % (latitude, longitude))
88
89         else:
90             raise ValueError("output_format %d is not recognized" % output_format, value)
91
92     return "\n".join(result)
93
94
95 class CoordtoolController:
96
97     def index(self):
98         return render_template('coordtool.html', result=None)
99
100     def convert(self):
101         assert request.method == 'POST'
102         input = request.form['input']
103         no_elevation = 'no_elevation' in request.form
104         simplify = 'simplify' in request.form
105         swap_latlon = 'swap_latlon' in request.form
106         no_geoformat = 'no_geoformat' in request.form
107         no_gpxformat = 'no_gpxformat' in request.form
108         no_gmapsformat = 'no_gmapsformat' in request.form
109         no_geocachingformat = 'no_geocachingformat' in request.form
110         
111         if input is None or len(input.strip()) == 0: 
112             return redirect(url_for('coordtool_index'))
113         
114         try:
115             result = multigeo_from_string(input, MultiGeo.FORMAT_GUESS)
116         except ValueError as e:
117             flash(str(e))
118             return redirect(url_for('coordtool_index'))
119         
120         if swap_latlon:
121             result = [(latitude, longitude, elevation) for (longitude, latitude, elevation) in result]
122         
123         if no_elevation:
124             result = [(longitude, latitude, None) for (longitude, latitude, elevation) in result]
125         
126         geo_winterrodeln = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_WINTERRODELN)
127         geo_gmapplugin = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GMAPPLUGIN)
128         geo_gpx = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GPX)
129         geo_geocaching = lambda value: multigeo_to_string(value, MultiGeo.FORMAT_GEOCACHING)
130         
131         return render_template('coordtool.html', result=result,
132                                no_geoformat=no_geoformat, geo_winterrodeln=geo_winterrodeln,
133                                no_gmapsformat=no_gmapsformat, geo_gmapplugin=geo_gmapplugin,
134                                no_gpxformat=no_gpxformat, geo_gpx=geo_gpx,
135                                no_geocachingformat=no_geocachingformat, geo_geocaching=geo_geocaching)