Pārlūkot izejas kodu

polygon support

Patrick Brosi 4 gadi atpakaļ
vecāks
revīzija
2c3ae38583

+ 117 - 69
src/osmfixer/index/StatIdx.cpp

@@ -30,27 +30,48 @@ void StatIdx::readFromFile(const std::string& path) {
30 30
     if (line.size() == 0) break;
31 31
 
32 32
     std::stringstream rec(line);
33
-    size_t osmid, origGroup, group;
34
-    double lat, lng;
33
+    int64_t osmid, origGroup, group;
34
+    double lat = 0, lng = 0;
35 35
     OsmAttrs attrs;
36 36
 
37 37
     rec >> osmid;
38
-    rec >> lat;
39
-    rec >> lng;
40 38
     rec >> origGroup;
41 39
     rec >> group;
42 40
 
41
+    util::geo::DLine geom;
42
+    util::geo::DLine latLngs;
43
+
43 44
     std::string temp;
45
+    std::string key, val;
46
+    uint8_t sw = 0;
44 47
     std::getline(rec, temp, '\t');
45 48
     while (std::getline(rec, temp, '\t')) {
46
-      std::string key, val;
47
-      key = temp;
48
-      std::getline(rec, temp, '\t');
49
-      val = temp;
50
-      attrs[key].push_back(val);
49
+      if (sw == 2) {
50
+        std::getline(rec, val, '\t');
51
+        attrs[temp].push_back(val);
52
+      } else {
53
+        try {
54
+          double a = std::stod(temp);
55
+          if (sw == 1) {
56
+            lat = a;
57
+            geom.push_back(util::geo::latLngToWebMerc<double>(lat, lng));
58
+            sw = 0;
59
+          } else if (sw == 0) {
60
+            lng = a;
61
+            sw = 1;
62
+          }
63
+        } catch (std::invalid_argument) {
64
+          sw = 2;
65
+          std::getline(rec, val, '\t');
66
+          attrs[temp].push_back(val);
67
+        }
68
+      }
51 69
     }
52 70
 
53
-    addStation(osmid, lat, lng, origGroup, group, attrs);
71
+    if (geom.size() > 1) geom = util::geo::simplify(geom, 0.5);
72
+    for (const auto& p : geom) latLngs.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
73
+
74
+    addStation(osmid, geom, latLngs, origGroup, group, attrs);
54 75
   }
55 76
   LOG(INFO) << "Done.";
56 77
 
@@ -61,7 +82,7 @@ void StatIdx::readFromFile(const std::string& path) {
61 82
     if (line.size() == 0) break;
62 83
 
63 84
     std::stringstream rec(line);
64
-    size_t osmid;
85
+    int64_t osmid;
65 86
     OsmAttrs attrs;
66 87
 
67 88
     rec >> osmid;
@@ -81,7 +102,7 @@ void StatIdx::readFromFile(const std::string& path) {
81 102
     size_t id;
82 103
     std::string attr, otherAttr;
83 104
     double conf;
84
-    size_t otherId;
105
+    int64_t otherId;
85 106
 
86 107
     rec >> id;
87 108
 
@@ -105,23 +126,23 @@ void StatIdx::readFromFile(const std::string& path) {
105 126
 }
106 127
 
107 128
 // _____________________________________________________________________________
108
-void StatIdx::addStation(size_t osmid, double lat, double lng, size_t origGroup,
129
+void StatIdx::addStation(int64_t osmid, const util::geo::DLine& geom,
130
+                         const util::geo::DLine& latLngs, size_t origGroup,
109 131
                          size_t group, const OsmAttrs& attrs) {
110
-  auto point = util::geo::latLngToWebMerc<double>(lat, lng);
111
-
112
-  _stations.emplace_back(
113
-      Station{_stations.size(),
114
-              osmid,
115
-              origGroup,
116
-              group,
117
-              point,
118
-              util::geo::webMercToLatLng<double>(point.getX(), point.getY()),
119
-              attrs,
120
-              {},
121
-              {}});
132
+  auto centroid = util::geo::centroid(latLngs);
133
+  _stations.emplace_back(Station{_stations.size(),
134
+                                 osmid,
135
+                                 origGroup,
136
+                                 group,
137
+                                 centroid,
138
+                                 geom,
139
+                                 latLngs,
140
+                                 attrs,
141
+                                 {},
142
+                                 {}});
122 143
 
123 144
   // extend bounding box
124
-  _bbox = util::geo::extendBox(point, _bbox);
145
+  for (const auto& point : geom) _bbox = util::geo::extendBox(point, _bbox);
125 146
 }
126 147
 
127 148
 // _____________________________________________________________________________
@@ -166,19 +187,27 @@ void StatIdx::initGroups() {
166 187
         double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
167 188
                              static_cast<double>(i));
168 189
 
169
-        mp.push_back(util::geo::DPoint(_stations[stid].pos.getX() + x,
170
-                                       _stations[stid].pos.getY() + y));
190
+        for (const auto& geom : _stations[stid].pos) {
191
+          mp.push_back(util::geo::DPoint(geom.getX() + x, geom.getY() + y));
192
+        }
171 193
       }
172 194
     }
173
-    _groups[i].poly = util::geo::convexHull(mp);
195
+    _groups[i].poly = util::geo::simplify(util::geo::convexHull(mp).getOuter(), 0.5);
196
+
197
+    for (auto p : _groups[i].poly.getOuter()) {
198
+      _groups[i].llPoly.getOuter().push_back(
199
+          util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
200
+    }
201
+
202
+    _groups[i].centroid = util::geo::centroid(_groups[i].llPoly);
174 203
   }
175 204
 }
176 205
 
177 206
 // _____________________________________________________________________________
178 207
 void StatIdx::initIndex() {
179 208
   double gSize = 10000;
180
-  _sgrid = util::geo::Grid<size_t, util::geo::Point, double>(gSize, gSize,
181
-                                                             _bbox, false);
209
+  _sgrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
210
+                                                               _bbox, false);
182 211
   _ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
183 212
                                                                _bbox, false);
