|
@@ -12,6 +12,7 @@
|
12
|
12
|
#include "util/log/Log.h"
|
13
|
13
|
|
14
|
14
|
using osmfixer::Group;
|
|
15
|
+using osmfixer::MetaGroup;
|
15
|
16
|
using osmfixer::OsmAttrs;
|
16
|
17
|
using osmfixer::StatIdx;
|
17
|
18
|
using osmfixer::Station;
|
|
@@ -170,8 +171,26 @@ void StatIdx::readFromFile(const std::string& path) {
|
170
|
171
|
}
|
171
|
172
|
LOG(INFO) << "Done.";
|
172
|
173
|
|
|
174
|
+ // fifth, parse meta groups
|
|
175
|
+ LOG(INFO) << "Parsing meta groups... ";
|
|
176
|
+ while (std::getline(f, line)) {
|
|
177
|
+ // empty line is separator between blocks
|
|
178
|
+ if (line.size() == 0) break;
|
|
179
|
+
|
|
180
|
+ std::stringstream rec(line);
|
|
181
|
+ size_t gid, osmid;
|
|
182
|
+
|
|
183
|
+ rec >> gid;
|
|
184
|
+ rec >> osmid;
|
|
185
|
+
|
|
186
|
+ addGroupToMeta(gid, osmid);
|
|
187
|
+ }
|
|
188
|
+
|
|
189
|
+ LOG(INFO) << "Done.";
|
|
190
|
+
|
173
|
191
|
LOG(INFO) << "Building indices...";
|
174
|
192
|
initGroups();
|
|
193
|
+ initMetaGroups();
|
175
|
194
|
initSuggestions();
|
176
|
195
|
|
177
|
196
|
initIndex();
|
|
@@ -179,6 +198,13 @@ void StatIdx::readFromFile(const std::string& path) {
|
179
|
198
|
}
|
180
|
199
|
|
181
|
200
|
// _____________________________________________________________________________
|
|
201
|
+void StatIdx::addGroupToMeta(size_t gid, size_t metaId) {
|
|
202
|
+ _groups[gid].metaGroupId = metaId;
|
|
203
|
+ _metaGroups[metaId].osmid = metaId;
|
|
204
|
+ _metaGroups[metaId].groups.push_back(gid);
|
|
205
|
+}
|
|
206
|
+
|
|
207
|
+// _____________________________________________________________________________
|
182
|
208
|
void StatIdx::addStation(int64_t osmid, const util::geo::DLine& geom,
|
183
|
209
|
const util::geo::DLine& latLngs, size_t origGroup,
|
184
|
210
|
size_t group, const OsmAttrs& attrs) {
|
|
@@ -203,11 +229,33 @@ void StatIdx::addGroup(size_t osmid, const OsmAttrs& attrs) {
|
203
|
229
|
Group g;
|
204
|
230
|
g.id = _groups.size();
|
205
|
231
|
g.osmid = osmid;
|
|
232
|
+ g.metaGroupId = 0;
|
|
233
|
+ g.mergeId = 0;
|
206
|
234
|
g.attrs = attrs;
|
207
|
235
|
_groups.emplace_back(g);
|
208
|
236
|
}
|
209
|
237
|
|
210
|
238
|
// _____________________________________________________________________________
|
|
239
|
+void StatIdx::initMetaGroups() {
|
|
240
|
+ // build hull polygons
|
|
241
|
+ for (auto& p : _metaGroups) {
|
|
242
|
+ auto& mg = p.second;
|
|
243
|
+ util::geo::MultiPoint<double> mp;
|
|
244
|
+ for (size_t gid : mg.groups) {
|
|
245
|
+ for (auto p : _groups[gid].poly.getOuter()) mp.push_back(p);
|
|
246
|
+ mg.poly = hull(mp, 11);
|
|
247
|
+ }
|
|
248
|
+
|
|
249
|
+ for (auto p : mg.poly.getOuter()) {
|
|
250
|
+ mg.llPoly.getOuter().push_back(
|
|
251
|
+ util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
|
|
252
|
+ }
|
|
253
|
+
|
|
254
|
+ mg.centroid = util::geo::centroid(mg.llPoly);
|
|
255
|
+ }
|
|
256
|
+}
|
|
257
|
+
|
|
258
|
+// _____________________________________________________________________________
|
211
|
259
|
void StatIdx::initGroups() {
|
212
|
260
|
for (size_t i = 0; i < _stations.size(); i++) {
|
213
|
261
|
// this should be ensured by the input file
|
|
@@ -220,6 +268,16 @@ void StatIdx::initGroups() {
|
220
|
268
|
_groups[_stations[i].origGroup].stations.push_back(i);
|
221
|
269
|
}
|
222
|
270
|
|
|
271
|
+ if (_stations[i].group != _stations[i].origGroup &&
|
|
272
|
+ _groups[_stations[i].group].osmid > 2 &&
|
|
273
|
+ _groups[_stations[i].origGroup].osmid > 2) {
|
|
274
|
+ auto& orGr = _groups[_stations[i].origGroup];
|
|
275
|
+ if (orGr.mergeId == 0)
|
|
276
|
+ orGr.mergeId = _stations[i].group;
|
|
277
|
+ else if (orGr.mergeId != _stations[i].group)
|
|
278
|
+ orGr.mergeId = _stations[i].group;
|
|
279
|
+ }
|
|
280
|
+
|
223
|
281
|
assert(_stations[i].group < _groups.size());
|
224
|
282
|
if (_stations[i].group != _stations[i].origGroup &&
|
225
|
283
|
_groups[_stations[i].group].osmid == 1) {
|
|
@@ -259,6 +317,14 @@ void StatIdx::initGroups() {
|
259
|
317
|
byAttrScore);
|
260
|
318
|
}
|
261
|
319
|
|
|
320
|
+ ByErrId byErrId(_stations);
|
|
321
|
+
|
|
322
|
+ // sort stations by error or sugg occurance
|
|
323
|
+ for (size_t gid = 0; gid < _groups.size(); gid++) {
|
|
324
|
+ std::sort(_groups[gid].stations.begin(), _groups[gid].stations.end(),
|
|
325
|
+ byErrId);
|
|
326
|
+ }
|
|
327
|
+
|
262
|
328
|
// build hull polygon
|
263
|
329
|
for (size_t i = 0; i < _groups.size(); i++) {
|
264
|
330
|
util::geo::MultiPoint<double> mp;
|
|
@@ -307,6 +373,8 @@ void StatIdx::initIndex() {
|
307
|
373
|
_bbox, false);
|
308
|
374
|
_ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
|
309
|
375
|
_bbox, false);
|
|
376
|
+ _mgrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
|
|
377
|
+ _bbox, false);
|
310
|
378
|
_suggrid = util::geo::Grid<size_t, util::geo::Line, double>(gSize, gSize,
|
311
|
379
|
_bbox, false);
|
312
|
380
|
|
|
@@ -315,6 +383,10 @@ void StatIdx::initIndex() {
|
315
|
383
|
if (_groups[i].polyStations.size() == 1 && _groups[i].osmid < 2) continue;
|
316
|
384
|
_ggrid.add(_groups[i].poly, i);
|
317
|
385
|
}
|
|
386
|
+ for (const auto& gp : _metaGroups) {
|
|
387
|
+ if (gp.second.poly.getOuter().size() < 2) continue;
|
|
388
|
+ _mgrid.add(gp.second.poly, gp.first);
|
|
389
|
+ }
|
318
|
390
|
for (size_t i = 0; i < _suggestions.size(); i++)
|
319
|
391
|
_suggrid.add(_suggestions[i].arrow, i);
|
320
|
392
|
|
|
@@ -417,6 +489,27 @@ void StatIdx::initIndex() {
|
417
|
489
|
}
|
418
|
490
|
|
419
|
491
|
// _____________________________________________________________________________
|
|
492
|
+std::vector<const MetaGroup*> StatIdx::getMetaGroups(
|
|
493
|
+ const util::geo::DBox bbox) const {
|
|
494
|
+ std::vector<const MetaGroup*> ret;
|
|
495
|
+ auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
|
496
|
+ bbox.getLowerLeft().getY());
|
|
497
|
+ auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
498
|
+ bbox.getUpperRight().getY());
|
|
499
|
+
|
|
500
|
+ std::set<size_t> tmp;
|
|
501
|
+ auto reqBox = util::geo::DBox(ll, ur);
|
|
502
|
+ _mgrid.get(reqBox, &tmp);
|
|
503
|
+
|
|
504
|
+ for (auto i : tmp) {
|
|
505
|
+ if (util::geo::intersects(_metaGroups.find(i)->second.poly, reqBox))
|
|
506
|
+ ret.push_back(&_metaGroups.find(i)->second);
|
|
507
|
+ }
|
|
508
|
+
|
|
509
|
+ return ret;
|
|
510
|
+}
|
|
511
|
+
|
|
512
|
+// _____________________________________________________________________________
|
420
|
513
|
std::vector<const Suggestion*> StatIdx::getSuggestions(
|
421
|
514
|
const util::geo::DBox bbox) const {
|
422
|
515
|
std::vector<const Suggestion*> ret;
|
|
@@ -582,6 +675,37 @@ void StatIdx::initSuggestions() {
|
582
|
675
|
Suggestion sug;
|
583
|
676
|
sug.station = i;
|
584
|
677
|
|
|
678
|
+ if (group.mergeId != 0 && group.mergeId != group.id) {
|
|
679
|
+ if (getGroup(group.mergeId)->metaGroupId) {
|
|
680
|
+ // move group into meta group
|
|
681
|
+ sug.type = 10;
|
|
682
|
+ sug.station = -group.id;
|
|
683
|
+ sug.orig_gid = 0;
|
|
684
|
+ sug.orig_osm_rel_id = 0;
|
|
685
|
+ sug.target_gid = getGroup(group.mergeId)->metaGroupId;
|
|
686
|
+ sug.target_osm_rel_id = getGroup(group.mergeId)->metaGroupId;
|
|
687
|
+
|
|
688
|
+ auto a = util::geo::centroid(group.poly);
|
|
689
|
+ auto b = util::geo::centroid(
|
|
690
|
+ getMetaGroup(getGroup(group.mergeId)->metaGroupId)->poly);
|
|
691
|
+ sug.arrow = getGroupArrow(a, b);
|
|
692
|
+ } else {
|
|
693
|
+ // merge two groups
|
|
694
|
+ sug.type = 9;
|
|
695
|
+ sug.station = -group.id;
|
|
696
|
+ sug.orig_gid = 0;
|
|
697
|
+ sug.orig_osm_rel_id = 0;
|
|
698
|
+ sug.target_gid = group.mergeId;
|
|
699
|
+ sug.target_osm_rel_id = getGroup(group.mergeId)->osmid;
|
|
700
|
+ auto a = util::geo::centroid(group.poly);
|
|
701
|
+ auto b = util::geo::centroid(getGroup(group.mergeId)->poly);
|
|
702
|
+ sug.arrow = getGroupArrow(a, b);
|
|
703
|
+ }
|
|
704
|
+
|
|
705
|
+ _suggestions.push_back(sug);
|
|
706
|
+ group.suggestions.push_back(_suggestions.size() - 1);
|
|
707
|
+ }
|
|
708
|
+
|
585
|
709
|
std::set<std::pair<std::string, uint16_t>> suggested;
|
586
|
710
|
for (auto attrErr : group.attrErrs) {
|
587
|
711
|
if (!attrErr.fromRel) continue;
|
|
@@ -620,8 +744,10 @@ void StatIdx::initSuggestions() {
|
620
|
744
|
// station suggestions
|
621
|
745
|
for (size_t i = 0; i < _stations.size(); i++) {
|
622
|
746
|
auto& stat = _stations[i];
|
|
747
|
+ auto centroid = util::geo::centroid(stat.pos);
|
623
|
748
|
|
624
|
|
- if (stat.attrs.count("name") == 0 && _groups[stat.group].attrs.count("name") == 0) {
|
|
749
|
+ if (stat.attrs.count("name") == 0 &&
|
|
750
|
+ _groups[stat.group].attrs.count("name") == 0) {
|
625
|
751
|
Suggestion sug;
|
626
|
752
|
sug.station = i;
|
627
|
753
|
sug.type = 7;
|
|
@@ -672,8 +798,6 @@ void StatIdx::initSuggestions() {
|
672
|
798
|
if (stat.group != stat.origGroup || getGroup(stat.group)->osmid == 1) {
|
673
|
799
|
Suggestion sug;
|
674
|
800
|
sug.station = i;
|
675
|
|
- auto centroid = util::geo::centroid(stat.pos);
|
676
|
|
- sug.arrow = util::geo::DLine{centroid, centroid};
|
677
|
801
|
|
678
|
802
|
if (getGroup(stat.origGroup)->osmid < 2) {
|
679
|
803
|
if (getGroup(stat.group)->osmid == 1 &&
|
|
@@ -692,7 +816,7 @@ void StatIdx::initSuggestions() {
|
692
|
816
|
sug.target_osm_rel_id = getGroup(stat.group)->osmid;
|
693
|
817
|
|
694
|
818
|
auto b = util::geo::centroid(getGroup(stat.group)->poly);
|
695
|
|
- sug.arrow = getGroupArrow(i, b);
|
|
819
|
+ sug.arrow = getGroupArrow(centroid, b);
|
696
|
820
|
|
697
|
821
|
_suggestions.push_back(sug);
|
698
|
822
|
stat.suggestions.push_back(_suggestions.size() - 1);
|
|
@@ -707,20 +831,37 @@ void StatIdx::initSuggestions() {
|
707
|
831
|
sug.target_gid = stat.group;
|
708
|
832
|
|
709
|
833
|
auto b = util::geo::centroid(getGroup(stat.group)->poly);
|
710
|
|
- sug.arrow = getGroupArrow(i, b);
|
|
834
|
+ sug.arrow = getGroupArrow(centroid, b);
|
711
|
835
|
|
712
|
836
|
_suggestions.push_back(sug);
|
713
|
837
|
stat.suggestions.push_back(_suggestions.size() - 1);
|
714
|
838
|
} else if (getGroup(stat.group)->osmid > 1) {
|
715
|
|
- // move station from relation into existing group
|
716
|
|
- sug.type = 4;
|
|
839
|
+ if (stat.group != getGroup(stat.origGroup)->mergeId) {
|
|
840
|
+ // move station from relation into existing group
|
|
841
|
+ sug.type = 4;
|
|
842
|
+ sug.target_gid = stat.group;
|
|
843
|
+ sug.target_osm_rel_id = getGroup(stat.group)->osmid;
|
|
844
|
+
|
|
845
|
+ // dont output arrow if move is part of a group merge
|
|
846
|
+ auto b = util::geo::centroid(getGroup(stat.group)->poly);
|
|
847
|
+ sug.arrow = getGroupArrow(centroid, b);
|
|
848
|
+ } else {
|
|
849
|
+ continue;
|
|
850
|
+ // size_t metaId =
|
|
851
|
+ // getGroup(getGroup(stat.origGroup)->mergeId)->metaGroupId;
|
|
852
|
+ // if (metaId) {
|
|
853
|
+ // sug.type = 10;
|
|
854
|
+ // sug.target_gid = metaId;
|
|
855
|
+ // sug.target_osm_rel_id = metaId;
|
|
856
|
+ // } else {
|
|
857
|
+ // sug.type = 9;
|
|
858
|
+ // sug.target_gid = stat.group;
|
|
859
|
+ // sug.target_osm_rel_id = getGroup(stat.group)->osmid;
|
|
860
|
+ // }
|
|
861
|
+ }
|
|
862
|
+
|
717
|
863
|
sug.orig_gid = stat.origGroup;
|
718
|
864
|
sug.orig_osm_rel_id = getGroup(stat.origGroup)->osmid;
|
719
|
|
- sug.target_gid = stat.group;
|
720
|
|
- sug.target_osm_rel_id = getGroup(stat.group)->osmid;
|
721
|
|
-
|
722
|
|
- auto b = util::geo::centroid(getGroup(stat.group)->poly);
|
723
|
|
- sug.arrow = getGroupArrow(i, b);
|
724
|
865
|
|
725
|
866
|
_suggestions.push_back(sug);
|
726
|
867
|
stat.suggestions.push_back(_suggestions.size() - 1);
|
|
@@ -738,7 +879,7 @@ void StatIdx::initSuggestions() {
|
738
|
879
|
b.setX(b.getX() + 50);
|
739
|
880
|
b.setY(b.getY() + 50);
|
740
|
881
|
|
741
|
|
- sug.arrow = getGroupArrow(i, b);
|
|
882
|
+ sug.arrow = getGroupArrow(centroid, b);
|
742
|
883
|
|
743
|
884
|
_suggestions.push_back(sug);
|
744
|
885
|
stat.suggestions.push_back(_suggestions.size() - 1);
|
|
@@ -749,10 +890,8 @@ void StatIdx::initSuggestions() {
|
749
|
890
|
}
|
750
|
891
|
|
751
|
892
|
// _____________________________________________________________________________
|
752
|
|
-util::geo::DLine StatIdx::getGroupArrow(size_t stat,
|
|
893
|
+util::geo::DLine StatIdx::getGroupArrow(const util::geo::DPoint& a,
|
753
|
894
|
const util::geo::DPoint& b) const {
|
754
|
|
- auto a = util::geo::centroid(getStation(stat)->pos);
|
755
|
|
-
|
756
|
895
|
auto pl = util::geo::PolyLine<double>(a, b);
|
757
|
896
|
auto bb = pl.getPointAtDist(fmax(pl.getLength() / 2, pl.getLength() - 5)).p;
|
758
|
897
|
|
|
@@ -804,6 +943,12 @@ const Group* StatIdx::getGroup(size_t id) const {
|
804
|
943
|
}
|
805
|
944
|
|
806
|
945
|
// _____________________________________________________________________________
|
|
946
|
+const MetaGroup* StatIdx::getMetaGroup(size_t id) const {
|
|
947
|
+ if (_metaGroups.count(id)) return &_metaGroups.find(id)->second;
|
|
948
|
+ return 0;
|
|
949
|
+}
|
|
950
|
+
|
|
951
|
+// _____________________________________________________________________________
|
807
|
952
|
int StatIdx::nameAttrRel(const std::string& attr) const {
|
808
|
953
|
if (attr == "uic_name") return 5;
|
809
|
954
|
if (attr == "ref_name") return 5;
|