Patrick Brosi 4 years ago
parent
commit
9023a6c07a

+ 45 - 6
src/osmfixer/FixerMain.cpp

@@ -8,8 +8,16 @@
8
 #include "util/http/Server.h"
8
 #include "util/http/Server.h"
9
 #include "util/log/Log.h"
9
 #include "util/log/Log.h"
10
 
10
 
11
-using osmfixer::StatServer;
11
+using osmfixer::IdRange;
12
 using osmfixer::StatIdx;
12
 using osmfixer::StatIdx;
13
+using osmfixer::StatServer;
14
+
15
+// _____________________________________________________________________________
16
+void printHelp(int argc, char** argv) {
17
+  UNUSED(argc);
18
+  std::cout << "Usage: " << argv[0] << " [-p <port>] [--help] [-h] <fix input files>" << "\n";
19
+  std::cout << "\nAllowed arguments:\n    -p <port>  Port for server to listen to\n";
20
+}
13
 
21
 
14
 // _____________________________________________________________________________
22
 // _____________________________________________________________________________
15
 int main(int argc, char** argv) {
23
 int main(int argc, char** argv) {
@@ -21,14 +29,44 @@ int main(int argc, char** argv) {
21
 
29
 
22
   int port = 9090;
30
   int port = 9090;
23
 
31
 
24
-  if (argc < 2) {
25
-    LOG(ERROR) << "Missing path to stations file.";
32
+  std::vector<std::string> inputPaths;
33
+
34
+  for (int i = 1; i < argc; i++) {
35
+    std::string cur = argv[i];
36
+    if (cur == "-h" || cur == "--help") {
37
+      printHelp(argc, argv);
38
+      exit(0);
39
+    } else if (cur == "-p") {
40
+      if (++i >= argc) {
41
+        LOG(ERROR) << "Missing argument for port (-p).";
42
+        exit(1);
43
+      }
44
+      port = atoi(argv[i]);
45
+    } else {
46
+      inputPaths.push_back(cur);
47
+    }
48
+  }
49
+
50
+  if (inputPaths.size() == 0) {
51
+    LOG(ERROR) << "Missing path(s) to stations file(s).";
52
+    printHelp(argc, argv);
26
     exit(1);
53
     exit(1);
27
   }
54
   }
28
 
55
 
29
-  std::vector<StatIdx> idx(argc - 1);
30
-  for(int i = 1; i < argc; i++) {
31
-    idx[i-1].readFromFile(argv[i]);
56
+  std::vector<std::pair<IdRange, StatIdx>> idx(inputPaths.size());
57
+  IdRange idRange{0, 0, 0, 0, 0, 0};
58
+  for (size_t i = 0; i < inputPaths.size(); i++) {
59
+    idx[i].first = idRange;
60
+    if (i > 0) {
61
+      idx[i].first.sidStart = idx[i - 1].first.sidEnd + 1;
62
+      idx[i].first.gidStart = idx[i - 1].first.gidEnd + 1;
63
+      idx[i].first.suggIdStart = idx[i - 1].first.suggIdStart + 1;
64
+    }
65
+    idx[i].second.readFromFile(inputPaths[i]);
66
+    idx[i].first.sidEnd = idx[i].first.sidStart + idx[i].second.maxSId() + 1;
67
+    idx[i].first.gidEnd = idx[i].first.gidStart + idx[i].second.maxGId() + 1;
68
+    idx[i].first.suggIdEnd =
69
+        idx[i].first.suggIdStart + idx[i].second.maxSuggId() + 1;
32
   }
70
   }
33
 
71
 
34
   LOG(INFO) << "Starting server...";
72
   LOG(INFO) << "Starting server...";
@@ -37,3 +75,4 @@ int main(int argc, char** argv) {
37
   LOG(INFO) << "Listening on port " << port;
75
   LOG(INFO) << "Listening on port " << port;
38
   util::http::HttpServer(port, &serv).run();
76
   util::http::HttpServer(port, &serv).run();
39
 }
77
 }
78
+

+ 4 - 0
src/osmfixer/index/StatIdx.h

@@ -63,6 +63,10 @@ class StatIdx {
63
 
63
 
64
   void readFromFile(const std::string& path);
64
   void readFromFile(const std::string& path);
65
 
65
 
66
+  size_t maxSId() const { return _stations.size() - 1; };
67
+  size_t maxGId() const { return _groups.size() - 1; };
68
+  size_t maxSuggId() const { return _suggestions.size() - 1; };
69
+
66
   std::vector<const Station*> getStations(const util::geo::DBox bbox) const;
70
   std::vector<const Station*> getStations(const util::geo::DBox bbox) const;
67
   std::vector<const Group*> getGroups(const util::geo::DBox bbox) const;
71
   std::vector<const Group*> getGroups(const util::geo::DBox bbox) const;
68
   std::vector<const Suggestion*> getSuggestions(
72
   std::vector<const Suggestion*> getSuggestions(

+ 128 - 68
src/osmfixer/server/StatServer.cpp

@@ -3,13 +3,13 @@
3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
 
4
 
5
 #include <vector>
5
 #include <vector>
6
+#include "osmfixer/build.h"
7
+#include "osmfixer/index.h"
6
 #include "osmfixer/server/StatServer.h"
8
 #include "osmfixer/server/StatServer.h"
7
 #include "util/Misc.h"
9
 #include "util/Misc.h"
8
 #include "util/String.h"
10
 #include "util/String.h"
9
 #include "util/geo/Geo.h"
11
 #include "util/geo/Geo.h"
10
 #include "util/log/Log.h"
12
 #include "util/log/Log.h"
11
-#include "osmfixer/index.h"
12
-#include "osmfixer/build.h"
13
 
13
 
14
 using osmfixer::Params;
14
 using osmfixer::Params;
15
 using osmfixer::StatServer;
15
 using osmfixer::StatServer;
@@ -24,10 +24,15 @@ util::http::Answer StatServer::handle(const util::http::Req& req,
24
     auto cmd = parseUrl(req.url, req.payload, &params);
24
     auto cmd = parseUrl(req.url, req.payload, &params);
25
 
25
 
26
     if (cmd == "/") {
26
     if (cmd == "/") {
27
-      a = util::http::Answer("200 OK", std::string(index_html, index_html + sizeof index_html / sizeof index_html[0]));
27
+      a = util::http::Answer(
28
+          "200 OK",
29
+          std::string(index_html,
30
+                      index_html + sizeof index_html / sizeof index_html[0]));
28
       a.params["Content-Type"] = "text/html; charset=utf-8";
31
       a.params["Content-Type"] = "text/html; charset=utf-8";
29
     } else if (cmd == "/build.js") {
32
     } else if (cmd == "/build.js") {
30
-      a = util::http::Answer("200 OK", std::string(build_js, build_js + sizeof build_js / sizeof build_js[0]));
33
+      a = util::http::Answer(
34
+          "200 OK", std::string(build_js, build_js + sizeof build_js /
35
+                                                         sizeof build_js[0]));
31
       a.params["Content-Type"] = "application/javascript; charset=utf-8";
36
       a.params["Content-Type"] = "application/javascript; charset=utf-8";
32
     } else if (cmd == "/map") {
37
     } else if (cmd == "/map") {
33
       a = handleMapReq(params);
38
       a = handleMapReq(params);
@@ -90,43 +95,49 @@ util::http::Answer StatServer::handleHeatMapReq(const Params& pars) const {
90
   json << "{\"ok\":[";
95
   json << "{\"ok\":[";
91
 
96
 
92
   char sep = ' ';
97
   char sep = ' ';
93
-  for (const auto& idx : _idxs) {
98
+  for (const auto& idxPair : _idxs) {
99
+    const auto& idx = idxPair.second;
100
+
94
     auto hgOk = idx.getHeatGridOk(bbox, z);
101
     auto hgOk = idx.getHeatGridOk(bbox, z);
95
     for (auto cluster : hgOk) {
102
     for (auto cluster : hgOk) {
96
       json << sep;
103
       json << sep;
97
       sep = ',';
104
       sep = ',';
98
 
105
 
99
-      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX() << ","
100
-           << cluster.size << "]";
106
+      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX()
107
+           << "," << cluster.size << "]";
101
     }
108
     }
102
   }
109
   }
103
 
110
 
104
   json << "],\"sugg\":[";
111
   json << "],\"sugg\":[";
105
 
112
 
106
   sep = ' ';
113
   sep = ' ';
107
-  for (const auto& idx : _idxs) {
114
+  for (const auto& idxPair : _idxs) {
115
+    const auto& idx = idxPair.second;
116
+
108
     auto hgSugg = idx.getHeatGridSugg(bbox, z);
117
     auto hgSugg = idx.getHeatGridSugg(bbox, z);
109
 
118
 
110
     for (auto cluster : hgSugg) {
119
     for (auto cluster : hgSugg) {
111
       json << sep;
120
       json << sep;
112
       sep = ',';
121
       sep = ',';
113
 
122
 
114
-      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX() << ","
115
-           << cluster.size << "]";
123
+      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX()
124
+           << "," << cluster.size << "]";
116
     }
125
     }
117
   }
126
   }
118
 
127
 
119
   json << "],\"err\":[";
128
   json << "],\"err\":[";
120
 
129
 
121
   sep = ' ';
130
   sep = ' ';
122
-  for (const auto& idx : _idxs) {
131
+  for (const auto& idxPair : _idxs) {
132
+    const auto& idx = idxPair.second;
133
+
123
     auto hgErr = idx.getHeatGridErr(bbox, z);
134
     auto hgErr = idx.getHeatGridErr(bbox, z);
124
     for (auto cluster : hgErr) {
135
     for (auto cluster : hgErr) {
125
       json << sep;
136
       json << sep;
126
       sep = ',';
137
       sep = ',';
127
 
138
 
128
-      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX() << ","
129
-           << cluster.size << "]";
139
+      json << "[" << cluster.latLng.getY() << "," << cluster.latLng.getX()
140
+           << "," << cluster.size << "]";
130
     }
141
     }
131
   }
142
   }
132
 
143
 
@@ -148,9 +159,6 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
148
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
159
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
149
   auto box = util::split(pars.find("bbox")->second, ',');
160
   auto box = util::split(pars.find("bbox")->second, ',');
150
 
161
 
151
-  // TODO!
152
-  size_t did = 0;
153
-
154
   if (box.size() != 4) throw std::invalid_argument("Invalid request.");
162
   if (box.size() != 4) throw std::invalid_argument("Invalid request.");
155
 
163
 
156
   double lat1 = atof(box[0].c_str());
164
   double lat1 = atof(box[0].c_str());
@@ -169,7 +177,9 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
169
   json << "{\"stats\":[";
177
   json << "{\"stats\":[";
170
 
178
 
171
   char sep = ' ';
179
   char sep = ' ';
172
-  for (const auto& idx : _idxs) {
180
+  for (size_t did = 0; did < _idxs.size(); did++) {
181
+    const auto& idx = _idxs[did].second;
182
+
173
     auto ret = idx.getStations(bbox);
183
     auto ret = idx.getStations(bbox);
174
     for (auto stat : ret) {
184
     for (auto stat : ret) {
175
       json << sep;
185
       json << sep;
@@ -180,24 +190,28 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
180
 
190
 
181
   json << "], \"groups\":[";
191
   json << "], \"groups\":[";
182
   sep = ' ';
192
   sep = ' ';
183
-  for (const auto& idx : _idxs) {
193
+  for (size_t did = 0; did < _idxs.size(); did++) {
194
+    const auto& idx = _idxs[did].second;
195
+
184
     auto gret = idx.getGroups(bbox);
196
     auto gret = idx.getGroups(bbox);
185
     for (auto group : gret) {
197
     for (auto group : gret) {
186
       if (group->polyStations.size() == 1 && group->osmid < 2) continue;
198
       if (group->polyStations.size() == 1 && group->osmid < 2) continue;
187
       json << sep;
199
       json << sep;
188
       sep = ',';
200
       sep = ',';
189
-      printGroup(group, &json);
201
+      printGroup(group, did, &json);
190
     }
202
     }
191
   }
203
   }
192
 
204
 
193
   json << "], \"su\":[";
205
   json << "], \"su\":[";
194
   sep = ' ';
206
   sep = ' ';
195
-  for (const auto& idx : _idxs) {
207
+  for (size_t did = 0; did < _idxs.size(); did++) {
208
+    const auto& idx = _idxs[did].second;
209
+
196
     auto suggs = idx.getSuggestions(bbox);
210
     auto suggs = idx.getSuggestions(bbox);
197
     for (auto sugg : suggs) {
211
     for (auto sugg : suggs) {
198
       json << sep;
212
       json << sep;
199
       sep = ',';
213
       sep = ',';
200
-      printSugg(sugg, &json);
214
+      printSugg(sugg, did, &json);
201
     }
215
     }
202
   }
216
   }
203
 
217
 
@@ -212,13 +226,17 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
212
 }
226
 }
213
 
227
 
214
 // _____________________________________________________________________________
228
 // _____________________________________________________________________________
215
-void StatServer::printStation(const Station* stat, size_t did, std::ostream* out) const {
229
+void StatServer::printStation(const Station* stat, size_t did,
230
+                              std::ostream* out) const {
231
+  const auto& idx = _idxs[did].second;
232
+  const auto& range = _idxs[did].first;
233
+
216
   auto latLng =
234
   auto latLng =
217
       util::geo::webMercToLatLng<double>(stat->pos.getX(), stat->pos.getY());
235
       util::geo::webMercToLatLng<double>(stat->pos.getX(), stat->pos.getY());
218
-  (*out) << "{\"id\":" << stat->id << ",\"lat\":" << latLng.getY()
219
-         << ",\"lon\":" << latLng.getX();
236
+  (*out) << "{\"id\":" << stat->id + range.sidStart
237
+         << ",\"lat\":" << latLng.getY() << ",\"lon\":" << latLng.getX();
220
 
238
 
221
-  if (stat->origGroup != stat->group || _idxs[did].getGroup(stat->group)->osmid == 1)
239
+  if (stat->origGroup != stat->group || idx.getGroup(stat->group)->osmid == 1)
222
     (*out) << ",\"su\":1";
240
     (*out) << ",\"su\":1";
223
 
241
 
224
   if (stat->attrErrs.size())
242
   if (stat->attrErrs.size())
@@ -227,15 +245,18 @@ void StatServer::printStation(const Station* stat, size_t did, std::ostream* out
227
 }
245
 }
228
 
246
 
229
 // _____________________________________________________________________________
247
 // _____________________________________________________________________________
230
-void StatServer::printSugg(const Suggestion* sugg, std::ostream* out) {
248
+void StatServer::printSugg(const Suggestion* sugg, size_t did,
249
+                           std::ostream* out) const {
250
+  const auto& range = _idxs[did].first;
251
+
231
   std::vector<util::geo::DPoint> projArrow;
252
   std::vector<util::geo::DPoint> projArrow;
232
 
253
 
233
   for (auto p : sugg->arrow) {
254
   for (auto p : sugg->arrow) {
234
     projArrow.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
255
     projArrow.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
235
   }
256
   }
236
 
257
 
237
-  (*out) << "{\"id\":" << sugg->station << ",\"type\":" << sugg->type
238
-         << ",\"arrow\":[";
258
+  (*out) << "{\"id\":" << sugg->station + range.suggIdStart
259
+         << ",\"type\":" << sugg->type << ",\"arrow\":[";
239
   char sep = ' ';
260
   char sep = ' ';
240
   for (auto p : projArrow) {
261
   for (auto p : projArrow) {
241
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
262
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
@@ -246,14 +267,17 @@ void StatServer::printSugg(const Suggestion* sugg, std::ostream* out) {
246
 }
267
 }
247
 
268
 
248
 // _____________________________________________________________________________
269
 // _____________________________________________________________________________
249
-void StatServer::printGroup(const Group* group, std::ostream* out) {
270
+void StatServer::printGroup(const Group* group, size_t did,
271
+                            std::ostream* out) const {
272
+  const auto& range = _idxs[did].first;
273
+
250
   std::vector<util::geo::DPoint> projPoly;
274
   std::vector<util::geo::DPoint> projPoly;
251
 
275
 
252
   for (auto p : group->poly.getOuter()) {
276
   for (auto p : group->poly.getOuter()) {
253
     projPoly.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
277
     projPoly.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
254
   }
278
   }
255
 
279
 
256
-  (*out) << "{\"id\":" << group->id << ",\"poly\":[";
280
+  (*out) << "{\"id\":" << group->id + range.gidStart << ",\"poly\":[";
257
   char sep = ' ';
281
   char sep = ' ';
258
   for (auto p : projPoly) {
282
   for (auto p : projPoly) {
259
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
283
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
@@ -290,6 +314,39 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
290
 }
314
 }
291
 
315
 
292
 // _____________________________________________________________________________
316
 // _____________________________________________________________________________
317
+size_t StatServer::getDidBySid(size_t sid) const {
318
+  for (size_t i = 0; i < _idxs.size(); i++) {
319
+    auto idx = _idxs[i].second;
320
+    auto range = _idxs[i].first;
321
+    if (sid >= range.sidStart && sid <= range.sidEnd) return i;
322
+  }
323
+
324
+  return 0;
325
+}
326
+
327
+// _____________________________________________________________________________
328
+size_t StatServer::getDidBySuggid(size_t suggid) const {
329
+  for (size_t i = 0; i < _idxs.size(); i++) {
330
+    auto idx = _idxs[i].second;
331
+    auto range = _idxs[i].first;
332
+    if (suggid >= range.suggIdStart && suggid <= range.suggIdEnd) return i;
333
+  }
334
+
335
+  return 0;
336
+}
337
+
338
+// _____________________________________________________________________________
339
+size_t StatServer::getDidByGid(size_t gid) const {
340
+  for (size_t i = 0; i < _idxs.size(); i++) {
341
+    auto idx = _idxs[i].second;
342
+    auto range = _idxs[i].first;
343
+    if (gid >= range.gidStart && gid <= range.gidEnd) return i;
344
+  }
345
+
346
+  return 0;
347
+}
348
+
349
+// _____________________________________________________________________________
293
 util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
350
 util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
294
   if (pars.count("id") == 0 || pars.find("id")->second.empty())
351
   if (pars.count("id") == 0 || pars.find("id")->second.empty())
295
     throw std::invalid_argument("No ID specified.");
352
     throw std::invalid_argument("No ID specified.");
@@ -298,10 +355,13 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
298
 
355
 
299
   size_t gid = atol(pars.find("id")->second.c_str());
356
   size_t gid = atol(pars.find("id")->second.c_str());
300
 
357
 
301
-  // TODO!
302
-  size_t did=0;
358
+  size_t did = getDidByGid(gid);
359
+
360
+  const auto& range = _idxs[did].first;
361
+  const auto& idx = _idxs[did].second;
362
+  size_t idxGid = gid - range.gidStart;
303
 
363
 
304
-  auto group = _idxs[did].getGroup(gid);
364
+  auto group = idx.getGroup(idxGid);
305
 
365
 
306
   if (!group) return util::http::Answer("404 Not Found", "Group not found.");
366
   if (!group) return util::http::Answer("404 Not Found", "Group not found.");
307
 
367
 
@@ -336,10 +396,10 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
336
   for (const auto& sid : group->stations) {
396
   for (const auto& sid : group->stations) {
337
     json << sep;
397
     json << sep;
338
     sep = ',';
398
     sep = ',';
339
-    const auto stat = _idxs[did].getStation(sid);
340
-    json << "{\"id\":" << sid << ","
399
+    const auto stat = idx.getStation(sid);
400
+    json << "{\"id\":" << sid + range.sidStart << ","
341
          << "\"osmid\":" << stat->osmid << ","
401
          << "\"osmid\":" << stat->osmid << ","
342
-         << "\"group\":" << stat->group << ","
402
+         << "\"group\":" << stat->group + range.gidStart << ","
343
          << "\"orig_group\":" << stat->origGroup << ","
403
          << "\"orig_group\":" << stat->origGroup << ","
344
          << "\"attrs\":{";
404
          << "\"attrs\":{";
345
 
405
 
@@ -381,10 +441,14 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
381
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
441
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
382
 
442
 
383
   size_t sid = atol(pars.find("id")->second.c_str());
443
   size_t sid = atol(pars.find("id")->second.c_str());
384
-  // TODO!
385
-  size_t did=0;
386
 
444
 
387
-  auto stat = _idxs[did].getStation(sid);
445
+  size_t did = getDidBySid(sid);
446
+
447
+  const auto& range = _idxs[did].first;
448
+  const auto& idx = _idxs[did].second;
449
+  size_t idxSid = sid - range.sidStart;
450
+
451
+  auto stat = idx.getStation(idxSid);
388
 
452
 
389
   if (!stat) return util::http::Answer("404 Not Found", "Station not found.");
453
   if (!stat) return util::http::Answer("404 Not Found", "Station not found.");
390
 
454
 
@@ -421,14 +485,14 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
421
   for (const auto& err : stat->attrErrs) {
485
   for (const auto& err : stat->attrErrs) {
422
     json << sep;
486
     json << sep;
423
     sep = ',';
487
     sep = ',';
424
-    const auto otherStat = _idxs[did].getStation(err.otherId);
488
+    const auto otherStat = idx.getStation(err.otherId);
425
     json << "{";
489
     json << "{";
426
     json << "\"attr\":[\"" << err.attr << "\",\"" << stat->attrs.at(err.attr)[0]
490
     json << "\"attr\":[\"" << err.attr << "\",\"" << stat->attrs.at(err.attr)[0]
427
          << "\"]";
491
          << "\"]";
428
     json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
492
     json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
429
          << otherStat->attrs.at(err.otherAttr)[0] << "\"]";
493
          << otherStat->attrs.at(err.otherAttr)[0] << "\"]";
430
     json << ",\"conf\":" << err.conf;
494
     json << ",\"conf\":" << err.conf;
431
-    json << ",\"other\":" << err.otherId;
495
+    json << ",\"other\":" << err.otherId + range.sidStart;
432
     json << ",\"other_osmid\":" << otherStat->osmid;
496
     json << ",\"other_osmid\":" << otherStat->osmid;
433
     json << "}";
497
     json << "}";
434
   }
498
   }
@@ -440,40 +504,36 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
440
   char seper = ' ';
504
   char seper = ' ';
441
 
505
 
442
   // suggestions
506
   // suggestions
443
-  if (stat->group != stat->origGroup ||
444
-      _idxs[did].getGroup(stat->group)->osmid == 1) {
445
-    if (_idxs[did].getGroup(stat->origGroup)->osmid < 2) {
446
-      if (_idxs[did].getGroup(stat->group)->osmid == 1) {
447
-        json << "{\"type\": 1, \"target_gid\":" << stat->group << "}";
507
+  if (stat->group != stat->origGroup || idx.getGroup(stat->group)->osmid == 1) {
508
+    if (idx.getGroup(stat->origGroup)->osmid < 2) {
509
+      if (idx.getGroup(stat->group)->osmid == 1) {
510
+        json << "{\"type\": 1, \"target_gid\":" << stat->group + range.gidStart
511
+             << "}";
448
         seper = ',';
512
         seper = ',';
449
-      } else if (_idxs[did].getGroup(stat->group)->osmid > 1) {
450
-        json << "{\"type\": 2, \"target_gid\":" << stat->group
451
-             << ",\"target_osm_rel_id\":" << _idxs[did].getGroup(stat->group)->osmid
513
+      } else if (idx.getGroup(stat->group)->osmid > 1) {
514
+        json << "{\"type\": 2, \"target_gid\":" << stat->group + range.gidStart
515
+             << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
452
              << "}";
516
              << "}";
453
         seper = ',';
517
         seper = ',';
454
       }
518
       }
455
     } else {
519
     } else {
456
-      if (_idxs[did].getGroup(stat->group)->osmid == 1 &&
457
-          _idxs[did].getGroup(stat->group)->stations.size() > 1) {
458
-        json << "{\"type\": 3,\"orig_gid\":" << stat->origGroup
459
-             << ",\"orig_osm_rel_id\":"
460
-             << _idxs[did].getGroup(stat->origGroup)->osmid
461
-             << ",\"target_gid\":" << stat->group << "}";
520
+      if (idx.getGroup(stat->group)->osmid == 1 &&
521
+          idx.getGroup(stat->group)->stations.size() > 1) {
522
+        json << "{\"type\": 3,\"orig_gid\":" << stat->origGroup + range.gidStart
523
+             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
524
+             << ",\"target_gid\":" << stat->group + range.gidStart << "}";
462
         seper = ',';
525
         seper = ',';
463
-      } else if (_idxs[did].getGroup(stat->group)->osmid > 1) {
464
-        json << "{\"type\": 4,\"orig_gid\":" << stat->origGroup
465
-             << ",\"orig_osm_rel_id\":"
466
-             << _idxs[did].getGroup(stat->origGroup)->osmid
467
-             << ",\"target_gid\":" << stat->group
468
-             << ",\"target_osm_rel_id\":" << _idxs[did].getGroup(stat->group)->osmid
469
-             << "}";
526
+      } else if (idx.getGroup(stat->group)->osmid > 1) {
527
+        json << "{\"type\": 4,\"orig_gid\":" << stat->origGroup + range.gidStart
528
+             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
529
+             << ",\"target_gid\":" << stat->group << ",\"target_osm_rel_id\":"
530
+             << idx.getGroup(stat->group)->osmid + range.gidStart << "}";
470
         seper = ',';
531
         seper = ',';
471
       } else {
532
       } else {
472
-        json << "{\"type\": 5,\"orig_gid\":" << stat->origGroup
473
-             << ",\"orig_osm_rel_id\":"
474
-             << _idxs[did].getGroup(stat->origGroup)->osmid
475
-             << ",\"target_gid\":" << stat->group
476
-             << ",\"target_osm_rel_id\":" << _idxs[did].getGroup(stat->group)->osmid
533
+        json << "{\"type\": 5,\"orig_gid\":" << stat->origGroup + range.gidStart
534
+             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
535
+             << ",\"target_gid\":" << stat->group + range.gidStart
536
+             << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
477
              << "}";
537
              << "}";
478
         seper = ',';
538
         seper = ',';
479
       }
539
       }
@@ -481,7 +541,7 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
481
   }
541
   }
482
 
542
 
483
   for (auto attrErr : stat->attrErrs) {
543
   for (auto attrErr : stat->attrErrs) {
484
-    const auto otherStat = _idxs[did].getStation(attrErr.otherId);
544
+    const auto otherStat = idx.getStation(attrErr.otherId);
485
     if (otherStat->osmid == stat->osmid) {
545
     if (otherStat->osmid == stat->osmid) {
486
       // fix attributes
546
       // fix attributes
487
       json << seper << "{\"type\": 6,\"attr\":\"" << attrErr.attr << "\""
547
       json << seper << "{\"type\": 6,\"attr\":\"" << attrErr.attr << "\""

+ 13 - 4
src/osmfixer/server/StatServer.h

@@ -12,11 +12,16 @@
12
 
12
 
13
 namespace osmfixer {
13
 namespace osmfixer {
14
 
14
 
15
+struct IdRange {
16
+  size_t sidStart, sidEnd, gidStart, gidEnd, suggIdStart, suggIdEnd;
17
+};
18
+
15
 typedef std::map<std::string, std::string> Params;
19
 typedef std::map<std::string, std::string> Params;
16
 
20
 
17
 class StatServer : public util::http::Handler {
21
 class StatServer : public util::http::Handler {
18
  public:
22
  public:
19
-  explicit StatServer(const std::vector<osmfixer::StatIdx>& idxs)
23
+  explicit StatServer(
24
+      const std::vector<std::pair<IdRange, osmfixer::StatIdx>>& idxs)
20
       : _idxs(idxs) {}
25
       : _idxs(idxs) {}
21
 
26
 
22
   virtual util::http::Answer handle(const util::http::Req& request,
27
   virtual util::http::Answer handle(const util::http::Req& request,
@@ -31,10 +36,14 @@ class StatServer : public util::http::Handler {
31
   util::http::Answer handleGroupReq(const Params& pars) const;
36
   util::http::Answer handleGroupReq(const Params& pars) const;
32
 
37
 
33
   void printStation(const Station* stat, size_t did, std::ostream* out) const;
38
   void printStation(const Station* stat, size_t did, std::ostream* out) const;
34
-  static void printGroup(const Group* stat, std::ostream* out);
35
-  static void printSugg(const Suggestion* stat, std::ostream* out);
39
+  void printGroup(const Group* stat, size_t did, std::ostream* out) const;
40
+  void printSugg(const Suggestion* stat, size_t did, std::ostream* out) const;
41
+
42
+  size_t getDidBySid(size_t sid) const;
43
+  size_t getDidBySuggid(size_t suggid) const;
44
+  size_t getDidByGid(size_t gid) const;
36
 
45
 
37
-  const std::vector<osmfixer::StatIdx>& _idxs;
46
+  const std::vector<std::pair<IdRange, osmfixer::StatIdx>>& _idxs;
38
 };
47
 };
39
 }  // namespace osmfixer
48
 }  // namespace osmfixer
40
 
49