Patrick Brosi преди 4 години
родител
ревизия
4ad506c78b
променени са 5 файла, в които са добавени 438 реда и са изтрити 101 реда
  1. 181 33
      src/osmfixer/index/StatIdx.cpp
  2. 6 1
      src/osmfixer/index/StatIdx.h
  3. 109 42
      src/osmfixer/server/StatServer.cpp
  4. 1 1
      web/index.html
  5. 141 24
      web/script.js

+ 181 - 33
src/osmfixer/index/StatIdx.cpp

@@ -68,8 +68,14 @@ void StatIdx::readFromFile(const std::string& path) {
68 68
       }
69 69
     }
70 70
 
71
+    if (geom.size() != 1 && util::geo::dist(geom.front(), geom.back()) > 1) {
72
+      // transform lines into polygons
73
+      geom = hull(geom, 2).getOuter();
74
+    }
75
+
71 76
     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()));
77
+    for (const auto& p : geom)
78
+      latLngs.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
73 79
 
74 80
     addStation(osmid, geom, latLngs, origGroup, group, attrs);
75 81
   }
@@ -87,13 +93,21 @@ void StatIdx::readFromFile(const std::string& path) {
87 93
 
88 94
     rec >> osmid;
89 95
 
96
+    std::string key;
97
+    std::getline(rec, key, '\t');
98
+    while (std::getline(rec, key, '\t')) {
99
+      std::string val;
100
+      std::getline(rec, val, '\t');
101
+      attrs[key].push_back(val);
102
+    }
103
+
90 104
     addGroup(osmid, attrs);
91 105
   }
92 106
 
93 107
   LOG(INFO) << "Done.";
94 108
 
95 109
   // third, parse attr errs
