GoogleMapProvider.cpp 8.58 KB
Newer Older
Cosmin Marc's avatar
Cosmin Marc committed
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
Cosmin Marc's avatar
Cosmin Marc committed
4 5 6 7 8 9
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10 11 12 13 14
#include "GoogleMapProvider.h"
#if defined(DEBUG_GOOGLE_MAPS)
#include <QFile>
#include <QStandardPaths>
#endif
Cosmin Marc's avatar
Cosmin Marc committed
15
#include <QtGlobal>
16

Cosmin Marc's avatar
Cosmin Marc committed
17
#include "QGCMapEngine.h"
18

Cosmin Marc's avatar
Cosmin Marc committed
19 20 21 22 23
GoogleMapProvider::GoogleMapProvider(const QString &imageFormat, const quint32 averageSize, const QGeoMapType::MapStyle mapType, QObject* parent)
    : MapProvider(QStringLiteral("https://www.google.com/maps/preview"), imageFormat, averageSize, mapType, parent)
    , _googleVersionRetrieved(false)
    , _googleReply(nullptr)
{
24
    // Google version strings
Cosmin Marc's avatar
Cosmin Marc committed
25 26 27 28 29 30
    _versionGoogleMap       = QStringLiteral("m@354000000");
    _versionGoogleSatellite = QStringLiteral("692");
    _versionGoogleLabels    = QStringLiteral("h@336");
    _versionGoogleTerrain   = QStringLiteral("t@354,r@354000000");
    _versionGoogleHybrid    = QStringLiteral("y");
    _secGoogleWord          = QStringLiteral("Galileo");
31 32 33 34 35 36 37 38
}

GoogleMapProvider::~GoogleMapProvider() {
    if (_googleReply)
        _googleReply->deleteLater();
}

//-----------------------------------------------------------------------------
Cosmin Marc's avatar
Cosmin Marc committed
39 40 41
void GoogleMapProvider::_getSecGoogleWords(const int x, const int y, QString& sec1, QString& sec2) const {
    sec1       = QStringLiteral(""); // after &x=...
    sec2       = QStringLiteral(""); // after &zoom=...
42 43 44
    int seclen = ((x * 3) + y) % 8;
    sec2       = _secGoogleWord.left(seclen);
    if (y >= 10000 && y < 100000) {
Cosmin Marc's avatar
Cosmin Marc committed
45
        sec1 = QStringLiteral("&s=");
46 47 48 49 50 51 52 53 54 55 56 57
    }
}

//-----------------------------------------------------------------------------
void GoogleMapProvider::_networkReplyError(QNetworkReply::NetworkError error) {
    qWarning() << "Could not connect to google maps. Error:" << error;
    if (_googleReply) {
        _googleReply->deleteLater();
        _googleReply = nullptr;
    }
}
//-----------------------------------------------------------------------------
Cosmin Marc's avatar
Cosmin Marc committed
58 59 60
void GoogleMapProvider::_replyDestroyed() {
    _googleReply = nullptr;
}
61 62 63 64 65 66

void GoogleMapProvider::_googleVersionCompleted() {
    if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
        qDebug() << "Error collecting Google maps version info";
        return;
    }
Cosmin Marc's avatar
Cosmin Marc committed
67
    const QString html = QString(_googleReply->readAll());
68 69

#if defined(DEBUG_GOOGLE_MAPS)
Cosmin Marc's avatar
Cosmin Marc committed
70 71
    QString filename = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
    filename += QStringLiteral("/google.output");
72 73 74 75 76 77 78
    QFile file(filename);
    if (file.open(QIODevice::ReadWrite)) {
        QTextStream stream(&file);
        stream << html << endl;
    }
#endif

Cosmin Marc's avatar
Cosmin Marc committed
79
    QRegExp reg(QStringLiteral("\"*https?://mt\\D?\\d..*/vt\\?lyrs=m@(\\d*)"), Qt::CaseInsensitive);
80
    if (reg.indexIn(html) != -1) {
Cosmin Marc's avatar
Cosmin Marc committed
81
        _versionGoogleMap = QString(QStringLiteral("m@%1")).arg(reg.capturedTexts().value(1, QString()));
82
    }
Cosmin Marc's avatar
Cosmin Marc committed
83
    reg = QRegExp(QStringLiteral("\"*https?://khm\\D?\\d.googleapis.com/kh\\?v=(\\d*)"), Qt::CaseInsensitive);
84
    if (reg.indexIn(html) != -1) {
Cosmin Marc's avatar
Cosmin Marc committed
85
        _versionGoogleSatellite = reg.capturedTexts().value(1);
86
    }
Cosmin Marc's avatar
Cosmin Marc committed
87
    reg = QRegExp(QStringLiteral("\"*https?://mt\\D?\\d..*/vt\\?lyrs=t@(\\d*),r@(\\d*)"), Qt::CaseInsensitive);