184 213
   _suggrid = util::geo::Grid<size_t, util::geo::Line, double>(gSize, gSize,
@@ -194,18 +223,25 @@ void StatIdx::initIndex() {
194 223
   _heatGridsErr.resize(10);
195 224
 
196 225
   for (size_t i = 0; i < 10; i++) {
197
-    _heatGridsOk[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
198
-        5000, 5000, _bbox, false));
199
-    _heatGridsSugg[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
200
-        5000, 5000, _bbox, false));
201
-    _heatGridsErr[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
202
-        5000, 5000, _bbox, false));
226
+    _heatGridsOk[i] =
227
+        (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
228
+            5000, 5000, _bbox, false));
229
+    _heatGridsSugg[i] =
230
+        (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
231
+            5000, 5000, _bbox, false));
232
+    _heatGridsErr[i] =
233
+        (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
234
+            5000, 5000, _bbox, false));
203 235
     int step = 2000 * (i + 1);
204 236
 
205 237
     for (size_t x = 1; x * step < (_sgrid.getXWidth() * gSize); x++) {
206 238
       for (size_t y = 1; y * step < (_sgrid.getYHeight() * gSize); y++) {
207 239
         std::set<size_t> tmp;
208
-        auto reqBox = util::geo::DBox({_bbox.getLowerLeft().getX() + (x - 1) * step, _bbox.getLowerLeft().getY() + (y - 1) * step}, {_bbox.getLowerLeft().getX() + x * step, _bbox.getLowerLeft().getY() + y * step});
240
+        auto reqBox =
241
+            util::geo::DBox({_bbox.getLowerLeft().getX() + (x - 1) * step,
242
+                             _bbox.getLowerLeft().getY() + (y - 1) * step},
243
+                            {_bbox.getLowerLeft().getX() + x * step,
244
+                             _bbox.getLowerLeft().getY() + y * step});
209 245
         _sgrid.get(reqBox, &tmp);
210 246
 
211 247
         size_t countOk = 0;
@@ -223,22 +259,28 @@ void StatIdx::initIndex() {
223 259
         for (auto j : tmp) {
224 260
           const auto& stat = _stations[j];
225 261
           if (stat.suggestions.size() == 0 && stat.attrErrs.size() == 0) {
226
-            if (util::geo::contains(stat.pos, reqBox)) {
227
-              countOk++;
228
-              avgXOk += stat.pos.getX();
229
-              avgYOk += stat.pos.getY();
262
+            for (const auto& pos : stat.pos) {
263
+              if (util::geo::contains(pos, reqBox)) {
264
+                countOk++;
265
+                avgXOk += pos.getX();
266
+                avgYOk += pos.getY();
267
+              }
230 268
             }
231 269
           } else if (stat.suggestions.size() > 0 && stat.attrErrs.size() == 0) {
232
-            if (util::geo::contains(stat.pos, reqBox)) {
233
-              countSugg++;
234
-              avgXSugg += stat.pos.getX();
235
-              avgYSugg += stat.pos.getY();
270
+            for (const auto& pos : stat.pos) {
271
+              if (util::geo::contains(pos, reqBox)) {
272
+                countSugg++;
273
+                avgXSugg += pos.getX();
274
+                avgYSugg += pos.getY();
275
+              }
236 276
             }
237 277
           } else if (stat.attrErrs.size() > 0) {
238
-            if (util::geo::contains(stat.pos, reqBox)) {
239
-              countErr++;
240
-              avgXErr += stat.pos.getX();
241
-              avgYErr += stat.pos.getY();
278
+            for (const auto& pos : stat.pos) {
279
+              if (util::geo::contains(pos, reqBox)) {
280
+                countErr++;
281
+                avgXErr += pos.getX();
282
+                avgYErr += pos.getY();
283
+              }
242 284
             }
243 285
           }
244 286
         }
@@ -248,7 +290,8 @@ void StatIdx::initIndex() {
248 290
           avgYOk /= countOk;
249 291
           auto ll = util::geo::webMercToLatLng<double>(avgXOk, avgYOk);
250 292
 
251
-          _heatGridsOk[i].add({avgXOk, avgYOk}, Cluster{{avgXOk, avgYOk}, ll, countOk});
293
+          _heatGridsOk[i].add({avgXOk, avgYOk},
294
+                              Cluster{{avgXOk, avgYOk}, ll, countOk});
252 295
         }
253 296
 
254 297
         if (countSugg != 0) {
@@ -256,7 +299,8 @@ void StatIdx::initIndex() {
256 299
           avgYSugg /= countSugg;
257 300
           auto ll = util::geo::webMercToLatLng<double>(avgXSugg, avgYSugg);
258 301
 
259
-          _heatGridsSugg[i].add({avgXSugg, avgYSugg}, Cluster{{avgXSugg, avgYSugg}, ll, countSugg});
302
+          _heatGridsSugg[i].add({avgXSugg, avgYSugg},
303
+                                Cluster{{avgXSugg, avgYSugg}, ll, countSugg});
260 304
         }
261 305
 
262 306
         if (countErr != 0) {
@@ -264,7 +308,8 @@ void StatIdx::initIndex() {
264 308
           avgYErr /= countErr;
265 309
           auto ll = util::geo::webMercToLatLng<double>(avgXErr, avgYErr);
266 310
 
267
-          _heatGridsErr[i].add({avgXErr, avgYErr}, Cluster{{avgXErr, avgYErr}, ll, countErr});
311
+          _heatGridsErr[i].add({avgXErr, avgYErr},
312
+                               Cluster{{avgXErr, avgYErr}, ll, countErr});
268 313
         }
269 314
       }
270 315
     }
@@ -305,7 +350,7 @@ std::vector<const Group*> StatIdx::getGroups(const util::geo::DBox bbox) const {
305 350
   _ggrid.get(reqBox, &tmp);
306 351
 
307 352
   for (auto i : tmp) {
308
-    // if (util::geo::intersects(_groups[i].poly, reqBox))
353
+    if (util::geo::intersects(_groups[i].poly, reqBox))
309 354
       ret.push_back(&_groups[i]);
310 355
   }
311 356
 
@@ -326,8 +371,10 @@ std::vector<const Station*> StatIdx::getStations(
326 371
   _sgrid.get(reqBox, &tmp);
327 372
 
328 373
   for (auto i : tmp) {
329
-    if (util::geo::contains(_stations[i].pos, reqBox))
374
+    if (util::geo::intersects(util::geo::Polygon<double>(_stations[i].pos),
375
+                              reqBox)) {
330 376
       ret.push_back(&_stations[i]);
377
+    }
331 378
   }
332 379
 
333 380
   return ret;
@@ -340,8 +387,8 @@ const Station* StatIdx::getStation(size_t id) const {
340 387
 }
341 388
 
342 389
 // _____________________________________________________________________________
343
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(const util::geo::DBox bbox,
344
-                                                    size_t z) const {
390
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(
391
+    const util::geo::DBox bbox, size_t z) const {
345 392
   auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
346 393
                                                bbox.getLowerLeft().getY());
347 394
   auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
@@ -366,8 +413,8 @@ std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(const util::geo::DBox bbo
366 413
 }
367 414
 
368 415
 // _____________________________________________________________________________
369
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(const util::geo::DBox bbox,
370
-                                                    size_t z) const {
416
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(
417
+    const util::geo::DBox bbox, size_t z) const {
371 418
   auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
372 419
                                                bbox.getLowerLeft().getY());
373 420
   auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
@@ -392,8 +439,8 @@ std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(const util::geo::DBox bbox
392 439
 }
393 440
 
394 441
 // _____________________________________________________________________________
395
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(const util::geo::DBox bbox,
396
-                                                    size_t z) const {
442
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(
443
+    const util::geo::DBox bbox, size_t z) const {
397 444
   auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
398 445
                                                bbox.getLowerLeft().getY());
399 446
   auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
@@ -423,7 +470,8 @@ void StatIdx::initSuggestions() {
423 470
     if (stat.group != stat.origGroup || getGroup(stat.group)->osmid == 1) {
424 471
       Suggestion sug;
425 472
       sug.station = i;
426
-      sug.arrow = util::geo::DLine{stat.pos, stat.pos};
473
+      auto centroid = util::geo::centroid(stat.pos);
474
+      sug.arrow = util::geo::DLine{centroid, centroid};
427 475
       if (getGroup(stat.origGroup)->osmid < 2) {
428 476
         if (getGroup(stat.group)->osmid == 1) {
429 477
           // move orphan into new group
@@ -481,7 +529,7 @@ void StatIdx::initSuggestions() {
481 529
           sug.target_gid = stat.group;
482 530
           sug.target_osm_rel_id = getGroup(stat.group)->osmid;
483 531
 
484
-          auto b = stat.pos;
532
+          auto b = util::geo::centroid(stat.pos);
485 533
           b.setX(b.getX() + 50);
486 534
           b.setY(b.getY() + 50);
487 535
 
@@ -512,8 +560,9 @@ void StatIdx::initSuggestions() {
512 560
 }
513 561
 
514 562
 // _____________________________________________________________________________
515
-util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b) const {
516
-  auto a = getStation(stat)->pos;
563
+util::geo::DLine StatIdx::getGroupArrow(size_t stat,
564
+                                        const util::geo::DPoint& b) const {
565
+  auto a = util::geo::centroid(getStation(stat)->pos);
517 566
 
518 567
   auto pl = util::geo::PolyLine<double>(a, b);
519 568
   auto bb = pl.getPointAtDist(fmax(pl.getLength() / 2, pl.getLength() - 5)).p;
@@ -528,7 +577,6 @@ util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b)
528 577
   if (util::geo::dist(a, bb) < 20) {
529 578
     line = {a, bb};
530 579
   } else {
531
-
532 580
     int side = rand() % 2;
533 581
     if (!side) side = -1;
534 582
 
@@ -536,9 +584,9 @@ util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b)
536 584
     auto rot2 = util::geo::rotate(util::geo::DLine{a, bb}, -20 * side, bb);
537 585
     auto rot3 = util::geo::rotate(util::geo::DLine{a, bb}, -120 * side, bb);
538 586
 
539
-    auto i =
540
-        util::geo::intersection(util::geo::LineSegment<double>{rot1[0], rot1[1]},
541
-                                util::geo::LineSegment<double>{rot2[0], rot2[1]});
587
+    auto i = util::geo::intersection(
588
+        util::geo::LineSegment<double>{rot1[0], rot1[1]},
589
+        util::geo::LineSegment<double>{rot2[0], rot2[1]});
542 590
 
543 591
     line =
544 592
         util::geo::BezierCurve<double>(a, i, rot3[0], bb).render(5).getLine();

+ 19 - 12
src/osmfixer/index/StatIdx.h

@@ -19,23 +19,26 @@ struct AttrErr {
19 19
   std::string attr;
20 20
   std::string otherAttr;
21 21
   double conf;
22
-  size_t otherId;
22
+  int64_t otherId;
23 23
 };
24 24
 
25 25
 struct Suggestion {
26 26
   uint16_t type;
27 27
   size_t station;
28
-  size_t target_gid, orig_gid, target_osm_rel_id, orig_osm_rel_id;
28
+  // if negative, it is a way!
29
+  int64_t target_gid, orig_gid, target_osm_rel_id, orig_osm_rel_id;
29 30
   std::string attrErrName;
30 31
   util::geo::DLine arrow;
31 32
 };
32 33
 
33 34
 struct Station {
34 35
   size_t id;
35
-  size_t osmid;
36
+  // if negative, it is a way!
37
+  int64_t osmid;
36 38
   size_t origGroup, group;
37
-  util::geo::DPoint pos;
38
-  util::geo::DPoint latLng;
39
+  util::geo::DPoint centroid;
40
+  util::geo::DLine pos;
41
+  util::geo::DLine latLng;
39 42
   OsmAttrs attrs;
40 43
   std::vector<AttrErr> attrErrs;
41 44
   std::vector<size_t> suggestions;
@@ -43,8 +46,10 @@ struct Station {
43 46
 
44 47
 struct Group {
45 48
   size_t id;
46
-  size_t osmid;
49
+  int64_t osmid;
47 50
   util::geo::DPolygon poly;
51
+  util::geo::DPolygon llPoly;
52
+  util::geo::DPoint centroid;
48 53
   OsmAttrs attrs;
49 54
   std::vector<size_t> stations;
50 55
   std::vector<size_t> polyStations;
@@ -77,16 +82,17 @@ class StatIdx {
77 82
   const Suggestion* getSuggestion(size_t id) const;
78 83
 
79 84
   std::vector<Cluster> getHeatGridOk(const util::geo::DBox bbox,
80
-      size_t z) const;
85
+                                     size_t z) const;
81 86
 
82 87
   std::vector<Cluster> getHeatGridSugg(const util::geo::DBox bbox,
83
-      size_t z) const;
88
+                                       size_t z) const;
84 89
 
85 90
   std::vector<Cluster> getHeatGridErr(const util::geo::DBox bbox,
86
-      size_t z) const;
91
+                                      size_t z) const;
87 92
 
88 93
  private:
89
-  void addStation(size_t id, double lat, double lng, size_t origGroup,
94
+  void addStation(int64_t osmid, const util::geo::DLine& geom,
95
+                  const util::geo::DLine& latLngs, size_t origGroup,
90 96
                   size_t group, const OsmAttrs& attrs);
91 97
   void addGroup(size_t id, const OsmAttrs& attrs);
92 98
 
@@ -101,12 +107,13 @@ class StatIdx {
101 107
   std::vector<Suggestion> _suggestions;
102 108
   util::geo::DBox _bbox;
103 109
 
104
-  util::geo::Grid<size_t, util::geo::Point, double> _sgrid;
110
+  util::geo::Grid<size_t, util::geo::Polygon, double> _sgrid;
105 111
   util::geo::Grid<size_t, util::geo::Polygon, double> _ggrid;
106 112
   util::geo::Grid<size_t, util::geo::Line, double> _suggrid;
107 113
 
108 114
   std::vector<util::geo::Grid<Cluster, util::geo::Point, double>> _heatGridsOk;
109
-  std::vector<util::geo::Grid<Cluster, util::geo::Point, double>> _heatGridsSugg;
115
+  std::vector<util::geo::Grid<Cluster, util::geo::Point, double>>
116
+      _heatGridsSugg;
110 117
   std::vector<util::geo::Grid<Cluster, util::geo::Point, double>> _heatGridsErr;
111 118
 };
112 119
 }  // namespace osmfixer

+ 81 - 55
src/osmfixer/server/StatServer.cpp

@@ -84,8 +84,8 @@ util::http::Answer StatServer::handleHeatMapReq(const Params& pars) const {
84 84
   std::stringstream json;
85 85
 
86 86
   size_t p = 5;
87
-  if (z < 11) p = 4;
88
-  if (z < 10) p = 3;
87
+  if (z < 11) p = 3;
88
+  if (z < 10) p = 2;
89 89
   if (z < 9) p = 2;
90 90
   if (z < 7) p = 1;
91 91
 
@@ -98,8 +98,8 @@ util::http::Answer StatServer::handleHeatMapReq(const Params& pars) const {
98 98
   for (const auto& idxPair : _idxs) {
99 99
     const auto& idx = idxPair.second;
100 100
 
101
-    auto hgOk = idx.getHeatGridOk(bbox, z);
102
-    for (auto cluster : hgOk) {
101
+    const auto& hgOk = idx.getHeatGridOk(bbox, z);
102
+    for (const auto& cluster : hgOk) {
103 103
       json << sep;
104 104
       sep = ',';
105 105
 
@@ -114,9 +114,9 @@ util::http::Answer StatServer::handleHeatMapReq(const Params& pars) const {
114 114
   for (const auto& idxPair : _idxs) {
115 115
     const auto& idx = idxPair.second;
116 116
 
117
-    auto hgSugg = idx.getHeatGridSugg(bbox, z);
117
+    const auto& hgSugg = idx.getHeatGridSugg(bbox, z);
118 118
 
119
-    for (auto cluster : hgSugg) {
119
+    for (const auto& cluster : hgSugg) {
120 120
       json << sep;
121 121
       sep = ',';
122 122
 
@@ -131,8 +131,8 @@ util::http::Answer StatServer::handleHeatMapReq(const Params& pars) const {
131 131
   for (const auto& idxPair : _idxs) {
132 132
     const auto& idx = idxPair.second;
133 133
 
134
-    auto hgErr = idx.getHeatGridErr(bbox, z);
135
-    for (auto cluster : hgErr) {
134
+    const auto& hgErr = idx.getHeatGridErr(bbox, z);
135
+    for (const auto& cluster : hgErr) {
136 136
       json << sep;
137 137
       sep = ',';
138 138
 
@@ -159,6 +159,9 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
159 159
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
160 160
   auto box = util::split(pars.find("bbox")->second, ',');
161 161
 
162
+  double z = 0;
163
+  if (pars.count("z")) z = atoi(pars.find("z")->second.c_str());
164
+
162 165
   if (box.size() != 4) throw std::invalid_argument("Invalid request.");
163 166
 
164 167
   double lat1 = atof(box[0].c_str());
@@ -169,9 +172,19 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
169 172
   util::geo::DBox bbox(util::geo::DPoint(lat1, lng1),
170 173
                        util::geo::DPoint(lat2, lng2));
171 174
 
175
+  size_t p = 7;
176
+  if (z < 20) p = 6;
177
+  if (z < 17) p = 5;
178
+  if (z < 15) p = 4;
179
+  if (z < 13) p = 3;
180
+  if (z < 10) p = 2;
181
+  if (z < 9) p = 2;
182
+  if (z < 7) p = 1;
183
+
184
+
172 185
   std::stringstream json;
173 186
 
174
-  json << std::fixed << std::setprecision(6);
187
+  json << std::fixed << std::setprecision(p);
175 188
 
176 189
   if (cb.size()) json << cb << "(";
177 190
   json << "{\"stats\":[";
@@ -180,11 +193,11 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
180 193
   for (size_t did = 0; did < _idxs.size(); did++) {
181 194
     const auto& idx = _idxs[did].second;
182 195
 
183
-    auto ret = idx.getStations(bbox);
184
-    for (auto stat : ret) {
196
+    const auto& ret = idx.getStations(bbox);
197
+    for (const auto& stat : ret) {
185 198
       json << sep;
186 199
       sep = ',';
187
-      printStation(stat, did, &json);
200
+      printStation(stat, did, z < 15, &json);
188 201
     }
189 202
   }
190 203
 
@@ -193,25 +206,27 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
193 206
   for (size_t did = 0; did < _idxs.size(); did++) {
194 207
     const auto& idx = _idxs[did].second;
195 208
 
196
-    auto gret = idx.getGroups(bbox);
197
-    for (auto group : gret) {
209
+    const auto& gret = idx.getGroups(bbox);
210
+    for (const auto& group : gret) {
198 211
       if (group->polyStations.size() == 1 && group->osmid < 2) continue;
199 212
       json << sep;
200 213
       sep = ',';
201
-      printGroup(group, did, &json);
214
+      printGroup(group, did, z < 15, &json);
202 215
     }
203 216
   }
204 217
 
205 218
   json << "], \"su\":[";
206 219
   sep = ' ';
207
-  for (size_t did = 0; did < _idxs.size(); did++) {
208
-    const auto& idx = _idxs[did].second;
209
-
210
-    auto suggs = idx.getSuggestions(bbox);
211
-    for (auto sugg : suggs) {
212
-      json << sep;
213
-      sep = ',';
214
-      printSugg(sugg, did, &json);
220
+  if (z > 15) {
221
+    for (size_t did = 0; did < _idxs.size(); did++) {
222
+      const auto& idx = _idxs[did].second;
223
+
224
+      const auto& suggs = idx.getSuggestions(bbox);
225
+      for (const auto& sugg : suggs) {
226
+        json << sep;
227
+        sep = ',';
228
+        printSugg(sugg, did, &json);
229
+      }
215 230
     }
216 231
   }
217 232
 
@@ -226,21 +241,32 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
226 241
 }
227 242
 
228 243
 // _____________________________________________________________________________
229
-void StatServer::printStation(const Station* stat, size_t did,
244
+void StatServer::printStation(const Station* stat, size_t did, bool simple,
230 245
                               std::ostream* out) const {
231 246
   const auto& idx = _idxs[did].second;
232 247
   const auto& range = _idxs[did].first;
233 248
 
234
-  auto latLng =
235
-      util::geo::webMercToLatLng<double>(stat->pos.getX(), stat->pos.getY());
236
-  (*out) << "{\"id\":" << stat->id + range.sidStart
237
-         << ",\"lat\":" << latLng.getY() << ",\"lon\":" << latLng.getX();
249
+  (*out) << "{\"i\":" << stat->id + range.sidStart << ",\"g\":[";
250
+
251
+  std::string sep = "";
252
+
253
+  if (simple) {
254
+      (*out) << sep << "[" << stat->centroid.getY() << "," << stat->centroid.getX() << "]";
255
+  } else {
256
+    for (const auto& ll : stat->latLng) {
257
+      (*out) << sep << "[" << ll.getY() << "," << ll.getX() << "]";
258
+      sep = ",";
259
+    }
260
+  }
261
+
262
+  (*out) << "]";
238 263
 
239 264
   if (stat->origGroup != stat->group || idx.getGroup(stat->group)->osmid == 1)
240
-    (*out) << ",\"su\":1";
265
+    (*out) << ",\"s\":1";
241 266
 
242 267
   if (stat->attrErrs.size())
243
-    (*out) << ",\"attrerrs\":" << stat->attrErrs.size();
268
+    (*out) << ",\"e\":" << stat->attrErrs.size();
269
+
244 270
   (*out) << "}";
245 271
 }
246 272
 
@@ -251,14 +277,14 @@ void StatServer::printSugg(const Suggestion* sugg, size_t did,
251 277
 
252 278
   std::vector<util::geo::DPoint> projArrow;
253 279
 
254
-  for (auto p : sugg->arrow) {
280
+  for (const auto& p : sugg->arrow) {
255 281
     projArrow.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
256 282
   }
257 283
 
258
-  (*out) << "{\"id\":" << sugg->station + range.suggIdStart
259
-         << ",\"type\":" << sugg->type << ",\"arrow\":[";
284
+  (*out) << "{\"i\":" << sugg->station + range.suggIdStart
285
+         << ",\"t\":" << sugg->type << ",\"a\":[";
260 286
   char sep = ' ';
261
-  for (auto p : projArrow) {
287
+  for (const auto& p : projArrow) {
262 288
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
263 289
     sep = ',';
264 290
   }
@@ -267,24 +293,22 @@ void StatServer::printSugg(const Suggestion* sugg, size_t did,
267 293
 }
268 294
 
269 295
 // _____________________________________________________________________________
270
-void StatServer::printGroup(const Group* group, size_t did,
296
+void StatServer::printGroup(const Group* group, size_t did, bool simple,
271 297
                             std::ostream* out) const {
272 298
   const auto& range = _idxs[did].first;
273 299
 
274
-  std::vector<util::geo::DPoint> projPoly;
275
-
276
-  for (auto p : group->poly.getOuter()) {
277
-    projPoly.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
278
-  }
279
-
280
-  (*out) << "{\"id\":" << group->id + range.gidStart << ",\"poly\":[";
300
+  (*out) << "{\"i\":" << group->id + range.gidStart << ",\"g\":[";
281 301
   char sep = ' ';
282
-  for (auto p : projPoly) {
283
-    (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
284
-    sep = ',';
302
+  if (simple) {
303
+    (*out) << sep << "[" << group->centroid.getY() << "," << group->centroid.getX() << "]";
304
+  } else {
305
+    for (const auto& p : group->llPoly.getOuter()) {
306
+      (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
307
+      sep = ',';
308
+    }
285 309
   }
286 310
   (*out) << "]";
287
-  if (group->osmid == 1) (*out) << ",\"new\":1";
311
+  if (group->osmid == 1) (*out) << ",\"n\":1";
288 312
   (*out) << "}";
289 313
 }
290 314
 
@@ -295,7 +319,7 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
295 319
 
296 320
   if (parts.size() > 1) {
297 321
     auto kvs = util::split(parts[1], '&');
298
-    for (auto kv : kvs) {
322
+    for (const auto& kv : kvs) {
299 323
       auto kvp = util::split(kv, '=');
300 324
       if (kvp.size() == 1) kvp.push_back("");
301 325
       (*params)[util::urlDecode(kvp[0])] = kvp[1];
@@ -304,7 +328,7 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
304 328
 
305 329
   // also parse post data
306 330
   auto kvs = util::split(pl, '&');
307
-  for (auto kv : kvs) {
331
+  for (const auto& kv : kvs) {
308 332
     auto kvp = util::split(kv, '=');
309 333
     if (kvp.size() == 1) kvp.push_back("");
310 334
     (*params)[util::urlDecode(kvp[0])] = kvp[1];
@@ -358,7 +382,7 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
358 382
   const auto& idx = _idxs[did].second;
359 383
   size_t idxGid = gid - range.gidStart;
360 384
 
361
-  auto group = idx.getGroup(idxGid);
385
+  const auto& group = idx.getGroup(idxGid);
362 386
 
363 387
   if (!group) return util::http::Answer("404 Not Found", "Group not found.");
364 388
 
@@ -393,7 +417,7 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
393 417
   for (const auto& sid : group->stations) {
394 418
     json << sep;
395 419
     sep = ',';
396
-    const auto stat = idx.getStation(sid);
420
+    const auto& stat = idx.getStation(sid);
397 421
     json << "{\"id\":" << sid + range.sidStart << ","
398 422
          << "\"osmid\":" << stat->osmid << ","
399 423
          << "\"group\":" << stat->group + range.gidStart << ","
@@ -445,7 +469,7 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
445 469
   const auto& idx = _idxs[did].second;
446 470
   size_t idxSid = sid - range.sidStart;
447 471
 
448
-  auto stat = idx.getStation(idxSid);
472
+  const auto& stat = idx.getStation(idxSid);
449 473
 
450 474
   if (!stat) return util::http::Answer("404 Not Found", "Station not found.");
451 475
 
@@ -453,11 +477,13 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
453 477
 
454 478
   json << std::fixed << std::setprecision(6);
455 479
 
480
+  auto centroid = util::geo::centroid(stat->latLng);
481
+
456 482
   if (cb.size()) json << cb << "(";
457 483
   json << "{\"id\":" << sid << ","
458 484
        << "\"osmid\":" << stat->osmid << ","
459
-       << "\"lat\":" << stat->latLng.getY() << ","
460
-       << "\"lon\":" << stat->latLng.getX() << ","
485
+       << "\"lat\":" << centroid.getY() << ","
486
+       << "\"lon\":" << centroid.getX() << ","
461 487
        << "\"attrs\":{";
462 488
 
463 489
   char sep = ' ';
@@ -482,7 +508,7 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
482 508
   for (const auto& err : stat->attrErrs) {
483 509
     json << sep;
484 510
     sep = ',';
485
-    const auto otherStat = idx.getStation(err.otherId);
511
+    const auto& otherStat = idx.getStation(err.otherId);
486 512
     json << "{";
487 513
     json << "\"attr\":[\"" << err.attr << "\",\"" << stat->attrs.at(err.attr)[0]
488 514
          << "\"]";
@@ -537,7 +563,7 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
537 563
     }
538 564
   }
539 565
 
540
-  for (auto attrErr : stat->attrErrs) {
566
+  for (const auto& attrErr : stat->attrErrs) {
541 567
     const auto otherStat = idx.getStation(attrErr.otherId);
542 568
     if (otherStat->osmid == stat->osmid) {
543 569
       // fix attributes

+ 2 - 2
src/osmfixer/server/StatServer.h

@@ -35,8 +35,8 @@ class StatServer : public util::http::Handler {
35 35
   util::http::Answer handleStatReq(const Params& pars) const;
36 36
   util::http::Answer handleGroupReq(const Params& pars) const;
37 37
 
38
-  void printStation(const Station* stat, size_t did, std::ostream* out) const;
39
-  void printGroup(const Group* stat, size_t did, std::ostream* out) const;
38
+  void printStation(const Station* stat, size_t did, bool simple, std::ostream* out) const;
39
+  void printGroup(const Group* stat, size_t did, bool simple, std::ostream* out) const;
40 40
   void printSugg(const Suggestion* stat, size_t did, std::ostream* out) const;
41 41
 
42 42
   size_t getDidBySid(size_t sid) const;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 13 - 9
web/index.html


+ 80 - 48
web/script.js

@@ -1,31 +1,43 @@
1
-widths = [12, 13, 13, 13, 13, 13, 13, 13];
2
-opas = [0.8, 0.6, 0.5, 0.5, 0.4];
3
-mwidths = [1, 1, 1, 1.5, 2, 3, 5, 6, 6, 4, 3, 2];
1
+var widths = [12, 13, 13, 13, 13, 13, 13, 13];
2
+var opas = [0.8, 0.6, 0.5, 0.5, 0.4];
3
+var mwidths = [1, 1, 1, 1.5, 2, 3, 5, 6, 6, 4, 3, 2];
4 4
 
5
-backend = "";
5
+var backend = "";
6
+var openGr = -1;
7
+var openSt = -1;
6 8
 
7 9
 function marker(stat, z) {
8
-    if (z > 15) {
9
-        return L.circle(
10
-            [stat.lat, stat.lon], {
11
-                color: 'black',
12
-                fillColor: stat.attrerrs ? 'red' : stat.su ? '#0000c3' : '#78f378',
13
-                radius: mwidths[23 - z],
14
-                fillOpacity: 1,
15
-                weight: 1,
16
-                id: stat.id
17
-            }
18
-        );
10
+    if (stat.g.length == 1) {
11
+        if (z > 15) {
12
+            return L.circle(
13
+                stat.g[0], {
14
+                    color: 'black',
15
+                    fillColor: stat.e ? 'red' : stat.s ? '#0000c3' : '#78f378',
16
+                    radius: mwidths[23 - z],
17
+                    fillOpacity: 1,
18
+                    weight: z > 17 ? 1.5 : 1,
19
+                    id: stat.i
20
+                }
21
+            );
22
+        } else {
23
+            return L.polyline(
24
+                [stat.g[0], stat.g[0]], {
25
+                    color: stat.e ? 'red' : stat.s ? '#0000c3' : '#78f378',
26
+                    weight: widths[15 - z],
27
+                    opacity: opas[15 - z],
28
+                    id: stat.i
29
+                }
30
+            );
31
+        }
19 32
     } else {
20
-        return L.polyline(
21
-            [
22
-                [stat.lat, stat.lon],
23
-                [stat.lat, stat.lon]
24
-            ], {
25
-                color: stat.attrerrs ? 'red' : stat.su ? '#0000c3' : '#78f378',
26
-                weight: widths[15 - z],
27
-                opacity: opas[15 - z],
28
-                id: stat.id
33
+        return L.polygon(
34
+            stat.g, {
35
+                color: z > 15 ? 'black': (stat.e ? 'red' : stat.s ? '#0000c3' : '#78f378'),
36
+                fillColor: stat.e ? 'red' : stat.s ? '#0000c3' : '#78f378',
37
+                smoothFactor: 0,
38
+                fillOpacity: 0.75,
39
+                weight: z > 17 ? 1.5 : 1,
40
+                id: stat.i
29 41
             }
30 42
         );
31 43
     }
@@ -34,24 +46,26 @@ function marker(stat, z) {
34 46
 function poly(group, z) {
35 47
     var style = {
36 48
         color: "#85f385",
49
+        fillColor: "#85f385",
37 50
         smoothFactor: 0.4,
38 51
         fillOpacity: 0.2,
39
-        id: group.id
52
+        id: group.i
40 53
     };
41 54
     if (group.new) {
42 55
         style.color = "#0000c3";
56
+        style.fillColor = "#0000c3";
43 57
     }
44 58
     if (z < 16) {
45 59
         style.weight = 11;
46 60
         style.opacity = 0.5;
47 61
         style.fillOpacity = 0.5;
48 62
     }
49
-    return L.polygon(group.poly, style)
63
+    return L.polygon(group.g, style)
50 64
 }
51 65
 
52 66
 function sugArr(sug, z) {
53
-    return L.polyline(sug.arrow, {
54
-        id: sug.id,
67
+    return L.polyline(sug.a, {
68
+        id: sug.i,
55 69
         color: '#0000c3',
56 70
         smoothFactor: 0.1,
57 71
         weight: 4,
@@ -60,12 +74,18 @@ function sugArr(sug, z) {
60 74
 }
61 75
 
62 76
 function renderStat(stat) {
77
+    openSt = stat.id;
78
+    nodeHl(stat.id);
63 79
     var attrrows = {};
64 80
     var ll = {
65 81
         lat: stat.lat,
66 82
         lon: stat.lon
67 83
     };
68 84
 
85
+    var way = stat.osmid < 0;
86
+    var osmid = Math.abs(stat.osmid);
87
+    var ident = way ? "Way" : "Node";
88
+
69 89
     var content = document.createElement('div');
70 90
     content.setAttribute("id", "nav")
71 91
     var attrTbl = document.createElement('table');
@@ -73,12 +93,14 @@ function renderStat(stat) {
73 93
     var suggD = document.createElement('div');
74 94
     suggD.setAttribute("id", "sugg")
75 95
 
96
+    content.innerHTML = ident + " <a target='_blank' href='https://www.openstreetmap.org/"+ident.toLowerCase()+"/" + osmid + "'>" + osmid + "</a>";
97
+
76 98
     if (stat.attrs.name) {
77
-        content.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a> (<b>\"" + stat.attrs.name + "\"</b>)";
78
-    } else {
79
-        content.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a>";
99
+        content.innerHTML += " (<b>\"" + stat.attrs.name + "\"</b>)";
80 100
     }
81 101
 
102
+    content.innerHTML += "<a class='editbut' target='_blank' href='https://www.openstreetmap.org/edit?" + ident.toLowerCase() + "=" + osmid +"'>&#9998;</a>";
103
+
82 104
     content.appendChild(attrTbl);
83 105
     content.appendChild(suggD);
84 106
 
@@ -106,7 +128,8 @@ function renderStat(stat) {
106 128
         var info = document.createElement('div');
107 129
 
108 130
         if (err.other_osmid != stat.osmid) {
109
-            info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in node <a onmouseover='nodeHl( " + err.other + ")' onmouseout='nodeUnHl( " + err.other + ")' target=\"_blank\" href=\"https://www.openstreetmap.org/node/" + err.other_osmid + "\">" + err.other_osmid + "</a>";
131
+            var ident = stat.osmid < 0 ? "way" : "node";
132
+            info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in " + ident + " <a onmouseover='nodeHl( " + err.other + ")' onmouseout='nodeUnHl( " + err.other + ")' target=\"_blank\" href=\"https://www.openstreetmap.org/"+ident+"/" + Math.abs(err.other_osmid) + "\">" + Math.abs(err.other_osmid) + "</a>";
110 133
         } else {
111 134
             info.innerHTML = "Does not match '" + err.other_attr[0] + "' = '" + err.other_attr[1];
112 135
         }
@@ -158,7 +181,8 @@ function renderStat(stat) {
158 181
         })
159 182
         .setLatLng(ll)
160 183
         .setContent(content)
161
-        .openOn(map);
184
+        .openOn(map)
185
+        .on('remove', function() {openSt = -1; nodeUnHl(stat.id);;});
162 186
 }
163 187
 
164 188
 function openStat(id) {
@@ -175,7 +199,9 @@ function openStat(id) {
175 199
 }
176 200
 
177 201
 function renderGroup(grp, ll) {
202
+    openGr = grp.id;
178 203
     var attrrows = {};
204
+    groupHl(grp.id);
179 205
 
180 206
     var content = document.createElement('div');
181 207
     content.setAttribute("id", "nav");
@@ -189,9 +215,10 @@ function renderGroup(grp, ll) {
189 215
     oldMembers.innerHTML = "<span class='oldmemberstit'>Existing Members</span>";
190 216
 
191 217
     if (grp.osmid == 1) {
192
-        content.innerHTML = "<span class='grouplink' onmouseover='groupHl( " + grp.id + ")' onmouseout='groupUnHl( " + grp.id + ")'>New relation</span> <tt>public_transport=stop_area</tt>";
218
+        content.innerHTML = "<span class='grouplink'>New relation</span> <tt>public_transport=stop_area</tt>";
193 219
     } else {
194
-        content.innerHTML = "OSM relation <a onmouseover='groupHl( " + grp.id + ")' onmouseout='groupUnHl( " + grp.id + ")' target='_blank' href='https://www.openstreetmap.org/relation/" + grp.osmid + "'>" + grp.osmid + "</a>";
220
+        content.innerHTML = "OSM relation <a target='_blank' href='https://www.openstreetmap.org/relation/" + grp.osmid + "'>" + grp.osmid + "</a>";
221
+        content.innerHTML += "<a class='editbut' target='_blank' href='https://www.openstreetmap.org/edit?relation=" + grp.osmid +"'>&#9998;</a>";
195 222
     }
196 223
 
197 224
     content.appendChild(newMembers);
@@ -200,11 +227,12 @@ function renderGroup(grp, ll) {
200 227
     for (var key in grp.stations) {
201 228
         var stat = grp.stations[key];
202 229
         var row = document.createElement('div');
230
+        var ident = stat.osmid < 0 ? "Way" : "Node";
231
+
232
+        row.innerHTML = ident + " <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/" + ident.toLowerCase() + "/" + Math.abs(stat.osmid) + "'>" + Math.abs(stat.osmid) + "</a>";
203 233
 
204 234
         if (stat.attrs.name) {
205
-            row.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a> (<b>\"" + stat.attrs.name + "\"</b>)";
206
-        } else {
207
-            row.innerHTML = "Node <a onmouseover='nodeHl( " + stat.id + ")' onmouseout='nodeUnHl( " + stat.id + ")' target='_blank' href='https://www.openstreetmap.org/node/" + stat.osmid + "'>" + stat.osmid + "</a>";
235
+            row.innerHTML += " (<b>\"" + stat.attrs.name + "\"</b>)";
208 236
         }
209 237
 
210 238
         if (grp.osmid == 1 || stat.orig_group != grp.id) newMembers.appendChild(row);
@@ -227,7 +255,8 @@ function renderGroup(grp, ll) {
227 255
         })
228 256
         .setLatLng(ll)
229 257
         .setContent(content)
230
-        .openOn(map);
258
+        .openOn(map)
259
+        .on('remove', function() {openGr = -1; groupUnHl(grp.id)});
231 260
 }
232 261
 
233 262
 function openGroup(id, ll) {
@@ -247,7 +276,7 @@ function groupHl(id) {
247 276
     if (!document.groupIdx[id]) return;
248 277
     document.groupIdx[id].setStyle({
249 278
         'weight': 6,
250
-        'fillOpacity': 0.5
279
+        'color': "#eecc00"
251 280
     });
252 281
 }
253 282
 
@@ -255,7 +284,7 @@ function groupUnHl(id) {
255 284
     if (!document.groupIdx[id]) return;
256 285
     document.groupIdx[id].setStyle({
257 286
         'weight': 3,
258
-        'fillOpacity': 0.2
287
+        'color': document.groupIdx[id].options["fillColor"]
259 288
     });
260 289
 }
261 290
 
@@ -285,10 +314,10 @@ map.addControl(L.control.attribution({
285 314
     prefix: '&copy; <a href="http://ad.cs.uni-freiburg.de">University of Freiburg, Chair of Algorithms and Data Structures</a>'
286 315
 }));
287 316
 
288
-L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
289
-    maxZoom: 23,
290
-    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attribution">CARTO</a>',
291
-    id: 'mapbox.streets'
317
+L.tileLayer('http://{s}.tile.stamen.com/toner-lite/{z}/{x}/{y}.png', {
318
+    maxZoom: 20,
319
+    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
320
+    opacity: 0.8
292 321
 }).addTo(map);
293 322
 
294 323
 var layer = L.featureGroup().addTo(map);
@@ -368,7 +397,7 @@ function render() {
368 397
                     stat = content.stats[i];
369 398
                     var ndMarker = marker(stat, map.getZoom());
370 399
                     stations.push(ndMarker);
371
-                    document.nodeIdx[stat.id] = ndMarker;
400
+                    document.nodeIdx[stat.i] = ndMarker;
372 401
                 }
373 402
 
374 403
                 var groups = [];
@@ -376,7 +405,7 @@ function render() {
376 405
                     group = content.groups[i];
377 406
                     var groupPoly = poly(group, map.getZoom());
378 407
                     groups.push(groupPoly);
379
-                    document.groupIdx[group.id] = groupPoly;
408
+                    document.groupIdx[group.i] = groupPoly;
380 409
                 }
381 410
 
382 411
                 var suggs = [];
@@ -402,10 +431,13 @@ function render() {
402 431
                 layer.addLayer(L.featureGroup(stations).on('click', function(a) {
403 432
                     openStat(a.layer.options.id);
404 433
                 }));
434
+
435
+                groupHl(openGr);
436
+                nodeHl(openSt);
405 437
             }
406 438
         };
407 439
 
408
-        window.xmlhttp.open("GET", backend + "/map?bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","), true);
440
+        window.xmlhttp.open("GET", backend + "/map?z=" + map.getZoom() + "&bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","), true);
409 441
         window.xmlhttp.send();
410 442
     }
411 443
 }