|
@@ -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
|
}
|