Browse Source

Much prettier drawing of orientations on the map

Note that we compute the angles on the server, in Python.
Baptiste Jonglez 10 years ago
parent
commit
09175893e7
2 changed files with 58 additions and 17 deletions
  1. 5 14
      assets/map.js
  2. 53 3
      backend.py

+ 5 - 14
assets/map.js

@@ -44,23 +44,14 @@ $( document ).ready(function() {
         }
 
         function drawSemiCircles(feature, layer) {
-            orientations_to_angle = {
-                'N': 0,
-                'NO': -45,
-                'O': -90,
-                'SO': -135,
-                'S': 180,
-                'SE': 135,
-                'E': 90,
-                'NE': 45
-            };
             if (feature.properties.place) {
-                feature.properties.place.orientations.map(function(orien) {
+                feature.properties.place.angles.map(function(angles) {
                     // Strangely enough, we need to invert the coordinates.
                     L.circle([feature.geometry.coordinates[1],
-                              feature.geometry.coordinates[0]], 150)
-                        .setDirection(orientations_to_angle[orien], 45)
-                        .addTo(map);
+                              feature.geometry.coordinates[0]], 150, {
+                                  startAngle: angles[0],
+                                  stopAngle: angles[1]
+                              }).addTo(map);
                 });
             }
         }

+ 53 - 3
backend.py

@@ -23,6 +23,18 @@ ORIENTATIONS = (
     ('NE', 'Nord-Est'),
 )
 
+# Angular sector for each direction, written as (start, stop) in degrees
+ANGLES = {
+     'N':  (-23, 22),
+     'NO': (292, 337),
+     'O':  (247, 292),
+     'SO': (202, 247),
+     'S':  (157, 202),
+     'SE': (112, 157),
+     'E':  (67, 112),
+     'NE': (22, 67)
+}
+
 TABLE_NAME = 'contribs'
 DB_FILENAME = join(dirname(__file__), 'db.sqlite3')
 DB = sqlite3.connect(DB_FILENAME)
@@ -196,6 +208,41 @@ def public_geojson():
 GeoJSON Functions
 """
 
+# Useful for merging angle intervals (orientations)
+def merge_intervals(l, wrap=360):
+    """Merge a list of intervals, assuming the space is cyclic.  The
+    intervals should already by sorted by start value."""
+    if l == []:
+        return []
+    result = list()
+    # Transform the 2-tuple into a 2-list to be able to modify it
+    result.append(list(l[0]))
+    for (start, stop) in l:
+        current = result[-1]
+        if start > current[1]:
+            result.append([start, stop])
+        else:
+            result[-1][1] = max(result[-1][1], stop)
+    if len(result) == 1:
+        return result
+    # Handle the cyclicity by merging the ends if necessary
+    last = result[-1]
+    first = result[0]
+    if first[0] <= last[1] - wrap:
+        result[-1][1] = max(result[-1][1], first[1] + wrap)
+        result.pop(0)
+    return result
+
+def orientations_to_angle(orientations):
+     """Return a list of (start, stop) angles from a list of orientations."""
+     # Hack to make leaflet-semicircle happy (drawing a full circle only
+     # works with (0, 360))
+     if len(orientations) == 8:
+          return [[0, 360]]
+     angles = [ANGLES[orientation] for orientation in orientations]
+     angles.sort(key=lambda (x, y): x)
+     return merge_intervals(angles)
+
 # Save feature collection to a json file
 def save_featurecollection_json(id, features):
     with open('json/' + id + '.json', 'w') as outfile:
@@ -220,7 +267,8 @@ def build_geojson():
     # Loop through results
     rows = cur.fetchall()
     for row in rows:
-
+        orientations = row['orientations'].split(',')
+        angles = orientations_to_angle(orientations)
         # Private JSON file
         private_features.append({
             "type" : "Feature",
@@ -234,7 +282,8 @@ def build_geojson():
                 "place" : {
                     'floor' : row['floor'],
                     'floor_total' : row['floor_total'],
-                    'orientations' : row['orientations'].split(','),
+                    'orientations' : orientations,
+                    'angles' : angles,
                     'roof' : row['roof'],
                 },
                 "comment" : row['comment']
@@ -267,7 +316,8 @@ def build_geojson():
             public_feature['properties']['place'] = {
                 'floor' : row['floor'],
                 'floor_total' : row['floor_total'],
-                'orientations' : row['orientations'].split(','),
+                'orientations' : orientations,
+                'angles' : angles,
                 'roof' : row['roof'],
             }