Commit 6e84f16c authored by Volker Krause's avatar Volker Krause
Browse files

Handle stations in all three primitive type forms, and cluster them

Fixes the PDX test, and improves the result in a few other tests.
parent 30a73505
......@@ -221,7 +221,7 @@ private Q_SLOTS:
QTest::newRow("AMS") << s("AMS") << 52.3095230f << 4.7621813f << 50;
QTest::newRow("ARN") << s("ARN") << 59.64927f << 17.92956f << 50;
QTest::newRow("BLR") << s("BLR") << 13.20023f << 77.70972f << 150;
QTest::newRow("BRE") << s("BRE") << 53.05266f << 8.78692f << 150;
QTest::newRow("BRE") << s("BRE") << 53.05266f << 8.78692f << 50;
QTest::newRow("BRU") << s("BRU") << 50.8985255f << 4.4830282f << 50;
QTest::newRow("BUD") << s("BUD") << 47.43279f << 19.26115f << 100;
QTest::newRow("CGN") << s("CGN") << 50.87856f << 7.12107f << 150;
......@@ -233,7 +233,7 @@ private Q_SLOTS:
QTest::newRow("EAP") << s("EAP") << 47.59960f << 7.53144f << 150;
QTest::newRow("EDI") << s("EDI") << 55.9483110f << -3.36353370f << 100;
QTest::newRow("EWR") << s("EWR") << 40.69049f << -74.17765f << 250;
QTest::newRow("FCO") << s("FCO") << 41.79348f << 12.25208f << 100;
QTest::newRow("FCO") << s("FCO") << 41.79348f << 12.25208f << 50;
QTest::newRow("FRA") << s("FRA") << 50.05100f << 8.571590f << 50;
QTest::newRow("GDN") << s("GDN") << 54.38234f << 18.46640f << 50;
QTest::newRow("GLA") << s("GLA") << 55.86405f << -4.43181f << 50;
......@@ -257,7 +257,7 @@ private Q_SLOTS:
QTest::newRow("ORD") << s("ORD") << 41.97779f << -87.90269f << 300;
QTest::newRow("OSL") << s("OSL") << 60.19361f << 11.09758f << 100;
QTest::newRow("OTP") << s("OTP") << 44.57040f << 26.07763f << 150;
QTest::newRow("PDX") << s("PDX") << 45.58833f << -122.59240f << 100;
QTest::newRow("PDX") << s("PDX") << 45.58833f << -122.59240f << 150;
QTest::newRow("PRG") << s("PRG") << 50.10640f << 14.26784f << 100;
QTest::newRow("PVG") << s("PVG") << 31.15240f << 121.80214f << 100;
QTest::newRow("REC") << s("REC") << -8.1314735f << -34.9177565f << 150;
......@@ -297,13 +297,12 @@ private Q_SLOTS:
QEXPECT_FAIL("GDN", "station/terminal proximity metric is too simple", Continue);
QEXPECT_FAIL("GLA", "airport is not a polygon in OSM", Continue);
QEXPECT_FAIL("GRU", "w777206182 interfering", Continue);
QEXPECT_FAIL("HKG", "way-type station elements not handled yet", Continue);
QEXPECT_FAIL("HKG", "freight terminals interfering, better station selection", Continue);
QEXPECT_FAIL("LIS", "station/terminal proximity metric is too simple", Continue);
QEXPECT_FAIL("PDX", "stop clustering missing", Continue);
QEXPECT_FAIL("PRG", "private/military terminals 3 and 4 interfering", Continue);
QEXPECT_FAIL("PVG", "needs way-type station element support, and subway vs generic type filter", Continue);
QEXPECT_FAIL("PVG", "complicated", Continue);
QEXPECT_FAIL("RIG", "open polygon in OSM", Continue);
QEXPECT_FAIL("SHA", "not optimized yet", Continue);
QEXPECT_FAIL("SHA", "station not detected?", Continue);
QEXPECT_FAIL("SXF", "w630509626 (government terminal) interfering", Continue);
QVERIFY(d <= dist);
#endif
......
......@@ -22,6 +22,10 @@
#include <QDebug>
#include <QFile>
enum {
StationClusterDistance = 100, // in meter
};
template <typename T>
static bool isActiveAirport(const T &elem)
{
......@@ -87,9 +91,7 @@ void OSMAirportDb::load(const QString &path)
}
// load railway stations
for (const auto &node : m_dataset.nodes) {
loadStation(node);
}
OSM::for_each(m_dataset, [this](const auto &elem) { loadStation(elem); });
for (auto &a : m_iataMap) {
filterStations(a.second);
}
......@@ -268,15 +270,15 @@ void OSMAirportDb::loadTerminal(const OSM::Way &elem)
}
}
void OSMAirportDb::loadStation(const OSM::Node &elem)
void OSMAirportDb::loadStation(OSM::Element elem)
{
const auto railway = OSM::tagValue(elem, QLatin1String("railway"));
const auto railway = elem.tagValue(QLatin1String("railway"));
if (railway != QLatin1String("station") && railway != QLatin1String("halt") && railway != QLatin1String("tram_stop")) {
return;
}
// try to filter out airport-interal transport systems, those are typically airside and thus not what we want
const auto station = OSM::tagValue(elem, QLatin1String("station"));
const auto station = elem.tagValue(QLatin1String("station"));
if (station == QLatin1String("monorail")) {
return;
}
......@@ -286,24 +288,24 @@ void OSMAirportDb::loadStation(const OSM::Node &elem)
// we need the exact path here, the bounding box can contain a lot more stuff
// the bounding box check is just for speed
if (!OSM::contains(airport.bbox, elem.coordinate)) {
if (!OSM::contains(airport.bbox, elem.center())) {
continue;
}
const auto onPremises = airport.airportPolygon.containsPoint(QPointF(elem.coordinate.latF(), elem.coordinate.lonF()), Qt::WindingFill);
const auto onPremises = airport.airportPolygon.containsPoint(QPointF(elem.center().latF(), elem.center().lonF()), Qt::WindingFill);
// one would assume that terminals are always within the airport bounds, but that's not the case
// they sometimes expand beyond them. A station inside a terminal is however most likely something relevant for us
const auto inTerminal = std::any_of(airport.terminalBboxes.begin(), airport.terminalBboxes.end(), [&elem](const auto &terminal) {
return OSM::contains(terminal, elem.coordinate);
return OSM::contains(terminal, elem.center());
});
const auto isCloseToTerminal = std::any_of(airport.terminalBboxes.begin(), airport.terminalBboxes.end(), [&elem](const auto &terminal) {
return OSM::distance(terminal.center(), elem.coordinate) < 100;
return OSM::distance(terminal.center(), elem.center()) < 100;
});
if (onPremises || inTerminal || isCloseToTerminal) {
//qDebug() << "found station for airport:" << elem.url() << (*it).first << (*it).second.source << onPremises << inTerminal << isCloseToTerminal;
(*it).second.stations.push_back(&elem);
(*it).second.stations.push_back(elem);
}
}
}
......@@ -313,7 +315,7 @@ void OSMAirportDb::filterStations(OSMAirportData &airport)
// if we have a full station, drop halts
// TODO similar filters are probably needed for various tram/subway variants for on-premises transport lines
auto it = std::partition(airport.stations.begin(), airport.stations.end(), [](auto station) {
return OSM::tagValue(*station, QLatin1String("railway")) == QLatin1String("station");
return station.tagValue(QLatin1String("railway")) == QLatin1String("station");
});
if (it != airport.stations.begin() && it != airport.stations.end()) {
airport.stations.erase(it, airport.stations.end());
......@@ -321,7 +323,7 @@ void OSMAirportDb::filterStations(OSMAirportData &airport)
// "creative" way of separating "real" and on-premises stations: only real ones tend to have Wikidata tags
it = std::partition(airport.stations.begin(), airport.stations.end(), [](auto station) {
return !OSM::tagValue(*station, QLatin1String("wikidata")).isEmpty();
return !station.tagValue(QLatin1String("wikidata")).isEmpty();
});
if (it != airport.stations.begin() && it != airport.stations.end()) {
airport.stations.erase(it, airport.stations.end());
......@@ -359,8 +361,19 @@ OSM::Coordinate OSMAirportDb::lookup(const QString &iata, float lat, float lon)
// single station
if (airport.stations.size() == 1) {
qDebug() << " by station:" << airport.stations[0]->url();
return airport.stations[0]->coordinate;
qDebug() << " by station:" << airport.stations[0].url();
return airport.stations[0].center();
}
// multiple stations, but close together
if (airport.stations.size() > 1) {
auto stationBbox = std::accumulate(airport.stations.begin(), airport.stations.end(), OSM::BoundingBox(), [](OSM::BoundingBox lhs, OSM::Element rhs) {
return OSM::unite(lhs, OSM::BoundingBox(rhs.boundingBox().center(), rhs.boundingBox().center()));
});
if (OSM::distance(stationBbox.min, stationBbox.max) < StationClusterDistance) {
qDebug() << " by clustered station:" << stationBbox;
return stationBbox.center();
}
}
// multiple terminals: take the center of the sum of all bounding boxes, and TODO check the result isn't ridiculously large
......
......@@ -19,6 +19,7 @@
#define OSMAIRPORTDB_H
#include <osm/datatypes.h>
#include <osm/element.h>
#include <QPolygonF>
......@@ -35,7 +36,7 @@ struct OSMAirportData
std::vector<OSM::BoundingBox> terminalBboxes;
std::vector<OSM::Coordinate> terminalEntrances;
std::vector<const OSM::Node*> stations;
std::vector<OSM::Element> stations;
};
/** OSM airport database for optimizing geo coordinates. */
......@@ -51,7 +52,7 @@ private:
void loadAirport(const OSM::Way &elem, const QString &iataCode);
void loadTerminal(const OSM::Relation &elem);
void loadTerminal(const OSM::Way &elem);
void loadStation(const OSM::Node &elem);
void loadStation(OSM::Element elem);
void filterStations(OSMAirportData &airport);
template <typename Iter>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment