Commit 8624fb71 authored by dogmaphobic's avatar dogmaphobic

Fixed Google Satellite

Download Speed Tweaks (+2 squashed commits)
Squashed commits:
[ff0ef7e] Cleanup (remove OpenStreetMap)
[370fa1d] Done (+25 squashed commits)
Squashed commits:
[9f3368f] Need to check how many instances of MapEngine are active.
[d557eac] Download Optimization
[392f50a] Almost there.
Trying to optimize download.
[a49d1d2] Settings
[a94be97] Mostly there. Needs to finish options and map thumbnail.
[38d5a0b] Downloading tiles and deleting sets
[81101b9] More UI Work
[c597d4b] Downloading tiles
[a815e35] Get rid of OpenMaps
[7e177ea] More reorg
[fa6b671] Start handling create tile set
Fix signal order when creating fetch tile task
[2a31f4d] Refactoring
[268b906] Renaming things
[947d66e] Fix resource load error.
[19e2de8] Adding MapBox
[c73e627] Preparing download
[87bbf22] UI Tweaks
[3c32a86] A lot of UI code done.
[ece8ce2] Starting to deal with tiles
[7f387bc] Save tile set
[f66f343] Adding more code
[4de3418] Working
[f0cc25d] Done for the night.
[2d1d86e] Added SQL database for holding out own tile cache.
[d405a87] Convert to camel case as this has been driving me nuts.
parent 7891f53c
......@@ -139,6 +139,7 @@
<file alias="buttonRight.svg">resources/buttonRight.svg</file>
<file alias="JoystickBezel.png">resources/JoystickBezel.png</file>
<file alias="JoystickBezelLight.png">resources/JoystickBezelLight.png</file>
<file alias="notile.png">resources/notile.png</file>
<file alias="Pause">resources/Pause.svg</file>
<file alias="Play">resources/Play.svg</file>
<file alias="PowerButton">resources/PowerButton.svg</file>
......
......@@ -203,6 +203,8 @@ INCLUDEPATH += \
src/ui/uas \
src/VehicleSetup \
src/ViewWidgets \
src/QtLocationPlugin \
src/QtLocationPlugin/QMLControl \
FORMS += \
src/ui/MainWindow.ui \
......@@ -284,7 +286,8 @@ HEADERS += \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.h \
src/AutoPilotPlugins/APM/APMAirframeLoader.h \
src/QmlControls/QGCImageProvider.h \
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h \
src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h \
DebugBuild {
HEADERS += \
......@@ -405,7 +408,8 @@ SOURCES += \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc \
src/AutoPilotPlugins/APM/APMAirframeLoader.cc \
src/QmlControls/QGCImageProvider.cc \
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.cc
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.cc \
src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc \
DebugBuild {
SOURCES += \
......
......@@ -27,6 +27,7 @@
<file alias="MavlinkSettings.qml">src/ui/preferences/MavlinkSettings.qml</file>
<file alias="MockLink.qml">src/ui/preferences/MockLink.qml</file>
<file alias="MockLinkSettings.qml">src/ui/preferences/MockLinkSettings.qml</file>
<file alias="OfflineMap.qml">src/QtLocationPlugin/QMLControl/OfflineMap.qml</file>
<file alias="SerialSettings.qml">src/ui/preferences/SerialSettings.qml</file>
<file alias="TcpSettings.qml">src/ui/preferences/TcpSettings.qml</file>
<file alias="UdpSettings.qml">src/ui/preferences/UdpSettings.qml</file>
......@@ -139,6 +140,7 @@
<file alias="SetupView.qml">src/VehicleSetup/SetupView.qml</file>
<file alias="test.qml">src/test.qml</file>
<file alias="VehicleSummary.qml">src/VehicleSetup/VehicleSummary.qml</file>
<file alias="QGroundControl/Controls/OfflineMapButton.qml">src/QmlControls/OfflineMapButton.qml</file>
</qresource>
<qresource prefix="/json">
<file alias="MavCmdInfoCommon.json">src/MissionManager/MavCmdInfoCommon.json</file>
......
......@@ -43,7 +43,7 @@ void FlightMapSettings::setToolbox(QGCToolbox *toolbox)
qmlRegisterUncreatableType<FlightMapSettings> ("QGroundControl", 1, 0, "FlightMapSetting", "Reference only");
_supportedMapProviders << "Bing" << "Google" << "OpenStreetMap";
_supportedMapProviders << "Bing" << "Google"; // << "OpenStreetMap";
_loadSettings();
}
......@@ -93,8 +93,10 @@ void FlightMapSettings::_setMapTypesForCurrentProvider(void)
_mapTypes << "Street Map" << "Satellite Map" << "Hybrid Map";
} else if (_mapProvider == "Google") {
_mapTypes << "Street Map" << "Satellite Map" << "Terrain Map";
/*
} else if (_mapProvider == "OpenStreetMap") {
_mapTypes << "Street Map";
*/
}
emit mapTypesChanged(_mapTypes);
......
......@@ -34,6 +34,7 @@
#include "MultiVehicleManager.h"
#include "QGCImageProvider.h"
#include "UASMessageHandler.h"
#include "QGCMapEngineManager.h"
QGCToolbox::QGCToolbox(QGCApplication* app)
: _audioOutput(NULL)
......@@ -48,6 +49,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
, _mavlinkProtocol(NULL)
, _missionCommands(NULL)
, _multiVehicleManager(NULL)
, _mapEngineManager(NULL)
, _uasMessageHandler(NULL)
{
_audioOutput = new GAudioOutput(app);
......@@ -62,6 +64,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_mavlinkProtocol = new MAVLinkProtocol(app);
_missionCommands = new MissionCommands(app);
_multiVehicleManager = new MultiVehicleManager(app);
_mapEngineManager = new QGCMapEngineManager(app);
_uasMessageHandler = new UASMessageHandler(app);
_audioOutput->setToolbox(this);
......@@ -76,6 +79,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_mavlinkProtocol->setToolbox(this);
_missionCommands->setToolbox(this);
_multiVehicleManager->setToolbox(this);
_mapEngineManager->setToolbox(this);
_uasMessageHandler->setToolbox(this);
}
......@@ -91,6 +95,7 @@ QGCToolbox::~QGCToolbox()
delete _linkManager;
delete _mavlinkProtocol;
delete _missionCommands;
delete _mapEngineManager;
delete _multiVehicleManager;
delete _uasMessageHandler;
}
......
......@@ -37,6 +37,7 @@ class LinkManager;
class MAVLinkProtocol;
class MissionCommands;
class MultiVehicleManager;
class QGCMapEngineManager;
class QGCApplication;
class QGCImageProvider;
class UASMessageHandler;
......@@ -58,6 +59,7 @@ public:
MAVLinkProtocol* mavlinkProtocol(void) { return _mavlinkProtocol; }
MissionCommands* missionCommands(void) { return _missionCommands; }
MultiVehicleManager* multiVehicleManager(void) { return _multiVehicleManager; }
QGCMapEngineManager* mapEngineManager(void) { return _mapEngineManager; }
QGCImageProvider* imageProvider() { return _imageProvider; }
UASMessageHandler* uasMessageHandler(void) { return _uasMessageHandler; }
......@@ -74,6 +76,7 @@ private:
MAVLinkProtocol* _mavlinkProtocol;
MissionCommands* _missionCommands;
MultiVehicleManager* _multiVehicleManager;
QGCMapEngineManager* _mapEngineManager;
UASMessageHandler* _uasMessageHandler;
};
......
import QtQuick 2.5
import QtQuick.Controls 1.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Rectangle
{
id: __mapButton
property var __qgcPal: QGCPalette { colorGroupEnabled: enabled }
property bool __showHighlight: (__pressed | __hovered | checked) && !__forceHoverOff
property bool __forceHoverOff: false
property int __lastGlobalMouseX: 0
property int __lastGlobalMouseY: 0
property bool __pressed: false
property bool __hovered: false
property bool checked: false
property bool complete: false
property alias text: nameLabel.text
property alias size: sizeLabel.text
signal clicked()
color: __showHighlight ? __qgcPal.buttonHighlight : __qgcPal.button
anchors.margins: ScreenTools.defaultFontPixelWidth
Row {
anchors.centerIn: parent
QGCLabel {
id: nameLabel
width: __mapButton.width * 0.4
color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
anchors.verticalCenter: parent.verticalCenter
}
QGCLabel {
id: sizeLabel
width: __mapButton.width * 0.4
horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter
color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
}
Item {
width: ScreenTools.defaultFontPixelWidth * 2
height: 1
}
Rectangle {
width: sizeLabel.height * 0.5
height: sizeLabel.height * 0.5
radius: width / 2
color: complete ? "#31f55b" : "#fc5656"
opacity: sizeLabel.text.length > 0 ? 1 : 0
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: ScreenTools.defaultFontPixelWidth * 2
height: 1
}
QGCColoredImage {
width: sizeLabel.height * 0.8
height: sizeLabel.height * 0.8
source: "/res/buttonRight.svg"
mipmap: true
fillMode: Image.PreserveAspectFit
color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onMouseXChanged: {
__lastGlobalMouseX = ScreenTools.mouseX()
__lastGlobalMouseY = ScreenTools.mouseY()
}
onMouseYChanged: {
__lastGlobalMouseX = ScreenTools.mouseX()
__lastGlobalMouseY = ScreenTools.mouseY()
}
onEntered: { __hovered = true; __forceHoverOff = false; hoverTimer.start() }
onExited: { __hovered = false; __forceHoverOff = false; hoverTimer.stop() }
onPressed: { __pressed = true; }
onReleased: { __pressed = false; }
onClicked: {
__mapButton.clicked()
}
}
Timer {
id: hoverTimer
interval: 250
repeat: true
onTriggered: {
if (__lastGlobalMouseX !== ScreenTools.mouseX() || __lastGlobalMouseY !== ScreenTools.mouseY()) {
__forceHoverOff = true
} else {
__forceHoverOff = false
}
}
}
}
......@@ -35,3 +35,4 @@ SubMenuButton 1.0 SubMenuButton.qml
VehicleRotationCal 1.0 VehicleRotationCal.qml
VehicleSummaryRow 1.0 VehicleSummaryRow.qml
ViewWidget 1.0 ViewWidget.qml
OfflineMapButton 1.0 OfflineMapButton.qml
......@@ -39,6 +39,7 @@ QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCApplication* app)
, _linkManager(NULL)
, _missionCommands(NULL)
, _multiVehicleManager(NULL)
, _mapEngineManager(NULL)
, _virtualTabletJoystick(false)
, _offlineEditingFirmwareTypeFact(QString(), "OfflineEditingFirmwareType", FactMetaData::valueTypeUint32, (uint32_t)MAV_AUTOPILOT_ARDUPILOTMEGA)
, _offlineEditingFirmwareTypeMetaData(FactMetaData::valueTypeUint32)
......@@ -65,12 +66,12 @@ QGroundControlQmlGlobal::~QGroundControlQmlGlobal()
void QGroundControlQmlGlobal::setToolbox(QGCToolbox* toolbox)
{
QGCTool::setToolbox(toolbox);
_flightMapSettings = toolbox->flightMapSettings();
_homePositionManager = toolbox->homePositionManager();
_linkManager = toolbox->linkManager();
_missionCommands = toolbox->missionCommands();
_multiVehicleManager = toolbox->multiVehicleManager();
_flightMapSettings = toolbox->flightMapSettings();
_homePositionManager = toolbox->homePositionManager();
_linkManager = toolbox->linkManager();
_missionCommands = toolbox->missionCommands();
_multiVehicleManager = toolbox->multiVehicleManager();
_mapEngineManager = toolbox->mapEngineManager();
}
......
......@@ -55,6 +55,7 @@ public:
Q_PROPERTY(LinkManager* linkManager READ linkManager CONSTANT)
Q_PROPERTY(MissionCommands* missionCommands READ missionCommands CONSTANT)
Q_PROPERTY(MultiVehicleManager* multiVehicleManager READ multiVehicleManager CONSTANT)
Q_PROPERTY(QGCMapEngineManager* mapEngineManager READ mapEngineManager CONSTANT)
Q_PROPERTY(qreal zOrderTopMost READ zOrderTopMost CONSTANT) ///< z order for top most items, toolbar, main window sub view
Q_PROPERTY(qreal zOrderWidgets READ zOrderWidgets CONSTANT) ///< z order value to widgets, for example: zoom controls, hud widgetss
......@@ -95,9 +96,10 @@ public:
FlightMapSettings* flightMapSettings () { return _flightMapSettings; }
HomePositionManager* homePositionManager () { return _homePositionManager; }
LinkManager* linkManager () { return _linkManager; }
MissionCommands* missionCommands () { return _missionCommands; }
LinkManager* linkManager () { return _linkManager; }
MissionCommands* missionCommands () { return _missionCommands; }
MultiVehicleManager* multiVehicleManager () { return _multiVehicleManager; }
QGCMapEngineManager* mapEngineManager () { return _mapEngineManager; }
qreal zOrderTopMost () { return 1000; }
qreal zOrderWidgets () { return 100; }
......@@ -149,6 +151,7 @@ private:
LinkManager* _linkManager;
MissionCommands* _missionCommands;
MultiVehicleManager* _multiVehicleManager;
QGCMapEngineManager* _mapEngineManager;
bool _virtualTabletJoystick;
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief QGC Open Pilot Mapping Tools
* @author Gus Grubba <mavlink@grubba.com>
* Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
*/
#include <QRegExp>
#include <QNetworkReply>
#include <QEventLoop>
#include <QTimer>
#include "OpenPilotMaps.h"
namespace OpenPilot {
const QString ProviderStrings::kLevelsForSigPacSpainMap[] =
{ "0", "1", "2", "3", "4",
"MTNSIGPAC",
"MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000",
"MTN200", "MTN200", "MTN200",
"MTN25", "MTN25",
"ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS" };
ProviderStrings::ProviderStrings()
{
// Google version strings
VersionGoogleMap = "m@313";
VersionGoogleSatellite = "s@177";
VersionGoogleLabels = "h@313";
VersionGoogleTerrain = "t@132,r@313";
SecGoogleWord = "Galileo";
// Google (China) version strings
VersionGoogleMapChina = "m@132";
VersionGoogleSatelliteChina = "s@71";
VersionGoogleLabelsChina = "h@132";
VersionGoogleTerrainChina = "t@125,r@132";
// Google (Korea) version strings
VersionGoogleMapKorea = "kr1.12";
VersionGoogleSatelliteKorea = "66";
VersionGoogleLabelsKorea = "kr1t.12";
/// <summary>
/// Google Maps API generated using http://greatmaps.codeplex.com/
/// from http://code.google.com/intl/en-us/apis/maps/signup.html
/// </summary>
GoogleMapsAPIKey = "ABQIAAAAWaQgWiEBF3lW97ifKnAczhRAzBk5Igf8Z5n2W3hNnMT0j2TikxTLtVIGU7hCLLHMAuAMt-BO5UrEWA";
// Yahoo version strings
VersionYahooMap = "4.3";
VersionYahooSatellite = "1.9";
VersionYahooLabels = "4.3";
// BingMaps
VersionBingMaps = "563";
// YandexMap
VersionYandexMap = "2.16.0";
/// <summary>
/// Bing Maps Customer Identification, more info here
/// http://msdn.microsoft.com/en-us/library/bb924353.aspx
/// </summary>
BingMapsClientToken = "";
}
UrlFactory::UrlFactory(QNetworkAccessManager *network)
: _timeout(5 * 1000)
, _googleVersionRetrieved(false)
, _network(network)
, _googleReply(NULL)
{
}
UrlFactory::~UrlFactory()
{
if(_googleReply)
_googleReply->deleteLater();
}
QString UrlFactory::_tileXYToQuadKey(const int& tileX, const int& tileY, const int& levelOfDetail) const
{
QString quadKey;
for (int i = levelOfDetail; i > 0; i--) {
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0) {
digit++;
}
if ((tileY & mask) != 0) {
digit++;
digit++;
}
quadKey.append(digit);
}
return quadKey;
}
int UrlFactory::_getServerNum(const QPoint &pos, const int &max) const
{
return (pos.x() + 2 * pos.y()) % max;
}
void UrlFactory::_networkReplyError(QNetworkReply::NetworkError error)
{
qWarning() << "Could not connect to google maps. Error:" << error;
if(_googleReply)
{
_googleReply->deleteLater();
_googleReply = NULL;
}
}
void UrlFactory::_replyDestroyed()
{
_googleReply = NULL;
}
void UrlFactory::_googleVersionCompleted()
{
if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
qDebug() << "Error collecting Google maps version info";
return;
}
QString html = QString(_googleReply->readAll());
QRegExp reg("\"*http://mts0.google.com/vt/lyrs=m@(\\d*)", Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
VersionGoogleMap = QString("m@%1").arg(gc[1]);
VersionGoogleMapChina = VersionGoogleMap;
VersionGoogleMapKorea = VersionGoogleMap;
}
reg = QRegExp("\"*http://mts0.google.com/vt/lyrs=h@(\\d*)", Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
VersionGoogleLabels = QString("h@%1").arg(gc[1]);
VersionGoogleLabelsChina = VersionGoogleLabels;
VersionGoogleLabelsKorea = VersionGoogleLabels;
}
reg = QRegExp("\"*http://khms0.google.com/kh/v=(\\d*)", Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
VersionGoogleSatellite = "s@" + gc[1];
VersionGoogleSatelliteKorea = VersionGoogleSatellite;
VersionGoogleSatelliteChina = VersionGoogleSatellite;
}
reg = QRegExp("\"*http://mts0.google.com/vt/lyrs=t@(\\d*),r@(\\d*)", Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
VersionGoogleTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]);
VersionGoogleTerrainChina = VersionGoogleTerrain;
VersionGoogleTerrainChina = VersionGoogleTerrain;
}
_googleReply->deleteLater();
_googleReply = NULL;
}
void UrlFactory::_tryCorrectGoogleVersions()
{
QMutexLocker locker(&_googleVersionMutex);
if (_googleVersionRetrieved) {
return;
}
_googleVersionRetrieved = true;
if(_network)
{
QNetworkRequest qheader;
QNetworkProxy proxy = _network->proxy();
QNetworkProxy tProxy;
tProxy.setType(QNetworkProxy::NoProxy);
_network->setProxy(tProxy);
QString url = "http://maps.google.com/maps?output=classic";
qheader.setUrl(QUrl(url));
#if defined Q_OS_MAC
QByteArray userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0";
#elif defined Q_OS_WIN32
QByteArray userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7";
#else
QByteArray userAgent = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0";
#endif
qheader.setRawHeader("User-Agent", userAgent);
_googleReply = _network->get(qheader);
connect(_googleReply, &QNetworkReply::finished, this, &UrlFactory::_googleVersionCompleted);
connect(_googleReply, &QNetworkReply::destroyed, this, &UrlFactory::_replyDestroyed);
connect(_googleReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
this, &UrlFactory::_networkReplyError);
_network->setProxy(proxy);
}
}
QString UrlFactory::makeImageUrl(const MapType &type, const QPoint& pos, const int &zoom, const QString &language)
{
switch (type) {
case GoogleMap:
{
// http://mt1.google.com/vt/lyrs=m
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMap).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleSatellite:
{
// http://mt1.google.com/vt/lyrs=s
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatellite).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleLabels:
{
QString server = "mts";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabels).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleTerrain:
{
QString server = "mts";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrain).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleMapChina:
{
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://mt0.google.cn/vt/v=w2.101&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
return QString("http://%1%2.google.cn/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMapChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleSatelliteChina:
{
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://khm0.google.cn/kh/v=46&x=12&y=6&z=4&s=Ga
return QString("http://%1%2.google.cn/%3/lyrs=%4&gl=cn&x=%5%6&y=%7&z=%8&s=%9").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatelliteChina).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleLabelsChina:
{
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://mt0.google.cn/vt/v=w2t.110&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
return QString("http://%1%2.google.cn/%3/imgtp=png32&lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleTerrainChina:
{
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://mt0.google.cn/vt/v=w2p.110&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrainChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleMapKorea:
{
QString server = "mts";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://mts0.google.com/vt/lyrs=m@224000000&hl=ko&gl=KR&src=app&x=107&y=50&z=7&s=Gal
// http://mts0.google.com/mt/v=kr1.11&hl=ko&x=109&y=49&z=7&s=
QString ret = QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMapKorea).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
return ret;
}
break;
case GoogleSatelliteKorea:
{
QString server = "khms";
QString request = "kh";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://khm1.google.co.kr/kh/v=54&x=109&y=49&z=7&s=
return QString("http://%1%2.google.co.kr/%3/v=%4&x=%5%6&y=%7&z=%8&s=%9").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatelliteKorea).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case GoogleLabelsKorea:
{
QString server = "mts";
QString request = "mt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(pos, sec1, sec2);
_tryCorrectGoogleVersions();
// http://mts1.gmaptiles.co.kr/mt/v=kr1t.11&hl=lt&x=109&y=50&z=7&s=G
return QString("http://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsKorea).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
}
break;
case YahooMap:
{
return QString("http://maps%1.yimg.com/hx/tl?v=%2&.intl=%3&x=%4&y=%5&z=%6&r=1").arg(((_getServerNum(pos, 2)) + 1)).arg(VersionYahooMap).arg(language).arg(pos.x()).arg((((1 << zoom) >> 1) - 1 - pos.y())).arg((zoom + 1));
}
case YahooSatellite:
{
return QString("http://maps%1.yimg.com/ae/ximg?v=%2&t=a&s=256&.intl=%3&x=%4&y=%5&z=%6&r=1").arg("3").arg(VersionYahooSatellite).arg(language).arg(pos.x()).arg(((1 << zoom) >> 1) - 1 - pos.y()).arg(zoom + 1);
}
break;
case YahooLabels:
{
return QString("http://maps%1.yimg.com/hx/tl?v=%2&t=h&.intl=%3&x=%4&y=%5&z=%6&r=1").arg("1").arg(VersionYahooLabels).arg(language).arg(pos.x()).arg(((1 << zoom) >> 1) - 1 - pos.y()).arg(zoom + 1);
}
break;
case OpenStreetMap:
{
char letter = "abc"[_getServerNum(pos, 3)];
return QString("http://%1.tile.openstreetmap.org/%2/%3/%4.png").arg(letter).arg(zoom).arg(pos.x()).arg(pos.y());
}
break;
case OpenStreetOsm:
{
char letter = "abc"[_getServerNum(pos, 3)];
return QString("http://%1.tah.openstreetmap.org/Tiles/tile/%2/%3/%4.png").arg(letter).arg(zoom).arg(pos.x()).arg(pos.y());
}
break;
case OpenStreetMapSurfer:
{
// http://tiles1.mapsurfer.net/tms_r.ashx?x=37378&y=20826&z=16
return QString("http://tiles1.mapsurfer.net/tms_r.ashx?x=%1&y=%2&z=%3").arg(pos.x()).arg(pos.y()).arg(zoom);
}
break;
case OpenStreetMapSurferTerrain:
{
// http://tiles2.mapsurfer.net/tms_t.ashx?x=9346&y=5209&z=14
return QString("http://tiles2.mapsurfer.net/tms_t.ashx?x=%1&y=%2&z=%3").arg(pos.x()).arg(pos.y()).arg(zoom);
}
break;
case BingMap:
{
QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
}
break;
case BingSatellite:
{
QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
}
break;
case BingHybrid:
{
QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
}
case ArcGIS_Map:
{
// http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/tile/0/0/0.jpg
return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
}
break;
case ArcGIS_Satellite:
{
// http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer/tile/1/0/1.jpg
return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
}
break;
case ArcGIS_ShadedRelief:
{
// http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_ShadedRelief_World_2D/MapServer/tile/1/0/1.jpg
return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_ShadedRelief_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
}
break;
case ArcGIS_Terrain:
{
// http://server.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer/tile/4/3/15
return QString("http://server.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
}
break;
case ArcGIS_MapsLT_OrtoFoto:
{
// http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L02/R0000001b/C00000028.jpg
// http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/0/9/13
// return string.Format("http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L{0:00}/R{1:x8}/C{2:x8}.jpg", zoom, pos.y(), pos.x());
// http://dc1.maps.lt/cache/mapslt_ortofoto_512/map/_alllayers/L03/R0000001c/C00000029.jpg
// return string.Format("http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/{0}/{1}/{2}", zoom, pos.y(), pos.x());
// http://dc1.maps.lt/cache/mapslt_ortofoto_512/map/_alllayers/L03/R0000001d/C0000002a.jpg
// TODO verificar
return QString("http://dc1.maps.lt/cache/mapslt_ortofoto/map/_alllayers/L%1/R%2/C%3.jpg").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
}
break;
case ArcGIS_MapsLT_Map:
{
// http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L02/R0000001b/C00000028.jpg
// http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/0/9/13
// return string.Format("http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L{0:00}/R{1:x8}/C{2:x8}.jpg", zoom, pos.y(), pos.x());
// http://arcgis.maps.lt/ArcGIS/rest/services/mapslt/MapServer/tile/7/1162/1684.png
// http://dc1.maps.lt/cache/mapslt_512/map/_alllayers/L03/R0000001b/C00000029.png
// TODO verificar
// http://dc1.maps.lt/cache/mapslt/map/_alllayers/L02/R0000001c/C00000029.png
return QString("http://dc1.maps.lt/cache/mapslt/map/_alllayers/L%1/R%2/C%3.png").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
}
break;
case ArcGIS_MapsLT_Map_Labels:
{
// http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto_overlay/MapServer/tile/0/9/13
// return string.Format("http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto_overlay/MapServer/tile/{0}/{1}/{2}", zoom, pos.y(), pos.x());
// http://dc1.maps.lt/cache/mapslt_ortofoto_overlay_512/map/_alllayers/L03/R0000001d/C00000029.png
// TODO verificar
return QString("http://dc1.maps.lt/cache/mapslt_ortofoto_overlay/map/_alllayers/L%1/R%2/C%3.png").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
}
break;
case PergoTurkeyMap:
{
// http://{domain}/{layerName}/{zoomLevel}/{first3LetterOfTileX}/{second3LetterOfTileX}/{third3LetterOfTileX}/{first3LetterOfTileY}/{second3LetterOfTileY}/{third3LetterOfTileXY}.png
// http://map3.pergo.com.tr/tile/00/000/000/001/000/000/000.png
// That means: Zoom Level: 0 TileX: 1 TileY: 0
// http://domain/tile/14/000/019/371/000/011/825.png
// That means: Zoom Level: 14 TileX: 19371 TileY:11825
// string x = pos.x().ToString("000000000").Insert(3, "/").Insert(7, "/"); // - 000/000/001
// string y = pos.y().ToString("000000000").Insert(3, "/").Insert(7, "/"); // - 000/000/000
QString x = QString("%1").arg(QString::number(pos.x()), 9, (QChar)'0');
x.insert(3, "/").insert(7, "/");
QString y = QString("%1").arg(QString::number(pos.y()), 9, (QChar)'0');
y.insert(3, "/").insert(7, "/");
// "http://map03.pergo.com.tr/tile/2/000/000/003/000/000/002.png"
return QString("http://map%1.pergo.com.tr/tile/%2/%3/%4.png").arg(_getServerNum(pos, 4)).arg(zoom, 2, 10, (QChar)'0').arg(x).arg(y);
}
break;
case SigPacSpainMap:
{
return QString("http://sigpac.mapa.es/kmlserver/raster/%1@3785/%2.%3.%4.img").arg(kLevelsForSigPacSpainMap[zoom]).arg(zoom).arg(pos.x()).arg((2 << (zoom - 1)) - pos.y() - 1);
}
break;
case YandexMapRu:
{
QString server = "vec";
// http://vec01.maps.yandex.ru/tiles?l=map&v=2.10.2&x=1494&y=650&z=11
return QString("http://%1").arg(server) + QString("0%2.maps.yandex.ru/tiles?l=map&v=%3&x=%4&y=%5&z=%6").arg(_getServerNum(pos, 4) + 1).arg(VersionYandexMap).arg(pos.x()).arg(pos.y()).arg(zoom);
}
break;
default:
qWarning("Unknown map id %d\n", type);
break;
}
return QString::null;
}
void UrlFactory::_getSecGoogleWords(const QPoint &pos, QString &sec1, QString &sec2)
{
sec1 = ""; // after &x=...
sec2 = ""; // after &zoom=...
int seclen = ((pos.x() * 3) + pos.y()) % 8;
sec2 = SecGoogleWord.left(seclen);
if (pos.y() >= 10000 && pos.y() < 100000) {
sec1 = "&s=";
}
}
}
......@@ -17,22 +17,29 @@ contains(QT_VERSION, 5.5.1) {
}
HEADERS += \
$$PWD/qgeoserviceproviderpluginqgc.h \
$$PWD/qgeotiledmappingmanagerengineqgc.h \
$$PWD/qgeotilefetcherqgc.h \
$$PWD/qgeomapreplyqgc.h \
$$PWD/qgeocodingmanagerengineqgc.h \
$$PWD/qgeocodereplyqgc.h \
$$PWD/OpenPilotMaps.h
$$PWD/QGCMapEngine.h \
$$PWD/QGCMapEngineData.h \
$$PWD/QGCMapTileSet.h \
$$PWD/QGCMapUrlEngine.h \
$$PWD/QGCTileCacheWorker.h \
$$PWD/QGeoCodeReplyQGC.h \
$$PWD/QGeoCodingManagerEngineQGC.h \
$$PWD/QGeoMapReplyQGC.h \
$$PWD/QGeoServiceProviderPluginQGC.h \
$$PWD/QGeoTileFetcherQGC.h \
$$PWD/QGeoTiledMappingManagerEngineQGC.h \
SOURCES += \
$$PWD/qgeoserviceproviderpluginqgc.cpp \
$$PWD/qgeotiledmappingmanagerengineqgc.cpp \
$$PWD/qgeotilefetcherqgc.cpp \
$$PWD/qgeomapreplyqgc.cpp \
$$PWD/qgeocodingmanagerengineqgc.cpp \
$$PWD/qgeocodereplyqgc.cpp \
$$PWD/OpenPilotMaps.cc
$$PWD/QGCMapEngine.cpp \
$$PWD/QGCMapTileSet.cpp \
$$PWD/QGCMapUrlEngine.cpp \
$$PWD/QGCTileCacheWorker.cpp \
$$PWD/QGeoCodeReplyQGC.cpp \
$$PWD/QGeoCodingManagerEngineQGC.cpp \
$$PWD/QGeoMapReplyQGC.cpp \
$$PWD/QGeoServiceProviderPluginQGC.cpp \
$$PWD/QGeoTileFetcherQGC.cpp \
$$PWD/QGeoTiledMappingManagerEngineQGC.cpp \
OTHER_FILES += \
$$PWD/qgc_maps_plugin.json
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Cache
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#include <math.h>
#include <QSettings>
#include <QStandardPaths>
#include <QDir>
#include "QGCMapEngine.h"
#include "QGCMapTileSet.h"
Q_DECLARE_METATYPE(QGCMapTask::TaskType)
Q_DECLARE_METATYPE(QGCTile)
Q_DECLARE_METATYPE(QList<QGCTile*>)
static const char* kDbFileName = "qgcMapCache.db";
static QLocale kLocale;
struct stQGeoTileCacheQGCMapTypes {
const char* name;
UrlFactory::MapType type;
};
//-- IMPORTANT
// Changes here must reflect those in QGeoTiledMappingManagerEngineQGC.cpp
stQGeoTileCacheQGCMapTypes kMapTypes[] = {
{"Google Street Map", UrlFactory::GoogleMap},
{"Google Satellite Map", UrlFactory::GoogleSatellite},
{"Google Terrain Map", UrlFactory::GoogleTerrain},
{"Bing Street Map", UrlFactory::BingMap},
{"Bing Satellite Map", UrlFactory::BingSatellite},
{"Bing Hybrid Map", UrlFactory::BingHybrid},
{"MapQuest Street Map", UrlFactory::MapQuestMap},
{"MapQuest Satellite Map", UrlFactory::MapQuestSat}
/*
{"Open Street Map", UrlFactory::OpenStreetMap}
*/
};
#define NUM_MAPS (sizeof(kMapTypes) / sizeof(stQGeoTileCacheQGCMapTypes))
stQGeoTileCacheQGCMapTypes kMapBoxTypes[] = {
{"MapBox Street Map", UrlFactory::MapBoxStreets},
{"MapBox Satellite Map", UrlFactory::MapBoxSatellite},
{"MapBox High Contrast Map",UrlFactory::MapBoxHighContrast},
{"MapBox Light Map", UrlFactory::MapBoxLight},
{"MapBox Dark Map", UrlFactory::MapBoxDark},
{"MapBox Hybrid Map", UrlFactory::MapBoxHybrid},
{"MapBox Wheat Paste Map", UrlFactory::MapBoxWheatPaste},
{"MapBox Streets Basic Map",UrlFactory::MapBoxStreetsBasic},
{"MapBox Comic Map", UrlFactory::MapBoxComic},
{"MapBox Outdoors Map", UrlFactory::MapBoxOutdoors},
{"MapBox Run, Byke and Hike Map", UrlFactory::MapBoxRunBikeHike},
{"MapBox Pencil Map", UrlFactory::MapBoxPencil},
{"MapBox Pirates Map", UrlFactory::MapBoxPirates},
{"MapBox Emerald Map", UrlFactory::MapBoxEmerald}
};
#define NUM_MAPBOXMAPS (sizeof(kMapBoxTypes) / sizeof(stQGeoTileCacheQGCMapTypes))
static const char* kMapBoxTokenKey = "MapBoxToken";
static const char* kMaxDiskCacheKey = "MaxDiskCache";
static const char* kMaxMemCacheKey = "MaxMemoryCache";
//-----------------------------------------------------------------------------
// Singleton
static QGCMapEngine* kMapEngine = NULL;
QGCMapEngine*
getQGCMapEngine()
{
if(!kMapEngine)
kMapEngine = new QGCMapEngine();
return kMapEngine;
}
//-----------------------------------------------------------------------------
void
destroyMapEngine()
{
if(kMapEngine) {
delete kMapEngine;
kMapEngine = NULL;
}
}
//-----------------------------------------------------------------------------
QGCMapEngine::QGCMapEngine()
: _urlFactory(new UrlFactory::UrlFactory())
#ifdef WE_ARE_KOSHER
//-- TODO: Get proper version
#if defined Q_OS_MAC
, _userAgent("QGroundControl (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/2.9.0")
#elif defined Q_OS_WIN32
, _userAgent("QGroundControl (Windows; Windows NT 6.0) (KHTML, like Gecko) Version/2.9.0")
#else
, _userAgent("QGroundControl (X11; Ubuntu; Linux x86_64) (KHTML, like Gecko) Version/2.9.0")
#endif
#else
#if defined Q_OS_MAC
, _userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:25.0) Gecko/20100101 Firefox/25.0")
#elif defined Q_OS_WIN32
, _userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0")
#else
, _userAgent("Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0")
#endif
#endif
, _maxDiskCache(0)
, _maxMemCache(0)
, _prunning(false)
{
qRegisterMetaType<QGCMapTask::TaskType>();
qRegisterMetaType<QGCTile>();
qRegisterMetaType<QList<QGCTile*>>();
connect(&_worker, &QGCCacheWorker::updateTotals, this, &QGCMapEngine::_updateTotals);
}
//-----------------------------------------------------------------------------
QGCMapEngine::~QGCMapEngine()
{
_worker.quit();
_worker.wait();
if(_urlFactory)
delete _urlFactory;
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::init()
{
#ifdef __mobile__
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1String("/QGCMapCache55");
#else
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache55");
#endif
if(!QDir::root().mkpath(cacheDir)) {
qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/");
if(!QDir::root().mkpath(cacheDir)) {
qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
cacheDir.clear();
}
}
_cachePath = cacheDir;
if(!_cachePath.isEmpty()) {
_cacheFile = kDbFileName;
_worker.setDatabaseFile(_cachePath + "/" + _cacheFile);
} else {
qCritical() << "Could not find suitable map cache directory.";
}
QGCMapTask* task = new QGCMapTask(QGCMapTask::taskInit);
_worker.enqueueTask(task);
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::addTask(QGCMapTask* task)
{
_worker.enqueueTask(task);
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::cacheTile(UrlFactory::MapType type, int x, int y, int z, const QByteArray& image, const QString &format, qulonglong set)
{
QString hash = getTileHash(type, x, y, z);
cacheTile(type, hash, image, format, set);
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::cacheTile(UrlFactory::MapType type, const QString& hash, const QByteArray& image, const QString& format, qulonglong set)
{
QGCSaveTileTask* task = new QGCSaveTileTask(new QGCCacheTile(hash, image, format, type, set));
_worker.enqueueTask(task);
}
//-----------------------------------------------------------------------------
QString
QGCMapEngine::getTileHash(UrlFactory::MapType type, int x, int y, int z)
{
char hashSource[64];
snprintf(hashSource, sizeof(hashSource), "%04d%08d%08d%03d", (int)type, x, y, z);
return QString(hashSource);
}
//-----------------------------------------------------------------------------
UrlFactory::MapType
QGCMapEngine::hashToType(const QString& hash)
{
QString type = hash.mid(0,4);
return (UrlFactory::MapType)type.toInt();
}
//-----------------------------------------------------------------------------
QGCFetchTileTask*
QGCMapEngine::createFetchTileTask(UrlFactory::MapType type, int x, int y, int z)
{
QString hash = getTileHash(type, x, y, z);
QGCFetchTileTask* task = new QGCFetchTileTask(hash);
return task;
}
//-----------------------------------------------------------------------------
QGCTileSet
QGCMapEngine::getTileCount(int zoom, double topleftLon, double topleftLat, double bottomRightLon, double bottomRightLat, UrlFactory::MapType mapType)
{
if(zoom < 1) zoom = 1;
if(zoom > 18) zoom = 18;
QGCTileSet set;
set.tileX0 = long2tileX(topleftLon, zoom);
set.tileY0 = lat2tileY(topleftLat, zoom);
set.tileX1 = long2tileX(bottomRightLon, zoom);
set.tileY1 = lat2tileY(bottomRightLat, zoom);
set.tileCount = (quint64)((quint64)set.tileX1 - (quint64)set.tileX0 + 1) * (quint64)((quint64)set.tileY1 - (quint64)set.tileY0 + 1);
set.tileSize = UrlFactory::averageSizeForType(mapType) * set.tileCount;
return set;
}
//-----------------------------------------------------------------------------
int
QGCMapEngine::long2tileX(double lon, int z)
{
return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
}
//-----------------------------------------------------------------------------
int
QGCMapEngine::lat2tileY(double lat, int z)
{
return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 / cos(lat * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, z)));
}
//-----------------------------------------------------------------------------
UrlFactory::MapType
QGCMapEngine::getTypeFromName(const QString& name)
{
size_t i;
for(i = 0; i < NUM_MAPS; i++) {
if(name.compare(kMapTypes[i].name, Qt::CaseInsensitive) == 0)
return kMapTypes[i].type;
}
for(i = 0; i < NUM_MAPBOXMAPS; i++) {
if(name.compare(kMapBoxTypes[i].name, Qt::CaseInsensitive) == 0)
return kMapBoxTypes[i].type;
}
return UrlFactory::Invalid;
}
//-----------------------------------------------------------------------------
QStringList
QGCMapEngine::getMapNameList()
{
QStringList mapList;
for(size_t i = 0; i < NUM_MAPS; i++) {
mapList << kMapTypes[i].name;
}
if(!getMapBoxToken().isEmpty()) {
for(size_t i = 0; i < NUM_MAPBOXMAPS; i++) {
mapList << kMapBoxTypes[i].name;
}
}
return mapList;
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::setMapBoxToken(const QString& token)
{
QSettings settings;
settings.setValue(kMapBoxTokenKey, token);
_mapBoxToken = token;
}
//-----------------------------------------------------------------------------
QString
QGCMapEngine::getMapBoxToken()
{
if(_mapBoxToken.isEmpty()) {
QSettings settings;
_mapBoxToken = settings.value(kMapBoxTokenKey).toString();
}
return _mapBoxToken;
}
//-----------------------------------------------------------------------------
quint32
QGCMapEngine::getMaxDiskCache()
{
if(!_maxDiskCache) {
QSettings settings;
_maxDiskCache = settings.value(kMaxDiskCacheKey, 1024).toUInt();
}
return _maxDiskCache;
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::setMaxDiskCache(quint32 size)
{
QSettings settings;
settings.setValue(kMaxDiskCacheKey, size);
_maxDiskCache = size;
}
//-----------------------------------------------------------------------------
quint32
QGCMapEngine::getMaxMemCache()
{
if(!_maxMemCache) {
QSettings settings;
#ifdef __mobile__
_maxMemCache = settings.value(kMaxMemCacheKey, 16).toUInt();
#else
_maxMemCache = settings.value(kMaxMemCacheKey, 128).toUInt();
#endif
}
return _maxMemCache;
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::setMaxMemCache(quint32 size)
{
QSettings settings;
settings.setValue(kMaxMemCacheKey, size);
_maxMemCache = size;
}
//-----------------------------------------------------------------------------
QString
QGCMapEngine::bigSizeToString(quint64 size)
{
if(size < 1024)
return kLocale.toString(size);
else if(size < 1024 * 1024)
return kLocale.toString((double)size / 1024.0, 'f', 1) + "kB";
else if(size < 1024 * 1024 * 1024)
return kLocale.toString((double)size / (1024.0 * 1024.0), 'f', 1) + "MB";
else if(size < 1024.0 * 1024.0 * 1024.0 * 1024.0)
return kLocale.toString((double)size / (1024.0 * 1024.0 * 1024.0), 'f', 1) + "GB";
else
return kLocale.toString((double)size / (1024.0 * 1024.0 * 1024.0 * 1024), 'f', 1) + "TB";
}
//-----------------------------------------------------------------------------
QString
QGCMapEngine::numberToString(quint32 number)
{
return kLocale.toString(number);
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::_updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
{
emit updateTotals(totaltiles, totalsize, defaulttiles, defaultsize);
quint64 maxSize = getMaxDiskCache() * 1024 * 1024;
if(!_prunning && defaultsize > maxSize) {
//-- Prune Disk Cache
_prunning = true;
QGCPruneCacheTask* task = new QGCPruneCacheTask(defaultsize - maxSize);
connect(task, &QGCPruneCacheTask::pruned, this, &QGCMapEngine::_pruned);
getQGCMapEngine()->addTask(task);
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngine::_pruned()
{
_prunning = false;
}
//-----------------------------------------------------------------------------
int
QGCMapEngine::concurrentDownloads(UrlFactory::MapType type)
{
switch(type) {
case UrlFactory::GoogleMap:
case UrlFactory::GoogleSatellite:
case UrlFactory::GoogleTerrain:
case UrlFactory::BingMap:
case UrlFactory::BingSatellite:
case UrlFactory::BingHybrid:
return 12;
case UrlFactory::MapQuestMap:
case UrlFactory::MapQuestSat:
return 8;
default:
break;
}
return 6;
}
//-----------------------------------------------------------------------------
QGCCreateTileSetTask::~QGCCreateTileSetTask()
{
//-- If not sent out, delete it
if(!_saved && _tileSet)
delete _tileSet;
}
// Resolution math: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Cache
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#ifndef QGC_MAP_ENGINE_H
#define QGC_MAP_ENGINE_H
#include <QString>
#include "QGCMapUrlEngine.h"
#include "QGCMapEngineData.h"
#include "QGCTileCacheWorker.h"
//-----------------------------------------------------------------------------
class QGCTileSet
{
public:
QGCTileSet()
{
clear();
}
QGCTileSet& operator += (QGCTileSet& other)
{
tileX0 += other.tileX0;
tileX1 += other.tileX1;
tileY0 += other.tileY0;
tileY1 += other.tileY1;
tileCount += other.tileCount;
tileSize += other.tileSize;
return *this;
}
void clear()
{
tileX0 = 0;
tileX1 = 0;
tileY0 = 0;
tileY1 = 0;
tileCount = 0;
tileSize = 0;
}
int tileX0;
int tileX1;
int tileY0;
int tileY1;
quint64 tileCount;
quint64 tileSize;
};
//-----------------------------------------------------------------------------
class QGCMapEngine : public QObject
{
Q_OBJECT
public:
QGCMapEngine ();
~QGCMapEngine ();
void init ();
void addTask (QGCMapTask *task);
void cacheTile (UrlFactory::MapType type, int x, int y, int z, const QByteArray& image, const QString& format, qulonglong set = UINT64_MAX);
void cacheTile (UrlFactory::MapType type, const QString& hash, const QByteArray& image, const QString& format, qulonglong set = UINT64_MAX);
QGCFetchTileTask* createFetchTileTask (UrlFactory::MapType type, int x, int y, int z);
QStringList getMapNameList ();
const QString userAgent () { return _userAgent; }
void setUserAgent (const QString& ua) { _userAgent = ua; }
UrlFactory::MapType hashToType (const QString& hash);
QString getMapBoxToken ();
void setMapBoxToken (const QString& token);
quint32 getMaxDiskCache ();
void setMaxDiskCache (quint32 size);
quint32 getMaxMemCache ();
void setMaxMemCache (quint32 size);
const QString getCachePath () { return _cachePath; }
const QString getCacheFilename () { return _cacheFile; }
UrlFactory* urlFactory () { return _urlFactory; }
//-- Tile Math
static QGCTileSet getTileCount (int zoom, double topleftLon, double topleftLat, double bottomRightLon, double bottomRightLat, UrlFactory::MapType mapType);
static int long2tileX (double lon, int z);
static int lat2tileY (double lat, int z);
static QString getTileHash (UrlFactory::MapType type, int x, int y, int z);
static UrlFactory::MapType getTypeFromName (const QString &name);
static QString bigSizeToString (quint64 size);
static QString numberToString (quint32 number);
static int concurrentDownloads (UrlFactory::MapType type);
private slots:
void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
void _pruned ();
signals:
void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
private:
QGCCacheWorker _worker;
QString _cachePath;
QString _cacheFile;
QString _mapBoxToken;
UrlFactory* _urlFactory;
QString _userAgent;
quint32 _maxDiskCache;
quint32 _maxMemCache;
bool _prunning;
};
extern QGCMapEngine* getQGCMapEngine();
extern void destroyMapEngine();
#endif // QGC_MAP_ENGINE_H
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Cache Data
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#ifndef QGC_MAP_ENGINE_DATA_H
#define QGC_MAP_ENGINE_DATA_H
#include <QObject>
#include <QString>
#include <QHash>
#include <QDateTime>
#include "QGCMapUrlEngine.h"
class QGCCachedTileSet;
//-----------------------------------------------------------------------------
class QGCTile : public QObject
{
Q_OBJECT
public:
QGCTile()
: _x(0)
, _y(0)
, _z(0)
, _set(UINT64_MAX)
, _type(UrlFactory::Invalid)
{
}
QGCTile(const QGCTile& other)
: _x(other.x())
, _y(other.y())
, _z(other.z())
, _set(other.set())
, _hash(other.hash())
, _type(other.type())
{
}
enum TyleState {
StatePending = 0,
StateDownloading,
StateError,
StateComplete
};
int x () const { return _x; }
int y () const { return _y; }
int z () const { return _z; }
qulonglong set () const { return _set; }
const QString hash () const { return _hash; }
UrlFactory::MapType type () const { return _type; }
void setX (int x) { _x = x; }
void setY (int y) { _y = y; }
void setZ (int z) { _z = z; }
void setTileSet (qulonglong set) { _set = set; }
void setHash (const QString& hash) { _hash = hash; }
void setType (UrlFactory::MapType type) { _type = type; }
private:
int _x;
int _y;
int _z;
qulonglong _set;
QString _hash;
UrlFactory::MapType _type;
};
//-----------------------------------------------------------------------------
class QGCCacheTile : public QObject
{
Q_OBJECT
public:
QGCCacheTile (const QString hash, const QByteArray img, const QString format, UrlFactory::MapType type, qulonglong set = UINT64_MAX)
: _set(set)
, _hash(hash)
, _img(img)
, _format(format)
, _type(type)
{
}
QGCCacheTile (const QString hash, qulonglong set)
: _set(set)
, _hash(hash)
{
}
qulonglong set () { return _set; }
QString hash () { return _hash; }
QByteArray img () { return _img; }
QString format () { return _format;}
UrlFactory::MapType type () { return _type; }
private:
qulonglong _set;
QString _hash;
QByteArray _img;
QString _format;
UrlFactory::MapType _type;
};
//-----------------------------------------------------------------------------
class QGCMapTask : public QObject
{
Q_OBJECT
public:
enum TaskType {
taskInit,
taskCacheTile,
taskFetchTile,
taskFetchTileSets,
taskCreateTileSet,
taskGetTileDownloadList,
taskUpdateTileDownloadState,
taskDeleteTileSet,
taskPruneCache,
taskReset
};
QGCMapTask(TaskType type)
: _type(type)
{}
virtual ~QGCMapTask()
{}
virtual TaskType type () { return _type; }
void setError(QString errorString)
{
emit error(_type, errorString);
}
signals:
void error (QGCMapTask::TaskType type, QString errorString);
private:
TaskType _type;
};
//-----------------------------------------------------------------------------
class QGCFetchTileSetTask : public QGCMapTask
{
Q_OBJECT
public:
QGCFetchTileSetTask()
: QGCMapTask(QGCMapTask::taskFetchTileSets)
{}
void setTileSetFetched(QGCCachedTileSet* tileSet)
{
emit tileSetFetched(tileSet);
}
signals:
void tileSetFetched (QGCCachedTileSet* tileSet);
};
//-----------------------------------------------------------------------------
class QGCCreateTileSetTask : public QGCMapTask
{
Q_OBJECT
public:
QGCCreateTileSetTask(QGCCachedTileSet* tileSet)
: QGCMapTask(QGCMapTask::taskCreateTileSet)
, _tileSet(tileSet)
, _saved(false)
{}
~QGCCreateTileSetTask();
QGCCachedTileSet* tileSet () { return _tileSet; }
void setTileSetSaved()
{
//-- Flag as saved. Signalee wll maintain it.
_saved = true;
emit tileSetSaved(_tileSet);
}
signals:
void tileSetSaved (QGCCachedTileSet* tileSet);
private:
QGCCachedTileSet* _tileSet;
bool _saved;
};
//-----------------------------------------------------------------------------
class QGCFetchTileTask : public QGCMapTask
{
Q_OBJECT
public:
QGCFetchTileTask(const QString hash)
: QGCMapTask(QGCMapTask::taskFetchTile)
, _hash(hash)
{}
~QGCFetchTileTask()
{
}
void setTileFetched(QGCCacheTile* tile)
{
emit tileFetched(tile);
}
QString hash() { return _hash; }
signals:
void tileFetched (QGCCacheTile* tile);
private:
QString _hash;
};
//-----------------------------------------------------------------------------
class QGCSaveTileTask : public QGCMapTask
{
Q_OBJECT
public:
QGCSaveTileTask(QGCCacheTile* tile)
: QGCMapTask(QGCMapTask::taskCacheTile)
, _tile(tile)
{}
~QGCSaveTileTask()
{
if(_tile)
delete _tile;
}
QGCCacheTile* tile() { return _tile; }
private:
QGCCacheTile* _tile;
};
//-----------------------------------------------------------------------------
class QGCGetTileDownloadListTask : public QGCMapTask
{
Q_OBJECT
public:
QGCGetTileDownloadListTask(qulonglong setID, int count)
: QGCMapTask(QGCMapTask::taskGetTileDownloadList)
, _setID(setID)
, _count(count)
{}
qulonglong setID() { return _setID; }
int count() { return _count; }
void setTileListFetched(QList<QGCTile*> tiles)
{
emit tileListFetched(tiles);
}
signals:
void tileListFetched (QList<QGCTile*> tiles);
private:
qulonglong _setID;
int _count;
};
//-----------------------------------------------------------------------------
class QGCUpdateTileDownloadStateTask : public QGCMapTask
{
Q_OBJECT
public:
QGCUpdateTileDownloadStateTask(qulonglong setID, QGCTile::TyleState state, const QString& hash)
: QGCMapTask(QGCMapTask::taskUpdateTileDownloadState)
, _setID(setID)
, _state(state)
, _hash(hash)
{}
QString hash () { return _hash; }
qulonglong setID () { return _setID; }
QGCTile::TyleState state () { return _state; }
private:
qulonglong _setID;
QGCTile::TyleState _state;
QString _hash;
};
//-----------------------------------------------------------------------------
class QGCDeleteTileSetTask : public QGCMapTask
{
Q_OBJECT
public:
QGCDeleteTileSetTask(qulonglong setID)
: QGCMapTask(QGCMapTask::taskDeleteTileSet)
, _setID(setID)
{}
qulonglong setID() { return _setID; }
void setTileSetDeleted()
{
emit tileSetDeleted(_setID);
}
signals:
void tileSetDeleted(qulonglong setID);
private:
qulonglong _setID;
};
//-----------------------------------------------------------------------------
class QGCPruneCacheTask : public QGCMapTask
{
Q_OBJECT
public:
QGCPruneCacheTask(quint64 amount)
: QGCMapTask(QGCMapTask::taskPruneCache)
, _amount(amount)
{}
quint64 amount() { return _amount; }
void setPruned()
{
emit pruned();
}
signals:
void pruned();
private:
quint64 _amount;
};
//-----------------------------------------------------------------------------
class QGCResetTask : public QGCMapTask
{
Q_OBJECT
public:
QGCResetTask()
: QGCMapTask(QGCMapTask::taskReset)
{}
void setResetCompleted()
{
emit resetCompleted();
}
signals:
void resetCompleted();
};
#endif // QGC_MAP_ENGINE_DATA_H
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Set
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#include <math.h>
#include <QSettings>
#include "QGCMapEngine.h"
#include "QGCMapTileSet.h"
#include "QGCMapEngineManager.h"
QGC_LOGGING_CATEGORY(QGCCachedTileSetLog, "QGCCachedTileSetLog")
#define TILE_BATCH_SIZE 256
//-----------------------------------------------------------------------------
QGCCachedTileSet::QGCCachedTileSet(const QString& name, const QString& description)
: _name(name)
, _description(description)
, _topleftLat(0.0)
, _topleftLon(0.0)
, _bottomRightLat(0.0)
, _bottomRightLon(0.0)
, _numTiles(0)
, _tilesSize(0)
, _savedTiles(0)
, _savedSize(0)
, _minZoom(3)
, _maxZoom(3)
, _defaultSet(false)
, _deleting(false)
, _downloading(false)
, _id(0)
, _type(UrlFactory::Invalid)
, _networkManager(NULL)
, _errorCount(0)
, _noMoreTiles(false)
, _batchRequested(false)
, _manager(NULL)
{
}
//-----------------------------------------------------------------------------
QGCCachedTileSet::~QGCCachedTileSet()
{
if(_networkManager) {
delete _networkManager;
}
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::errorCountStr()
{
return QGCMapEngine::numberToString(_errorCount);
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::numTilesStr()
{
return QGCMapEngine::numberToString(_numTiles);
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::tilesSizeStr()
{
return QGCMapEngine::bigSizeToString(_tilesSize);
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::savedTilesStr()
{
return QGCMapEngine::numberToString(_savedTiles);
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::savedSizeStr()
{
return QGCMapEngine::bigSizeToString(_savedSize);
}
//-----------------------------------------------------------------------------
QString
QGCCachedTileSet::downloadStatus()
{
//-- Default size has no estimage. If complete, show only total size as well.
if(_defaultSet || _numTiles == _savedTiles) {
return savedSizeStr();
} else {
return savedSizeStr() + " / " + tilesSizeStr();
}
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::createDownloadTask()
{
if(!_downloading) {
_errorCount = 0;
_downloading = true;
_noMoreTiles = false;
emit downloadingChanged();
emit errorCountChanged();
}
QGCGetTileDownloadListTask* task = new QGCGetTileDownloadListTask(_id, TILE_BATCH_SIZE);
connect(task, &QGCGetTileDownloadListTask::tileListFetched, this, &QGCCachedTileSet::_tileListFetched);
if(_manager)
connect(task, &QGCMapTask::error, _manager, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
emit numTilesChanged();
emit tilesSizeChanged();
_batchRequested = true;
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::resumeDownloadTask()
{
//-- Reset and download error flag (for all tiles)
QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StatePending, "*");
getQGCMapEngine()->addTask(task);
//-- Start download
createDownloadTask();
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::cancelDownloadTask()
{
if(_downloading) {
_downloading = false;
emit downloadingChanged();
}
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::_tileListFetched(QList<QGCTile *> tiles)
{
_batchRequested = false;
//-- Done?
if(tiles.size() < TILE_BATCH_SIZE) {
_noMoreTiles = true;
}
if(!tiles.size()) {
return;
}
//-- If this is the first time, create Network Manager
if (!_networkManager) {
_networkManager = new QNetworkAccessManager(this);
}
//-- Add tiles to the list
_tilesToDownload += tiles;
//-- Kick downloads
_prepareDownload();
}
//-----------------------------------------------------------------------------
void QGCCachedTileSet::_prepareDownload()
{
if(!_tilesToDownload.count()) {
//-- Are we done?
if(_noMoreTiles) {
if(!_errorCount) {
_numTiles = _savedTiles;
_tilesSize = _savedSize;
}
emit numTilesChanged();
emit tilesSizeChanged();
emit savedSizeChanged();
emit savedTilesChanged();
_downloading = false;
emit downloadingChanged();
emit completeChanged();
} else {
if(!_batchRequested)
createDownloadTask();
}
return;
}
//-- Prepare queue (QNetworkAccessManager has a limit for concurrent downloads)
for(int i = _replies.count(); i < QGCMapEngine::concurrentDownloads(_type); i++) {
if(_tilesToDownload.count()) {
QGCTile* tile = _tilesToDownload.first();
_tilesToDownload.removeFirst();
QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(tile->type(), tile->x(), tile->y(), tile->z(), _networkManager);
request.setAttribute(QNetworkRequest::User, tile->hash());
QNetworkReply* reply = _networkManager->get(request);
reply->setParent(0);
connect(reply, &QNetworkReply::finished, this, &QGCCachedTileSet::_networkReplyFinished);
connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &QGCCachedTileSet::_networkReplyError);
_replies.insert(tile->hash(), reply);
tile->deleteLater();
//-- Refill queue if running low
if(!_batchRequested && !_noMoreTiles && _tilesToDownload.count() < (QGCMapEngine::concurrentDownloads(_type) * 10)) {
//-- Request new batch of tiles
createDownloadTask();
}
}
}
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::_networkReplyFinished()
{
//-- Figure out which reply this is
QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
if(!reply) {
qWarning() << "QGCMapEngineManager::networkReplyFinished() NULL Reply";
return;
}
//-- Get tile hash
const QString hash = reply->request().attribute(QNetworkRequest::User).toString();
if(!hash.isEmpty()) {
if(_replies.contains(hash)) {
_replies.remove(hash);
} else {
qWarning() << "QGCMapEngineManager::networkReplyFinished() Reply not in list: " << hash;
}
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "QGCMapEngineManager::networkReplyFinished() Error:" << reply->errorString();
return;
}
qCDebug(QGCCachedTileSetLog) << "Tile fetched" << hash;
QByteArray image = reply->readAll();
UrlFactory::MapType type = getQGCMapEngine()->hashToType(hash);
QString format = getQGCMapEngine()->urlFactory()->getImageFormat(type, image);
if(!format.isEmpty()) {
//-- Cache tile
getQGCMapEngine()->cacheTile(type, hash, image, format, _id);
QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StateComplete, hash);
getQGCMapEngine()->addTask(task);
//-- Updated cached (downloaded) data
_savedSize += image.size();
_savedTiles++;
emit savedSizeChanged();
emit savedTilesChanged();
//-- Update estimate
if(_savedTiles % 10 == 0) {
quint32 avg = _savedSize / _savedTiles;
_tilesSize = avg * _numTiles;
emit tilesSizeChanged();
}
}
//-- Setup a new download
_prepareDownload();
} else {
qWarning() << "QGCMapEngineManager::networkReplyFinished() Empty Hash";
}
reply->deleteLater();
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::_networkReplyError(QNetworkReply::NetworkError error)
{
//-- Figure out which reply this is
QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
if (!reply) {
return;
}
//-- Upodate error count
_errorCount++;
emit errorCountChanged();
//-- Get tile hash
QString hash = reply->request().attribute(QNetworkRequest::User).toString();
qCDebug(QGCCachedTileSetLog) << "Error fetching tile" << reply->errorString();
if(!hash.isEmpty()) {
if(_replies.contains(hash)) {
_replies.remove(hash);
} else {
qWarning() << "QGCMapEngineManager::networkReplyError() Reply not in list: " << hash;
}
if (error != QNetworkReply::OperationCanceledError) {
qWarning() << "QGCMapEngineManager::networkReplyError() Error:" << reply->errorString();
}
QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StateError, hash);
getQGCMapEngine()->addTask(task);
} else {
qWarning() << "QGCMapEngineManager::networkReplyError() Empty Hash";
}
//-- Setup a new download
_prepareDownload();
reply->deleteLater();
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::setManager(QGCMapEngineManager* mgr)
{
_manager = mgr;
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Set
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#ifndef QGC_MAP_TILE_SET_H
#define QGC_MAP_TILE_SET_H
#include <QObject>
#include <QString>
#include <QHash>
#include <QDateTime>
#include <QImage>
#include "QGCLoggingCategory.h"
#include "QGCMapEngineData.h"
#include "QGCMapUrlEngine.h"
Q_DECLARE_LOGGING_CATEGORY(QGCCachedTileSetLog)
class QGCTile;
class QGCMapEngineManager;
//-----------------------------------------------------------------------------
class QGCCachedTileSet : public QObject
{
Q_OBJECT
public:
QGCCachedTileSet (const QString& name, const QString& description);
~QGCCachedTileSet ();
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString description READ description CONSTANT)
Q_PROPERTY(QString mapTypeStr READ mapTypeStr CONSTANT)
Q_PROPERTY(double topleftLon READ topleftLon CONSTANT)
Q_PROPERTY(double topleftLat READ topleftLat CONSTANT)
Q_PROPERTY(double bottomRightLon READ bottomRightLon CONSTANT)
Q_PROPERTY(double bottomRightLat READ bottomRightLat CONSTANT)
Q_PROPERTY(int minZoom READ minZoom CONSTANT)
Q_PROPERTY(int maxZoom READ maxZoom CONSTANT)
Q_PROPERTY(quint32 numTiles READ numTiles NOTIFY numTilesChanged)
Q_PROPERTY(QString numTilesStr READ numTilesStr NOTIFY numTilesChanged)
Q_PROPERTY(quint64 tilesSize READ tilesSize NOTIFY tilesSizeChanged)
Q_PROPERTY(QString tilesSizeStr READ tilesSizeStr NOTIFY tilesSizeChanged)
Q_PROPERTY(quint32 savedTiles READ savedTiles NOTIFY savedTilesChanged)
Q_PROPERTY(QString savedTilesStr READ savedTilesStr NOTIFY savedTilesChanged)
Q_PROPERTY(quint64 savedSize READ savedSize NOTIFY savedSizeChanged)
Q_PROPERTY(QString savedSizeStr READ savedSizeStr NOTIFY savedSizeChanged)
Q_PROPERTY(QString downloadStatus READ downloadStatus NOTIFY savedSizeChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate CONSTANT)
Q_PROPERTY(bool complete READ complete NOTIFY completeChanged)
Q_PROPERTY(bool defaultSet READ defaultSet CONSTANT)
Q_PROPERTY(quint64 setID READ setID CONSTANT)
Q_PROPERTY(bool deleting READ deleting NOTIFY deletingChanged)
Q_PROPERTY(bool downloading READ downloading NOTIFY downloadingChanged)
Q_PROPERTY(quint32 errorCount READ errorCount NOTIFY errorCountChanged)
Q_PROPERTY(QString errorCountStr READ errorCountStr NOTIFY errorCountChanged)
Q_PROPERTY(QImage thumbNail READ thumbNail CONSTANT)
Q_INVOKABLE void createDownloadTask ();
Q_INVOKABLE void resumeDownloadTask ();
Q_INVOKABLE void cancelDownloadTask ();
void setManager (QGCMapEngineManager* mgr);
QString name () { return _name; }
QString description () { return _description; }
QString mapTypeStr () { return _mapTypeStr; }
double topleftLat () { return _topleftLat; }
double topleftLon () { return _topleftLon; }
double bottomRightLat () { return _bottomRightLat; }
double bottomRightLon () { return _bottomRightLon; }
quint32 numTiles () { return (quint32)_numTiles; }
QString numTilesStr ();
quint64 tilesSize () { return (quint64)_tilesSize; }
QString tilesSizeStr ();
quint32 savedTiles () { return (quint32)_savedTiles; }
QString savedTilesStr ();
quint64 savedSize () { return (quint64)_savedSize; }
QString savedSizeStr ();
QString downloadStatus ();
int minZoom () { return _minZoom; }
int maxZoom () { return _maxZoom; }
QDateTime creationDate () { return _creationDate; }
quint64 id () { return _id; }
UrlFactory::MapType type () { return _type; }
bool complete () { return _defaultSet || (_numTiles == _savedTiles); }
bool defaultSet () { return _defaultSet; }
quint64 setID () { return _id; }
bool deleting () { return _deleting; }
bool downloading () { return _downloading; }
quint32 errorCount () { return _errorCount; }
QString errorCountStr ();
QImage thumbNail () { return _thumbNail; }
void setName (QString name) { _name = name; }
void setDescription (QString desc) { _description = desc; }
void setMapTypeStr (QString typeStr) { _mapTypeStr = typeStr; }
void setTopleftLat (double lat) { _topleftLat = lat; }
void setTopleftLon (double lon) { _topleftLon = lon; }
void setBottomRightLat (double lat) { _bottomRightLat = lat; }
void setBottomRightLon (double lon) { _bottomRightLon = lon; }
void setNumTiles (quint32 num) { _numTiles = num; }
void setTilesSize (quint64 size) { _tilesSize = size; }
void setSavedTiles (quint32 num) { _savedTiles = num; emit savedTilesChanged(); }
void setSavedSize (quint64 size) { _savedSize = size; emit savedSizeChanged(); }
void setMinZoom (int zoom) { _minZoom = zoom; }
void setMaxZoom (int zoom) { _maxZoom = zoom; }
void setCreationDate (QDateTime date) { _creationDate = date; }
void setId (quint64 id) { _id = id; }
void setType (UrlFactory::MapType type) { _type = type; }
void setDefaultSet (bool def) { _defaultSet = def; }
void setDeleting (bool del) { _deleting = del; emit deletingChanged(); }
void setDownloading (bool down) { _downloading = down; }
void setThumbNail (const QImage& thumb) { _thumbNail = thumb; }
signals:
void deletingChanged ();
void downloadingChanged ();
void numTilesChanged ();
void tilesSizeChanged ();
void savedTilesChanged ();
void savedSizeChanged ();
void completeChanged ();
void errorCountChanged ();
private slots:
void _tileListFetched (QList<QGCTile*> tiles);
void _networkReplyFinished ();
void _networkReplyError (QNetworkReply::NetworkError error);
private:
void _prepareDownload ();
private:
QString _name;
QString _description;
QString _mapTypeStr;
double _topleftLat;
double _topleftLon;
double _bottomRightLat;
double _bottomRightLon;
quint32 _numTiles;
quint64 _tilesSize;
quint32 _savedTiles;
quint64 _savedSize;
int _minZoom;
int _maxZoom;
bool _defaultSet;
bool _deleting;
bool _downloading;
QDateTime _creationDate;
quint64 _id;
UrlFactory::MapType _type;
QNetworkAccessManager* _networkManager;
QHash<QString, QNetworkReply*> _replies;
quint32 _errorCount;
//-- Tile download
QList<QGCTile *> _tilesToDownload;
bool _noMoreTiles;
bool _batchRequested;
QGCMapEngineManager* _manager;
QImage _thumbNail;
};
#endif // QGC_MAP_TILE_SET_H
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @author Gus Grubba <mavlink@grubba.com>
* Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
*/
#include <QRegExp>
#include <QNetworkReply>
#include <QEventLoop>
#include <QTimer>
#include <QString>
#include <QByteArray>
#include "QGCMapEngine.h"
//-----------------------------------------------------------------------------
UrlFactory::UrlFactory()
: _timeout(5 * 1000)
, _googleVersionRetrieved(false)
, _googleReply(NULL)
{
QStringList langs = QLocale::system().uiLanguages();
if (langs.length() > 0) {
_language = langs[0];
}
// Google version strings
_versionGoogleMap = "m@336";
_versionGoogleSatellite = "194";
_versionGoogleLabels = "h@336";
_versionGoogleTerrain = "t@132,r@336";
_secGoogleWord = "Galileo";
// BingMaps
_versionBingMaps = "563";
}
//-----------------------------------------------------------------------------
UrlFactory::~UrlFactory()
{
if(_googleReply)
_googleReply->deleteLater();
}
//-----------------------------------------------------------------------------
QString
UrlFactory::getImageFormat(MapType type, const QByteArray& image)
{
QString format;
if(image.size() > 2)
{
if((char)image[0] == (char)0xff && (char)image[1] == (char)0xd8)
format = "jpg";
else if((char)image[0] == (char)0x89 && (char)image[1] == (char)0x50)
format = "png";
else {
switch (type) {
case GoogleMap:
case GoogleLabels:
case GoogleTerrain:
case GoogleHybrid:
case BingMap:
case OpenStreetMap:
format = "png";
break;
case MapQuestMap:
case MapQuestSat:
case MapBoxStreets:
case MapBoxLight:
case MapBoxDark:
case MapBoxSatellite:
case MapBoxHybrid:
case MapBoxWheatPaste:
case MapBoxStreetsBasic:
case MapBoxComic:
case MapBoxOutdoors:
case MapBoxRunBikeHike:
case MapBoxPencil:
case MapBoxPirates:
case MapBoxEmerald:
case MapBoxHighContrast:
case GoogleSatellite:
case BingSatellite:
case BingHybrid:
format = "jpg";
break;
default:
qWarning("UrlFactory::getImageFormat() Unknown map id %d", type);
break;
}
}
}
return format;
}
//-----------------------------------------------------------------------------
QNetworkRequest
UrlFactory::getTileURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager)
{
//-- Build URL
QNetworkRequest request;
QString url = _getURL(type, x, y, zoom, networkManager);
if(url.isEmpty())
return request;
request.setUrl(QUrl(url));
request.setRawHeader("Accept", "*/*");
request.setRawHeader("User-Agent", _userAgent);
switch (type) {
case GoogleMap:
case GoogleSatellite:
case GoogleLabels:
case GoogleTerrain:
case GoogleHybrid:
request.setRawHeader("Referrer", "http://maps.google.com/");
break;
case BingHybrid:
case BingMap:
case BingSatellite:
request.setRawHeader("Referrer", "http://www.bing.com/maps/");
break;
/*
case OpenStreetMapSurfer:
case OpenStreetMapSurferTerrain:
request.setRawHeader("Referrer", "http://www.mapsurfer.net/");
break;
case OpenStreetMap:
case OpenStreetOsm:
request.setRawHeader("Referrer", "https://www.openstreetmap.org/");
break;
*/
default:
break;
}
return request;
}
//-----------------------------------------------------------------------------
void
UrlFactory::_getSecGoogleWords(int x, int y, QString &sec1, QString &sec2)
{
sec1 = ""; // after &x=...
sec2 = ""; // after &zoom=...
int seclen = ((x * 3) + y) % 8;
sec2 = _secGoogleWord.left(seclen);
if (y >= 10000 && y < 100000) {
sec1 = "&s=";
}
}
//-----------------------------------------------------------------------------
QString
UrlFactory::_getURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager)
{
switch (type) {
case GoogleMap:
{
// http://mt1.google.com/vt/lyrs=m
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(x, y, sec1, sec2);
_tryCorrectGoogleVersions(networkManager);
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleMap).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
}
break;
case GoogleSatellite:
{
// http://mt1.google.com/vt/lyrs=s
QString server = "khm";
QString request = "kh";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(x, y, sec1, sec2);
_tryCorrectGoogleVersions(networkManager);
return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleSatellite).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
}
break;
case GoogleLabels:
{
QString server = "mts";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(x, y, sec1, sec2);
_tryCorrectGoogleVersions(networkManager);
return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleLabels).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
}
break;
case GoogleTerrain:
{
QString server = "mt";
QString request = "vt";
QString sec1 = ""; // after &x=...
QString sec2 = ""; // after &zoom=...
_getSecGoogleWords(x, y, sec1, sec2);
_tryCorrectGoogleVersions(networkManager);
return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleTerrain).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
}
break;
/*
case OpenStreetMap:
{
char letter = "abc"[_getServerNum(x, y, 3)];
return QString("https://%1.tile.openstreetmap.org/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y);
}
break;
case OpenStreetOsm:
{
char letter = "abc"[_getServerNum(x, y, 3)];
return QString("http://%1.tah.openstreetmap.org/Tiles/tile/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y);
}
break;
case OpenStreetMapSurfer:
{
// http://tiles1.mapsurfer.net/tms_r.ashx?x=37378&y=20826&z=16
return QString("http://tiles1.mapsurfer.net/tms_r.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
}
break;
case OpenStreetMapSurferTerrain:
{
// http://tiles2.mapsurfer.net/tms_t.ashx?x=9346&y=5209&z=14
return QString("http://tiles2.mapsurfer.net/tms_t.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
}
break;
*/
case BingMap:
{
QString key = _tileXYToQuadKey(x, y, zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
}
break;
case BingSatellite:
{
QString key = _tileXYToQuadKey(x, y, zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
}
break;
case BingHybrid:
{
QString key = _tileXYToQuadKey(x, y, zoom);
return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
}
case MapQuestMap:
{
char letter = "1234"[_getServerNum(x, y, 4)];
return QString("http://otile%1.mqcdn.com/tiles/1.0.0/map/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y);
}
break;
case MapQuestSat:
{
char letter = "1234"[_getServerNum(x, y, 4)];
return QString("http://otile%1.mqcdn.com/tiles/1.0.0/sat/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y);
}
break;
case MapBoxStreets:
case MapBoxLight:
case MapBoxDark:
case MapBoxSatellite:
case MapBoxHybrid:
case MapBoxWheatPaste:
case MapBoxStreetsBasic:
case MapBoxComic:
case MapBoxOutdoors:
case MapBoxRunBikeHike:
case MapBoxPencil:
case MapBoxPirates:
case MapBoxEmerald:
case MapBoxHighContrast:
{
QString mapBoxToken = getQGCMapEngine()->getMapBoxToken();
if(!mapBoxToken.isEmpty()) {
QString server = "https://api.mapbox.com/v4/";
switch(type) {
case MapBoxStreets:
server += "mapbox.streets";
break;
case MapBoxLight:
server += "mapbox.light";
break;
case MapBoxDark:
server += "mapbox.dark";
break;
case MapBoxSatellite:
server += "mapbox.satellite";
break;
case MapBoxHybrid:
server += "mapbox.streets-satellite";
break;
case MapBoxWheatPaste:
server += "mapbox.wheatpaste";
break;
case MapBoxStreetsBasic:
server += "mapbox.streets-basic";
break;
case MapBoxComic:
server += "mapbox.comic";
break;
case MapBoxOutdoors:
server += "mapbox.outdoors";
break;
case MapBoxRunBikeHike:
server += "mapbox.run-bike-hike";
break;
case MapBoxPencil:
server += "mapbox.pencil";
break;
case MapBoxPirates:
server += "mapbox.pirates";
break;
case MapBoxEmerald:
server += "mapbox.emerald";
break;
case MapBoxHighContrast:
server += "mapbox.high-contrast";
break;
default:
return QString::null;
}
server += QString("/%1/%2/%3.jpg80?access_token=%4").arg(zoom).arg(x).arg(y).arg(mapBoxToken);
return server;
}
}
break;
default:
qWarning("Unknown map id %d\n", type);
break;
}
return QString::null;
}
//-----------------------------------------------------------------------------
QString
UrlFactory::_tileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
{
QString quadKey;
for (int i = levelOfDetail; i > 0; i--) {
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0) {
digit++;
}
if ((tileY & mask) != 0) {
digit++;
digit++;
}
quadKey.append(digit);
}
return quadKey;
}
//-----------------------------------------------------------------------------
int
UrlFactory::_getServerNum(int x, int y, int max)
{
return (x + 2 * y) % max;
}
//-----------------------------------------------------------------------------
void
UrlFactory::_networkReplyError(QNetworkReply::NetworkError error)
{
qWarning() << "Could not connect to google maps. Error:" << error;
if(_googleReply)
{
_googleReply->deleteLater();
_googleReply = NULL;
}
}
//-----------------------------------------------------------------------------
void
UrlFactory::_replyDestroyed()
{
_googleReply = NULL;
}
//-----------------------------------------------------------------------------
void
UrlFactory::_googleVersionCompleted()
{
if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
qDebug() << "Error collecting Google maps version info";
return;
}
QString html = QString(_googleReply->readAll());
QRegExp reg("\"*http://mt0.google.com/vt/lyrs=m@(\\d*)",Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
_versionGoogleMap = QString("m@%1").arg(gc[1]);
}
reg = QRegExp("\"*http://mt0.google.com/vt/lyrs=h@(\\d*)",Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
_versionGoogleLabels = QString("h@%1").arg(gc[1]);
}
reg = QRegExp("\"*http://khm\\D?\\d.google.com/kh/v=(\\d*)",Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
_versionGoogleSatellite = gc[1];
}
reg = QRegExp("\"*http://mt0.google.com/vt/lyrs=t@(\\d*),r@(\\d*)",Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts();
_versionGoogleTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]);
}
_googleReply->deleteLater();
_googleReply = NULL;
}
//-----------------------------------------------------------------------------
void
UrlFactory::_tryCorrectGoogleVersions(QNetworkAccessManager* networkManager)
{
QMutexLocker locker(&_googleVersionMutex);
if (_googleVersionRetrieved) {
return;
}
_googleVersionRetrieved = true;
if(networkManager)
{
QNetworkRequest qheader;
QNetworkProxy proxy = networkManager->proxy();
QNetworkProxy tProxy;
tProxy.setType(QNetworkProxy::NoProxy);
networkManager->setProxy(tProxy);
QString url = "http://maps.google.com/maps";
qheader.setUrl(QUrl(url));
QByteArray ua;
ua.append(getQGCMapEngine()->userAgent());
qheader.setRawHeader("User-Agent", ua);
_googleReply = networkManager->get(qheader);
connect(_googleReply, &QNetworkReply::finished, this, &UrlFactory::_googleVersionCompleted);
connect(_googleReply, &QNetworkReply::destroyed, this, &UrlFactory::_replyDestroyed);
connect(_googleReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
this, &UrlFactory::_networkReplyError);
networkManager->setProxy(proxy);
}
}
#define AVERAGE_GOOGLE_STREET_MAP 4913
#define AVERAGE_GOOGLE_TERRAIN_MAP 19391
#define AVERAGE_BING_STREET_MAP 1297
#define AVERAGE_BING_SAT_MAP 19597
#define AVERAGE_GOOGLE_SAT_MAP 56887
#define AVERAGE_MAPBOX_SAT_MAP 15739
#define AVERAGE_MAPBOX_STREET_MAP 5648
#define AVERAGE_TILE_SIZE 13652
//-----------------------------------------------------------------------------
quint32
UrlFactory::averageSizeForType(MapType type)
{
switch (type) {
case GoogleMap:
return AVERAGE_GOOGLE_STREET_MAP;
case BingMap:
return AVERAGE_BING_STREET_MAP;
case GoogleSatellite:
return AVERAGE_GOOGLE_SAT_MAP;
case MapBoxSatellite:
return AVERAGE_MAPBOX_SAT_MAP;
case BingHybrid:
case BingSatellite:
return AVERAGE_BING_SAT_MAP;
case GoogleTerrain:
return AVERAGE_GOOGLE_TERRAIN_MAP;
case MapBoxStreets:
case MapBoxStreetsBasic:
case MapBoxRunBikeHike:
return AVERAGE_MAPBOX_STREET_MAP;
case GoogleLabels:
case MapBoxDark:
case MapBoxLight:
case MapBoxOutdoors:
case MapBoxPencil:
case OpenStreetMap:
case GoogleHybrid:
case MapBoxComic:
case MapBoxEmerald:
case MapBoxHighContrast:
case MapBoxHybrid:
case MapBoxPirates:
case MapBoxWheatPaste:
default:
break;
}
return AVERAGE_TILE_SIZE;
}
......@@ -2,7 +2,7 @@
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
......@@ -23,13 +23,11 @@ This file is part of the QGROUNDCONTROL project
/**
* @file
* @brief QGC Open Pilot Mapping Tools
* @author Gus Grubba <mavlink@grubba.com>
* Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
*/
#ifndef OPENPILOTTOOLS_H
#define OPENPILOTTOOLS_H
#ifndef QGC_MAP_URL_ENGINE_H
#define QGC_MAP_URL_ENGINE_H
#include <QString>
#include <QPoint>
......@@ -38,107 +36,57 @@ This file is part of the QGROUNDCONTROL project
#include <QNetworkReply>
#include <QMutex>
#define MAX_MAP_ZOOM (20.0)
#define MAX_MAP_ZOOM (18.0)
namespace OpenPilot {
class UrlFactory : public QObject {
Q_OBJECT
public:
enum MapType
{
Invalid = -1,
enum MapType
{
GoogleMap = 1,
GoogleSatellite = 4,
GoogleLabels = 8,
GoogleTerrain = 16,
GoogleHybrid = 20,
GoogleMapChina = 22,
GoogleSatelliteChina = 24,
GoogleLabelsChina = 26,
GoogleTerrainChina = 28,
GoogleHybridChina = 29,
OpenStreetMap = 32,
OpenStreetOsm = 33,
OpenStreetMapSurfer = 34,
OpenStreetMapSurferTerrain=35,
YahooMap = 64,
YahooSatellite = 128,
YahooLabels = 256,
YahooHybrid = 333,
BingMap = 444,
BingSatellite = 555,
BingHybrid = 666,
ArcGIS_Map = 777,
ArcGIS_Satellite = 788,
ArcGIS_ShadedRelief = 799,
ArcGIS_Terrain = 811,
ArcGIS_MapsLT_Map = 1000,
ArcGIS_MapsLT_OrtoFoto = 1001,
ArcGIS_MapsLT_Map_Labels= 1002,
ArcGIS_MapsLT_Map_Hybrid= 1003,
PergoTurkeyMap = 2001,
SigPacSpainMap = 3001,
GoogleMapKorea = 4001,
GoogleSatelliteKorea = 4002,
GoogleLabelsKorea = 4003,
GoogleHybridKorea = 4005,
YandexMapRu = 5000
};
class ProviderStrings : public QObject {
Q_OBJECT
public:
ProviderStrings();
static const QString kLevelsForSigPacSpainMap[];
QString GoogleMapsAPIKey;
// Google version strings
QString VersionGoogleMap;
QString VersionGoogleSatellite;
QString VersionGoogleLabels;
QString VersionGoogleTerrain;
QString SecGoogleWord;
// Google (China) version strings
QString VersionGoogleMapChina;
QString VersionGoogleSatelliteChina;
QString VersionGoogleLabelsChina;
QString VersionGoogleTerrainChina;
// Google (Korea) version strings
QString VersionGoogleMapKorea;
QString VersionGoogleSatelliteKorea;
QString VersionGoogleLabelsKorea;
/// <summary>
/// Google Maps API generated using http://greatmaps.codeplex.com/
/// from http://code.google.com/intl/en-us/apis/maps/signup.html
/// </summary>
// Yahoo version strings
QString VersionYahooMap;
QString VersionYahooSatellite;
QString VersionYahooLabels;
// BingMaps
QString VersionBingMaps;
// YandexMap
QString VersionYandexMap;
/// <summary>
/// Bing Maps Customer Identification, more info here
/// http://msdn.microsoft.com/en-us/library/bb924353.aspx
/// </summary>
QString BingMapsClientToken;
};
class UrlFactory : public ProviderStrings {
Q_OBJECT
public:
UrlFactory(QNetworkAccessManager* network);
~UrlFactory();
QString makeImageUrl (const MapType &type, const QPoint &pos, const int &zoom, const QString &language);
MapQuestMap = 700,
MapQuestSat = 701,
MapBoxStreets = 6000,
MapBoxLight = 6001,
MapBoxDark = 6002,
MapBoxSatellite = 6003,
MapBoxHybrid = 6004,
MapBoxWheatPaste = 6005,
MapBoxStreetsBasic = 6006,
MapBoxComic = 6007,
MapBoxOutdoors = 6008,
MapBoxRunBikeHike = 6009,
MapBoxPencil = 6010,
MapBoxPirates = 6011,
MapBoxEmerald = 6012,
MapBoxHighContrast = 6013
};
UrlFactory ();
~UrlFactory ();
QNetworkRequest getTileURL (MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager);
QString getImageFormat (MapType type, const QByteArray& image);
static quint32 averageSizeForType (MapType type);
private slots:
void _networkReplyError (QNetworkReply::NetworkError error);
......@@ -146,19 +94,28 @@ private slots:
void _replyDestroyed ();
private:
void _getSecGoogleWords (const QPoint &pos, QString &sec1, QString &sec2);
int _getServerNum (const QPoint& pos, const int &max) const;
void _tryCorrectGoogleVersions ();
QString _tileXYToQuadKey (const int &tileX, const int &tileY, const int &levelOfDetail) const;
int _timeout;
bool _googleVersionRetrieved;
QNetworkAccessManager* _network;
QNetworkReply* _googleReply;
QMutex _googleVersionMutex;
QByteArray _userAgent;
};
QString _getURL (MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager);
void _getSecGoogleWords (int x, int y, QString& sec1, QString& sec2);
int _getServerNum (int x, int y, int max);
void _tryCorrectGoogleVersions (QNetworkAccessManager* networkManager);
QString _tileXYToQuadKey (int tileX, int tileY, int levelOfDetail);
int _timeout;
bool _googleVersionRetrieved;
QNetworkReply* _googleReply;
QMutex _googleVersionMutex;
QByteArray _userAgent;
QString _language;
// Google version strings
QString _versionGoogleMap;
QString _versionGoogleSatellite;
QString _versionGoogleLabels;
QString _versionGoogleTerrain;
QString _secGoogleWord;
// BingMaps
QString _versionBingMaps;
}
};
#endif // FOO_H
#endif
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Cache Worker Thread
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#include <QVariant>
#include <QtSql/QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QDateTime>
#include <QApplication>
#include <QFile>
#include "time.h"
#include "QGCMapEngine.h"
#include "QGCMapTileSet.h"
const char* kDefaultSet = "Default Tile Set";
const QString kSession = QLatin1String("QGeoTileWorkerSession");
QGC_LOGGING_CATEGORY(QGCTileCacheLog, "QGCTileCacheLog")
//-- Update intervals
#define LONG_TIMEOUT 5
#define SHORT_TIMEOUT 2
//-----------------------------------------------------------------------------
QGCCacheWorker::QGCCacheWorker()
: _db(NULL)
, _valid(false)
, _failed(false)
, _defaultSet(UINT64_MAX)
, _totalSize(0)
, _totalCount(0)
, _defaultSize(0)
, _defaultCount(0)
, _lastUpdate(0)
, _updateTimeout(SHORT_TIMEOUT)
{
}
//-----------------------------------------------------------------------------
QGCCacheWorker::~QGCCacheWorker()
{
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::setDatabaseFile(const QString& path)
{
_databasePath = path;
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::quit()
{
_mutex.lock();
while(_taskQueue.count()) {
QGCMapTask* task = _taskQueue.dequeue();
delete task;
}
_mutex.unlock();
if(this->isRunning()) {
_waitc.wakeAll();
}
}
//-----------------------------------------------------------------------------
bool
QGCCacheWorker::enqueueTask(QGCMapTask* task)
{
//-- If not initialized, the only allowed task is Init
if(!_valid && task->type() != QGCMapTask::taskInit) {
task->setError("Database Not Initialized");
task->deleteLater();
return false;
}
if(!_taskQueue.contains(task))
{
_mutex.lock();
_taskQueue.enqueue(task);
_mutex.unlock();
if(this->isRunning()) {
_waitc.wakeAll();
} else {
this->start(QThread::NormalPriority);
}
return true;
}
//-- Should never happen
return false;
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::run()
{
if(!_valid && !_failed) {
_init();
}
if(_valid) {
_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession));
_db->setDatabaseName(_databasePath);
_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
_valid = _db->open();
}
while(true) {
QGCMapTask* task;
if(_taskQueue.count()) {
_mutex.lock();
task = _taskQueue.dequeue();
_mutex.unlock();
switch(task->type()) {
case QGCMapTask::taskInit:
break;
case QGCMapTask::taskCacheTile:
_saveTile(task);
break;
case QGCMapTask::taskFetchTile:
_getTile(task);
break;
case QGCMapTask::taskFetchTileSets:
_getTileSets(task);
break;
case QGCMapTask::taskCreateTileSet:
_createTileSet(task);
break;
case QGCMapTask::taskGetTileDownloadList:
_getTileDownloadList(task);
break;
case QGCMapTask::taskUpdateTileDownloadState:
_updateTileDownloadState(task);
break;
case QGCMapTask::taskDeleteTileSet:
_deleteTileSet(task);
break;
case QGCMapTask::taskPruneCache:
_pruneCache(task);
break;
case QGCMapTask::taskReset:
_resetCacheDatabase(task);
break;
}
task->deleteLater();
//-- Check for update timeout
size_t count = _taskQueue.count();
if(count > 100) {
_updateTimeout = LONG_TIMEOUT;
} else if(count < 25) {
_updateTimeout = SHORT_TIMEOUT;
}
if(!count || (time(0) - _lastUpdate > _updateTimeout)) {
_updateTotals();
}
} else {
//-- Wait a bit before shutting things down
_waitmutex.lock();
int timeout = 5000;
if(!_waitc.wait(&_waitmutex, timeout))
{
_waitmutex.unlock();
_mutex.lock();
//-- If nothing to do, close db and leave thread
if(!_taskQueue.count()) {
_mutex.unlock();
break;
}
_mutex.unlock();
}
_waitmutex.unlock();
}
}
if(_db) {
delete _db;
_db = NULL;
QSqlDatabase::removeDatabase(kSession);
}
}
//-----------------------------------------------------------------------------
bool
QGCCacheWorker::_findTileSetID(const QString name, quint64& setID)
{
QSqlQuery query(*_db);
QString s = QString("SELECT setID FROM TileSets WHERE name = \"%1\"").arg(name);
if(query.exec(s)) {
if(query.next()) {
setID = query.value(0).toULongLong();
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
quint64
QGCCacheWorker::_getDefaultTileSet()
{
if(_defaultSet != UINT64_MAX)
return _defaultSet;
QSqlQuery query(*_db);
QString s = QString("SELECT setID FROM TileSets WHERE defaultSet = 1");
if(query.exec(s)) {
if(query.next()) {
_defaultSet = query.value(0).toULongLong();
return _defaultSet;
}
}
return 1L;
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_saveTile(QGCMapTask *mtask)
{
if(_valid) {
QGCSaveTileTask* task = static_cast<QGCSaveTileTask*>(mtask);
QSqlQuery query(*_db);
query.prepare("INSERT INTO Tiles(hash, format, tile, size, type, date) VALUES(?, ?, ?, ?, ?, ?)");
query.addBindValue(task->tile()->hash());
query.addBindValue(task->tile()->format());
query.addBindValue(task->tile()->img());
query.addBindValue(task->tile()->img().size());
query.addBindValue(task->tile()->type());
query.addBindValue(QDateTime::currentDateTime().toTime_t());
if(query.exec()) {
quint64 tileID = query.lastInsertId().toULongLong();
quint64 setID = task->tile()->set() == UINT64_MAX ? _getDefaultTileSet() : task->tile()->set();
QString s = QString("INSERT INTO SetTiles(tileID, setID) VALUES(%1, %2)").arg(tileID).arg(setID);
query.prepare(s);
if(!query.exec()) {
qWarning() << "Map Cache SQL error (add tile into SetTiles):" << query.lastError().text();
}
qCDebug(QGCTileCacheLog) << "_saveTile() HASH:" << task->tile()->hash();
} else {
//-- Tile was already there.
// QtLocation some times requests the same tile twice in a row. The first is saved, the second is already there.
}
} else {
qWarning() << "Map Cache SQL error (saveTile() open db):" << _db->lastError();
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_getTile(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
bool found = false;
QGCFetchTileTask* task = static_cast<QGCFetchTileTask*>(mtask);
QSqlQuery query(*_db);
QString s = QString("SELECT tile, format, type FROM Tiles WHERE hash = \"%1\"").arg(task->hash());
if(query.exec(s)) {
if(query.next()) {
QByteArray ar = query.value(0).toByteArray();
QString format = query.value(1).toString();
UrlFactory::MapType type = (UrlFactory::MapType)query.value(2).toInt();
qCDebug(QGCTileCacheLog) << "_getTile() (Found in DB) HASH:" << task->hash();
QGCCacheTile* tile = new QGCCacheTile(task->hash(), ar, format, type);
task->setTileFetched(tile);
found = true;
}
}
if(!found) {
qCDebug(QGCTileCacheLog) << "_getTile() (NOT in DB) HASH:" << task->hash();
task->setError("Tile not in cache database");
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_getTileSets(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QGCFetchTileSetTask* task = static_cast<QGCFetchTileSetTask*>(mtask);
QSqlQuery query(*_db);
QString s = QString("SELECT * FROM TileSets ORDER BY defaultSet DESC, name ASC");
if(query.exec(s)) {
while(query.next()) {
QString name = query.value("name").toString();
QString desc = query.value("description").toString();
QGCCachedTileSet* set = new QGCCachedTileSet(name, desc);
set->setId(query.value("setID").toULongLong());
set->setMapTypeStr(query.value("typeStr").toString());
set->setTopleftLat(query.value("topleftLat").toDouble());
set->setTopleftLon(query.value("topleftLon").toDouble());
set->setBottomRightLat(query.value("bottomRightLat").toDouble());
set->setBottomRightLon(query.value("bottomRightLon").toDouble());
set->setMinZoom(query.value("minZoom").toInt());
set->setMaxZoom(query.value("maxZoom").toInt());
set->setType((UrlFactory::MapType)query.value("type").toInt());
set->setNumTiles(query.value("numTiles").toUInt());
set->setTilesSize(query.value("tilesSize").toULongLong());
set->setDefaultSet(query.value("defaultSet").toInt() != 0);
set->setCreationDate(QDateTime::fromTime_t(query.value("date").toUInt()));
//-- Load thumbnail (if not default set)
if(!set->defaultSet()) {
int w = query.value("thumbW").toInt();
int h = query.value("thumbH").toInt();
if(w && h) {
QByteArray ba = query.value("thumbNail").toByteArray();
set->setThumbNail(QImage((uchar*)(void*)ba.data(), w, h, QImage::Format_RGB32));
}
}
_updateSetTotals(set);
//-- Object created here must be moved to app thread to be used there
set->moveToThread(QApplication::instance()->thread());
task->tileSetFetched(set);
}
} else {
task->setError("No tile set in database");
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_updateSetTotals(QGCCachedTileSet* set)
{
_updateTotals();
if(set->defaultSet()) {
//-- Default Set is already computed
set->setSavedTiles(_totalCount);
set->setSavedSize(_totalSize);
set->setNumTiles(_defaultCount);
set->setTilesSize(_defaultSize);
return;
}
QSqlQuery subquery(*_db);
//-- Count everythin for Default Set
QString sq = QString("SELECT COUNT(size), SUM(size) FROM Tiles A INNER JOIN SetTiles B on A.tileID = B.tileID WHERE B.setID = %1").arg(set->id());
if(subquery.exec(sq)) {
if(subquery.next()) {
set->setSavedTiles(subquery.value(0).toUInt());
set->setSavedSize(subquery.value(1).toULongLong());
//-- Update estimated size
if(set->savedTiles() > 10 && set->savedSize()) {
quint32 avg = set->savedSize() / set->savedTiles();
set->setTilesSize(avg * set->numTiles());
}
}
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_updateTotals()
{
QSqlQuery query(*_db);
QString s;
s = QString("SELECT COUNT(size), SUM(size) FROM Tiles");
if(query.exec(s)) {
if(query.next()) {
_totalCount = query.value(0).toUInt();
_totalSize = query.value(1).toULongLong();
}
}
s = QString("SELECT COUNT(size), SUM(size) FROM Tiles A INNER JOIN SetTiles B on A.tileID = B.tileID WHERE B.setID = %1").arg(_getDefaultTileSet());
if(query.exec(s)) {
if(query.next()) {
_defaultCount = query.value(0).toUInt();
_defaultSize = query.value(1).toULongLong();
}
}
emit updateTotals(_totalCount, _totalSize, _defaultCount, _defaultSize);
_lastUpdate = time(0);
}
//-----------------------------------------------------------------------------
bool
QGCCacheWorker::_findTile(const QString hash)
{
QSqlQuery query(*_db);
QString s = QString("SELECT type FROM Tiles WHERE hash = \"%1\"").arg(hash);
if(query.exec(s)) {
if(query.next()) {
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_createTileSet(QGCMapTask *mtask)
{
if(_valid) {
//-- Create Tile Set
quint32 actual_count = 0;
QGCCreateTileSetTask* task = static_cast<QGCCreateTileSetTask*>(mtask);
QSqlQuery query(*_db);
query.prepare("INSERT INTO TileSets("
"name, description, typeStr, topleftLat, topleftLon, bottomRightLat, bottomRightLon, minZoom, maxZoom, type, numTiles, tilesSize, thumbNail, thumbW, thumbH, date"
") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
query.addBindValue(task->tileSet()->name());
query.addBindValue(task->tileSet()->description());
query.addBindValue(task->tileSet()->mapTypeStr());
query.addBindValue(task->tileSet()->topleftLat());
query.addBindValue(task->tileSet()->topleftLon());
query.addBindValue(task->tileSet()->bottomRightLat());
query.addBindValue(task->tileSet()->bottomRightLon());
query.addBindValue(task->tileSet()->minZoom());
query.addBindValue(task->tileSet()->maxZoom());
query.addBindValue(task->tileSet()->type());
query.addBindValue(task->tileSet()->numTiles());
query.addBindValue(task->tileSet()->tilesSize());
if(task->tileSet()->thumbNail().isNull()) {
query.addBindValue(QByteArray(1,'\0'));
query.addBindValue(0);
query.addBindValue(0);
} else {
query.addBindValue(QByteArray((const char *)(void*)task->tileSet()->thumbNail().convertToFormat(QImage::Format_RGB32).bits(), task->tileSet()->thumbNail().byteCount()));
query.addBindValue(task->tileSet()->thumbNail().width());
query.addBindValue(task->tileSet()->thumbNail().height());
}
query.addBindValue(QDateTime::currentDateTime().toTime_t());
if(!query.exec()) {
qWarning() << "Map Cache SQL error (add tileSet into TileSets):" << query.lastError().text();
} else {
//-- Get just creted (auto-incremented) setID
quint64 setID = query.lastInsertId().toULongLong();
task->tileSet()->setId(setID);
//-- Prepare Download List
for(int z = task->tileSet()->minZoom(); z <= task->tileSet()->maxZoom(); z++) {
QGCTileSet set = QGCMapEngine::getTileCount(z,
task->tileSet()->topleftLon(), task->tileSet()->topleftLat(),
task->tileSet()->bottomRightLon(), task->tileSet()->bottomRightLat(), task->tileSet()->type());
UrlFactory::MapType type = task->tileSet()->type();
for(int x = set.tileX0; x <= set.tileX1; x++) {
for(int y = set.tileY0; y <= set.tileY1; y++) {
//-- See if tile is already downloaded
QString hash = QGCMapEngine::getTileHash(type, x, y, z);
if(!_findTile(hash)) {
//-- Set to download
query.prepare("INSERT OR IGNORE INTO TilesDownload(setID, hash, type, x, y, z, state) VALUES(?, ?, ?, ?, ? ,? ,?)");
query.addBindValue(setID);
query.addBindValue(hash);
query.addBindValue(type);
query.addBindValue(x);
query.addBindValue(y);
query.addBindValue(z);
query.addBindValue(0);
if(!query.exec()) {
qWarning() << "Map Cache SQL error (add tile into TilesDownload):" << query.lastError().text();
mtask->setError("Error creating tile set download list");
return;
} else
actual_count++;
}
}
}
}
//-- Now update how many tiles we actually have to download
quint64 actual_size = actual_count * UrlFactory::averageSizeForType(task->tileSet()->type());
QString s = QString("UPDATE TileSets SET numTiles = %1, tilesSize = %2 WHERE setID = %3").arg(actual_count).arg(actual_size).arg(task->tileSet()->setID());
if(!query.exec(s)) {
qWarning() << "Map Cache SQL error (set TilesDownload state):" << query.lastError().text();
}
//-- Done
_updateSetTotals(task->tileSet());
task->setTileSetSaved();
return;
}
}
mtask->setError("Error saving tile set");
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_getTileDownloadList(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QList<QGCTile*> tiles;
QGCGetTileDownloadListTask* task = static_cast<QGCGetTileDownloadListTask*>(mtask);
QSqlQuery query(*_db);
QString s = QString("SELECT hash, type, x, y, z FROM TilesDownload WHERE setID = %1 AND state = 0 LIMIT %2").arg(task->setID()).arg(task->count());
if(query.exec(s)) {
while(query.next()) {
QGCTile* tile = new QGCTile;
tile->setHash(query.value("hash").toString());
tile->setType((UrlFactory::MapType)query.value("type").toInt());
tile->setX(query.value("x").toInt());
tile->setY(query.value("y").toInt());
tile->setZ(query.value("z").toInt());
tiles.append(tile);
}
for(int i = 0; i < tiles.size(); i++) {
s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2 and hash = \"%3\"").arg((int)QGCTile::StateDownloading).arg(task->setID()).arg(tiles[i]->hash());
if(!query.exec(s)) {
qWarning() << "Map Cache SQL error (set TilesDownload state):" << query.lastError().text();
}
}
}
task->setTileListFetched(tiles);
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_updateTileDownloadState(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QGCUpdateTileDownloadStateTask* task = static_cast<QGCUpdateTileDownloadStateTask*>(mtask);
QSqlQuery query(*_db);
QString s;
if(task->state() == QGCTile::StateComplete) {
s = QString("DELETE FROM TilesDownload WHERE setID = %1 AND hash = \"%2\"").arg(task->setID()).arg(task->hash());
} else {
if(task->hash() == "*") {
s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2").arg((int)task->state()).arg(task->setID());
} else {
s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2 AND hash = \"%3\"").arg((int)task->state()).arg(task->setID()).arg(task->hash());
}
}
if(!query.exec(s)) {
qWarning() << "QGCCacheWorker::_updateTileDownloadState() Error:" << query.lastError().text();
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_pruneCache(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QGCPruneCacheTask* task = static_cast<QGCPruneCacheTask*>(mtask);
QSqlQuery query(*_db);
QString s;
s = QString("SELECT tileID, size, hash FROM Tiles WHERE tileID IN (SELECT tileID FROM SetTiles WHERE setID = %1) ORDER BY DATE ASC LIMIT 128").arg(_getDefaultTileSet());
qint64 amount = (qint64)task->amount();
QList<quint64> tlist;
if(query.exec(s)) {
while(query.next() && amount >= 0) {
tlist << query.value(0).toULongLong();
amount -= query.value(1).toULongLong();
qCDebug(QGCTileCacheLog) << "_pruneCache() HASH:" << query.value(2).toString();
}
while(tlist.count()) {
s = QString("DELETE FROM Tiles WHERE tileID = %1").arg(tlist[0]);
tlist.removeFirst();
if(!query.exec(s))
break;
}
task->setPruned();
}
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_deleteTileSet(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QGCDeleteTileSetTask* task = static_cast<QGCDeleteTileSetTask*>(mtask);
QSqlQuery query(*_db);
QString s;
s = QString("DELETE FROM Tiles WHERE tileID IN (SELECT tileID FROM SetTiles WHERE setID = %1)").arg(task->setID());
query.exec(s);
s = QString("DELETE FROM TilesDownload WHERE setID = %1").arg(task->setID());
query.exec(s);
s = QString("DELETE FROM TileSets WHERE setID = %1").arg(task->setID());
query.exec(s);
s = QString("DELETE FROM SetTiles WHERE setID = %1").arg(task->setID());
query.exec(s);
_updateTotals();
task->setTileSetDeleted();
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_resetCacheDatabase(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return;
}
QGCResetTask* task = static_cast<QGCResetTask*>(mtask);
QSqlQuery query(*_db);
QString s;
s = QString("DROP TABLE Tiles");
query.exec(s);
s = QString("DROP TABLE TileSets");
query.exec(s);
s = QString("DROP TABLE SetTiles");
query.exec(s);
s = QString("DROP TABLE TilesDownload");
query.exec(s);
_createDB();
task->setResetCompleted();
}
//-----------------------------------------------------------------------------
bool
QGCCacheWorker::_init()
{
_failed = false;
if(!_databasePath.isEmpty()) {
qCDebug(QGCTileCacheLog) << "Mapping cache directory:" << _databasePath;
//-- Initialize Database
_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession));
_db->setDatabaseName(_databasePath);
_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
if (_db->open()) {
_createDB();
} else {
qCritical() << "Map Cache SQL error (init() open db):" << _db->lastError();
_failed = true;
}
delete _db;
_db = NULL;
QSqlDatabase::removeDatabase(kSession);
} else {
qCritical() << "Could not find suitable cache directory.";
_failed = true;
}
return _failed;
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_createDB()
{
QSqlQuery query(*_db);
if(!query.exec(
"CREATE TABLE IF NOT EXISTS Tiles ("
"tileID INTEGER PRIMARY KEY NOT NULL, "
"hash TEXT NOT NULL UNIQUE, "
"format TEXT NOT NULL, "
"tile BLOB NULL, "
"size INTEGER, "
"type INTEGER, "
"date INTEGER DEFAULT 0)"))
{
qWarning() << "Map Cache SQL error (create Tiles db):" << query.lastError().text();
} else {
if(!query.exec(
"CREATE TABLE IF NOT EXISTS TileSets ("
"setID INTEGER PRIMARY KEY NOT NULL, "
"name TEXT NOT NULL UNIQUE, "
"description TEXT NOT NULL, "
"typeStr TEXT, "
"topleftLat REAL DEFAULT 0.0, "
"topleftLon REAL DEFAULT 0.0, "
"bottomRightLat REAL DEFAULT 0.0, "
"bottomRightLon REAL DEFAULT 0.0, "
"minZoom INTEGER DEFAULT 3, "
"maxZoom INTEGER DEFAULT 3, "
"type INTEGER DEFAULT -1, "
"numTiles INTEGER DEFAULT 0, "
"tilesSize INTEGER DEFAULT 0, "
"defaultSet INTEGER DEFAULT 0, "
"thumbNail BLOB NULL, "
"thumbW INTEGER DEFAULT 0, "
"thumbH INTEGER DEFAULT 0, "
"date INTEGER DEFAULT 0)"))
{
qWarning() << "Map Cache SQL error (create TileSets db):" << query.lastError().text();
} else {
if(!query.exec(
"CREATE TABLE IF NOT EXISTS SetTiles ("
"setID INTEGER, "
"tileID INTEGER)"))
{
qWarning() << "Map Cache SQL error (create SetTiles db):" << query.lastError().text();
} else {
if(!query.exec(
"CREATE TABLE IF NOT EXISTS TilesDownload ("
"setID INTEGER, "
"hash TEXT NOT NULL UNIQUE, "
"type INTEGER, "
"x INTEGER, "
"y INTEGER, "
"z INTEGER, "
"state INTEGER DEFAULT 0)"))
{
qWarning() << "Map Cache SQL error (create TilesDownload db):" << query.lastError().text();
} else {
//-- Database it ready for use
_valid = true;
}
}
}
}
//-- Create default tile set
if(_valid) {
QString s = QString("SELECT name FROM TileSets WHERE name = \"%1\"").arg(kDefaultSet);
if(query.exec(s)) {
if(!query.next()) {
query.prepare("INSERT INTO TileSets(name, description, defaultSet, date) VALUES(?, ?, ?, ?)");
query.addBindValue(kDefaultSet);
query.addBindValue("System wide tile cache");
query.addBindValue(1);
query.addBindValue(QDateTime::currentDateTime().toTime_t());
if(!query.exec()) {
qWarning() << "Map Cache SQL error (Creating default tile set):" << _db->lastError();
_valid = false;
}
}
} else {
qWarning() << "Map Cache SQL error (Looking for default tile set):" << _db->lastError();
}
}
if(!_valid) {
QFile file(_databasePath);
file.remove();
}
_failed = !_valid;
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Map Tile Cache Worker Thread
*
* @author Gus Grubba <mavlink@grubba.com>
*
*/
#ifndef QGC_TILE_CACHE_WORKER_H
#define QGC_TILE_CACHE_WORKER_H
#include <QString>
#include <QThread>
#include <QQueue>
#include <QMutex>
#include <QWaitCondition>
#include <QMutexLocker>
#include <QtSql/QSqlDatabase>
#include "QGCLoggingCategory.h"
Q_DECLARE_LOGGING_CATEGORY(QGCTileCacheLog)
class QGCMapTask;
class QGCCachedTileSet;
//-----------------------------------------------------------------------------
class QGCCacheWorker : public QThread
{
Q_OBJECT
public:
QGCCacheWorker ();
~QGCCacheWorker ();
void quit ();
bool enqueueTask (QGCMapTask* task);
void setDatabaseFile (const QString& path);
protected:
void run ();
private:
void _saveTile (QGCMapTask* mtask);
void _getTile (QGCMapTask* mtask);
void _getTileSets (QGCMapTask* mtask);
void _createTileSet (QGCMapTask* mtask);
void _getTileDownloadList (QGCMapTask* mtask);
void _updateTileDownloadState(QGCMapTask* mtask);
void _deleteTileSet (QGCMapTask* mtask);
void _resetCacheDatabase (QGCMapTask* mtask);
void _pruneCache (QGCMapTask* mtask);
bool _findTile (const QString hash);
bool _findTileSetID (const QString name, quint64& setID);
void _updateSetTotals (QGCCachedTileSet* set);
bool _init ();
void _createDB ();
quint64 _getDefaultTileSet ();
void _updateTotals ();
signals:
void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
private:
QQueue<QGCMapTask*> _taskQueue;
QMutex _mutex;
QMutex _waitmutex;
QWaitCondition _waitc;
QString _databasePath;
QSqlDatabase* _db;
bool _valid;
bool _failed;
quint64 _defaultSet;
quint64 _totalSize;
quint32 _totalCount;
quint64 _defaultSize;
quint32 _defaultCount;
time_t _lastUpdate;
int _updateTimeout;
};
#endif // QGC_TILE_CACHE_WORKER_H
......@@ -54,7 +54,7 @@
#include <QSet>
#include <QDebug>
#include "qgeocodereplyqgc.h"
#include "QGeoCodeReplyQGC.h"
enum QGeoCodeTypeGoogle {
GeoCodeTypeUnknown,
......
......@@ -44,8 +44,8 @@
**
****************************************************************************/
#ifndef QGEOCODEREPLYGOOGLE_H
#define QGEOCODEREPLYGOOGLE_H
#ifndef QGEOCODEREPLYQGC_H
#define QGEOCODEREPLYQGC_H
#include <QtNetwork/QNetworkReply>
#include <QtLocation/QGeoCodeReply>
......@@ -68,4 +68,4 @@ private:
QNetworkReply *m_reply;
};
#endif // QGEOCODEREPLYGOOGLE_H
#endif // QGEOCODEREPLYQGC_H
......@@ -57,8 +57,8 @@
#include <QtPositioning/QGeoRectangle>
#include <QDebug>
#include "qgeocodingmanagerengineqgc.h"
#include "qgeocodereplyqgc.h"
#include "QGeoCodingManagerEngineQGC.h"
#include "QGeoCodeReplyQGC.h"
static QString addressToQuery(const QGeoAddress &address)
{
......
......@@ -44,8 +44,8 @@
**
****************************************************************************/
#ifndef QGEOCODINGMANAGERENGINEGOOGLE_H
#define QGEOCODINGMANAGERENGINEGOOGLE_H
#ifndef QGEOCODINGMANAGERENGINEQGC_H
#define QGEOCODINGMANAGERENGINEQGC_H
#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/QGeoCodingManagerEngine>
......@@ -78,4 +78,4 @@ private:
QT_END_NAMESPACE
#endif // QGEOCODINGMANAGERENGINEGOOGLE_H
#endif // QGEOCODINGMANAGERENGINEQGC_H
......@@ -45,114 +45,127 @@
****************************************************************************/
#include <QtLocation/private/qgeotilespec_p.h>
#include <QtNetwork/QNetworkAccessManager>
#include <QFile>
#include "qgeomapreplyqgc.h"
#include "OpenPilotMaps.h"
#include "QGCMapEngine.h"
#include "QGeoMapReplyQGC.h"
QGeoMapReplyQGC::QGeoMapReplyQGC(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
//-----------------------------------------------------------------------------
QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent)
: QGeoTiledMapReply(spec, parent)
, m_reply(reply)
, _reply(NULL)
, _request(request)
, _networkManager(networkManager)
{
if(!reply)
{
setError(QGeoTiledMapReply::UnknownError, "Invalid tile request");
if(_request.url().isEmpty()) {
if(!_badMapBox.size()) {
QFile b(":/res/notile.png");
if(b.open(QFile::ReadOnly))
_badMapBox = b.readAll();
}
setMapImageData(_badMapBox);
setMapImageFormat("png");
setFinished(true);
}
else
{
connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(m_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed()));
setCached(false);
} else {
QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom());
connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply);
connect(task, &QGCMapTask::error, this, &QGeoTiledMapReplyQGC::cacheError);
getQGCMapEngine()->addTask(task);
}
}
QGeoMapReplyQGC::~QGeoMapReplyQGC()
//-----------------------------------------------------------------------------
QGeoTiledMapReplyQGC::~QGeoTiledMapReplyQGC()
{
if (m_reply) {
m_reply->deleteLater();
m_reply = 0;
if (_reply) {
_reply->deleteLater();
_reply = 0;
}
}
void QGeoMapReplyQGC::abort()
{
if (!m_reply)
return;
m_reply->abort();
}
QNetworkReply *QGeoMapReplyQGC::networkReply() const
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::abort()
{
return m_reply;
if (_reply)
_reply->abort();
}
void QGeoMapReplyQGC::replyDestroyed()
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::replyDestroyed()
{
m_reply = 0;
_reply = 0;
}
void QGeoMapReplyQGC::networkReplyFinished()
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::networkReplyFinished()
{
if (!m_reply)
{
if (!_reply) {
return;
}
if (m_reply->error() != QNetworkReply::NoError)
{
if (_reply->error() != QNetworkReply::NoError) {
return;
}
QByteArray a = m_reply->readAll();
QByteArray a = _reply->readAll();
setMapImageData(a);
if(a.size() > 2)
{
if((char)a[0] == (char)0xff && (char)a[1] == (char)0xd8)
setMapImageFormat("jpg");
else if((char)a[0] == (char)0x89 && (char)a[1] == (char)0x50)
setMapImageFormat("png");
else
{
switch ((OpenPilot::MapType)tileSpec().mapId()) {
case OpenPilot::GoogleMap:
case OpenPilot::GoogleLabels:
case OpenPilot::GoogleTerrain:
case OpenPilot::GoogleHybrid:
case OpenPilot::BingMap:
case OpenPilot::OpenStreetMap:
setMapImageFormat("png");
break;
case OpenPilot::GoogleSatellite:
case OpenPilot::BingSatellite:
case OpenPilot::BingHybrid:
setMapImageFormat("jpg");
break;
default:
qWarning("Unknown map id %d", tileSpec().mapId());
break;
}
}
QString format = getQGCMapEngine()->urlFactory()->getImageFormat((UrlFactory::MapType)tileSpec().mapId(), a);
if(!format.isEmpty()) {
setMapImageFormat(format);
getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format);
}
setFinished(true);
m_reply->deleteLater();
m_reply = 0;
_reply->deleteLater();
_reply = 0;
}
void QGeoMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error)
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error)
{
if (!m_reply)
{
if (!_reply) {
return;
}
if (error != QNetworkReply::OperationCanceledError) {
qWarning() << "Fetch tile error:" << _reply->errorString();
}
_reply->deleteLater();
_reply = 0;
if(!_badTile.size()) {
QFile b(":/res/notile.png");
if(b.open(QFile::ReadOnly))
_badTile = b.readAll();
}
setMapImageData(_badTile);
setMapImageFormat("png");
setFinished(true);
setCached(false);
}
if (error != QNetworkReply::OperationCanceledError)
{
setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString /*errorString*/)
{
if(type != QGCMapTask::taskFetchTile) {
qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task";
}
//-- Tile not in cache. Get it off the Internet.
_reply = _networkManager->get(_request);
_reply->setParent(0);
connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed()));
}
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::cacheReply(QGCCacheTile* tile)
{
setMapImageData(tile->img());
setMapImageFormat(tile->format());
setFinished(true);
m_reply->deleteLater();
m_reply = 0;
setCached(true);
tile->deleteLater();
}
......@@ -44,31 +44,35 @@
**
****************************************************************************/
#ifndef QGEOMAPREPLYGOOGLE_H
#define QGEOMAPREPLYGOOGLE_H
#ifndef QGEOMAPREPLYQGC_H
#define QGEOMAPREPLYQGC_H
#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h>
class QGeoMapReplyQGC : public QGeoTiledMapReply
#include "QGCMapEngineData.h"
class QGeoTiledMapReplyQGC : public QGeoTiledMapReply
{
Q_OBJECT
public:
explicit QGeoMapReplyQGC(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);
~QGeoMapReplyQGC();
QGeoTiledMapReplyQGC(QNetworkAccessManager* networkManager, const QNetworkRequest& request, const QGeoTileSpec &spec, QObject *parent = 0);
~QGeoTiledMapReplyQGC();
void abort();
QNetworkReply *networkReply() const;
private Q_SLOTS:
private slots:
void replyDestroyed ();
void networkReplyFinished ();
void networkReplyError (QNetworkReply::NetworkError error);
void cacheReply (QGCCacheTile* tile);
void cacheError (QGCMapTask::TaskType type, QString errorString);
private:
QNetworkReply* m_reply;
QNetworkReply* _reply;
QNetworkRequest _request;
QNetworkAccessManager* _networkManager;
QByteArray _badMapBox;
QByteArray _badTile;
};
#endif // QGEOMAPREPLYGOOGLE_H
#endif // QGEOMAPREPLYQGC_H
......@@ -47,38 +47,48 @@
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>
#include "qdebug.h"
#include "qgeoserviceproviderpluginqgc.h"
#include "qgeotiledmappingmanagerengineqgc.h"
#include "qgeocodingmanagerengineqgc.h"
#include "QGeoServiceProviderPluginQGC.h"
#include "QGeoTiledMappingManagerEngineQGC.h"
#include "QGeoCodingManagerEngineQGC.h"
Q_EXTERN_C Q_DECL_EXPORT const char *qt_plugin_query_metadata();
Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance();
//-----------------------------------------------------------------------------
const QT_PREPEND_NAMESPACE(QStaticPlugin) qt_static_plugin_QGeoServiceProviderFactoryQGC()
{
QT_PREPEND_NAMESPACE(QStaticPlugin) plugin = { qt_plugin_instance, qt_plugin_query_metadata};
return plugin;
}
QGeoCodingManagerEngine *QGeoServiceProviderFactoryQGC::createGeocodingManagerEngine(
//-----------------------------------------------------------------------------
QGeoCodingManagerEngine*
QGeoServiceProviderFactoryQGC::createGeocodingManagerEngine(
const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
{
return new QGeoCodingManagerEngineQGC(parameters, error, errorString);
}
QGeoMappingManagerEngine *QGeoServiceProviderFactoryQGC::createMappingManagerEngine(
//-----------------------------------------------------------------------------
QGeoMappingManagerEngine*
QGeoServiceProviderFactoryQGC::createMappingManagerEngine(
const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
{
return new QGeoTiledMappingManagerEngineQGC(parameters, error, errorString);
}
QGeoRoutingManagerEngine *QGeoServiceProviderFactoryQGC::createRoutingManagerEngine(
//-----------------------------------------------------------------------------
QGeoRoutingManagerEngine*
QGeoServiceProviderFactoryQGC::createRoutingManagerEngine(
const QVariantMap &, QGeoServiceProvider::Error *, QString *) const
{
// Not implemented for QGC
return NULL;
}
QPlaceManagerEngine *QGeoServiceProviderFactoryQGC::createPlaceManagerEngine(
//-----------------------------------------------------------------------------
QPlaceManagerEngine*
QGeoServiceProviderFactoryQGC::createPlaceManagerEngine(
const QVariantMap &, QGeoServiceProvider::Error *, QString *) const
{
// Not implemented for QGC
......
......@@ -44,8 +44,8 @@
**
****************************************************************************/
#ifndef QGEOSERVICEPROVIDER_GOOGLE_H
#define QGEOSERVICEPROVIDER_GOOGLE_H
#ifndef QGEOSERVICEPROVIDERQGC_H
#define QGEOSERVICEPROVIDERQGC_H
#include <QtCore/QObject>
#include <QtLocation/QGeoServiceProviderFactory>
......@@ -64,4 +64,4 @@ public:
QPlaceManagerEngine* createPlaceManagerEngine (const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const;
};
#endif // QGEOSERVICEPROVIDER_GOOGLE_H
#endif // QGEOSERVICEPROVIDERQGC_H
/****************************************************************************
**
** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
** 2015.4.4
** Adapted for use with QGroundControl
**
** Gus Grubba <mavlink@grubba.com>
**
****************************************************************************/
#include <QtCore/QLocale>
#include <QtNetwork/QNetworkRequest>
#include <QtLocation/private/qgeotilespec_p.h>
#include "QGCMapEngine.h"
#include "QGeoTileFetcherQGC.h"
#include "QGeoMapReplyQGC.h"
//-----------------------------------------------------------------------------
QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
: QGeoTileFetcher(parent)
, _networkManager(new QNetworkAccessManager(this))
{
}
//-----------------------------------------------------------------------------
QGeoTileFetcherQGC::~QGeoTileFetcherQGC()
{
}
//-----------------------------------------------------------------------------
QGeoTiledMapReply*
QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec)
{
//-- Build URL
QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom(), _networkManager);
return new QGeoTiledMapReplyQGC(_networkManager, request, spec);
}
......@@ -44,12 +44,12 @@
**
****************************************************************************/
#ifndef QGEOTILEFETCHERGOOGLE_H
#define QGEOTILEFETCHERGOOGLE_H
#ifndef QGEOTILEFETCHERQGC_H
#define QGEOTILEFETCHERQGC_H
#include <QtLocation/private/qgeotilefetcher_p.h>
#include <QtLocation/private/qgeotilecache_p.h>
#include "OpenPilotMaps.h"
#include "QGCMapUrlEngine.h"
class QGeoTiledMappingManagerEngine;
class QNetworkAccessManager;
......@@ -57,19 +57,13 @@ class QNetworkAccessManager;
class QGeoTileFetcherQGC : public QGeoTileFetcher
{
Q_OBJECT
public:
explicit QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent = 0);
explicit QGeoTileFetcherQGC (QGeoTiledMappingManagerEngine *parent = 0);
~QGeoTileFetcherQGC();
void setUserAgent(const QByteArray &userAgent);
private:
QGeoTiledMapReply* getTileImage(const QGeoTileSpec &spec);
QNetworkAccessManager* m_networkManager;
QByteArray m_userAgent;
OpenPilot::UrlFactory* m_UrlFactory;
QString m_Language;
QGeoTiledMapReply* getTileImage (const QGeoTileSpec &spec);
private:
QNetworkAccessManager* _networkManager;
};
#endif // QGEOTILEFETCHERGOOGLE_H
#endif // QGEOTILEFETCHERQGC_H
......@@ -54,11 +54,12 @@
#include <QDir>
#include <QStandardPaths>
#include "qgeotiledmappingmanagerengineqgc.h"
#include "qgeotilefetcherqgc.h"
#include "OpenPilotMaps.h"
#include "QGCMapEngine.h"
#include "QGeoTiledMappingManagerEngineQGC.h"
#include "QGeoTileFetcherQGC.h"
#if QT_VERSION >= 0x050500
//-----------------------------------------------------------------------------
QGeoTiledMapQGC::QGeoTiledMapQGC(QGeoTiledMappingManagerEngine *engine, QObject *parent)
: QGeoTiledMap(engine, parent)
{
......@@ -66,9 +67,11 @@ QGeoTiledMapQGC::QGeoTiledMapQGC(QGeoTiledMappingManagerEngine *engine, QObject
}
#endif
//-----------------------------------------------------------------------------
QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
: QGeoTiledMappingManagerEngine()
{
QGeoCameraCapabilities cameraCaps;
cameraCaps.setMinimumZoomLevel(2.0);
cameraCaps.setMaximumZoomLevel(MAX_MAP_ZOOM);
......@@ -77,32 +80,70 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian
setTileSize(QSize(256, 256));
/*
* Most of these don't seem kosher at all. This was based on original code from OpenPilot and heavily modified to be used in QGC.
*/
//-- IMPORTANT
// Changes here must reflect those in QGCMapEngine.cpp
QList<QGeoMapType> mapTypes;
mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Google Street Map"), tr("Google street map"), false, false, OpenPilot::GoogleMap);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Google Satellite Map"),tr("Google satellite map"), false, false, OpenPilot::GoogleSatellite);
mapTypes << QGeoMapType(QGeoMapType::TerrainMap, tr("Google Terrain Map"), tr("Google terrain map"), false, false, OpenPilot::GoogleTerrain);
// TODO:
// Proper google hybrid maps requires collecting two separate bimaps and overlaying them.
//mapTypes << QGeoMapType(QGeoMapType::HybridMap, tr("Google Hybrid Map"), tr("Google hybrid map"), false, false, OpenPilot::GoogleHybrid);
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Google Street Map", "Google street map", false, false, UrlFactory::GoogleMap);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Google Satellite Map", "Google satellite map", false, false, UrlFactory::GoogleSatellite);
mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Google Terrain Map", "Google terrain map", false, false, UrlFactory::GoogleTerrain);
/* TODO:
* Proper google hybrid maps requires collecting two separate bimaps and overlaying them.
*
* mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Google Hybrid Map", "Google hybrid map", false, false, UrlFactory::GoogleHybrid);
*
*/
// Bing
mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Bing Street Map"), tr("Bing street map"), false, false, OpenPilot::BingMap);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Bing Satellite Map"), tr("Bing satellite map"), false, false, OpenPilot::BingSatellite);
mapTypes << QGeoMapType(QGeoMapType::HybridMap, tr("Bing Hybrid Map"), tr("Bing hybrid map"), false, false, OpenPilot::BingHybrid);
mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Open Street Map"), tr("Open Street map"), false, false, OpenPilot::OpenStreetMap);
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Bing Street Map", "Bing street map", false, false, UrlFactory::BingMap);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Bing Satellite Map", "Bing satellite map", false, false, UrlFactory::BingSatellite);
mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Bing Hybrid Map", "Bing hybrid map", false, false, UrlFactory::BingHybrid);
/* See: https://wiki.openstreetmap.org/wiki/Tile_usage_policy
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Open Street Map", "Open Street map", false, false, UrlFactory::OpenStreetMap);
*/
// MapQuest
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapQuest Street Map", "MapQuest street map", false, false, UrlFactory::MapQuestMap);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapQuest Satellite Map", "MapQuest satellite map", false, false, UrlFactory::MapQuestSat);
/*
* These are OK as you need your own token for accessing it. Out-of-the box, QGC does not even offer these unless you enter a proper MapBox token.
*/
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Street Map", "MapBox Street Map", false, false, UrlFactory::MapBoxStreets);
mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapBox Satellite Map", "MapBox Satellite Map", false, false, UrlFactory::MapBoxSatellite);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox High Contrast Map", "MapBox High Contrast Map", false, false, UrlFactory::MapBoxHighContrast);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Light Map", "MapBox Light Map", false, false, UrlFactory::MapBoxLight);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Dark Map", "MapBox Dark Map", false, false, UrlFactory::MapBoxDark);
mapTypes << QGeoMapType(QGeoMapType::HybridMap, "MapBox Hybrid Map", "MapBox Hybrid Map", false, false, UrlFactory::MapBoxHybrid);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Wheat Paste Map", "MapBox Wheat Paste Map", false, false, UrlFactory::MapBoxWheatPaste);
mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Streets Basic Map", "MapBox Streets Basic Map", false, false, UrlFactory::MapBoxStreetsBasic);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Comic Map", "MapBox Comic Map", false, false, UrlFactory::MapBoxComic);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Outdoors Map", "MapBox Outdoors Map", false, false, UrlFactory::MapBoxOutdoors);
mapTypes << QGeoMapType(QGeoMapType::CycleMap, "MapBox Run, Byke and Hike Map", "MapBox Run, Byke and Hike Map", false, false, UrlFactory::MapBoxRunBikeHike);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pencil Map", "MapBox Pencil Map", false, false, UrlFactory::MapBoxPencil);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pirates Map", "MapBox Pirates Map", false, false, UrlFactory::MapBoxPirates);
mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Emerald Map", "MapBox Emerald Map", false, false, UrlFactory::MapBoxEmerald);
setSupportedMapTypes(mapTypes);
QGeoTileFetcherQGC *tileFetcher = new QGeoTileFetcherQGC(this);
//-- Users (QML code) can define a different user agent
if (parameters.contains(QStringLiteral("useragent"))) {
const QByteArray ua = parameters.value(QStringLiteral("useragent")).toString().toLatin1();
tileFetcher->setUserAgent(ua);
} else
// QGC Default
tileFetcher->setUserAgent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7");
getQGCMapEngine()->setUserAgent(parameters.value(QStringLiteral("useragent")).toString().toLatin1());
}
#if QT_VERSION >= 0x050500
_setCache(parameters);
#endif
setTileFetcher(tileFetcher);
setTileFetcher(new QGeoTileFetcherQGC(this));
*error = QGeoServiceProvider::NoError;
errorString->clear();
......@@ -113,12 +154,14 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian
#endif
}
//-----------------------------------------------------------------------------
QGeoTiledMappingManagerEngineQGC::~QGeoTiledMappingManagerEngineQGC()
{
}
#if QT_VERSION < 0x050500
//-----------------------------------------------------------------------------
QGeoMapData *QGeoTiledMappingManagerEngineQGC::createMapData()
{
return new QGeoTiledMapData(this, 0);
......@@ -126,12 +169,16 @@ QGeoMapData *QGeoTiledMappingManagerEngineQGC::createMapData()
#else
QGeoMap *QGeoTiledMappingManagerEngineQGC::createMap()
//-----------------------------------------------------------------------------
QGeoMap*
QGeoTiledMappingManagerEngineQGC::createMap()
{
return new QGeoTiledMapQGC(this);
}
QString QGeoTiledMappingManagerEngineQGC::customCopyright() const
//-----------------------------------------------------------------------------
QString
QGeoTiledMappingManagerEngineQGC::customCopyright() const
{
return m_customCopyright;
}
......@@ -139,18 +186,11 @@ QString QGeoTiledMappingManagerEngineQGC::customCopyright() const
#endif
#if QT_VERSION >= 0x050500
void QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap &parameters)
//-----------------------------------------------------------------------------
void
QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap &parameters)
{
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache");
//-- Clear old cache
QDir baseDir(cacheDir);
if (baseDir.exists()) {
const QStringList oldCacheFiles = baseDir.entryList(QDir::Files);
foreach (const QString& file, oldCacheFiles)
baseDir.remove(file);
}
QString cacheDir;
if (parameters.contains(QStringLiteral("mapping.cache.directory")))
cacheDir = parameters.value(QStringLiteral("mapping.cache.directory")).toString();
else {
......@@ -160,52 +200,34 @@ void QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap &parameters)
cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/");
}
}
if(!QDir::root().mkpath(cacheDir))
{
qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
cacheDir.clear();
if(!QFileInfo(cacheDir).exists()) {
if(!QDir::root().mkpath(cacheDir)) {
qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
cacheDir.clear();
}
}
else {
qDebug() << "Mapping cache directory:" << cacheDir;
//-- Memory Cache
uint32_t memLimit = 0;
if (parameters.contains(QStringLiteral("mapping.cache.memory.size"))) {
bool ok = false;
memLimit = parameters.value(QStringLiteral("mapping.cache.memory.size")).toString().toUInt(&ok);
if (!ok)
memLimit = 0;
}
if(!memLimit)
{
//-- Value saved in MB
memLimit = getQGCMapEngine()->getMaxMemCache() * (1024 * 1024);
}
//-- It won't work with less than 1M of memory cache
if(memLimit < 1024 * 1024)
memLimit = 1024 * 1024;
//-- Disable Qt's disk cache (set memory cache otherwise Qtlocation won't work)
QGeoTileCache* pTileCache = createTileCacheWithDir(cacheDir);
if(pTileCache)
{
int cacheLimit = 0;
//-- Disk Cache
if (parameters.contains(QStringLiteral("mapping.cache.disk.size"))) {
bool ok = false;
cacheLimit = parameters.value(QStringLiteral("mapping.cache.disk.size")).toString().toInt(&ok);
if (!ok)
cacheLimit = 0;
}
if(!cacheLimit)
{
#ifdef __mobile__
cacheLimit = 128 * 1024 * 1024;
#else
cacheLimit = 1024 * 1024 * 1024;
#endif
}
pTileCache->setMaxDiskUsage(cacheLimit);
//-- Memory Cache
cacheLimit = 0;
if (parameters.contains(QStringLiteral("mapping.cache.memory.size"))) {
bool ok = false;
cacheLimit = parameters.value(QStringLiteral("mapping.cache.memory.size")).toString().toInt(&ok);
if (!ok)
cacheLimit = 0;
}
if(!cacheLimit)
{
#ifdef __mobile__
cacheLimit = 16 * 1024 * 1024;
#else
cacheLimit = 128 * 1024 * 1024;
#endif
}
pTileCache->setMaxMemoryUsage(cacheLimit);
pTileCache->setMaxDiskUsage(1);
pTileCache->setMaxMemoryUsage(memLimit);
}
}
#endif
......@@ -44,8 +44,8 @@
**
****************************************************************************/
#ifndef QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
#define QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
#ifndef QGEOTILEDMAPPINGMANAGERENGINEQGC_H
#define QGEOTILEDMAPPINGMANAGERENGINEQGC_H
#include <QtLocation/QGeoServiceProvider>
#if QT_VERSION >= 0x050500
......@@ -62,6 +62,8 @@ public:
};
#endif
class QGeoTileFetcherQGC;
class QGeoTiledMappingManagerEngineQGC : public QGeoTiledMappingManagerEngine
{
Q_OBJECT
......@@ -81,4 +83,4 @@ private:
#endif
};
#endif // QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
#endif // QGEOTILEDMAPPINGMANAGERENGINEQGC_H
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.2
import QtLocation 5.3
import QtPositioning 5.3
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
Rectangle {
id: _offlineMapRoot
color: __qgcPal.window
anchors.fill: parent
anchors.margins: ScreenTools.defaultFontPixelWidth
property var _currentSelection: null
property string mapKey: "lastMapType"
property string mapType: QGroundControl.mapEngineManager.loadSetting(mapKey, "Google Street Map")
property int mapMargin: (ScreenTools.defaultFontPixelHeight * 0.2).toFixed(0)
property real infoWidth: Math.max(Math.max(nameLabel.width, descLabel.width), (ScreenTools.defaultFontPixelWidth * 40))
property bool isDefaultSet: _offlineMapRoot._currentSelection && _offlineMapRoot._currentSelection.defaultSet
property real oldlon0: 0
property real oldlon1: 0
property real oldlat0: 0
property real oldlat1: 0
property int oldz0: 0
property int oldz1: 0
Component.onCompleted: {
QGroundControl.mapEngineManager.loadTileSets()
updateMap()
}
Connections {
target: QGroundControl.mapEngineManager
onTileSetsChanged: {
setName.text = QGroundControl.mapEngineManager.getUniqueName()
}
onErrorMessageChanged: {
errorDialog.visible = true
}
}
ExclusiveGroup { id: setGroup }
function handleChanges() {
var xl = mapMargin
var yl = mapMargin
var xr = _map.width.toFixed(0) - mapMargin
var yr = _map.height.toFixed(0) - mapMargin
var c0 = _map.toCoordinate(Qt.point(xl, yl))
var c1 = _map.toCoordinate(Qt.point(xr, yr))
if(oldlon0 !== c0.longitude || oldlat0 !== c0.latitude || oldlon1 !== c1.longitude || oldlat1 !== c1.latitude || oldz0 !== _slider0.value || oldz1 !== _slider1.value) {
QGroundControl.mapEngineManager.updateForCurrentView(c0.longitude, c0.latitude, c1.longitude, c1.latitude, _slider0.value, _slider1.value, mapType)
}
}
function checkSanity() {
if(QGroundControl.mapEngineManager.crazySize) {
_slider1.value = _slider1.value - 1
handleChanges()
}
}
function updateMap() {
for (var i = 0; i < _map.supportedMapTypes.length; i++) {
if (mapType === _map.supportedMapTypes[i].name) {
_map.activeMapType = _map.supportedMapTypes[i]
handleChanges()
return
}
}
}
function showOptions() {
_tileSetList.visible = false
_infoView.visible = false
_mapView.visible = false
_optionsView.visible = true
}
function showMap() {
_tileSetList.visible = false
_infoView.visible = false
_mapView.visible = true
_optionsView.visible = false
}
function showList() {
_tileSetList.visible = true
_infoView.visible = false
_mapView.visible = false
_optionsView.visible = false
}
function showInfo() {
if(_currentSelection && !_offlineMapRoot._currentSelection.deleting) {
_tileSetList.visible = false
_mapView.visible = false
_infoView.visible = true
_optionsView.visible = false
} else
showList()
}
ExclusiveGroup {
id: _dropButtonsExclusiveGroup
}
onMapTypeChanged: {
updateMap()
QGroundControl.mapEngineManager.saveSetting(mapKey, mapType)
}
MessageDialog {
id: errorDialog
visible: false
text: QGroundControl.mapEngineManager.errorMessage
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
title: "Errror Message"
onYes: {
errorDialog.visible = false
}
}
Rectangle {
id: _offlineMapTopRect
width: parent.width
height: labelTitle.height + ScreenTools.defaultFontPixelHeight
color: __qgcPal.window
anchors.top: parent.top
Row {
spacing: ScreenTools.defaultFontPixelHeight * 2
anchors.verticalCenter: parent.verticalCenter
QGCLabel {
id: labelTitle
text: "Offline Maps"
font.pixelSize: ScreenTools.mediumFontPixelSize
anchors.verticalCenter: parent.verticalCenter
}
QGCCheckBox {
id: showTilePreview
text: "Show tile min/max zoom level preview"
checked: false
visible: _mapView.visible
anchors.verticalCenter: parent.verticalCenter
}
}
}
QGCFlickable {
id: _tileSetList
clip: true
anchors.top: _offlineMapTopRect.bottom
width: parent.width
height: parent.height - _offlineMapTopRect.height
contentHeight: _cacheList.height
contentWidth: parent.width
flickableDirection: Flickable.VerticalFlick
Column {
id: _cacheList
width: _offlineMapRoot.width
anchors.margins: ScreenTools.defaultFontPixelWidth
spacing: (ScreenTools.defaultFontPixelHeight * 0.5).toFixed(0)
OfflineMapButton {
text: "Add new set"
width: (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)
height: (ScreenTools.defaultFontPixelHeight * 2).toFixed(0)
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
_offlineMapRoot._currentSelection = null
showMap()
}
}
Repeater {
model: QGroundControl.mapEngineManager.tileSets
delegate: OfflineMapButton {
text: object.name
size: object.downloadStatus
complete: object.complete
width: (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)
height: (ScreenTools.defaultFontPixelHeight * 2).toFixed(0)
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
_offlineMapRoot._currentSelection = object
showInfo()
}
}
}
}
}
QGCButton {
id: _optionsButton
text: "Options"
width: ScreenTools.defaultFontPixelWidth * 10
visible: _tileSetList.visible
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: ScreenTools.defaultFontPixelWidth
onClicked: showOptions()
}
//-- Offline Map Definition
Rectangle {
id: _mapView
color: __qgcPal.window
width: parent.width
anchors.top: _offlineMapTopRect.bottom
anchors.bottom: parent.bottom
anchors.margins: ScreenTools.defaultFontPixelWidth
visible: false
Rectangle {
width: parent.width
anchors.top: parent.top
anchors.bottom: bottomRect.top
color: (__qgcPal.globalTheme === QGCPalette.Light) ? "black" : "#98aca4"
Map {
id: _map
anchors.fill: parent
anchors.margins: ScreenTools.defaultFontPixelHeight * 0.15
zoomLevel: 10
center: QGroundControl.defaultMapPosition
gesture.flickDeceleration: 3000
gesture.activeGestures: MapGestureArea.ZoomGesture | MapGestureArea.PanGesture | MapGestureArea.FlickGesture
plugin: Plugin { name: "QGroundControl" }
onCenterChanged: {
handleChanges()
checkSanity()
}
onZoomLevelChanged: {
handleChanges()
checkSanity()
}
onWidthChanged: {
handleChanges()
checkSanity()
}
onHeightChanged: {
handleChanges()
checkSanity()
}
}
Rectangle {
width: ScreenTools.defaultFontPixelHeight * 16
height: ScreenTools.defaultFontPixelHeight * 9
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: ScreenTools.defaultFontPixelHeight
color: "black"
visible: showTilePreview.checked
Map {
id: _mapMin
anchors.fill: parent
anchors.margins: 2
zoomLevel: _slider0.value
center: _map.center
gesture.enabled: false
activeMapType: _map.activeMapType
plugin: Plugin { name: "QGroundControl" }
}
}
Rectangle {
width: ScreenTools.defaultFontPixelHeight * 16
height: ScreenTools.defaultFontPixelHeight * 9
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: ScreenTools.defaultFontPixelHeight
color: "black"
visible: showTilePreview.checked
Map {
id: _mapMax
anchors.fill: parent
anchors.margins: 2
zoomLevel: _slider1.value
center: _map.center
gesture.enabled: false
activeMapType: _map.activeMapType
plugin: Plugin { name: "QGroundControl" }
}
}
}
Rectangle {
id: bottomRect
width: parent.width
height: _controlRow.height + (ScreenTools.defaultFontPixelHeight * 2)
color: __qgcPal.window
anchors.bottom: parent.bottom
Row {
id: _controlRow
anchors.centerIn: parent
spacing: ScreenTools.defaultFontPixelWidth * 2
Rectangle {
height: _zoomRow.height + ScreenTools.defaultFontPixelHeight * 1.5
width: _zoomRow.width + ScreenTools.defaultFontPixelWidth
color: "#98aca4"
border.color: "black"
border.width: 2
radius: ScreenTools.defaultFontPixelWidth * 0.5
anchors.verticalCenter: parent.verticalCenter
Row {
id: _zoomRow
anchors.centerIn: parent
Column {
spacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.verticalCenter: parent.verticalCenter
Row {
spacing: ScreenTools.defaultFontPixelWidth * 0.5
Column {
anchors.verticalCenter: parent.verticalCenter
Label {
text: "Min"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 5
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
Label {
text: "Zoom"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 5
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
}
Slider {
id: _slider0
minimumValue: 3
maximumValue: 18
stepSize: 1
tickmarksEnabled: false
orientation: Qt.Horizontal
updateValueWhileDragging: true
anchors.verticalCenter: parent.verticalCenter
style: SliderStyle {
groove: Rectangle {
implicitWidth: ScreenTools.defaultFontPixelWidth * 16
implicitHeight: 4
color: "gray"
radius: 4
}
handle: Rectangle {
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 30
implicitHeight: 30
radius: 10
Label {
text: _slider0.value
anchors.centerIn: parent
}
}
}
Component.onCompleted: {
_slider0.value = _map.zoomLevel - 2
}
onValueChanged: {
if(_slider1) {
if(_slider0.value > _slider1.value)
_slider1.value = _slider0.value
else {
handleChanges()
checkSanity()
}
}
}
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth * 0.5
Column {
anchors.verticalCenter: parent.verticalCenter
Label {
text: "Max"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 5
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
Label {
text: "Zoom"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 5
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
}
Slider {
id: _slider1
minimumValue: 3
maximumValue: 18
stepSize: 1
tickmarksEnabled: false
orientation: Qt.Horizontal
updateValueWhileDragging: true
anchors.verticalCenter: parent.verticalCenter
style: SliderStyle {
groove: Rectangle {
implicitWidth: ScreenTools.defaultFontPixelWidth * 16
implicitHeight: 4
color: "gray"
radius: 4
}
handle: Rectangle {
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 30
implicitHeight: 30
radius: 10
Label {
text: _slider1.value
anchors.centerIn: parent
}
}
}
Component.onCompleted: {
_slider1.value = _map.zoomLevel + 2
}
onValueChanged: {
if(_slider1.value < _slider0.value)
_slider0.value = _slider1.value
else {
handleChanges()
checkSanity()
}
}
}
}
}
Column {
spacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.verticalCenter: parent.verticalCenter
Label {
text: "Tile Count"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 12
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
Label {
text: QGroundControl.mapEngineManager.tileCountStr
color: "black"
width: ScreenTools.defaultFontPixelWidth * 12
horizontalAlignment: Text.AlignHCenter
}
Label {
text: "Set Size (Est)"
color: "black"
width: ScreenTools.defaultFontPixelWidth * 12
font.pixelSize: ScreenTools.smallFontPixelSize
horizontalAlignment: Text.AlignHCenter
}
Label {
text: QGroundControl.mapEngineManager.tileSizeStr
color: "black"
width: ScreenTools.defaultFontPixelWidth * 12
horizontalAlignment: Text.AlignHCenter
}
}
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: ScreenTools.defaultFontPixelHeight * 0.5
Row {
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCLabel {
text: "Name:"
width: ScreenTools.defaultFontPixelWidth * 10
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
}
QGCTextField {
id: setName
width: ScreenTools.defaultFontPixelWidth * 30
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCLabel {
text: "Description:"
width: ScreenTools.defaultFontPixelWidth * 10
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
}
QGCTextField {
id: setDescription
text: "Description"
width: ScreenTools.defaultFontPixelWidth * 30
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCLabel {
text: "Map Type:"
width: ScreenTools.defaultFontPixelWidth * 10
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
}
QGCComboBox {
id: mapCombo
width: ScreenTools.defaultFontPixelWidth * 30
model: QGroundControl.mapEngineManager.mapList
onActivated: {
mapType = textAt(index)
if(_dropButtonsExclusiveGroup.current)
_dropButtonsExclusiveGroup.current.checked = false
_dropButtonsExclusiveGroup.current = null
}
Component.onCompleted: {
var index = mapCombo.find(mapType)
if (index === -1) {
console.warn("Active map name not in combo", mapType)
} else {
mapCombo.currentIndex = index
}
}
}
}
}
Item {
height: 1
width: ScreenTools.defaultFontPixelWidth * 2
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: ScreenTools.defaultFontPixelHeight * 0.5
QGCButton {
text: "Download"
enabled: setName.text.length > 0
width: ScreenTools.defaultFontPixelWidth * 10
onClicked: {
if(QGroundControl.mapEngineManager.findName(setName.text)) {
duplicateName.visible = true
} else {
/* Broken in Qt 5.5.1
var mapImage
_map.grabToImage(function(result) { mapImage = result; })
QGroundControl.mapEngineManager.startDownload(setName.text, setDescription.text, mapType, mapImage);
*/
QGroundControl.mapEngineManager.startDownload(setName.text, setDescription.text, mapType);
showList()
}
}
}
QGCButton {
text: "Cancel"
width: ScreenTools.defaultFontPixelWidth * 10
onClicked: {
showList()
}
}
MessageDialog {
id: duplicateName
visible: false
icon: StandardIcon.Warning
standardButtons: StandardButton.Ok
title: "Tile Set Already Exists"
text: "Tile Set \"" + setName.text + "\" already exists.\nPlease select a different name."
onYes: {
duplicateName.visible = false
}
}
}
}
}
}
Rectangle {
id: _infoView
color: __qgcPal.windowShade
width: parent.width
anchors.top: _offlineMapTopRect.bottom
anchors.bottom: parent.bottom
anchors.margins: ScreenTools.defaultFontPixelWidth
visible: false
Column {
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight
Item {
height: ScreenTools.defaultFontPixelHeight
width: 1
}
Rectangle {
width: infoWidth
height: nameLabel.height + (ScreenTools.defaultFontPixelHeight * 2)
color: __qgcPal.window
radius: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel {
id: nameLabel
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.name : ""
font.pixelSize: ScreenTools.largeFontPixelSize
anchors.centerIn: parent
}
}
QGCLabel {
id: descLabel
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.description : ""
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
id: infoRect
width: infoWidth
height: infoGrid.height + (ScreenTools.defaultFontPixelHeight * 4)
color: __qgcPal.window
radius: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
GridLayout {
id: infoGrid
columns: 2
anchors.centerIn: parent
anchors.margins: ScreenTools.defaultFontPixelWidth * 2
rowSpacing: ScreenTools.defaultFontPixelWidth
columnSpacing: ScreenTools.defaultFontPixelHeight * 2
QGCLabel {
text: "Map Type:"
visible: !isDefaultSet
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.mapTypeStr : ""
visible: !isDefaultSet
}
QGCLabel {
text: "Min Zoom:"
visible: !isDefaultSet
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.minZoom : ""
visible: !isDefaultSet
}
QGCLabel {
text: "Max Zoom:"
visible: !isDefaultSet
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.maxZoom : ""
visible: !isDefaultSet
}
QGCLabel {
text: isDefaultSet ? "Default Set Size:" : "Total Size:"
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.tilesSizeStr : ""
}
QGCLabel {
text: isDefaultSet ? "Default Set Tile Count:" : "Total Tile Count:"
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.numTilesStr : ""
}
QGCLabel {
text: isDefaultSet ? "Total Size:" : "Downloaded Size:"
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.savedSizeStr : ""
}
QGCLabel {
text: isDefaultSet ? "Total Count:" : "Downloaded Count:"
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.savedTilesStr : ""
}
QGCLabel {
text: "Error Count:"
visible: !isDefaultSet && _offlineMapRoot._currentSelection && !_offlineMapRoot._currentSelection.complete
}
QGCLabel {
text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.errorCountStr : ""
visible: !isDefaultSet && _offlineMapRoot._currentSelection && !_offlineMapRoot._currentSelection.complete
}
}
}
Item {
height: ScreenTools.defaultFontPixelHeight
width: 1
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Back"
width: ScreenTools.defaultFontPixelWidth * 18
onClicked: showList()
}
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 18
text: "Delete"
enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting)
onClicked: {
if(_offlineMapRoot._currentSelection)
deleteDialog.visible = true
}
MessageDialog {
id: deleteDialog
visible: false
icon: StandardIcon.Warning
standardButtons: StandardButton.Yes | StandardButton.No
title: "Delete Tile Set"
text: {
if(_offlineMapRoot._currentSelection) {
var blurb = "Delete " + _offlineMapRoot._currentSelection.name + " and all its tiles.\nIs this really what you want?"
if(_offlineMapRoot._currentSelection.defaultSet)
return blurb + "\nNote that deleteting the Default Set deletes all tiles from all sets."
else
return blurb
}
return ""
}
onYes: {
if(_offlineMapRoot._currentSelection)
QGroundControl.mapEngineManager.deleteTileSet(_offlineMapRoot._currentSelection)
deleteDialog.visible = false
showList()
}
onNo: {
deleteDialog.visible = false
}
}
}
QGCButton {
text: "Resume Download"
width: ScreenTools.defaultFontPixelWidth * 18
enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting && !_offlineMapRoot._currentSelection.downloading)
visible: !isDefaultSet && _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.complete && !_offlineMapRoot._currentSelection.downloading)
onClicked: {
if(_offlineMapRoot._currentSelection)
_offlineMapRoot._currentSelection.resumeDownloadTask()
}
}
QGCButton {
text: "Cancel Download"
width: ScreenTools.defaultFontPixelWidth * 18
enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting && _offlineMapRoot._currentSelection.downloading)
visible: !isDefaultSet && _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.complete && _offlineMapRoot._currentSelection.downloading)
onClicked: {
if(_offlineMapRoot._currentSelection)
_offlineMapRoot._currentSelection.cancelDownloadTask()
}
}
}
}
}
Rectangle {
id: _optionsView
color: __qgcPal.windowShade
width: parent.width
anchors.top: _offlineMapTopRect.bottom
anchors.bottom: parent.bottom
anchors.margins: ScreenTools.defaultFontPixelWidth
visible: false
onVisibleChanged: {
if(_optionsView.visible) {
mapBoxToken.text = QGroundControl.mapEngineManager.mapboxToken
maxCacheSize.text = QGroundControl.mapEngineManager.maxDiskCache
maxCacheMemSize.text = QGroundControl.mapEngineManager.maxDiskCache
}
}
Column {
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight
Item {
height: ScreenTools.defaultFontPixelHeight
width: 1
}
Rectangle {
width: infoWidth
height: optionsLabel.height + (ScreenTools.defaultFontPixelHeight * 2)
color: __qgcPal.window
radius: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel {
id: optionsLabel
text: "Offline Map Options"
font.pixelSize: ScreenTools.largeFontPixelSize
anchors.centerIn: parent
}
}
Rectangle {
id: optionsRect
width: optionsGrid.width + (ScreenTools.defaultFontPixelWidth * 4)
height: optionsGrid.height + (ScreenTools.defaultFontPixelHeight * 4)
color: __qgcPal.window
radius: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
GridLayout {
id: optionsGrid
columns: 2
anchors.centerIn: parent
anchors.margins: ScreenTools.defaultFontPixelWidth * 2
rowSpacing: ScreenTools.defaultFontPixelWidth * 1.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 2
QGCLabel {
text: "Max Cache Disk Size (MB):"
}
QGCTextField {
id: maxCacheSize
maximumLength: 256
inputMethodHints: Qt.ImhDigitsOnly
validator: IntValidator {bottom: 1; top: 262144;}
}
QGCLabel {
text: "Max Cache Memory Size (MB):"
}
QGCTextField {
id: maxCacheMemSize
maximumLength: 256
inputMethodHints: Qt.ImhDigitsOnly
validator: IntValidator {bottom: 1; top: 4096;}
}
Item {
Layout.columnSpan: 2
Layout.fillWidth: true
implicitHeight: ScreenTools.defaultFontPixelHeight * 1.5
QGCLabel {
anchors.centerIn: parent
text: "Memory cache changes require a restart to take effect."
font.pixelSize: ScreenTools.defaultFontPixelSize * 0.85
}
}
Rectangle {
Layout.columnSpan: 2
Layout.fillWidth: true
implicitHeight: 1
color: __qgcPal.text
}
QGCLabel {
text: "MapBox Access Token"
}
QGCTextField {
id: mapBoxToken
Layout.fillWidth: true
maximumLength: 256
implicitWidth : ScreenTools.defaultFontPixelHeight * 30
}
Item {
Layout.columnSpan: 2
Layout.fillWidth: true
implicitHeight: ScreenTools.defaultFontPixelHeight * 1.5
QGCLabel {
anchors.centerIn: parent
text: "With an access token, you can use MapBox Maps."
font.pixelSize: ScreenTools.defaultFontPixelSize * 0.85
}
}
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Save"
width: ScreenTools.defaultFontPixelWidth * 18
onClicked: {
showList()
}
}
QGCButton {
text: "Cancel"
width: ScreenTools.defaultFontPixelWidth * 18
onClicked: {
showList()
}
}
}
}
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Gus Grubba <mavlink@grubba.com>
#include "QGCMapEngineManager.h"
#include "QGCApplication.h"
#include <QSettings>
#include "QGCMapTileSet.h"
#include "QGCMapUrlEngine.h"
#include <QStorageInfo>
QGC_LOGGING_CATEGORY(QGCMapEngineManagerLog, "QGCMapEngineManagerLog")
static const char* kQmlOfflineMapKeyName = "QGCOfflineMap";
//-----------------------------------------------------------------------------
QGCMapEngineManager::QGCMapEngineManager(QGCApplication* app)
: QGCTool(app)
, _topleftLat(0.0)
, _topleftLon(0.0)
, _bottomRightLat(0.0)
, _bottomRightLon(0.0)
, _minZoom(0)
, _maxZoom(0)
, _setID(UINT64_MAX)
, _freeDiskSpace(0)
, _diskSpace(0)
{
}
//-----------------------------------------------------------------------------
QGCMapEngineManager::~QGCMapEngineManager()
{
//_clearTileSets();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::setToolbox(QGCToolbox *toolbox)
{
QGCTool::setToolbox(toolbox);
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<QGCMapEngineManager>("QGroundControl.QGCMapEngineManager", 1, 0, "QGCMapEngineManager", "Reference only");
connect(getQGCMapEngine(), &QGCMapEngine::updateTotals, this, &QGCMapEngineManager::_updateTotals);
_updateDiskFreeSpace();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::updateForCurrentView(double lon0, double lat0, double lon1, double lat1, int minZoom, int maxZoom, const QString& mapName)
{
UrlFactory::MapType mapType = QGCMapEngine::getTypeFromName(mapName);
_topleftLat = lat0;
_topleftLon = lon0;
_bottomRightLat = lat1;
_bottomRightLon = lon1;
_minZoom = minZoom;
_maxZoom = maxZoom;
_totalSet.clear();
for(int z = minZoom; z <= maxZoom; z++) {
QGCTileSet set = QGCMapEngine::getTileCount(z, lon0, lat0, lon1, lat1, mapType);
_totalSet += set;
}
//-- Beyond 100,000,000 tiles is just nuts
if(_totalSet.tileCount > 100 * 1000 * 1000) {
_crazySize = true;
emit crazySizeChanged();
} else {
_crazySize = false;
emit crazySizeChanged();
emit tileX0Changed();
emit tileX1Changed();
emit tileY0Changed();
emit tileY1Changed();
emit tileCountChanged();
emit tileSizeChanged();
}
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::tileCountStr()
{
return QGCMapEngine::numberToString(_totalSet.tileCount);
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::tileSizeStr()
{
return QGCMapEngine::bigSizeToString(_totalSet.tileSize);
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::loadTileSets()
{
if(_tileSets.count()) {
_clearTileSets();
emit tileSetsChanged();
}
QGCFetchTileSetTask* task = new QGCFetchTileSetTask();
connect(task, &QGCFetchTileSetTask::tileSetFetched, this, &QGCMapEngineManager::_tileSetFetched);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_tileSetFetched(QGCCachedTileSet* tileSet)
{
//-- A blank (default) type means it uses various types and not just one
if(tileSet->type() == UrlFactory::Invalid) {
tileSet->setMapTypeStr("Various");
}
_tileSets.append(tileSet);
tileSet->setManager(this);
emit tileSetsChanged();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_clearTileSets()
{
while(_tileSets.count()) {
QGCCachedTileSet* tileSet = qobject_cast<QGCCachedTileSet*>(_tileSets[0]);
if(tileSet)
delete tileSet;
_tileSets.removeAt(0);
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::startDownload(const QString& name, const QString& description, const QString& mapType, const QImage& image)
{
if(_totalSet.tileSize) {
QGCCachedTileSet* set = new QGCCachedTileSet(name, description);
set->setMapTypeStr(mapType);
set->setTopleftLat(_topleftLat);
set->setTopleftLon(_topleftLon);
set->setBottomRightLat(_bottomRightLat);
set->setBottomRightLon(_bottomRightLon);
set->setMinZoom(_minZoom);
set->setMaxZoom(_maxZoom);
set->setTilesSize(_totalSet.tileSize);
set->setNumTiles(_totalSet.tileCount);
set->setType(QGCMapEngine::getTypeFromName(mapType));
if(!image.isNull())
set->setThumbNail(image);
QGCCreateTileSetTask* task = new QGCCreateTileSetTask(set);
//-- Create Tile Set (it will also create a list of tiles to download)
connect(task, &QGCCreateTileSetTask::tileSetSaved, this, &QGCMapEngineManager::_tileSetSaved);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
} else {
qWarning() << "QGCMapEngineManager::startDownload() No Tiles to save";
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_tileSetSaved(QGCCachedTileSet *set)
{
qCDebug(QGCMapEngineManagerLog) << "New tile set saved (" << set->name() << "). Starting download...";
_tileSets.append(set);
emit tileSetsChanged();
//-- Start downloading tiles
set->createDownloadTask();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::saveSetting (const QString& key, const QString& value)
{
QSettings settings;
settings.beginGroup(kQmlOfflineMapKeyName);
settings.setValue(key, value);
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::loadSetting (const QString& key, const QString& defaultValue)
{
QSettings settings;
settings.beginGroup(kQmlOfflineMapKeyName);
return settings.value(key, defaultValue).toString();
}
//-----------------------------------------------------------------------------
QStringList
QGCMapEngineManager::mapList()
{
return getQGCMapEngine()->getMapNameList();
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::mapboxToken()
{
return getQGCMapEngine()->getMapBoxToken();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::setMapboxToken(QString token)
{
getQGCMapEngine()->setMapBoxToken(token);
}
//-----------------------------------------------------------------------------
quint32
QGCMapEngineManager::maxMemCache()
{
return getQGCMapEngine()->getMaxMemCache();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::setMaxMemCache(quint32 size)
{
getQGCMapEngine()->setMaxMemCache(size);
}
//-----------------------------------------------------------------------------
quint32
QGCMapEngineManager::maxDiskCache()
{
return getQGCMapEngine()->getMaxDiskCache();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::setMaxDiskCache(quint32 size)
{
getQGCMapEngine()->setMaxDiskCache(size);
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::deleteTileSet(QGCCachedTileSet* tileSet)
{
qCDebug(QGCMapEngineManagerLog) << "Deleting tile set " << tileSet->name();
//-- If deleting default set, delete it all
if(tileSet->defaultSet()) {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setDeleting(true);
}
QGCResetTask* task = new QGCResetTask();
connect(task, &QGCResetTask::resetCompleted, this, &QGCMapEngineManager::_resetCompleted);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
} else {
tileSet->setDeleting(true);
QGCDeleteTileSetTask* task = new QGCDeleteTileSetTask(tileSet->setID());
connect(task, &QGCDeleteTileSetTask::tileSetDeleted, this, &QGCMapEngineManager::_tileSetDeleted);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_resetCompleted()
{
//-- Reload sets
loadTileSets();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_tileSetDeleted(quint64 setID)
{
//-- Tile Set successfully deleted
QGCCachedTileSet* setToDelete = NULL;
int i = 0;
for(i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->setID() == setID) {
setToDelete = set;
break;
}
}
if(setToDelete) {
_tileSets.removeAt(i);
delete setToDelete;
}
emit tileSetsChanged();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::taskError(QGCMapTask::TaskType type, QString error)
{
QString task;
switch(type) {
case QGCMapTask::taskFetchTileSets:
task = "Fetch Tile Set";
break;
case QGCMapTask::taskCreateTileSet:
task = "Create Tile Set";
break;
case QGCMapTask::taskGetTileDownloadList:
task = "Get Tile Download List";
break;
case QGCMapTask::taskUpdateTileDownloadState:
task = "Update Tile Download Status";
break;
case QGCMapTask::taskDeleteTileSet:
task = "Delete Tile Set";
break;
case QGCMapTask::taskReset:
task = "Reset Tile Sets";
break;
default:
task = "Database Error";
break;
}
QString serror = "Error in task: " + task;
serror += "\nError description:\n";
serror += error;
qWarning() << "QGCMapEngineManager::_taskError()";
setErrorMessage(serror);
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
{
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->defaultSet()) {
set->setSavedSize(totalsize);
set->setSavedTiles(totaltiles);
set->setNumTiles(defaulttiles);
set->setTilesSize(defaultsize);
return;
}
}
_updateDiskFreeSpace();
}
//-----------------------------------------------------------------------------
bool
QGCMapEngineManager::findName(const QString& name)
{
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->name() == name) {
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::getUniqueName()
{
QString test = "Tile Set ";
QString name;
int count = 1;
while (true) {
char numb[16];
snprintf(numb, sizeof(numb), "%03d", count++);
name = test;
name += numb;
if(!findName(name))
return name;
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_updateDiskFreeSpace()
{
QString path = getQGCMapEngine()->getCachePath();
if(!path.isEmpty()) {
QStorageInfo info(path);
quint32 total = (quint32)(info.bytesTotal() / 1024);
quint32 free = (quint32)(info.bytesFree() / 1024);
qCDebug(QGCMapEngineManagerLog) << info.rootPath() << "has" << free << "Mbytes available.";
if(_freeDiskSpace != free) {
_freeDiskSpace = free;
_diskSpace = total;
emit freeDiskSpaceChanged();
}
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Gus Grubba <mavlink@grubba.com>
#ifndef OfflineMapsManager_H
#define OfflineMapsManager_H
#include "QmlObjectListModel.h"
#include "QGCToolbox.h"
#include "QGCLoggingCategory.h"
#include "QGCMapEngine.h"
#include "QGCMapTileSet.h"
Q_DECLARE_LOGGING_CATEGORY(QGCMapEngineManagerLog)
class QGCMapEngineManager : public QGCTool
{
Q_OBJECT
public:
QGCMapEngineManager(QGCApplication* app);
~QGCMapEngineManager();
Q_PROPERTY(int tileX0 READ tileX0 NOTIFY tileX0Changed)
Q_PROPERTY(int tileX1 READ tileX1 NOTIFY tileX1Changed)
Q_PROPERTY(int tileY0 READ tileY0 NOTIFY tileY0Changed)
Q_PROPERTY(int tileY1 READ tileY1 NOTIFY tileY1Changed)
Q_PROPERTY(quint64 tileCount READ tileCount NOTIFY tileCountChanged)
Q_PROPERTY(QString tileCountStr READ tileCountStr NOTIFY tileCountChanged)
Q_PROPERTY(quint64 tileSize READ tileSize NOTIFY tileSizeChanged)
Q_PROPERTY(QString tileSizeStr READ tileSizeStr NOTIFY tileSizeChanged)
Q_PROPERTY(bool crazySize READ crazySize NOTIFY crazySizeChanged)
Q_PROPERTY(QmlObjectListModel* tileSets READ tileSets NOTIFY tileSetsChanged)
Q_PROPERTY(QStringList mapList READ mapList CONSTANT)
Q_PROPERTY(QString mapboxToken READ mapboxToken WRITE setMapboxToken NOTIFY mapboxTokenChanged)
Q_PROPERTY(quint32 maxMemCache READ maxMemCache WRITE setMaxMemCache NOTIFY maxMemCacheChanged)
Q_PROPERTY(quint32 maxDiskCache READ maxDiskCache WRITE setMaxDiskCache NOTIFY maxDiskCacheChanged)
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
//-- Disk Space in MB
Q_PROPERTY(quint32 freeDiskSpace READ freeDiskSpace NOTIFY freeDiskSpaceChanged)
Q_PROPERTY(quint32 diskSpace READ diskSpace CONSTANT)
Q_INVOKABLE void loadTileSets ();
Q_INVOKABLE void updateForCurrentView (double lon0, double lat0, double lon1, double lat1, int minZoom, int maxZoom, const QString& mapName);
Q_INVOKABLE void startDownload (const QString& name, const QString& description, const QString& mapType, const QImage& image = QImage());
Q_INVOKABLE void saveSetting (const QString& key, const QString& value);
Q_INVOKABLE QString loadSetting (const QString& key, const QString& defaultValue);
Q_INVOKABLE void deleteTileSet (QGCCachedTileSet* tileSet);
Q_INVOKABLE QString getUniqueName ();
Q_INVOKABLE bool findName (const QString& name);
int tileX0 () { return _totalSet.tileX0; }
int tileX1 () { return _totalSet.tileX1; }
int tileY0 () { return _totalSet.tileY0; }
int tileY1 () { return _totalSet.tileY1; }
quint64 tileCount () { return _totalSet.tileCount; }
QString tileCountStr ();
quint64 tileSize () { return _totalSet.tileSize; }
QString tileSizeStr ();
bool crazySize () { return _crazySize; }
QStringList mapList ();
QString mapboxToken ();
QmlObjectListModel* tileSets () { return &_tileSets; }
quint32 maxMemCache ();
quint32 maxDiskCache ();
QString errorMessage () { return _errorMessage; }
quint64 freeDiskSpace () { return _freeDiskSpace; }
quint64 diskSpace () { return _diskSpace; }
void setMapboxToken (QString token);
void setMaxMemCache (quint32 size);
void setMaxDiskCache (quint32 size);
void setErrorMessage (const QString& error) { _errorMessage = error; emit errorMessageChanged(); }
// Override from QGCTool
void setToolbox(QGCToolbox *toolbox);
signals:
void tileX0Changed ();
void tileX1Changed ();
void tileY0Changed ();
void tileY1Changed ();
void tileCountChanged ();
void tileSizeChanged ();
void crazySizeChanged ();
void mapboxTokenChanged ();
void tileSetsChanged ();
void maxMemCacheChanged ();
void maxDiskCacheChanged ();
void errorMessageChanged ();
void freeDiskSpaceChanged ();
public slots:
void taskError (QGCMapTask::TaskType type, QString error);
private slots:
void _tileSetSaved (QGCCachedTileSet* set);
void _tileSetFetched (QGCCachedTileSet* tileSets);
void _tileSetDeleted (quint64 setID);
void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
void _resetCompleted ();
private:
void _clearTileSets ();
void _updateDiskFreeSpace ();
private:
QGCTileSet _totalSet;
bool _crazySize;
double _topleftLat;
double _topleftLon;
double _bottomRightLat;
double _bottomRightLon;
int _minZoom;
int _maxZoom;
quint64 _setID;
quint32 _freeDiskSpace;
quint32 _diskSpace;
QmlObjectListModel _tileSets;
QString _errorMessage;
};
#endif
/****************************************************************************
**
** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
** 2015.4.4
** Adapted for use with QGroundControl
**
** Gus Grubba <mavlink@grubba.com>
**
****************************************************************************/
#include <QtCore/QLocale>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtLocation/private/qgeotilespec_p.h>
#include "qgeotilefetcherqgc.h"
#include "qgeomapreplyqgc.h"
QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
: QGeoTileFetcher(parent)
, m_networkManager(new QNetworkAccessManager(this))
#if defined Q_OS_MAC
, m_userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0")
#elif defined Q_OS_WIN32
, m_userAgent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7")
#else
, m_userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0")
#endif
, m_UrlFactory(NULL)
{
QStringList langs = QLocale::system().uiLanguages();
if (langs.length() > 0) {
m_Language = langs[0];
}
m_UrlFactory = new OpenPilot::UrlFactory(m_networkManager);
}
QGeoTileFetcherQGC::~QGeoTileFetcherQGC()
{
if(m_UrlFactory)
delete m_UrlFactory;
}
void QGeoTileFetcherQGC::setUserAgent(const QByteArray &userAgent)
{
m_userAgent = userAgent;
}
QGeoTiledMapReply *QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec)
{
QNetworkRequest request;
QString url = m_UrlFactory->makeImageUrl((OpenPilot::MapType)spec.mapId(), QPoint(spec.x(), spec.y()), spec.zoom(), m_Language);
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", m_userAgent);
request.setRawHeader("Accept", "*/*");
switch ((OpenPilot::MapType)spec.mapId()) {
case OpenPilot::GoogleMap:
case OpenPilot::GoogleSatellite:
case OpenPilot::GoogleLabels:
case OpenPilot::GoogleTerrain:
case OpenPilot::GoogleHybrid:
{
request.setRawHeader("Referrer", "http://maps.google.com/");
}
break;
case OpenPilot::GoogleMapChina:
case OpenPilot::GoogleSatelliteChina:
case OpenPilot::GoogleLabelsChina:
case OpenPilot::GoogleTerrainChina:
case OpenPilot::GoogleHybridChina:
{
request.setRawHeader("Referrer", "http://ditu.google.cn/");
}
break;
case OpenPilot::BingHybrid:
case OpenPilot::BingMap:
case OpenPilot::BingSatellite:
{
request.setRawHeader("Referrer", "http://www.bing.com/maps/");
}
break;
case OpenPilot::YahooHybrid:
case OpenPilot::YahooLabels:
case OpenPilot::YahooMap:
case OpenPilot::YahooSatellite:
{
request.setRawHeader("Referrer", "http://maps.yahoo.com/");
}
break;
case OpenPilot::ArcGIS_MapsLT_Map_Labels:
case OpenPilot::ArcGIS_MapsLT_Map:
case OpenPilot::ArcGIS_MapsLT_OrtoFoto:
case OpenPilot::ArcGIS_MapsLT_Map_Hybrid:
{
request.setRawHeader("Referrer", "http://www.maps.lt/map_beta/");
}
break;
case OpenPilot::OpenStreetMapSurfer:
case OpenPilot::OpenStreetMapSurferTerrain:
{
request.setRawHeader("Referrer", "http://www.mapsurfer.net/");
}
break;
case OpenPilot::OpenStreetMap:
case OpenPilot::OpenStreetOsm:
{
request.setRawHeader("Referrer", "http://www.openstreetmap.org/");
}
break;
case OpenPilot::YandexMapRu:
{
request.setRawHeader("Referrer", "http://maps.yandex.ru/");
}
break;
default:
break;
}
QNetworkReply *reply = m_networkManager->get(request);
reply->setParent(0);
return new QGeoMapReplyQGC(reply, spec);
}
......@@ -56,6 +56,7 @@ This file is part of the QGROUNDCONTROL project
#endif
#include <iostream>
#include "QGCMapEngine.h"
/* SDL does ugly things to main() */
#ifdef main
......@@ -218,6 +219,8 @@ int main(int argc, char *argv[])
qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
app->_initCommon();
//-- Initialize Cache System
getQGCMapEngine()->init();
int exitCode = 0;
......@@ -251,6 +254,8 @@ int main(int argc, char *argv[])
}
delete app;
//-- Shutdown Cache System
destroyMapEngine();
qDebug() << "After app delete";
......
......@@ -174,6 +174,19 @@ Item {
checked = true
}
}
QGCButton {
width: parent.width * 0.85
height: ScreenTools.defaultFontPixelHeight * 2.5
text: "Offline Maps"
exclusiveGroup: panelActionGroup
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
if(__rightPanel.source != "OfflineMap.qml") {
__rightPanel.source = "OfflineMap.qml"
}
checked = true
}
}
QGCButton {
width: parent.width * 0.85
height: ScreenTools.defaultFontPixelHeight * 2.5
......
......@@ -133,7 +133,6 @@ Rectangle {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
//-----------------------------------------------------------------
//-- Map Providers
Row {
......
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