GoogleMapProvider.cpp 8.42 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 119
        connect(_googleReply, &QNetworkReply::finished, this, &GoogleMapProvider::_googleVersionCompleted);
        connect(_googleReply, &QNetworkReply::destroyed, this, &GoogleMapProvider::_replyDestroyed);
        connect(_googleReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &GoogleMapProvider::_networkReplyError);
120 121 122
        networkManager->setProxy(proxy);
    }
}
Pierre TILAK's avatar
Pierre TILAK committed
123

Cosmin Marc's avatar
Cosmin Marc committed
124
QString GoogleStreetMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
125
    // http://mt1.google.com/vt/lyrs=m
Cosmin Marc's avatar
Cosmin Marc committed
126 127 128 129
    QString server  = QStringLiteral("mt");
    QString request = QStringLiteral("vt");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
130 131
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
132
    return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
133 134 135 136 137 138 139 140 141 142 143 144
        .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
145
QString GoogleSatelliteMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
Pierre TILAK's avatar
Pierre TILAK committed
146
    // http://mt1.google.com/vt/lyrs=s
Cosmin Marc's avatar
Cosmin Marc committed
147 148 149 150
    QString server  = QStringLiteral("khm");
    QString request = QStringLiteral("kh");
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
151 152
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
153
    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
154 155 156 157 158 159 160 161 162 163 164
        .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
165

Cosmin Marc's avatar
Cosmin Marc committed
166
QString GoogleLabelsMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
Pierre TILAK's avatar
Pierre TILAK committed
167 168
    QString server  = "mts";
    QString request = "vt";
Cosmin Marc's avatar
Cosmin Marc committed
169 170
    QString sec1; // after &x=...
    QString sec2; // after &zoom=...
Pierre TILAK's avatar
Pierre TILAK committed
171 172
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
173
    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
174 175 176 177 178 179 180 181 182 183 184 185
        .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
186 187 188 189 190
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
191 192
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
193
    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
194 195 196 197 198 199 200 201 202 203 204
        .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
205

Cosmin Marc's avatar
Cosmin Marc committed
206 207 208 209 210
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
211 212
    _getSecGoogleWords(x, y, sec1, sec2);
    _tryCorrectGoogleVersions(networkManager);
Cosmin Marc's avatar
Cosmin Marc committed
213
    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
214 215 216 217 218 219 220 221 222 223 224
        .arg(server)
        .arg(_getServerNum(x, y, 4))
        .arg(request)
        .arg(_versionGoogleHybrid)
        .arg(_language)
        .arg(x)
        .arg(sec1)
        .arg(y)
        .arg(zoom)
        .arg(sec2);
}