|
@@ -30,27 +30,48 @@ void StatIdx::readFromFile(const std::string& path) {
|
30
|
30
|
if (line.size() == 0) break;
|
31
|
31
|
|
32
|
32
|
std::stringstream rec(line);
|
33
|
|
- size_t osmid, origGroup, group;
|
34
|
|
- double lat, lng;
|
|
33
|
+ int64_t osmid, origGroup, group;
|
|
34
|
+ double lat = 0, lng = 0;
|
35
|
35
|
OsmAttrs attrs;
|
36
|
36
|
|
37
|
37
|
rec >> osmid;
|
38
|
|
- rec >> lat;
|
39
|
|
- rec >> lng;
|
40
|
38
|
rec >> origGroup;
|
41
|
39
|
rec >> group;
|
42
|
40
|
|
|
41
|
+ util::geo::DLine geom;
|
|
42
|
+ util::geo::DLine latLngs;
|
|
43
|
+
|
43
|
44
|
std::string temp;
|
|
45
|
+ std::string key, val;
|
|
46
|
+ uint8_t sw = 0;
|
44
|
47
|
std::getline(rec, temp, '\t');
|
45
|
48
|
while (std::getline(rec, temp, '\t')) {
|
46
|
|
- std::string key, val;
|
47
|
|
- key = temp;
|
48
|
|
- std::getline(rec, temp, '\t');
|
49
|
|
- val = temp;
|
50
|
|
- attrs[key].push_back(val);
|
|
49
|
+ if (sw == 2) {
|
|
50
|
+ std::getline(rec, val, '\t');
|
|
51
|
+ attrs[temp].push_back(val);
|
|
52
|
+ } else {
|
|
53
|
+ try {
|
|
54
|
+ double a = std::stod(temp);
|
|
55
|
+ if (sw == 1) {
|
|
56
|
+ lat = a;
|
|
57
|
+ geom.push_back(util::geo::latLngToWebMerc<double>(lat, lng));
|
|
58
|
+ sw = 0;
|
|
59
|
+ } else if (sw == 0) {
|
|
60
|
+ lng = a;
|
|
61
|
+ sw = 1;
|
|
62
|
+ }
|
|
63
|
+ } catch (std::invalid_argument) {
|
|
64
|
+ sw = 2;
|
|
65
|
+ std::getline(rec, val, '\t');
|
|
66
|
+ attrs[temp].push_back(val);
|
|
67
|
+ }
|
|
68
|
+ }
|
51
|
69
|
}
|
52
|
70
|
|
53
|
|
- addStation(osmid, lat, lng, origGroup, group, attrs);
|
|
71
|
+ 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()));
|
|
73
|
+
|
|
74
|
+ addStation(osmid, geom, latLngs, origGroup, group, attrs);
|
54
|
75
|
}
|
55
|
76
|
LOG(INFO) << "Done.";
|
56
|
77
|
|
|
@@ -61,7 +82,7 @@ void StatIdx::readFromFile(const std::string& path) {
|
61
|
82
|
if (line.size() == 0) break;
|
62
|
83
|
|
63
|
84
|
std::stringstream rec(line);
|
64
|
|
- size_t osmid;
|
|
85
|
+ int64_t osmid;
|
65
|
86
|
OsmAttrs attrs;
|
66
|
87
|
|
67
|
88
|
rec >> osmid;
|
|
@@ -81,7 +102,7 @@ void StatIdx::readFromFile(const std::string& path) {
|
81
|
102
|
size_t id;
|
82
|
103
|
std::string attr, otherAttr;
|
83
|
104
|
double conf;
|
84
|
|
- size_t otherId;
|
|
105
|
+ int64_t otherId;
|
85
|
106
|
|
86
|
107
|
rec >> id;
|
87
|
108
|
|
|
@@ -105,23 +126,23 @@ void StatIdx::readFromFile(const std::string& path) {
|
105
|
126
|
}
|
106
|
127
|
|
107
|
128
|
// _____________________________________________________________________________
|
108
|
|
-void StatIdx::addStation(size_t osmid, double lat, double lng, size_t origGroup,
|
|
129
|
+void StatIdx::addStation(int64_t osmid, const util::geo::DLine& geom,
|
|
130
|
+ const util::geo::DLine& latLngs, size_t origGroup,
|
109
|
131
|
size_t group, const OsmAttrs& attrs) {
|
110
|
|
- auto point = util::geo::latLngToWebMerc<double>(lat, lng);
|
111
|
|
-
|
112
|
|
- _stations.emplace_back(
|
113
|
|
- Station{_stations.size(),
|
114
|
|
- osmid,
|
115
|
|
- origGroup,
|
116
|
|
- group,
|
117
|
|
- point,
|
118
|
|
- util::geo::webMercToLatLng<double>(point.getX(), point.getY()),
|
119
|
|
- attrs,
|
120
|
|
- {},
|
121
|
|
- {}});
|
|
132
|
+ auto centroid = util::geo::centroid(latLngs);
|
|
133
|
+ _stations.emplace_back(Station{_stations.size(),
|
|
134
|
+ osmid,
|
|
135
|
+ origGroup,
|
|
136
|
+ group,
|
|
137
|
+ centroid,
|
|
138
|
+ geom,
|
|
139
|
+ latLngs,
|
|
140
|
+ attrs,
|
|
141
|
+ {},
|
|
142
|
+ {}});
|
122
|
143
|
|
123
|
144
|
// extend bounding box
|
124
|
|
- _bbox = util::geo::extendBox(point, _bbox);
|
|
145
|
+ for (const auto& point : geom) _bbox = util::geo::extendBox(point, _bbox);
|
125
|
146
|
}
|
126
|
147
|
|
127
|
148
|
// _____________________________________________________________________________
|
|
@@ -166,19 +187,27 @@ void StatIdx::initGroups() {
|
166
|
187
|
double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
|
167
|
188
|
static_cast<double>(i));
|
168
|
189
|
|
169
|
|
- mp.push_back(util::geo::DPoint(_stations[stid].pos.getX() + x,
|
170
|
|
- _stations[stid].pos.getY() + y));
|
|
190
|
+ for (const auto& geom : _stations[stid].pos) {
|
|
191
|
+ mp.push_back(util::geo::DPoint(geom.getX() + x, geom.getY() + y));
|
|
192
|
+ }
|
171
|
193
|
}
|
172
|
194
|
}
|
173
|
|
- _groups[i].poly = util::geo::convexHull(mp);
|
|
195
|
+ _groups[i].poly = util::geo::simplify(util::geo::convexHull(mp).getOuter(), 0.5);
|
|
196
|
+
|
|
197
|
+ for (auto p : _groups[i].poly.getOuter()) {
|
|
198
|
+ _groups[i].llPoly.getOuter().push_back(
|
|
199
|
+ util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
|
|
200
|
+ }
|
|
201
|
+
|
|
202
|
+ _groups[i].centroid = util::geo::centroid(_groups[i].llPoly);
|
174
|
203
|
}
|
175
|
204
|
}
|
176
|
205
|
|
177
|
206
|
// _____________________________________________________________________________
|
178
|
207
|
void StatIdx::initIndex() {
|
179
|
208
|
double gSize = 10000;
|
180
|
|
- _sgrid = util::geo::Grid<size_t, util::geo::Point, double>(gSize, gSize,
|
181
|
|
- _bbox, false);
|
|
209
|
+ _sgrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
|
|
210
|
+ _bbox, false);
|
182
|
211
|
_ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(gSize, gSize,
|
183
|
212
|
_bbox, false);
|
184
|
213
|
_suggrid = util::geo::Grid<size_t, util::geo::Line, double>(gSize, gSize,
|
|
@@ -194,18 +223,25 @@ void StatIdx::initIndex() {
|
194
|
223
|
_heatGridsErr.resize(10);
|
195
|
224
|
|
196
|
225
|
for (size_t i = 0; i < 10; i++) {
|
197
|
|
- _heatGridsOk[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
198
|
|
- 5000, 5000, _bbox, false));
|
199
|
|
- _heatGridsSugg[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
200
|
|
- 5000, 5000, _bbox, false));
|
201
|
|
- _heatGridsErr[i] = (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
202
|
|
- 5000, 5000, _bbox, false));
|
|
226
|
+ _heatGridsOk[i] =
|
|
227
|
+ (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
228
|
+ 5000, 5000, _bbox, false));
|
|
229
|
+ _heatGridsSugg[i] =
|
|
230
|
+ (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
231
|
+ 5000, 5000, _bbox, false));
|
|
232
|
+ _heatGridsErr[i] =
|
|
233
|
+ (util::geo::Grid<osmfixer::Cluster, util::geo::Point, double>(
|
|
234
|
+ 5000, 5000, _bbox, false));
|
203
|
235
|
int step = 2000 * (i + 1);
|
204
|
236
|
|
205
|
237
|
for (size_t x = 1; x * step < (_sgrid.getXWidth() * gSize); x++) {
|
206
|
238
|
for (size_t y = 1; y * step < (_sgrid.getYHeight() * gSize); y++) {
|
207
|
239
|
std::set<size_t> tmp;
|
208
|
|
- 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});
|
|
240
|
+ auto reqBox =
|
|
241
|
+ util::geo::DBox({_bbox.getLowerLeft().getX() + (x - 1) * step,
|
|
242
|
+ _bbox.getLowerLeft().getY() + (y - 1) * step},
|
|
243
|
+ {_bbox.getLowerLeft().getX() + x * step,
|
|
244
|
+ _bbox.getLowerLeft().getY() + y * step});
|
209
|
245
|
_sgrid.get(reqBox, &tmp);
|
210
|
246
|
|
211
|
247
|
size_t countOk = 0;
|
|
@@ -223,22 +259,28 @@ void StatIdx::initIndex() {
|
223
|
259
|
for (auto j : tmp) {
|
224
|
260
|
const auto& stat = _stations[j];
|
225
|
261
|
if (stat.suggestions.size() == 0 && stat.attrErrs.size() == 0) {
|
226
|
|
- if (util::geo::contains(stat.pos, reqBox)) {
|
227
|
|
- countOk++;
|
228
|
|
- avgXOk += stat.pos.getX();
|
229
|
|
- avgYOk += stat.pos.getY();
|
|
262
|
+ for (const auto& pos : stat.pos) {
|
|
263
|
+ if (util::geo::contains(pos, reqBox)) {
|
|
264
|
+ countOk++;
|
|
265
|
+ avgXOk += pos.getX();
|
|
266
|
+ avgYOk += pos.getY();
|
|
267
|
+ }
|
230
|
268
|
}
|
231
|
269
|
} else if (stat.suggestions.size() > 0 && stat.attrErrs.size() == 0) {
|
232
|
|
- if (util::geo::contains(stat.pos, reqBox)) {
|
233
|
|
- countSugg++;
|
234
|
|
- avgXSugg += stat.pos.getX();
|
235
|
|
- avgYSugg += stat.pos.getY();
|
|
270
|
+ for (const auto& pos : stat.pos) {
|
|
271
|
+ if (util::geo::contains(pos, reqBox)) {
|
|
272
|
+ countSugg++;
|
|
273
|
+ avgXSugg += pos.getX();
|
|
274
|
+ avgYSugg += pos.getY();
|
|
275
|
+ }
|
236
|
276
|
}
|
237
|
277
|
} else if (stat.attrErrs.size() > 0) {
|
238
|
|
- if (util::geo::contains(stat.pos, reqBox)) {
|
239
|
|
- countErr++;
|
240
|
|
- avgXErr += stat.pos.getX();
|
241
|
|
- avgYErr += stat.pos.getY();
|
|
278
|
+ for (const auto& pos : stat.pos) {
|
|
279
|
+ if (util::geo::contains(pos, reqBox)) {
|
|
280
|
+ countErr++;
|
|
281
|
+ avgXErr += pos.getX();
|
|
282
|
+ avgYErr += pos.getY();
|
|
283
|
+ }
|
242
|
284
|
}
|
243
|
285
|
}
|
244
|
286
|
}
|
|
@@ -248,7 +290,8 @@ void StatIdx::initIndex() {
|
248
|
290
|
avgYOk /= countOk;
|
249
|
291
|
auto ll = util::geo::webMercToLatLng<double>(avgXOk, avgYOk);
|
250
|
292
|
|
251
|
|
- _heatGridsOk[i].add({avgXOk, avgYOk}, Cluster{{avgXOk, avgYOk}, ll, countOk});
|
|
293
|
+ _heatGridsOk[i].add({avgXOk, avgYOk},
|
|
294
|
+ Cluster{{avgXOk, avgYOk}, ll, countOk});
|
252
|
295
|
}
|
253
|
296
|
|
254
|
297
|
if (countSugg != 0) {
|
|
@@ -256,7 +299,8 @@ void StatIdx::initIndex() {
|
256
|
299
|
avgYSugg /= countSugg;
|
257
|
300
|
auto ll = util::geo::webMercToLatLng<double>(avgXSugg, avgYSugg);
|
258
|
301
|
|
259
|
|
- _heatGridsSugg[i].add({avgXSugg, avgYSugg}, Cluster{{avgXSugg, avgYSugg}, ll, countSugg});
|
|
302
|
+ _heatGridsSugg[i].add({avgXSugg, avgYSugg},
|
|
303
|
+ Cluster{{avgXSugg, avgYSugg}, ll, countSugg});
|
260
|
304
|
}
|
261
|
305
|
|
262
|
306
|
if (countErr != 0) {
|
|
@@ -264,7 +308,8 @@ void StatIdx::initIndex() {
|
264
|
308
|
avgYErr /= countErr;
|
265
|
309
|
auto ll = util::geo::webMercToLatLng<double>(avgXErr, avgYErr);
|
266
|
310
|
|
267
|
|
- _heatGridsErr[i].add({avgXErr, avgYErr}, Cluster{{avgXErr, avgYErr}, ll, countErr});
|
|
311
|
+ _heatGridsErr[i].add({avgXErr, avgYErr},
|
|
312
|
+ Cluster{{avgXErr, avgYErr}, ll, countErr});
|
268
|
313
|
}
|
269
|
314
|
}
|
270
|
315
|
}
|
|
@@ -305,7 +350,7 @@ std::vector<const Group*> StatIdx::getGroups(const util::geo::DBox bbox) const {
|
305
|
350
|
_ggrid.get(reqBox, &tmp);
|
306
|
351
|
|
307
|
352
|
for (auto i : tmp) {
|
308
|
|
- // if (util::geo::intersects(_groups[i].poly, reqBox))
|
|
353
|
+ if (util::geo::intersects(_groups[i].poly, reqBox))
|
309
|
354
|
ret.push_back(&_groups[i]);
|
310
|
355
|
}
|
311
|
356
|
|
|
@@ -326,8 +371,10 @@ std::vector<const Station*> StatIdx::getStations(
|
326
|
371
|
_sgrid.get(reqBox, &tmp);
|
327
|
372
|
|
328
|
373
|
for (auto i : tmp) {
|
329
|
|
- if (util::geo::contains(_stations[i].pos, reqBox))
|
|
374
|
+ if (util::geo::intersects(util::geo::Polygon<double>(_stations[i].pos),
|
|
375
|
+ reqBox)) {
|
330
|
376
|
ret.push_back(&_stations[i]);
|
|
377
|
+ }
|
331
|
378
|
}
|
332
|
379
|
|
333
|
380
|
return ret;
|
|
@@ -340,8 +387,8 @@ const Station* StatIdx::getStation(size_t id) const {
|
340
|
387
|
}
|
341
|
388
|
|
342
|
389
|
// _____________________________________________________________________________
|
343
|
|
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(const util::geo::DBox bbox,
|
344
|
|
- size_t z) const {
|
|
390
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(
|
|
391
|
+ const util::geo::DBox bbox, size_t z) const {
|
345
|
392
|
auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
346
|
393
|
bbox.getLowerLeft().getY());
|
347
|
394
|
auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
@@ -366,8 +413,8 @@ std::vector<osmfixer::Cluster> StatIdx::getHeatGridErr(const util::geo::DBox bbo
|
366
|
413
|
}
|
367
|
414
|
|
368
|
415
|
// _____________________________________________________________________________
|
369
|
|
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(const util::geo::DBox bbox,
|
370
|
|
- size_t z) const {
|
|
416
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(
|
|
417
|
+ const util::geo::DBox bbox, size_t z) const {
|
371
|
418
|
auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
372
|
419
|
bbox.getLowerLeft().getY());
|
373
|
420
|
auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
@@ -392,8 +439,8 @@ std::vector<osmfixer::Cluster> StatIdx::getHeatGridOk(const util::geo::DBox bbox
|
392
|
439
|
}
|
393
|
440
|
|
394
|
441
|
// _____________________________________________________________________________
|
395
|
|
-std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(const util::geo::DBox bbox,
|
396
|
|
- size_t z) const {
|
|
442
|
+std::vector<osmfixer::Cluster> StatIdx::getHeatGridSugg(
|
|
443
|
+ const util::geo::DBox bbox, size_t z) const {
|
397
|
444
|
auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
|
398
|
445
|
bbox.getLowerLeft().getY());
|
399
|
446
|
auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
|
|
@@ -423,7 +470,8 @@ void StatIdx::initSuggestions() {
|
423
|
470
|
if (stat.group != stat.origGroup || getGroup(stat.group)->osmid == 1) {
|
424
|
471
|
Suggestion sug;
|
425
|
472
|
sug.station = i;
|
426
|
|
- sug.arrow = util::geo::DLine{stat.pos, stat.pos};
|
|
473
|
+ auto centroid = util::geo::centroid(stat.pos);
|
|
474
|
+ sug.arrow = util::geo::DLine{centroid, centroid};
|
427
|
475
|
if (getGroup(stat.origGroup)->osmid < 2) {
|
428
|
476
|
if (getGroup(stat.group)->osmid == 1) {
|
429
|
477
|
// move orphan into new group
|
|
@@ -481,7 +529,7 @@ void StatIdx::initSuggestions() {
|
481
|
529
|
sug.target_gid = stat.group;
|
482
|
530
|
sug.target_osm_rel_id = getGroup(stat.group)->osmid;
|
483
|
531
|
|
484
|
|
- auto b = stat.pos;
|
|
532
|
+ auto b = util::geo::centroid(stat.pos);
|
485
|
533
|
b.setX(b.getX() + 50);
|
486
|
534
|
b.setY(b.getY() + 50);
|
487
|
535
|
|
|
@@ -512,8 +560,9 @@ void StatIdx::initSuggestions() {
|
512
|
560
|
}
|
513
|
561
|
|
514
|
562
|
// _____________________________________________________________________________
|
515
|
|
-util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b) const {
|
516
|
|
- auto a = getStation(stat)->pos;
|
|
563
|
+util::geo::DLine StatIdx::getGroupArrow(size_t stat,
|
|
564
|
+ const util::geo::DPoint& b) const {
|
|
565
|
+ auto a = util::geo::centroid(getStation(stat)->pos);
|
517
|
566
|
|
518
|
567
|
auto pl = util::geo::PolyLine<double>(a, b);
|
519
|
568
|
auto bb = pl.getPointAtDist(fmax(pl.getLength() / 2, pl.getLength() - 5)).p;
|
|
@@ -528,7 +577,6 @@ util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b)
|
528
|
577
|
if (util::geo::dist(a, bb) < 20) {
|
529
|
578
|
line = {a, bb};
|
530
|
579
|
} else {
|
531
|
|
-
|
532
|
580
|
int side = rand() % 2;
|
533
|
581
|
if (!side) side = -1;
|
534
|
582
|
|
|
@@ -536,9 +584,9 @@ util::geo::DLine StatIdx::getGroupArrow(size_t stat, const util::geo::DPoint& b)
|
536
|
584
|
auto rot2 = util::geo::rotate(util::geo::DLine{a, bb}, -20 * side, bb);
|
537
|
585
|
auto rot3 = util::geo::rotate(util::geo::DLine{a, bb}, -120 * side, bb);
|
538
|
586
|
|
539
|
|
- auto i =
|
540
|
|
- util::geo::intersection(util::geo::LineSegment<double>{rot1[0], rot1[1]},
|
541
|
|
- util::geo::LineSegment<double>{rot2[0], rot2[1]});
|
|
587
|
+ auto i = util::geo::intersection(
|
|
588
|
+ util::geo::LineSegment<double>{rot1[0], rot1[1]},
|
|
589
|
+ util::geo::LineSegment<double>{rot2[0], rot2[1]});
|
542
|
590
|
|
543
|
591
|
line =
|
544
|
592
|
util::geo::BezierCurve<double>(a, i, rot3[0], bb).render(5).getLine();
|