source: osmose-frontend/map.py

Last change on this file was e7f8984, checked in by Frederic Rodrigo <fred.rodrigo@…>, 5 years ago

Replace 'Error' by 'Issue' in string deplayed at user

  • Property mode set to 100644
File size: 10.2 KB
Line 
1#! /usr/bin/env python
2#-*- coding: utf-8 -*-
3
4###########################################################################
5##                                                                       ##
6## Copyrights Etienne Chové <chove@crans.org> 2009                       ##
7##                                                                       ##
8## This program is free software: you can redistribute it and/or modify  ##
9## it under the terms of the GNU General Public License as published by  ##
10## the Free Software Foundation, either version 3 of the License, or     ##
11## (at your option) any later version.                                   ##
12##                                                                       ##
13## This program is distributed in the hope that it will be useful,       ##
14## but WITHOUT ANY WARRANTY; without even the implied warranty of        ##
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         ##
16## GNU General Public License for more details.                          ##
17##                                                                       ##
18## You should have received a copy of the GNU General Public License     ##
19## along with this program.  If not, see <http://www.gnu.org/licenses/>. ##
20##                                                                       ##
21###########################################################################
22
23from bottle import route, request, template, response, redirect, abort, static_file
24from tools import utils, query, query_meta, assets
25import byuser
26import errors
27import datetime
28import math, StringIO
29from PIL import Image
30from PIL import ImageDraw
31
32
33def check_items(items, all_items):
34    if items == None or items == 'xxxx':
35        return all_items
36    else:
37        items = items.split(',')
38        it = filter(lambda i: str(i)[0]+'xxx' in items, all_items)
39        for i in items:
40            try:
41                n = int(i)
42                it.append(n)
43            except:
44                pass
45        return it
46
47
48@route('/map')
49def index_redirect():
50    new_url = "map/"
51    if request.query_string:
52        new_url += "?"
53        new_url += request.query_string
54    redirect(new_url)
55
56@route('/map/')
57def index(db, lang):
58    # valeurs par défaut
59    params = { "lat":    46.97,
60               "lon":    2.75,
61               "zoom":   6,
62               "item":   None,
63               "level":  1,
64               "source": '',
65               "class":  '',
66               "username": '',
67               "country": '',
68               "tags":    '',
69               "fixable": None,
70             }
71
72    for p in ["lat", "lon", "zoom", "item", "level", "tags", "fixable"]:
73        if request.cookies.get("last_" + p, default=None):
74            params[p] = request.cookies.get("last_" + p)
75
76    for p in ["lat", "lon", "zoom", "item", "useDevItem", "level", "source", "username", "class", "country", "tags", "fixable"]:
77        if request.params.get(p, default=None):
78            params[p] = request.params.get(p)
79
80    for p in ["lat", "lon"]:
81        params[p] = float(params[p])
82
83    for p in ["zoom"]:
84        params[p] = int(params[p])
85
86    if not params.has_key("useDevItem"):
87        params["useDevItem"] = ""
88
89    tags = query_meta._tags(db, lang)
90    tags_selected = {}
91    tags_params = params["tags"].split(',')
92    for t in tags:
93      if t in tags_params:
94        tags_selected[t] = " selected=\"selected\""
95      else:
96        tags_selected[t] = ""
97
98    fixable_selected = {}
99    fixable_selected['online'] = " selected=\"selected\"" if params["fixable"] and params["fixable"] == "online" else ""
100    fixable_selected['josm'] = " selected=\"selected\"" if params["fixable"] and params["fixable"] == "josm" else ""
101
102    all_items = []
103    db.execute("SELECT item FROM dynpoi_item GROUP BY item;")
104    for res in db.fetchall():
105        all_items.append(int(res[0]))
106    active_items = check_items(params["item"], all_items)
107
108    level_selected = {}
109    for l in ("_all", "1", "2", "3", "1,2", "1,2,3"):
110        level_selected[l] = ""
111
112    if params["level"] == "":
113        level_selected["1"] = " selected=\"selected\""
114    elif params["level"] in ("1", "2", "3", "1,2", "1,2,3"):
115        level_selected[params["level"]] = " selected=\"selected\""
116
117    categories = query_meta._categories(db, lang)
118
119    item_tags = {}
120    item_levels = {"1": set(), "2": set(), "3": set()}
121    for categ in categories:
122        for err in categ["item"]:
123            for l in err["levels"]:
124                item_levels[str(l)].add(err["item"])
125            if err["tags"]:
126                for t in err["tags"]:
127                    if not item_tags.has_key(t):
128                        item_tags[t] = set()
129                    item_tags[t].add(err["item"])
130
131    item_levels["1,2"] = item_levels["1"] | item_levels["2"]
132    item_levels["1,2,3"] = item_levels["1,2"] | item_levels["3"]
133
134    urls = []
135    # TRANSLATORS: link to help in appropriate language
136    urls.append(("byuser", _("Issues by user"), "../byuser/"))
137    urls.append(("relation_analyser", _("Relation analyser"), "http://analyser.openstreetmap.fr/"))
138    # TRANSLATORS: link to source code
139    urls.append(("statistics", _("Statistics"), "../control/update_matrix"))
140
141    helps = []
142    helps.append((_("Contact"), "../contact"))
143    helps.append((_("Help on wiki"), _("http://wiki.openstreetmap.org/wiki/Osmose")))
144    helps.append((_("Copyright"), "../copyright"))
145    helps.append((_("Sources"), "https://gitorious.org/osmose"))
146    helps.append((_("Translation"), "../translation"))
147
148    sql = """
149SELECT
150    EXTRACT(EPOCH FROM ((now())-timestamp)) AS age
151FROM
152    dynpoi_update_last
153ORDER BY
154    timestamp
155LIMIT
156    1
157OFFSET
158    (SELECT COUNT(*)/2 FROM dynpoi_update_last)
159;
160"""
161    db.execute(sql)
162    delay = db.fetchone()
163    if delay and delay[0]:
164        delay = delay[0]/60/60/24
165    else:
166        delay = 0
167
168    if request.session.has_key('user'):
169        if request.session['user']:
170            user = request.session['user']['osm']['user']['@display_name']
171            user_error_count = byuser._user_count(db, user.encode('utf-8'))
172        else:
173            user = '[user name]'
174            user_error_count = {1: 0, 2: 0, 3: 0}
175    else:
176        user = None
177        user_error_count = None
178
179    return template('map/index', categories=categories, lat=params["lat"], lon=params["lon"], zoom=params["zoom"],
180        source=params["source"], username=params["username"], classs=params["class"], country=params["country"],
181        item_tags=item_tags, tags_selected=tags_selected, tags=tags, fixable_selected=fixable_selected,
182        item_levels=item_levels, level_selected=level_selected,
183        active_items=active_items, useDevItem=params["useDevItem"],
184        urls=urls, helps=helps, delay=delay, languages_name=utils.languages_name, translate=utils.translator(lang),
185        website=utils.website, request=request, assets=assets.environment,
186        user=user, user_error_count=user_error_count)
187
188
189def num2deg(xtile, ytile, zoom):
190    n = 2.0 ** zoom
191    lon_deg = xtile / n * 360.0 - 180.0
192    lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
193    lat_deg = math.degrees(lat_rad)
194    return (lat_deg, lon_deg)
195
196@route('/map/heat/<z:int>/<x:int>/<y:int>.png')
197def heat(db, z, x, y):
198    x2,y1 = num2deg(x,y,z)
199    x1,y2 = num2deg(x+1,y+1,z)
200
201    params = query._params()
202    params.bbox = [y1, x1, y2, x2]
203    items = query._build_where_item(params.item, "dynpoi_item")
204
205    db.execute("""
206SELECT
207    SUM((SELECT SUM(t) FROM UNNEST(number) t))
208FROM
209    dynpoi_item
210WHERE
211""" + items)
212    max = db.fetchone()
213    if max and max[0]:
214        max = float(max[0])
215    else:
216        response.content_type = 'image/png'
217        return static_file("images/tile-empty.png", root='static')
218
219    join, where = query._build_param(None, None, params.bbox, params.source, params.item, params.level, params.users, params.classs, params.country, params.useDevItem, params.status, params.tags, params.fixable)
220    join = join.replace("%", "%%")
221    where = where.replace("%", "%%")
222
223    COUNT=32
224
225    sql = """
226SELECT
227    COUNT(*),
228    (((lon-%(y1)s))*%(count)s/(%(y2)s-%(y1)s)-0.5)::int AS latn,
229    (((lat-%(x1)s))*%(count)s/(%(x2)s-%(x1)s)-0.5)::int AS lonn
230FROM
231""" + join + """
232WHERE
233""" + where + """
234GROUP BY
235    latn,
236    lonn
237"""
238    db.execute(sql, {"x1":x1, "y1":y1, "x2":x2, "y2":y2, "count":COUNT})
239    im = Image.new("RGB", (256,256), "#ff0000")
240    draw = ImageDraw.Draw(im)
241
242    transparent_area = (0,0,256,256)
243    mask = Image.new('L', im.size, color=255)
244    mask_draw = ImageDraw.Draw(mask)
245    mask_draw.rectangle(transparent_area, fill=0)
246
247    for row in db.fetchall():
248        count, x, y = row
249        count = int(math.log(count) / math.log(max / ((z-4+1+math.sqrt(COUNT))**2)) * 255)
250        count = 255 if count > 255 else count
251        r = [(x*256/COUNT,(COUNT-1-y)*256/COUNT), ((x+1)*256/COUNT-1,((COUNT-1-y+1)*256/COUNT-1))]
252        mask_draw.rectangle(r, fill=count)
253
254    im.putalpha(mask)
255    del draw
256
257    buf = StringIO.StringIO()
258    im.save(buf, 'PNG')
259    response.content_type = 'image/png'
260    return buf.getvalue()
261
262
263@route('/map/markers')
264def markers(db, lang):
265    params = query._params()
266
267    if (not params.users) and (not params.source) and (params.zoom < 6):
268        return
269
270    params.limit = 200
271    params.full = False
272
273    expires = datetime.datetime.now() + datetime.timedelta(days=365)
274    path = '/'.join(request.fullpath.split('/')[0:-1])
275    response.set_cookie('last_lat', str(params.lat), expires=expires, path=path)
276    response.set_cookie('last_lon', str(params.lon), expires=expires, path=path)
277    response.set_cookie('last_zoom', str(params.zoom), expires=expires, path=path)
278    response.set_cookie('last_level', str(params.level), expires=expires, path=path)
279    response.set_cookie('last_item', str(params.item), expires=expires, path=path)
280    response.set_cookie('last_tags', str(','.join(params.tags)) if params.tags else '', expires=expires, path=path)
281    response.set_cookie('last_fixable', str(params.fixable) if params.fixable else '', expires=expires, path=path)
282
283    return errors._errors_geo(db, lang, params)
284
285
286@route('/tpl/popup.tpl')
287def popup_template(lang):
288    return template('map/popup', mustache_delimiter="{{={% %}=}}", website=utils.website)
289
290@route('/tpl/editor.tpl')
291def editor_template(lang):
292    return template('map/editor', mustache_delimiter="{{={% %}=}}")
Note: See TracBrowser for help on using the repository browser.