Browse Source

Demo : show a map with all point of interest

Olivier Marty 8 years ago
parent
commit
0b0103409f
4 changed files with 95 additions and 35 deletions
  1. 63 8
      demo.py
  2. 3 3
      geocoding.py
  3. 3 3
      main.py
  4. 26 21
      source.py

+ 63 - 8
demo.py

@@ -2,11 +2,65 @@ from geocoding import *
 import webbrowser
 import main
 import notification
+import tempfile
+import os
 
-def open_pos(pos):
-  pos_str = '(' + str(pos[0]) + ', ' + str(pos[1]) + ')'
-  if input('Montrer la position ' + pos_str + ' ? [Y/n] ') != 'n':
-    webbrowser.open_new("https://www.google.fr/maps/search/" + pos_str)
+def str_of_pos(pos):
+  return '{lat: ' + str(pos[0]) + ', lng: ' + str(pos[1]) + '}'
+
+def str_of_marker(pos, description):
+  return """
+  marker = new google.maps.Marker({
+    position: """ + str_of_pos(pos) + """,
+    map: map,
+    title: '""" + description + """'
+  });
+  var infowindow = new google.maps.InfoWindow({
+    content: '""" + description + """'
+  });
+  infowindow.open(marker.get('map'), marker);"""
+
+
+def open_markers(center, markers):
+  # markers_str = map(lambda pos_name: '&markers=color:blue|label:' + pos_name[1] + '|' + str_of_pos(pos_name[0]) , markers)
+  # if input('Montrer la carte ? [Y/n] ') != 'n':
+  #   url = "http://maps.google.com/maps/api/staticmap?center" + str_of_pos(center) +\
+  #   '&zoom=14&size=512x512&maptype=roadmap' +\
+  #   '&markers=color:red|label:destination|' + str_of_pos(center) + ''.join(markers_str)
+  #   webbrowser.open_new(url)
+  if input('Montrer la carte ? [Y/n] ') != 'n':
+    html = """<!DOCTYPE html>
+<html>
+  <head>
+    <style type="text/css">
+      html, body { height: 100%; margin: 0; padding: 0; }
+      #map { height: 100%; }
+    </style>
+  </head>
+  <body>
+    <div id="map"></div>
+    <script type="text/javascript">
+var map;
+function initMap() {
+  map = new google.maps.Map(document.getElementById('map'), {
+    center: """ + str_of_pos(center) + """,
+    zoom: 15
+  });
+""" + str_of_marker(center, 'destination')
+    for (pos, name) in markers:
+      html += str_of_marker(pos, name)
+    html += """
+}
+    </script>
+    <script async defer
+      src="https://maps.googleapis.com/maps/api/js?key=""" + config.api_key['google_maps'] + """&callback=initMap">
+    </script>
+  </body>
+</html>"""
+    (f, path) = tempfile.mkstemp(suffix=".html")
+    os.write(f, html.encode())
+    os.close(f)
+    webbrowser.open_new('file://' + path)
 
 def message():
   yield("Faisons un essai !\n")
@@ -26,7 +80,8 @@ for m in message():
   if not position:
     print("Désolé, l'adresse n'est pas reconnue :-(")
   else:
-    open_pos(position)
+    #open_pos(position)
+    markers = []
 
     for source in main.gen_sources(sourceProviders, location):
         if source.problem():
@@ -34,9 +89,9 @@ for m in message():
         else:
             print("Pas de problème : ", end='')
         notification.notify(source.message)
-        if "full" in source.id:
-            pos = sourceProviders[1].dic_of_positions()[source.id][0]
-            open_pos(pos)
+        markers.append((source.pos, source.id))
+
+    open_markers(position, markers)
 
   # empty line
   print()

+ 3 - 3
geocoding.py

@@ -25,10 +25,10 @@ def dist(posa, posb):
         return vincenty(posa, posb).km
 
 def k_neighbors(positions, fro, n):