96
-  LOG(INFO) << "Parsing errors... ";
110
+  LOG(INFO) << "Parsing station errors... ";
97 111
   while (std::getline(f, line)) {
98 112
     // empty line is separator between blocks
99 113
     if (line.size() == 0) break;
@@ -102,7 +116,7 @@ void StatIdx::readFromFile(const std::string& path) {
102 116
     size_t id;
103 117
     std::string attr, otherAttr;
104 118
     double conf;
105
-    int64_t otherId;
119
+    int64_t otherIdRaw;
106 120
 
107 121
     rec >> id;
108 122
 
@@ -111,9 +125,48 @@ void StatIdx::readFromFile(const std::string& path) {
111 125
     std::getline(rec, otherAttr, '\t');
112 126
 
113 127
     rec >> conf;
114
-    rec >> otherId;
128
+    rec >> otherIdRaw;
115 129
 
116
-    _stations[id].attrErrs.push_back({attr, otherAttr, conf, otherId});
130
+    size_t otherId;
131
+    bool fromRel = false;
132
+
133
+    if (otherIdRaw < 0) fromRel = true;
134
+
135
+    otherId = labs(otherIdRaw);
136
+
137
+    _stations[id].attrErrs.push_back({attr, otherAttr, conf, otherId, fromRel});
138
+  }
139
+  LOG(INFO) << "Done.";
140
+
141
+  // fourth, parse attr errs in groups
142
+  LOG(INFO) << "Parsing group errors... ";
143
+  while (std::getline(f, line)) {
144
+    // empty line is separator between blocks
145
+    if (line.size() == 0) break;
146
+
147
+    std::stringstream rec(line);
148
+    size_t id;
149
+    std::string attr, otherAttr;
150
+    double conf;
151
+    int64_t otherIdRaw;
152
+
153
+    rec >> id;
154
+
155
+    std::getline(rec, attr, '\t');
156
+    std::getline(rec, attr, '\t');
157
+    std::getline(rec, otherAttr, '\t');
158
+
159
+    rec >> conf;
160
+    rec >> otherIdRaw;
161
+
162
+    size_t otherId;
163
+    bool fromRel = false;
164
+
165
+    if (otherIdRaw < 0) fromRel = true;
166
+
167
+    otherId = labs(otherIdRaw);
168
+
169
+    _groups[id].attrErrs.push_back({attr, otherAttr, conf, otherId, fromRel});
117 170
   }
118 171
   LOG(INFO) << "Done.";
119 172
 
@@ -175,24 +228,17 @@ void StatIdx::initGroups() {
175 228
     }
176 229
   }
177 230
 
231
+
178 232
   // build hull polygon
179 233
   for (size_t i = 0; i < _groups.size(); i++) {
180 234
     util::geo::MultiPoint<double> mp;
181 235
     for (size_t stid : _groups[i].polyStations) {
182
-      double rad = 11.0;
183
-      int n = 20;
184
-      for (int i = 0; i < n; i++) {
185
-        double x = rad * cos((2.0 * M_PI / static_cast<double>(n)) *
186
-                             static_cast<double>(i));
187
-        double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
188
-                             static_cast<double>(i));
189
-
190
-        for (const auto& geom : _stations[stid].pos) {
191
-          mp.push_back(util::geo::DPoint(geom.getX() + x, geom.getY() + y));
192
-        }
236
+      for (const auto& geom : _stations[stid].pos) {
237
+        mp.push_back(util::geo::DPoint(geom.getX(), geom.getY()));
193 238
       }
194 239
     }
195
-    _groups[i].poly = util::geo::simplify(util::geo::convexHull(mp).getOuter(), 0.5);
240
+
241
+    _groups[i].poly = hull(mp, 11);
196 242
 
197 243
     for (auto p : _groups[i].poly.getOuter()) {
198 244
       _groups[i].llPoly.getOuter().push_back(
@@ -204,6 +250,28 @@ void StatIdx::initGroups() {
204 250
 }
205 251
 
206 252
 // _____________________________________________________________________________
253
+util::geo::Polygon<double> StatIdx::hull(
254
+    const util::geo::MultiPoint<double>& imp, double rad) const {
255
+  util::geo::MultiPoint<double> mp;
256
+  util::geo::Polygon<double> ret;
257
+  for (const auto& geom : imp) {
258
+    // double rad = 11.0;
259
+    int n = 20;
260
+    for (int i = 0; i < n; i++) {
261
+      double x = rad * cos((2.0 * M_PI / static_cast<double>(n)) *
262
+                           static_cast<double>(i));
263
+      double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
264
+                           static_cast<double>(i));
265
+
266
+      mp.push_back(util::geo::DPoint(geom.getX() + x, geom.getY() + y));
267
+    }
268
+  }
269
+  ret = util::geo::simplify(util::geo::convexHull(mp).getOuter(), 0.5);
270
+
271
+  return ret;
272
+}
273
+
274
+// _____________________________________________________________________________
207 275
 void StatIdx::initIndex() {
208 276
   double gSize = 10000;
209 277
   _sgrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
@@ -465,21 +533,80 @@ std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(
465 533
 }
466 534
 // _____________________________________________________________________________
467 535
 void StatIdx::initSuggestions() {
536
+  // group suggestions
537
+  for (size_t i = 0; i < _groups.size(); i++) {
538
+    auto& group = _groups[i];
539
+
540
+    if (group.attrs.size() == 0) {
541
+      Suggestion sug;
542
+      sug.station = i;
543
+      sug.type = 7;
544
+      _suggestions.push_back(sug);
545
+      group.suggestions.push_back(_suggestions.size() - 1);
546
+    }
547
+
548
+    Suggestion sug;
549
+    sug.station = i;
550
+
551
+    std::set<std::pair<std::string, uint16_t>> suggested;
552
+    for (auto attrErr : group.attrErrs) {
553
+      if (!attrErr.fromRel) continue;
554
+
555
+      const auto otherGrp = getGroup(attrErr.otherId);
556
+      if (group.id == attrErr.otherId && attrErr.attr == attrErr.otherAttr) {
557
+        if (suggested.count({attrErr.attr, 8})) continue;
558
+        // fix track number as name
559
+        suggested.insert({attrErr.attr, 8});
560
+        sug.type = 8;
561
+        sug.orig_gid = 0;
562
+        sug.orig_osm_rel_id = 0;
563
+        sug.target_gid = 0;
564
+        sug.target_osm_rel_id = 0;
565
+        sug.attrErrName = attrErr.attr;
566
+
567
+        _suggestions.push_back(sug);
568
+        group.suggestions.push_back(_suggestions.size() - 1);
569
+      } else if (otherGrp->osmid == group.osmid) {
570
+        if (suggested.count({attrErr.attr, 6})) continue;
571
+        // fix attributes
572
+        suggested.insert({attrErr.attr, 6});
573
+        sug.type = 6;
574
+        sug.orig_gid = 0;
575
+        sug.orig_osm_rel_id = 0;
576
+        sug.target_gid = 0;
577
+        sug.target_osm_rel_id = 0;
578
+        sug.attrErrName = attrErr.attr;
579
+
580
+        _suggestions.push_back(sug);
581
+        group.suggestions.push_back(_suggestions.size() - 1);
582
+      }
583
+    }
584
+  }
585
+
586
+  // station suggestions
468 587
   for (size_t i = 0; i < _stations.size(); i++) {
469 588
     auto& stat = _stations[i];
589
+
590
+    if (stat.attrs.size() == 0) {
591
+      Suggestion sug;
592
+      sug.station = i;
593
+      sug.type = 7;
594
+      _suggestions.push_back(sug);
595
+      stat.suggestions.push_back(_suggestions.size() - 1);
596
+    }
597
+
470 598
     if (stat.group != stat.origGroup || getGroup(stat.group)->osmid == 1) {
471 599
       Suggestion sug;
472 600
       sug.station = i;
473 601
       auto centroid = util::geo::centroid(stat.pos);
474 602
       sug.arrow = util::geo::DLine{centroid, centroid};
603
+
475 604
       if (getGroup(stat.origGroup)->osmid < 2) {
476 605
         if (getGroup(stat.group)->osmid == 1) {
477 606
           // move orphan into new group
478 607
           sug.type = 1;
479 608
           sug.target_gid = stat.group;
480 609
 
481
-          // sug.arrow = getGroupArrow(i, stat.group);
482
-
483 610
           _suggestions.push_back(sug);
484 611
           stat.suggestions.push_back(_suggestions.size() - 1);
485 612
 
@@ -539,21 +666,42 @@ void StatIdx::initSuggestions() {
539 666
           stat.suggestions.push_back(_suggestions.size() - 1);
540 667
         }
541 668
       }
669
+    }
542 670
 
543
-      for (auto attrErr : stat.attrErrs) {
544
-        const auto otherStat = getStation(attrErr.otherId);
545
-        if (otherStat->osmid == stat.osmid) {
546
-          // fix attributes
547
-          sug.type = 6;
548
-          sug.orig_gid = 0;
549
-          sug.orig_osm_rel_id = 0;
550
-          sug.target_gid = 0;
551
-          sug.target_osm_rel_id = 0;
552
-          sug.attrErrName = attrErr.attr;
553
-
554
-          _suggestions.push_back(sug);
555
-          stat.suggestions.push_back(_suggestions.size() - 1);
556
-        }
671
+    Suggestion sug;
672
+    sug.station = i;
673
+
674
+    std::set<std::pair<std::string, uint16_t>> suggested;
675
+    for (auto attrErr : stat.attrErrs) {
676
+      if (attrErr.fromRel) continue;
677
+
678
+      const auto otherStat = getStation(attrErr.otherId);
679
+      if (stat.id == attrErr.otherId && attrErr.attr == attrErr.otherAttr) {
680
+        if (suggested.count({attrErr.attr, 8})) continue;
681
+        suggested.insert({attrErr.attr, 8});
682
+        // fix track number as name
683
+        sug.type = 8;
684
+        sug.orig_gid = 0;
685
+        sug.orig_osm_rel_id = 0;
686
+        sug.target_gid = 0;
687
+        sug.target_osm_rel_id = 0;
688
+        sug.attrErrName = attrErr.attr;
689
+
690
+        _suggestions.push_back(sug);
691
+        stat.suggestions.push_back(_suggestions.size() - 1);
692
+      } else if (otherStat->osmid == stat.osmid) {
693
+        if (suggested.count({attrErr.attr, 6})) continue;
694
+        suggested.insert({attrErr.attr, 6});
695
+        // fix attributes
696
+        sug.type = 6;
697
+        sug.orig_gid = 0;
698
+        sug.orig_osm_rel_id = 0;
699
+        sug.target_gid = 0;
700
+        sug.target_osm_rel_id = 0;
701
+        sug.attrErrName = attrErr.attr;
702
+
703
+        _suggestions.push_back(sug);
704
+        stat.suggestions.push_back(_suggestions.size() - 1);
557 705
       }
558 706
     }
559 707
   }

+ 6 - 1
src/osmfixer/index/StatIdx.h

@@ -19,7 +19,8 @@ struct AttrErr {
19 19
   std::string attr;
20 20
   std::string otherAttr;
21 21
   double conf;
22
-  int64_t otherId;
22
+  size_t otherId;
23
+  bool fromRel;
23 24
 };
24 25
 
25 26
 struct Suggestion {
@@ -53,6 +54,8 @@ struct Group {
53 54
   OsmAttrs attrs;
54 55
   std::vector<size_t> stations;
55 56
   std::vector<size_t> polyStations;
57
+  std::vector<AttrErr> attrErrs;
58
+  std::vector<size_t> suggestions;
56 59
 };
57 60
 
58 61
 struct Cluster {
@@ -102,6 +105,8 @@ class StatIdx {
102 105
 
103 106
   util::geo::DLine getGroupArrow(size_t stat, const util::geo::DPoint& p) const;
104 107
 
108
+  util::geo::Polygon<double> hull(const util::geo::MultiPoint<double>& imp, double rad) const;
109
+
105 110
   std::vector<Station> _stations;
106 111
   std::vector<Group> _groups;
107 112
   std::vector<Suggestion> _suggestions;

+ 109 - 42
src/osmfixer/server/StatServer.cpp

@@ -181,7 +181,6 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
181 181
   if (z < 9) p = 2;
182 182
   if (z < 7) p = 1;
183 183
 
184
-
185 184
   std::stringstream json;
186 185
 
187 186
   json << std::fixed << std::setprecision(p);
@@ -243,7 +242,6 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
243 242
 // _____________________________________________________________________________
244 243
 void StatServer::printStation(const Station* stat, size_t did, bool simple,
245 244
                               std::ostream* out) const {
246
-  const auto& idx = _idxs[did].second;
247 245
   const auto& range = _idxs[did].first;
248 246
 
249 247
   (*out) << "{\"i\":" << stat->id + range.sidStart << ",\"g\":[";
@@ -261,7 +259,7 @@ void StatServer::printStation(const Station* stat, size_t did, bool simple,
261 259
 
262 260
   (*out) << "]";
263 261
 
264
-  if (stat->origGroup != stat->group || idx.getGroup(stat->group)->osmid == 1)
262
+  if (stat->suggestions.size() > 0)
265 263
     (*out) << ",\"s\":1";
266 264
 
267 265
   if (stat->attrErrs.size())
@@ -309,6 +307,12 @@ void StatServer::printGroup(const Group* group, size_t did, bool simple,
309 307
   }
310 308
   (*out) << "]";
311 309
   if (group->osmid == 1) (*out) << ",\"n\":1";
310
+
311
+  if (group->suggestions.size() > 0)
312
+    (*out) << ",\"s\":1";
313
+
314
+  if (group->attrErrs.size())
315
+    (*out) << ",\"e\":" << group->attrErrs.size();
312 316
   (*out) << "}";
313 317
 }
314 318
 
@@ -411,7 +415,39 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
411 415
     json << "]";
412 416
   }
413 417
 
414
-  json << "},\"stations\":[";
418
+  json << "},\"attrerrs\":[";
419
+
420
+  sep = ' ';
421
+  for (const auto& err : group->attrErrs) {
422
+    // self errors denote names named as tracks
423
+    if (err.fromRel && err.otherId == group->id && err.attr == err.otherAttr) continue;
424
+
425
+    json << sep;
426
+    sep = ',';
427
+    json << "{";
428
+    json << "\"attr\":[\"" << err.attr << "\",\"" << group->attrs.at(err.attr)[0]
429
+         << "\"]";
430
+    json << ",\"conf\":" << err.conf;
431
+
432
+    if (err.fromRel) {
433
+      const auto otherGroup = idx.getGroup(err.otherId);
434
+      json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
435
+           << otherGroup->attrs.at(err.otherAttr)[0] << "\"]";
436
+      json << ",\"other_grp\":" << err.otherId + range.gidStart;
437
+      json << ",\"other_osmid\":" << otherGroup->osmid;
438
+    } else {
439
+      const auto otherStat = idx.getStation(err.otherId);
440
+      json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
441
+           << otherStat->attrs.at(err.otherAttr)[0] << "\"]";
442
+      json << ",\"other\":" << err.otherId + range.sidStart;
443
+      json << ",\"other_osmid\":" << otherStat->osmid;
444
+    }
445
+    json << "}";
446
+  }
447
+
448
+  json << "]";
449
+
450
+  json << ",\"stations\":[";
415 451
 
416 452
   sep = ' ';
417 453
   for (const auto& sid : group->stations) {
@@ -439,11 +475,39 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
439 475
       }
440 476
       json << "]";
441 477
     }
442
-    json << "}}";
478
+    json << "}";
479
+    if (stat->suggestions.size() > 0)
480
+      json << ",\"s\":1";
481
+
482
+    if (stat->attrErrs.size())
483
+      json << ",\"e\":" << stat->attrErrs.size();
484
+    json << "}";
443 485
   }
444 486
 
445 487
   json << "]";
446 488
 
489
+  json << ",\"su\":[";
490
+
491
+  std::string seper = "";
492
+
493
+  for (size_t sid : group->suggestions) {
494
+      const auto* sugg = idx.getSuggestion(sid);
495
+      if (sugg->type == 6) {
496
+       json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
497
+            << "}";
498
+      } else if (sugg->type == 7) {
499
+        json << seper << "{\"type\":7}";
500
+      } else if (sugg->type == 8) {
501
+       json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
502
+            << "}";
503
+      } else {
504
+        json << seper << "{\"type\":" << sugg->type << "}";
505
+      }
506
+      seper = ',';
507
+    }
508
+
509
+  json << "]";
510
+
447 511
   json << "}";
448 512
 
449 513
   if (cb.size()) json << ")";
@@ -506,17 +570,29 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
506 570
 
507 571
   sep = ' ';
508 572
   for (const auto& err : stat->attrErrs) {
573
+    // self errors denote names named as tracks
574
+    if (!err.fromRel && err.otherId == stat->id && err.attr == err.otherAttr) continue;
509 575
     json << sep;
510 576
     sep = ',';
511
-    const auto& otherStat = idx.getStation(err.otherId);
512 577
     json << "{";
513 578
     json << "\"attr\":[\"" << err.attr << "\",\"" << stat->attrs.at(err.attr)[0]
514 579
          << "\"]";
515
-    json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
516
-         << otherStat->attrs.at(err.otherAttr)[0] << "\"]";
517 580
     json << ",\"conf\":" << err.conf;
518
-    json << ",\"other\":" << err.otherId + range.sidStart;
519
-    json << ",\"other_osmid\":" << otherStat->osmid;
581
+
582
+    if (err.fromRel) {
583
+      const auto otherGroup = idx.getGroup(err.otherId);
584
+      json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
585
+           << otherGroup->attrs.at(err.otherAttr)[0] << "\"]";
586
+      json << ",\"other_grp\":" << err.otherId + range.gidStart;
587
+      json << ",\"other_osmid\":" << otherGroup->osmid;
588
+    } else {
589
+      const auto otherStat = idx.getStation(err.otherId);
590
+      json << ",\"other_attr\":[\"" << err.otherAttr << "\",\""
591
+           << otherStat->attrs.at(err.otherAttr)[0] << "\"]";
592
+      json << ",\"other\":" << err.otherId + range.sidStart;
593
+      json << ",\"other_osmid\":" << otherStat->osmid;
594
+    }
595
+
520 596
     json << "}";
521 597
   }
522 598
 
@@ -524,54 +600,45 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
524 600
 
525 601
   json << ",\"su\":[";
526 602
 
527
-  char seper = ' ';
603
+  std::string seper = "";
528 604
 
529
-  // suggestions
530
-  if (stat->group != stat->origGroup || idx.getGroup(stat->group)->osmid == 1) {
531
-    if (idx.getGroup(stat->origGroup)->osmid < 2) {
532
-      if (idx.getGroup(stat->group)->osmid == 1) {
533
-        json << "{\"type\": 1, \"target_gid\":" << stat->group + range.gidStart
605
+  for (size_t sid : stat->suggestions) {
606
+      const auto* sugg = idx.getSuggestion(sid);
607
+      if (sugg->type == 1) {
608
+        json << seper << "{\"type\":1, \"target_gid\":" << stat->group + range.gidStart
534 609
              << "}";
535
-        seper = ',';
536
-      } else if (idx.getGroup(stat->group)->osmid > 1) {
537
-        json << "{\"type\": 2, \"target_gid\":" << stat->group + range.gidStart
610
+      } else if (sugg->type == 2) {
611
+        json << seper << "{\"type\":2, \"target_gid\":" << stat->group + range.gidStart
538 612
              << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
539 613
              << "}";
540
-        seper = ',';
541
-      }
542
-    } else {
543
-      if (idx.getGroup(stat->group)->osmid == 1 &&
544
-          idx.getGroup(stat->group)->stations.size() > 1) {
545
-        json << "{\"type\": 3,\"orig_gid\":" << stat->origGroup + range.gidStart
614
+      } else if (sugg->type == 3) {
615
+        json << seper << "{\"type\":3,\"orig_gid\":" << stat->origGroup + range.gidStart
546 616
              << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
547 617
              << ",\"target_gid\":" << stat->group + range.gidStart << "}";
548
-        seper = ',';
549
-      } else if (idx.getGroup(stat->group)->osmid > 1) {
550
-        json << "{\"type\": 4,\"orig_gid\":" << stat->origGroup + range.gidStart
618
+      } else if (sugg->type == 4) {
619
+        json << seper << "{\"type\":4,\"orig_gid\":" << stat->origGroup + range.gidStart
551 620
              << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
552 621
              << ",\"target_gid\":" << stat->group << ",\"target_osm_rel_id\":"
553 622
              << idx.getGroup(stat->group)->osmid + range.gidStart << "}";
554
-        seper = ',';
555
-      } else {
556
-        json << "{\"type\": 5,\"orig_gid\":" << stat->origGroup + range.gidStart
623
+      } else if (sugg->type == 5) {
624
+        json << seper << "{\"type\":5,\"orig_gid\":" << stat->origGroup + range.gidStart
557 625
              << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
558 626
              << ",\"target_gid\":" << stat->group + range.gidStart
559 627
              << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
560 628
              << "}";
561
-        seper = ',';
629
+      } else if (sugg->type == 6) {
630
+       json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
631
+            << "}";
632
+      } else if (sugg->type == 7) {
633
+        json << seper << "{\"type\":7}";
634
+      } else if (sugg->type == 8) {
635
+       json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
636
+            << "}";
637
+      } else {
638
+        json << seper << "{\"type\":" << sugg->type << "}";
562 639
       }
563
-    }
564
-  }
565
-
566
-  for (const auto& attrErr : stat->attrErrs) {
567
-    const auto otherStat = idx.getStation(attrErr.otherId);
568
-    if (otherStat->osmid == stat->osmid) {
569
-      // fix attributes
570
-      json << seper << "{\"type\": 6,\"attr\":\"" << attrErr.attr << "\""
571
-           << "}";
572 640
       seper = ',';
573 641
     }
574
-  }
575 642
 
576 643
   json << "]";
577 644
 

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
web/index.html


Файловите разлики са ограничени, защото са твърде много
+ 141 - 24
web/script.js