88
    if (reg.indexIn(html) != -1) {
Cosmin Marc's avatar
Cosmin Marc committed
89 90
        const QStringList gc  = reg.capturedTexts();
        _versionGoogleTerrain = QString(QStringLiteral("t@%1,r@%2")).arg(gc.value(1), gc.value(2));
91 92 93 94 95
    }
    _googleReply->deleteLater();
    _googleReply = nullptr;
}

Cosmin Marc's avatar
Cosmin Marc committed
96
void GoogleMapProvider::_tryCorrectGoogleVersions(QNetworkAccessManager* networkManager) {
97 98 99 100 101 102 103 104 105 106 107 108 109 110
    QMutexLocker locker(&_googleVersionMutex);
    if (_googleVersionRetrieved) {
        return;
    }
    _googleVersionRetrieved = true;
    if (networkManager) {
        QNetworkRequest qheader;
        QNetworkProxy   proxy = networkManager->proxy();
        QNetworkProxy   tProxy;
        tProxy.setType(QNetworkProxy::DefaultProxy);
        networkManager->setProxy(tProxy);
        QSslConfiguration conf = qheader.sslConfiguration();
        conf.setPeerVerifyMode(QSslSocket::VerifyNone);
        qheader.setSslConfiguration(conf);
Cosmin Marc's avatar
Cosmin Marc committed
111
        const QString url = QStringLiteral("http://maps.google.com/maps/api/js?v=3.2&sensor=false");
112 113 114 115 116
        qheader.setUrl(QUrl(url));
        QByteArray ua;
        ua.append(getQGCMapEngine()->userAgent());
        qheader.setRawHeader("User-Agent", ua);
        _googleReply = networkManager->get(qheader);
Cosmin Marc's avatar
Cosmin Marc committed
117 118
        connect(_googleReply, &QNetworkReply::finished, this, &GoogleMapProvider::_googleVersionCompleted);
        connect(_googleReply, &QNetworkReply::destroyed, this, &GoogleMapProvider::_replyDestroyed);
119
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
Cosmin Marc's avatar
Cosmin Marc committed
120
        connect(_googleReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &GoogleMapProvider::_networkReplyError);
121 122 123
#else
        connect(_googleReply, &QNetworkReply::errorOccurred, this, &GoogleMapProvider::_networkReplyError);
#endif
124 125 126
        networkManager->setProxy(proxy);
    }
}
Pierre TILAK's avatar
Pierre TILAK committed
127

Cosmin Marc's avatar
Cosmin Marc committed
128
QString GoogleStreetMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
129
    // http://mt1.google.com/vt/lyrs=m
Cosmin Marc's avatar
Cosmin Marc committed
130 131 132 133
    QString server  = QStringLiteral("mt");
    QString request = QStringLiteral("vt");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
134 135
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
136
    return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
137 138 139 140 141 142 143 144 145 146 147 148
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleMap)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}

Cosmin Marc's avatar
Cosmin Marc committed
149
QString GoogleSatelliteMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
Pierre TILAK's avatar
Pierre TILAK committed
150
    // http://mt1.google.com/vt/lyrs=s
Cosmin Marc's avatar
Cosmin Marc committed
151 152 153 154
    QString server  = QStringLiteral("khm");
    QString request = QStringLiteral("kh");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
155 156
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
157
    return QString(QStringLiteral("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
Pierre TILAK's avatar
Pierre TILAK committed
158 159 160 161 162 163 164 165 166 167 168
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleSatellite)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}
Pierre TILAK's avatar
Pierre TILAK committed
169

Cosmin Marc's avatar
Cosmin Marc committed
170
QString GoogleLabelsMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
Pierre TILAK's avatar
Pierre TILAK committed
171 172
    QString server  = "mts";
    QString request = "vt";
Cosmin Marc's avatar
Cosmin Marc committed
173 174
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
175 176
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
177
    return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
Pierre TILAK's avatar
Pierre TILAK committed
178 179 180 181 182 183 184 185 186 187 188 189
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleLabels)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}

Cosmin Marc's avatar
Cosmin Marc committed
190 191 192 193 194
QString GoogleTerrainMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
    QString server  = QStringLiteral("mt");
    QString request = QStringLiteral("vt");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
195 196
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
197
    return QString(QStringLiteral("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
Pierre TILAK's avatar
Pierre TILAK committed
198 199 200 201 202 203 204 205 206 207 208
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleTerrain)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}
Pierre TILAK's avatar
Pierre TILAK committed
209

Cosmin Marc's avatar
Cosmin Marc committed
210 211 212 213 214
QString GoogleHybridMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
    QString server = QStringLiteral("mt");
    QString request = QStringLiteral("vt");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
215 216
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
217
    return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
Pierre TILAK's avatar
Pierre TILAK committed
218 219 220 221 222 223 224 225 226 227 228
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleHybrid)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}