-  """returns a list of (dist, id) of the n nearest points from fro
+  """returns a list of (dist, pos, id) of the n nearest points from fro
   positions is a dictionary id -> (lat, long)"""
   distances = []
   for (id, pos) in positions.items():
-    dmin = min(map(lambda p : dist(fro, p), pos))
-    distances.append((dmin, id))
+    (dmin, pmin) = min(map(lambda p : (dist(fro, p), p), pos))
+    distances.append((dmin, pmin, id))
   return sorted(distances)[:n]

+ 3 - 3
main.py

@@ -24,9 +24,9 @@ def gen_sources(sourceProviders, location):
   else:
     for sp in sourceProviders:
       # keep 2 nearest sources, if distance < 2 km
-      ids = [id for (dist, id) in k_neighbors(sp.dic_of_positions(), position, 2) if dist < 2]
-      print('Cherches les sources : ', ids)
-      for source in sp.sources_of_ids(ids):
+      ids_pos = {id: pos for (dist, pos, id) in k_neighbors(sp.dic_of_positions(), position, 2) if dist < 2}
+      print('Cherches les sources : ', list(ids_pos.keys()))
+      for source in sp.sources_of_ids(ids_pos):
           yield source
 
 def get_events():

+ 26 - 21
source.py

@@ -18,17 +18,18 @@ class SourceProvider:
     """Returns a dictionary mapping ids to a list of positions (for geocoding.py)"""
     return []
 
-  def sources_of_ids(self, ids):
-    """Returns a generator of Source these ids"""
+  def sources_of_ids(self, ids_pos):
+    """Returns a generator of Source these ids (a dictionary id -> position (only for display))"""
     return []
 
 
 ############## RATP ##############
 
 class Source_ratp(Source):
-  def __init__(self, ident, status, message):
+  def __init__(self, ident, pos, status, message):
     self.source = 'ratp_trafic'
     self.id = ident
+    self.pos = pos
     self.status = status
     self.message = message
 
@@ -64,19 +65,20 @@ class SourceProvider_ratp(SourceProvider):
         raise e
     return self.positions
 
-  def sources_of_ids(self, ids):
+  def sources_of_ids(self, ids_pos):
     for tag in XML(url="http://www.ratp.fr/meteo/", lang="html").data.select('div.encadre_ligne'):
-      if tag['id'] in ids:
-        yield Source_ratp(tag['id'], tag.img['alt'],\
+      if tag['id'] in ids_pos:
+        yield Source_ratp(tag['id'], ids_pos[tag['id']], tag.img['alt'],\
           tag['id'].replace('_', ' ') + ' : ' + tag.select('span.perturb_message')[0].string)
 
 
 ############## JCDECAUX_VLS ##############
 
 class Source_jcdecaux_vls(Source):
-  def __init__(self, ident, nom, timestamp, status):
+  def __init__(self, ident, pos, nom, timestamp, status):
     self.source = 'jcdecaux_vls'
     self.id = ident
+    self.pos = pos
     self.status = status # TODO dans l'API pour 1 station il semble que c'est toujours OPEN :-(
     self.date = datetime.datetime.fromtimestamp(int(timestamp)/1000).strftime('à %Hh%M le %d/%m')
     if status != "OPEN":
@@ -88,8 +90,8 @@ class Source_jcdecaux_vls(Source):
     return self.status != "OPEN"
 
 class Source_jcdecaux_vls_full(Source_jcdecaux_vls):
-  def __init__(self, ident, nom, timestamp, places, status):
-    super(Source_jcdecaux_vls_full, self).__init__(ident, nom, timestamp, status)
+  def __init__(self, ident, pos, nom, timestamp, places, status):
+    super(Source_jcdecaux_vls_full, self).__init__(ident, pos, nom, timestamp, status)
     self.id += "_full"
     self.places = int(places)
     if not self.message:
@@ -106,8 +108,8 @@ class Source_jcdecaux_vls_full(Source_jcdecaux_vls):
 
 
 class Source_jcdecaux_vls_empty(Source_jcdecaux_vls):
-  def __init__(self, ident, nom, timestamp, bikes, status):
-    super(Source_jcdecaux_vls_empty, self).__init__(ident, nom, timestamp, status)
+  def __init__(self, ident, pos, nom, timestamp, bikes, status):
+    super(Source_jcdecaux_vls_empty, self).__init__(ident, pos, nom, timestamp, status)
     self.id += "_empty"
     self.bikes = int(bikes)
     if not self.message:
@@ -154,24 +156,27 @@ class SourceProvider_jcdecaux_vls(SourceProvider):
         # we use find('name') because .name is the current tag name
     return self.positions
 
-  def sources_of_ids(self, ids):
-    ids_set = set(map(lambda s : s.rsplit('_', 1)[0], ids))
+  def sources_of_ids(self, ids_pos):
+    ids_set = set(map(lambda s : s[0].rsplit('_', 1)[0], ids_pos.items()))
     for station in ids_set:
       (contract, number) = list(station.split('_'))
       xml = XML(url="https://api.jcdecaux.com/vls/v1/stations/" + number + "?contract=" + contract + "&apiKey="+config.api_key['jcdecaux_vls'], lang="json")
       tag = xml.data.json
-      if contract + '_' + number + '_full' in ids:
-        yield Source_jcdecaux_vls_full(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bike_stands.string, tag.status.string)
-      if contract + '_' + number + '_empty' in ids:
-        yield Source_jcdecaux_vls_empty(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bikes.string, tag.status.string)
+      id = contract + '_' + number + '_full'
+      if id in ids_pos:
+        yield Source_jcdecaux_vls_full(contract + '_' + number, ids_pos[id], tag.find('name').string, tag.last_update.string, tag.available_bike_stands.string, tag.status.string)
+      id = contract + '_' + number + '_empty'
+      if id in ids_pos:
+        yield Source_jcdecaux_vls_empty(contract + '_' + number, ids_pos[id], tag.find('name').string, tag.last_update.string, tag.available_bikes.string, tag.status.string)
 
 
 ############## TRANSILIEN ##############
 
 class Source_transilien(Source):
-  def __init__(self, ident, message):
+  def __init__(self, ident, pos, message):
     self.source = 'transilien'
     self.id = ident
+    self.pos = pos
     self.message = message
 
   def problem(self):
@@ -196,12 +201,12 @@ class SourceProvider_transilien(SourceProvider):
   def dic_of_positions(self):
     return {} # TODO
 
-  def sources_of_ids(self, ids):
+  def sources_of_ids(self, ids_pos):
     xml = XML(url="http://www.transilien.com/info-trafic/temps-reel", lang="html").data
     container = xml.select('div.b_info_trafic')[0]
     for line in container.find_all('div', recursive=False):
       id = line.select('.picto-transport')[1].get_text()
-      if id in ids:
+      if id in ids_pos:
         message = ""
         for c in line.select_one('.title').children:
           if c.name: # a tag
@@ -212,4 +217,4 @@ class SourceProvider_transilien(SourceProvider):
         for det in line.select('.item-disruption'):
           message += det.get_text()
         message = " ".join(message.split()) # delete multiple spaces
-        yield Source_transilien(id, message)
+        yield Source_transilien(id, ids_pos[id], message)