|
@@ -9,11 +9,12 @@
|
9
|
9
|
#include <string>
|
10
|
10
|
#include "osmfixer/index/StatIdx.h"
|
11
|
11
|
#include "util/geo/BezierCurve.h"
|
|
12
|
+#include "util/log/Log.h"
|
12
|
13
|
|
13
|
|
-using osmfixer::StatIdx;
|
|
14
|
+using osmfixer::Group;
|
14
|
15
|
using osmfixer::OsmAttrs;
|
|
16
|
+using osmfixer::StatIdx;
|
15
|
17
|
using osmfixer::Station;
|
16
|
|
-using osmfixer::Group;
|
17
|
18
|
using osmfixer::Suggestion;
|
18
|
19
|
|
19
|
20
|
// _____________________________________________________________________________
|
|
@@ -23,6 +24,7 @@ void StatIdx::readFromFile(const std::string& path) {
|
23
|
24
|
std::string line;
|
24
|
25
|
|
25
|
26
|
// first, parse nodes
|
|
27
|
+ LOG(INFO) << "Parsing nodes...";
|
26
|
28
|
while (std::getline(f, line)) {
|
27
|
29
|
// empty line is separator between blocks
|
28
|
30
|
if (line.size() == 0) break;
|
|
@@ -50,8 +52,10 @@ void StatIdx::readFromFile(const std::string& path) {
|
50
|
52
|
|
51
|
53
|
addStation(osmid, lat, lng, origGroup, group, attrs);
|
52
|
54
|
}
|
|
55
|
+ LOG(INFO) << "Done.";
|
53
|
56
|
|
54
|
57
|
// second, parse groups
|
|
58
|
+ LOG(INFO) << "Parsing groups... ";
|
55
|
59
|
while (std::getline(f, line)) {
|
56
|
60
|
// empty line is separator between blocks
|
57
|
61
|
if (line.size() == 0) break;
|
|
@@ -65,7 +69,10 @@ void StatIdx::readFromFile(const std::string& path) {
|
65
|
69
|
addGroup(osmid, attrs);
|
66
|
70
|
}
|
67
|
71
|
|
|
72
|
+ LOG(INFO) << "Done.";
|
|
73
|
+
|
68
|
74
|
// third, parse attr errs
|
|
75
|
+ LOG(INFO) << "Parsing errors... ";
|
69
|
76
|
while (std::getline(f, line)) {
|
70
|
77
|
// empty line is separator between blocks
|
71
|
78
|
if (line.size() == 0) break;
|
|
@@ -87,10 +94,13 @@ void StatIdx::readFromFile(const std::string& path) {
|
87
|
94
|
|
88
|
95
|
_stations[id].attrErrs.push_back({attr, otherAttr, conf, otherId});
|
89
|
96
|
}
|
|
97
|
+ LOG(INFO) << "Done.";
|
90
|
98
|
|
|
99
|
+ LOG(INFO) << "Building indices...";
|
91
|
100
|
initGroups();
|
92
|
101
|
initSuggestions();
|
93
|
102
|
initIndex();
|
|
103
|
+ LOG(INFO) << "Done.";
|
94
|
104
|
}
|
95
|
105
|
|
96
|
106
|
// _____________________________________________________________________________
|
|
@@ -99,7 +109,15 @@ void StatIdx::addStation(size_t osmid, double lat, double lng, size_t origGroup,
|
99
|
109
|
auto point = util::geo::latLngToWebMerc<double>(lat, lng);
|
100
|
110
|
|
101
|
111
|
_stations.emplace_back(
|
102
|
|
- Station{_stations.size(), osmid, origGroup, group, point, attrs});
|
|
112
|
+ Station{_stations.size(),
|
|
113
|
+ osmid,
|
|
114
|
+ origGroup,
|
|
115
|
+ group,
|
|
116
|
+ point,
|
|
117
|
+ util::geo::webMercToLatLng<double>(point.getX(), point.getY()),
|
|
118
|
+ attrs,
|
|
119
|
+ {},
|
|
120
|
+ {}});
|
103
|
121
|
|
104
|
122
|
// extend bounding box
|
105
|
123
|
_bbox = util::geo::extendBox(point, _bbox);
|
|
@@ -119,19 +137,22 @@ void StatIdx::initGroups() {
|
119
|
137
|
for (size_t i = 0; i < _stations.size(); i++) {
|
120
|
138
|
// this should be ensured by the input file
|
121
|
139
|
assert(_stations[i].origGroup < _groups.size());
|
122
|
|
- _groups[_stations[i].origGroup].stations.push_back(i);
|
|
140
|
+ _groups[_stations[i].origGroup].polyStations.push_back(i);
|
|
141
|
+
|
|
142
|
+ _groups[_stations[i].group].stations.push_back(i);
|
123
|
143
|
|
124
|
144
|
assert(_stations[i].group < _groups.size());
|
125
|
145
|
if (_stations[i].group != _stations[i].origGroup &&
|
126
|
146
|
_groups[_stations[i].group].osmid == 1) {
|
127
|
|
- // only add non-orig groups to polygons of new (non-osm) groups
|
128
|
|
- _groups[_stations[i].group].stations.push_back(i);
|
|
147
|
+ // only add non-orig stations to polygons of new (non-osm) groups
|
|
148
|
+ _groups[_stations[i].group].polyStations.push_back(i);
|
129
|
149
|
}
|
130
|
150
|
}
|
131
|
151
|
|
|
152
|
+ // build hull polygon
|
132
|
153
|
for (size_t i = 0; i < _groups.size(); i++) {
|
133
|
154
|
util::geo::MultiPoint<double> mp;
|
134
|
|
- for (size_t stid : _groups[i].stations) {
|
|
155
|
+ for (size_t stid : _groups[i].polyStations) {
|
135
|
156
|
double rad = 11.0;
|
136
|
157
|
int n = 20;
|
137
|
158
|
for (int i = 0; i < n; i++) {
|
|
@@ -150,16 +171,99 @@ void StatIdx::initGroups() {
|
150
|
171
|
|
151
|
172
|
// _____________________________________________________________________________
|
152
|
173
|
void StatIdx::initIndex() {
|
153
|
|
- _sgrid = util::geo::Grid<size_t, util::geo::Point, double>(5000, 5000, _bbox,
|
154
|
|
- false);
|
155
|
|
- _ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(5000, 5000,
|
|
174
|
+ double gSize = 10000;
|
|
175
|
+ _sgrid = util::geo::Grid<size_t, util::geo::Point, double>(gSize, gSize,
|
|
176
|
+ _bbox, false);
|
|
177
|
+ _ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
|
156
|
178
|
_bbox, false);
|
157
|
|
- _suggrid = util::geo::Grid<size_t, util::geo::Line, double>(5000, 5000, _bbox,
|
158
|
|
- false);
|
|
179
|
+ _suggrid = util::geo::Grid<size_t, util::geo::Line, double>(gSize, gSize,
|
|
180
|
+ _bbox, false);
|
|
181
|
+
|
159
|
182
|
for (size_t i = 0; i < _stations.size(); i++) _sgrid.add(_stations[i].pos, i);
|
160
|
183
|
for (size_t i = 0; i < _groups.size(); i++) _ggrid.add(_groups[i].poly, i);
|
161
|
184
|
for (size_t i = 0; i < _suggestions.size(); i++)
|
162
|
185
|
_suggrid.add(_suggestions[i].arrow, i);
|
|
186
|
+
|
|
187
|
+ _heatGridsOk.resize(10);
|
|
188
|
+ _heatGridsSugg.resize(10);
|
|
189
|
+ _heatGridsErr.resize(10);
|
|
190
|
+
|
|
191
|
+ for (size_t i = 0; i < 10; i++) {
|
|
192
|
+ _heatGridsOk[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
193
|
+ 5000, 5000, _bbox, false));
|
|
194
|
+ _heatGridsSugg[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
195
|
+ 5000, 5000, _bbox, false));
|
|
196
|
+ _heatGridsErr[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
197
|
+ 5000, 5000, _bbox, false));
|
|
198
|
+ int step = 2000 * (i + 1);
|
|
199
|
+
|
|
200
|
+ for (size_t x = 1; x * step < (_sgrid.getXWidth() * gSize); x++) {
|
|
201
|
+ for (size_t y = 1; y * step < (_sgrid.getYHeight() * gSize); y++) {
|
|
202
|
+ std::set<size_t> tmp;
|
|
203
|
+ 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});
|
|
204
|
+ _sgrid.get(reqBox, &tmp);
|
|
205
|
+
|
|
206
|
+ size_t countOk = 0;
|
|
207
|
+ double avgXOk = 0;
|
|
208
|
+ double avgYOk = 0;
|
|
209
|
+
|
|
210
|
+ size_t countSugg = 0;
|
|
211
|
+ double avgXSugg = 0;
|
|
212
|
+ double avgYSugg = 0;
|
|
213
|
+
|
|
214
|
+ size_t countErr = 0;
|
|
215
|
+ double avgXErr = 0;
|
|
216
|
+ double avgYErr = 0;
|
|
217
|
+
|
|
218
|
+ for (auto j : tmp) {
|
|
219
|
+ const auto& stat = _stations[j];
|
|
220
|
+ if (stat.suggestions.size() == 0 && stat.attrErrs.size() == 0) {
|
|
221
|
+ if (util::geo::contains(stat.pos, reqBox)) {
|
|
222
|
+ countOk++;
|
|
223
|
+ avgXOk += stat.pos.getX();
|
|
224
|
+ avgYOk += stat.pos.getY();
|
|
225
|
+ }
|
|
226
|
+ } else if (stat.suggestions.size() > 0 && stat.attrErrs.size() == 0) {
|
|
227
|
+ if (util::geo::contains(stat.pos, reqBox)) {
|
|
228
|
+ countSugg++;
|
|
229
|
+ avgXSugg += stat.pos.getX();
|
|
230
|
+ avgYSugg += stat.pos.getY();
|
|
231
|
+ }
|
|
232
|
+ } else if (stat.attrErrs.size() > 0) {
|
|
233
|
+ if (util::geo::contains(stat.pos, reqBox)) {
|
|
234
|
+ countErr++;
|
|
235
|
+ avgXErr += stat.pos.getX();
|
|
236
|
+ avgYErr += stat.pos.getY();
|
|
237
|
+ }
|
|
238
|
+ }
|
|
239
|
+ }
|
|
240
|
+
|
|
241
|
+ if (countOk != 0) {
|
|
242
|
+ avgXOk /= countOk;
|
|
243
|
+ avgYOk /= countOk;
|
|
244
|
+ auto ll = util::geo::webMercToLatLng<double>(avgXOk, avgYOk);
|
|
245
|
+
|
|
246
|
+ _heatGridsOk[i].add({avgXOk, avgYOk}, Cluster{{avgXOk, avgYOk}, ll, countOk});
|
|
247
|
+ }
|
|
248
|
+
|
|
249
|
+ if (countSugg != 0) {
|
|
250
|
+ avgXSugg /= countSugg;
|
|
251
|
+ avgYSugg /= countSugg;
|
|
252
|
+ auto ll = util::geo::webMercToLatLng<double>(avgXSugg, avgYSugg);
|
|
253
|
+
|
|
254
|
+ _heatGridsSugg[i].add({avgXSugg, avgYSugg}, Cluster{{avgXSugg, avgYSugg}, ll, countSugg});
|
|
255
|
+ }
|
|
256
|
+
|
|
257
|
+ if (countErr != 0) {
|
|
258
|
+ avgXErr /= countErr;
|
|
259
|
+ avgYErr /= countErr;
|
|
260
|
+ auto ll = util::geo::webMercToLatLng<double>(avgXErr, avgYErr);
|
|
261
|
+
|
|
262
|
+ _heatGridsErr[i].add({avgXErr, avgYErr}, Cluster{{avgXErr, avgYErr}, ll, countErr});
|
|
263
|
+ }
|
|
264
|
+ }
|
|
265
|
+ }
|
|
266
|
+ }
|
163
|
267
|
}
|
164
|
268
|
|
165
|
269
|
// _____________________________________________________________________________
|
|
@@ -196,7 +300,7 @@ std::vector<const Group*> StatIdx::getGroups(const util::geo::DBox bbox) const {
|
196
|
300
|
_ggrid.get(reqBox, &tmp);
|
197
|
301
|
|
198
|
302
|
for (auto i : tmp) {
|
199
|
|
- if (util::geo::intersects(_groups[i].poly, reqBox))
|
|
303
|
+ // if (util::geo::intersects(_groups[i].poly, reqBox))
|
200
|
304
|
ret.push_back(&_groups[i]);
|
201
|
305
|
}
|
202
|
306
|
|
|
@@ -231,6 +335,83 @@ const Station* StatIdx::getStation(size_t id) const {
|
231
|
335
|
}
|
232
|
336
|
|
233
|
337
|
// _____________________________________________________________________________
|
|
338
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(const util::geo::DBox bbox,
|
|
339
|
+ size_t z) const {
|
|
340
|
+ auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
|
341
|
+ bbox.getLowerLeft().getY());
|
|
342
|
+ auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
343
|
+ bbox.getUpperRight().getY());
|
|
344
|
+
|
|
345
|
+ auto reqBox = util::geo::DBox(ll, ur);
|
|
346
|
+
|
|
347
|
+ z = fmin(9, z);
|
|
348
|
+ z = fmax(0, z);
|
|
349
|
+
|
|
350
|
+ const auto& grid = _heatGridsErr[9 - z];
|
|
351
|
+ std::vector<osmfixer::Cluster> ret;
|
|
352
|
+
|
|
353
|
+ std::set<osmfixer::Cluster> tmp;
|
|
354
|
+ grid.get(reqBox, &tmp);
|
|
355
|
+
|
|
356
|
+ for (const auto& i : tmp) {
|
|
357
|
+ if (util::geo::contains(i.pos, reqBox)) ret.push_back(i);
|
|
358
|
+ }
|
|
359
|
+
|
|
360
|
+ return ret;
|
|
361
|
+}
|
|
362
|
+
|
|
363
|
+// _____________________________________________________________________________
|
|
364
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(const util::geo::DBox bbox,
|
|
365
|
+ size_t z) const {
|
|
366
|
+ auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
|
367
|
+ bbox.getLowerLeft().getY());
|
|
368
|
+ auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
369
|
+ bbox.getUpperRight().getY());
|
|
370
|
+
|
|
371
|
+ auto reqBox = util::geo::DBox(ll, ur);
|
|
372
|
+
|
|
373
|
+ z = fmin(9, z);
|
|
374
|
+ z = fmax(0, z);
|
|
375
|
+
|
|
376
|
+ const auto& grid = _heatGridsOk[9 - z];
|
|
377
|
+ std::vector<osmfixer::Cluster> ret;
|
|
378
|
+
|
|
379
|
+ std::set<osmfixer::Cluster> tmp;
|
|
380
|
+ grid.get(reqBox, &tmp);
|
|
381
|
+
|
|
382
|
+ for (const auto& i : tmp) {
|
|
383
|
+ if (util::geo::contains(i.pos, reqBox)) ret.push_back(i);
|
|
384
|
+ }
|
|
385
|
+
|
|
386
|
+ return ret;
|
|
387
|
+}
|
|
388
|
+
|
|
389
|
+// _____________________________________________________________________________
|
|
390
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(const util::geo::DBox bbox,
|
|
391
|
+ size_t z) const {
|
|
392
|
+ auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
|
393
|
+ bbox.getLowerLeft().getY());
|
|
394
|
+ auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
395
|
+ bbox.getUpperRight().getY());
|
|
396
|
+
|
|
397
|
+ auto reqBox = util::geo::DBox(ll, ur);
|
|
398
|
+
|
|
399
|
+ z = fmin(9, z);
|
|
400
|
+ z = fmax(0, z);
|
|
401
|
+
|
|
402
|
+ const auto& grid = _heatGridsSugg[9 - z];
|
|
403
|
+ std::vector<osmfixer::Cluster> ret;
|
|
404
|
+
|
|
405
|
+ std::set<osmfixer::Cluster> tmp;
|
|
406
|
+ grid.get(reqBox, &tmp);
|
|
407
|
+
|
|
408
|
+ for (const auto& i : tmp) {
|
|
409
|
+ if (util::geo::contains(i.pos, reqBox)) ret.push_back(i);
|
|
410
|
+ }
|
|
411
|
+
|
|
412
|
+ return ret;
|
|
413
|
+}
|
|
414
|
+// _____________________________________________________________________________
|
234
|
415
|
void StatIdx::initSuggestions() {
|
235
|
416
|
for (size_t i = 0; i < _stations.size(); i++) {
|
236
|
417
|
auto& stat = _stations[i];
|
|
@@ -261,7 +442,8 @@ void StatIdx::initSuggestions() {
|
261
|
442
|
stat.suggestions.push_back(_suggestions.size() - 1);
|
262
|
443
|
}
|
263
|
444
|
} else {
|
264
|
|
- if (getGroup(stat.group)->osmid == 1) {
|
|
445
|
+ if (getGroup(stat.group)->osmid == 1 &&
|
|
446
|
+ getGroup(stat.group)->stations.size() > 1) {
|
265
|
447
|
// move station from relation into new group
|
266
|
448
|
sug.type = 3;
|
267
|
449
|
sug.orig_gid = stat.origGroup;
|