Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
941b8e25bd | |||
8ad2d57ca1 | |||
dbc18227ff | |||
95d354f10c | |||
aedbc99a6c | |||
04f9457085 | |||
2adf0d4089 | |||
f572d68420 | |||
bbc03ae59f | |||
4d40cd6458 | |||
69e1198efa | |||
059ed3aa14 | |||
7eba9ef39b | |||
1d494d26aa | |||
f258ca1a3e | |||
58d2d84555 | |||
dcf9d625ac | |||
47664c8cbd | |||
055b068379 | |||
b1655c6348 | |||
132ccb7696 | |||
ea3257b7d0 | |||
8419dee824 | |||
22821796f2 | |||
816b18b8cc | |||
8ebd73115f | |||
720c0f94bd | |||
e450e62d8d | |||
a33ec51c9b | |||
57e3bb293c | |||
c6aca7940b | |||
10bce1e974 | |||
21a5f53759 | |||
a589d4ee9e | |||
97bc9164a2 | |||
8e5b4a8007 | |||
148de41eb7 | |||
75a757cc0c | |||
2c804780c4 | |||
b27981fe0f | |||
2374a7d1dd |
@ -1,4 +1,4 @@
|
||||
version: 13.10.{build}
|
||||
version: 13.11.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
@ -5,7 +5,7 @@ GPS log file formats.
|
||||
## Features
|
||||
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON,
|
||||
OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN, ONmove OMD/GHP,
|
||||
TwoNav (TRK, RTE, WPT) and geotagged JPEG files.
|
||||
TwoNav (TRK, RTE, WPT), GPSDump and geotagged JPEG files.
|
||||
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS,
|
||||
QuadTiles).
|
||||
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
||||
@ -24,7 +24,7 @@ GPS log file formats.
|
||||
* Real-time GPS position.
|
||||
* Windows, macOS, Linux and Android builds.
|
||||
|
||||

|
||||

|
||||
|
||||
## Build
|
||||
Build requirements:
|
||||
@ -39,8 +39,6 @@ qmake gpxsee.pro
|
||||
make # nmake on windows
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Download
|
||||
* [Windows & OS X builds](https://sourceforge.net/projects/gpxsee)
|
||||
* [Linux packages](https://software.opensuse.org/download.html?project=home%3Atumic%3AGPXSee&package=gpxsee)
|
||||
@ -75,4 +73,5 @@ different, GPL compatible, licenses:
|
||||
[Transverse Mercator](src/map/proj/transversemercator.cpp) projections - NIMA
|
||||
Source Code Disclaimer
|
||||
* [Projection parameters CSV files](data/CRS) - BSD/EPSG/Public domain
|
||||
* [Mapsforge render theme](data/mapsforge/default.xml) and its [icons](icons/map/mapsforge) - LGPLv3
|
||||
* [Mapsforge render theme](data/mapsforge/default.xml) and its
|
||||
[icons](icons/map/mapsforge) - LGPLv3
|
||||
|
@ -3,7 +3,7 @@ unix:!macx:!android {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 13.10
|
||||
VERSION = 13.11
|
||||
|
||||
|
||||
QT += core \
|
||||
@ -118,6 +118,7 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/pngexportdialog.h \
|
||||
src/GUI/timezoneinfo.h \
|
||||
src/GUI/passwordedit.h \
|
||||
src/data/gpsdumpparser.h \
|
||||
src/data/style.h \
|
||||
src/data/twonavparser.h \
|
||||
src/map/ENC/attributes.h \
|
||||
@ -338,6 +339,7 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/pngexportdialog.cpp \
|
||||
src/GUI/projectioncombobox.cpp \
|
||||
src/GUI/passwordedit.cpp \
|
||||
src/data/gpsdumpparser.cpp \
|
||||
src/data/twonavparser.cpp \
|
||||
src/map/ENC/atlasdata.cpp \
|
||||
src/map/ENC/mapdata.cpp \
|
||||
|
@ -0,0 +1,4 @@
|
||||
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||
<path fill="#ff9900" d="M 17.417969 5.5 L 10.082031 5.5 L 8.25 3.667969 L 3.667969 3.667969 C 2.660156 3.667969 1.832031 4.492188 1.832031 5.5 L 1.832031 16.5 C 1.832031 17.507812 2.660156 18.332031 3.667969 18.332031 L 17.875 18.332031 C 18.652344 18.332031 19.25 17.738281 19.25 16.957031 L 19.25 7.332031 C 19.25 6.324219 18.425781 5.5 17.417969 5.5 Z M 17.417969 5.5 "/>
|
||||
<path fill="#ffcc00" d="M 19.339844 8.25 L 7.011719 8.25 C 6.140625 8.25 5.363281 8.890625 5.226562 9.761719 L 3.667969 18.332031 L 18.195312 18.332031 C 19.066406 18.332031 19.847656 17.691406 19.984375 16.820312 L 21.128906 10.402344 C 21.359375 9.304688 20.488281 8.25 19.339844 8.25 Z M 19.339844 8.25 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 773 B |
10
icons/GUI/Papirus/actions/22x22/document-open-recent.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" version="1.1">
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">
|
||||
.ColorScheme-Text { color:#444444; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
|
||||
</style>
|
||||
</defs>
|
||||
<g transform="translate(3,3)">
|
||||
<path style="fill:currentColor;fill-rule:evenodd" class="ColorScheme-Text" d="M 7,4 H 9 V 7.5 L 11,9.5 9.5,11 7,8.5 Z M 8,1 A 7,7 0 0 0 1,8 7,7 0 0 0 8,15 7,7 0 0 0 15,8 7,7 0 0 0 8,1 Z M 8,3 A 5,5 0 0 1 13,8 5,5 0 0 1 8,13 5,5 0 0 1 3,8 5,5 0 0 1 8,3 Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 678 B |
BIN
icons/symbols/Ferry.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/symbols/Funicular.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/symbols/Lodge.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/symbols/Pizza.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
icons/symbols/Railway.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
icons/symbols/Shower.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
@ -16,4 +16,4 @@ Icon=gpxsee
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt
|
||||
MimeType=application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue
|
||||
MimeType=application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt
|
||||
|
@ -177,6 +177,16 @@
|
||||
<glob pattern="*.wpt"/>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/vnd.gpsdump.wpt">
|
||||
<comment>GPSDump Waypoint File</comment>
|
||||
<sub-class-of type="text/plain"/>
|
||||
<generic-icon name="text/plain"/>
|
||||
<magic>
|
||||
<match type="string" offset="0" value="$FormatGEO"/>
|
||||
<match type="string" offset="0" value="$FormatUTM"/>
|
||||
</magic>
|
||||
<glob pattern="*.wpt"/>
|
||||
</mime-type>
|
||||
|
||||
<!-- Maps -->
|
||||
|
||||
|
@ -37,7 +37,7 @@ Unicode true
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "13.10"
|
||||
!define VERSION "13.11"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
|
@ -70,7 +70,9 @@ App::App(int &argc, char **argv) : QApplication(argc, argv)
|
||||
loadPCSs();
|
||||
Waypoint::loadSymbolIcons(ProgramPaths::symbolsDir());
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
|
||||
QIcon::setFallbackThemeName(APP_NAME);
|
||||
#endif // QT 5.12
|
||||
|
||||
_gui = new GUI();
|
||||
|
||||
|
123
src/GUI/gui.cpp
@ -59,12 +59,13 @@
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
#define MAX_RECENT_FILES 10
|
||||
#define TOOLBAR_ICON_SIZE 22
|
||||
|
||||
GUI::GUI()
|
||||
{
|
||||
QString activeMap;
|
||||
QStringList disabledPOIs;
|
||||
QStringList disabledPOIs, recentFiles;
|
||||
|
||||
_poi = new POI(this);
|
||||
_dem = new DEMLoader(ProgramPaths::demDir(true), this);
|
||||
@ -108,10 +109,13 @@ GUI::GUI()
|
||||
_movingTime = 0;
|
||||
_lastTab = 0;
|
||||
|
||||
readSettings(activeMap, disabledPOIs);
|
||||
readSettings(activeMap, disabledPOIs, recentFiles);
|
||||
|
||||
loadInitialMaps(activeMap);
|
||||
loadInitialPOIs(disabledPOIs);
|
||||
#ifndef Q_OS_ANDROID
|
||||
loadRecentFiles(recentFiles);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
updateGraphTabs();
|
||||
updateStatusBarInfo();
|
||||
@ -261,6 +265,15 @@ void GUI::createActions()
|
||||
_statisticsAction->setActionGroup(_fileActionGroup);
|
||||
connect(_statisticsAction, &QAction::triggered, this, &GUI::statistics);
|
||||
addAction(_statisticsAction);
|
||||
#ifndef Q_OS_ANDROID
|
||||
_recentFilesActionGroup = new QActionGroup(this);
|
||||
connect(_recentFilesActionGroup, &QActionGroup::triggered, this,
|
||||
&GUI::recentFileSelected);
|
||||
_clearRecentFilesAction = new QAction(tr("Clear list"), this);
|
||||
_clearRecentFilesAction->setMenuRole(QAction::NoRole);
|
||||
connect(_clearRecentFilesAction, &QAction::triggered, this,
|
||||
&GUI::clearRecentFiles);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
// POI actions
|
||||
_poisActionGroup = new QActionGroup(this);
|
||||
@ -614,6 +627,15 @@ void GUI::createMenus()
|
||||
{
|
||||
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
fileMenu->addAction(_openFileAction);
|
||||
#ifndef Q_OS_ANDROID
|
||||
_recentFilesMenu = fileMenu->addMenu(tr("Open recent"));
|
||||
_recentFilesMenu->setIcon(QIcon::fromTheme(OPEN_RECENT_NAME,
|
||||
QIcon(OPEN_RECENT_ICON)));
|
||||
_recentFilesMenu->menuAction()->setMenuRole(QAction::NoRole);
|
||||
_recentFilesMenu->setEnabled(false);
|
||||
_recentFilesEnd = _recentFilesMenu->addSeparator();
|
||||
_recentFilesMenu->addAction(_clearRecentFilesAction);
|
||||
#endif // Q_OS_ANDROID
|
||||
fileMenu->addAction(_openDirAction);
|
||||
fileMenu->addSeparator();
|
||||
#ifndef Q_OS_ANDROID
|
||||
@ -659,6 +681,7 @@ void GUI::createMenus()
|
||||
dataMenu->addAction(_showRouteWaypointsAction);
|
||||
dataMenu->addAction(_showTicksAction);
|
||||
QMenu *markerMenu = dataMenu->addMenu(tr("Position info"));
|
||||
markerMenu->menuAction()->setMenuRole(QAction::NoRole);
|
||||
markerMenu->addAction(_hideMarkersAction);
|
||||
markerMenu->addAction(_showMarkersAction);
|
||||
markerMenu->addAction(_showMarkerDateAction);
|
||||
@ -696,13 +719,16 @@ void GUI::createMenus()
|
||||
|
||||
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
|
||||
QMenu *timeMenu = settingsMenu->addMenu(tr("Time"));
|
||||
timeMenu->menuAction()->setMenuRole(QAction::NoRole);
|
||||
timeMenu->addAction(_totalTimeAction);
|
||||
timeMenu->addAction(_movingTimeAction);
|
||||
QMenu *unitsMenu = settingsMenu->addMenu(tr("Units"));
|
||||
unitsMenu->menuAction()->setMenuRole(QAction::NoRole);
|
||||
unitsMenu->addAction(_metricUnitsAction);
|
||||
unitsMenu->addAction(_imperialUnitsAction);
|
||||
unitsMenu->addAction(_nauticalUnitsAction);
|
||||
QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
|
||||
coordinatesMenu->menuAction()->setMenuRole(QAction::NoRole);
|
||||
coordinatesMenu->addAction(_decimalDegreesAction);
|
||||
coordinatesMenu->addAction(_degreesMinutesAction);
|
||||
coordinatesMenu->addAction(_dmsAction);
|
||||
@ -1018,6 +1044,9 @@ bool GUI::openFile(const QString &fileName, bool tryUnknown, int &showError)
|
||||
updateNavigationActions();
|
||||
updateStatusBarInfo();
|
||||
updateWindowTitle();
|
||||
#ifndef Q_OS_ANDROID
|
||||
updateRecentFiles(fileName);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1992,6 +2021,48 @@ void GUI::updateWindowTitle()
|
||||
setWindowTitle(APP_NAME);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
void GUI::updateRecentFiles(const QString &fileName)
|
||||
{
|
||||
QAction *a = 0;
|
||||
|
||||
QList<QAction *> actions(_recentFilesActionGroup->actions());
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
if (actions.at(i)->text() == fileName) {
|
||||
a = actions.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a)
|
||||
delete a;
|
||||
else if (actions.size() == MAX_RECENT_FILES)
|
||||
delete actions.last();
|
||||
|
||||
actions = _recentFilesActionGroup->actions();
|
||||
QAction *before = actions.size() ? actions.last() : _recentFilesEnd;
|
||||
_recentFilesMenu->insertAction(before,
|
||||
new QAction(fileName, _recentFilesActionGroup));
|
||||
_recentFilesMenu->setEnabled(true);
|
||||
}
|
||||
|
||||
void GUI::clearRecentFiles()
|
||||
{
|
||||
QList<QAction *> actions(_recentFilesActionGroup->actions());
|
||||
|
||||
for (int i = 0; i < actions.size(); i++)
|
||||
delete actions.at(i);
|
||||
|
||||
_recentFilesMenu->setEnabled(false);
|
||||
}
|
||||
|
||||
void GUI::recentFileSelected(QAction *action)
|
||||
{
|
||||
int showError = 1;
|
||||
openFile(action->text(), true, showError);
|
||||
}
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
void GUI::mapChanged(QAction *action)
|
||||
{
|
||||
_map = action->data().value<Map*>();
|
||||
@ -2353,6 +2424,18 @@ void GUI::writeSettings()
|
||||
#endif // Q_OS_ANDROID
|
||||
settings.endGroup();
|
||||
|
||||
/* File */
|
||||
#ifndef Q_OS_ANDROID
|
||||
QList<QAction*> recentActions(_recentFilesActionGroup->actions());
|
||||
QStringList recent;
|
||||
for (int i = 0; i < recentActions.size(); i++)
|
||||
recent.append(recentActions.at(i)->text());
|
||||
|
||||
settings.beginGroup(SETTINGS_FILE);
|
||||
WRITE(recentDataFiles, recent);
|
||||
settings.endGroup();
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
/* Map */
|
||||
settings.beginGroup(SETTINGS_MAP);
|
||||
WRITE(activeMap, _map->name());
|
||||
@ -2372,11 +2455,11 @@ void GUI::writeSettings()
|
||||
settings.endGroup();
|
||||
|
||||
/* POI */
|
||||
QList<QAction*> actions(_poisActionGroup->actions());
|
||||
QList<QAction*> disabledActions(_poisActionGroup->actions());
|
||||
QStringList disabled;
|
||||
for (int i = 0; i < actions.size(); i++)
|
||||
if (!actions.at(i)->isChecked())
|
||||
disabled.append(actions.at(i)->data().toString());
|
||||
for (int i = 0; i < disabledActions.size(); i++)
|
||||
if (!disabledActions.at(i)->isChecked())
|
||||
disabled.append(disabledActions.at(i)->data().toString());
|
||||
|
||||
settings.beginGroup(SETTINGS_POI);
|
||||
WRITE(showPoi, _showPOIAction->isChecked());
|
||||
@ -2511,7 +2594,8 @@ void GUI::writeSettings()
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void GUI::readSettings(QString &activeMap, QStringList &disabledPOIs)
|
||||
void GUI::readSettings(QString &activeMap, QStringList &disabledPOIs,
|
||||
QStringList &recentFiles)
|
||||
{
|
||||
#define READ(name) \
|
||||
(Settings::name.read(settings))
|
||||
@ -2560,6 +2644,15 @@ void GUI::readSettings(QString &activeMap, QStringList &disabledPOIs)
|
||||
#endif // Q_OS_ANDROID
|
||||
settings.endGroup();
|
||||
|
||||
/* File */
|
||||
#ifndef Q_OS_ANDROID
|
||||
settings.beginGroup(SETTINGS_FILE);
|
||||
recentFiles = READ(recentDataFiles);
|
||||
settings.endGroup();
|
||||
#else // Q_OS_ANDROID
|
||||
Q_UNUSED(recentFiles);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
/* Map */
|
||||
settings.beginGroup(SETTINGS_MAP);
|
||||
if (READ(showMap).toBool()) {
|
||||
@ -3052,6 +3145,22 @@ void GUI::loadInitialPOIs(const QStringList &disabled)
|
||||
_unselectAllPOIAction->setEnabled(!poiActions.isEmpty());
|
||||
}
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
void GUI::loadRecentFiles(const QStringList &files)
|
||||
{
|
||||
QAction *before = _recentFilesEnd;
|
||||
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
QAction *a = new QAction(files.at(i), _recentFilesActionGroup);
|
||||
_recentFilesMenu->insertAction(before, a);
|
||||
before = a;
|
||||
}
|
||||
|
||||
if (!files.isEmpty())
|
||||
_recentFilesMenu->setEnabled(true);
|
||||
}
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
QAction *GUI::mapAction(const QString &name)
|
||||
{
|
||||
QList<QAction *> maps(_mapsActionGroup->actions());
|
||||
|
@ -92,6 +92,10 @@ private slots:
|
||||
void poiFileChecked(QAction *action);
|
||||
void selectAllPOIs();
|
||||
void unselectAllPOIs();
|
||||
#ifndef Q_OS_ANDROID
|
||||
void recentFileSelected(QAction *action);
|
||||
void clearRecentFiles();
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
void next();
|
||||
void prev();
|
||||
@ -161,6 +165,9 @@ private:
|
||||
void updateWindowTitle();
|
||||
bool updateGraphTabs();
|
||||
void updateDEMDownloadAction();
|
||||
#ifndef Q_OS_ANDROID
|
||||
void updateRecentFiles(const QString &fileName);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
TimeType timeType() const;
|
||||
Units units() const;
|
||||
@ -174,10 +181,14 @@ private:
|
||||
qreal movingTime() const;
|
||||
QAction *mapAction(const QString &name);
|
||||
QGeoPositionInfoSource *positionSource(const Options &options);
|
||||
void readSettings(QString &activeMap, QStringList &disabledPOIs);
|
||||
void readSettings(QString &activeMap, QStringList &disabledPOIs,
|
||||
QStringList &recentFiles);
|
||||
|
||||
void loadInitialMaps(const QString &selected);
|
||||
void loadInitialPOIs(const QStringList &disabled);
|
||||
#ifndef Q_OS_ANDROID
|
||||
void loadRecentFiles(const QStringList &files);
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
void loadOptions();
|
||||
void updateOptions(const Options &options);
|
||||
@ -198,11 +209,17 @@ private:
|
||||
#endif // Q_OS_ANDROID
|
||||
QMenu *_poiMenu;
|
||||
QMenu *_mapMenu;
|
||||
#ifndef Q_OS_ANDROID
|
||||
QMenu *_recentFilesMenu;
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
QActionGroup *_fileActionGroup;
|
||||
QActionGroup *_navigationActionGroup;
|
||||
QActionGroup *_mapsActionGroup;
|
||||
QActionGroup *_poisActionGroup;
|
||||
#ifndef Q_OS_ANDROID
|
||||
QActionGroup *_recentFilesActionGroup;
|
||||
#endif // Q_OS_ANDROID
|
||||
#if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
|
||||
QAction *_exitAction;
|
||||
#endif // Q_OS_MAC + Q_OS_ANDROID
|
||||
@ -276,6 +293,10 @@ private:
|
||||
QAction *_showDEMTilesAction;
|
||||
QAction *_mapsEnd;
|
||||
QAction *_poisEnd;
|
||||
#ifndef Q_OS_ANDROID
|
||||
QAction *_clearRecentFilesAction;
|
||||
QAction *_recentFilesEnd;
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
QLabel *_fileNameLabel;
|
||||
QLabel *_distanceLabel;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
// Toolbar/menu icons
|
||||
#define OPEN_FILE_ICON ":/icons/" APP_NAME "/actions/22x22/document-open.svg"
|
||||
#define OPEN_RECENT_ICON ":/icons/" APP_NAME "/actions/22x22/document-open-recent.svg"
|
||||
#define OPEN_DIR_ICON ":/icons/" APP_NAME "/actions/22x22/document-open-folder.svg"
|
||||
#define EXPORT_FILE_ICON ":/icons/" APP_NAME "/actions/22x22/document-export.svg"
|
||||
#define PRINT_FILE_ICON ":/icons/" APP_NAME "/actions/22x22/document-print.svg"
|
||||
@ -40,6 +41,7 @@
|
||||
|
||||
// Desktop theme names
|
||||
#define OPEN_FILE_NAME "document-open"
|
||||
#define OPEN_RECENT_NAME "document-open-recent"
|
||||
#define OPEN_DIR_NAME "document-open-folder"
|
||||
#define EXPORT_FILE_NAME "document-export"
|
||||
#define PRINT_FILE_NAME "document-print"
|
||||
|
@ -268,3 +268,8 @@ const Settings::SettingMap Settings::positionPluginParameters
|
||||
|
||||
const Settings::SettingList Settings::disabledPoiFiles
|
||||
= Settings::SettingList("disabled", "file");
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
const Settings::SettingList Settings::recentDataFiles
|
||||
= Settings::SettingList("recent", "file");
|
||||
#endif // Q_OS_ANDROID
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#define SETTINGS_WINDOW "Window"
|
||||
#define SETTINGS_SETTINGS "Settings"
|
||||
#define SETTINGS_FILE "File"
|
||||
#define SETTINGS_MAP "Map"
|
||||
#define SETTINGS_GRAPH "Graph"
|
||||
#define SETTINGS_POI "POI"
|
||||
@ -84,6 +85,11 @@ public:
|
||||
static const Setting showToolbars;
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
/* File */
|
||||
#ifndef Q_OS_ANDROID
|
||||
static const SettingList recentDataFiles;
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
/* Map */
|
||||
static const Setting activeMap;
|
||||
static const Setting showMap;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "itnparser.h"
|
||||
#include "onmoveparsers.h"
|
||||
#include "twonavparser.h"
|
||||
#include "gpsdumpparser.h"
|
||||
#include "data.h"
|
||||
|
||||
|
||||
@ -46,6 +47,7 @@ static ITNParser itn;
|
||||
static OMDParser omd;
|
||||
static GHPParser ghp;
|
||||
static TwoNavParser twonav;
|
||||
static GPSDumpParser gpsdump;
|
||||
|
||||
static QMultiMap<QString, Parser*> parsers()
|
||||
{
|
||||
@ -78,6 +80,7 @@ static QMultiMap<QString, Parser*> parsers()
|
||||
map.insert("trk", &twonav);
|
||||
map.insert("rte", &twonav);
|
||||
map.insert("wpt", &twonav);
|
||||
map.insert("wpt", &gpsdump);
|
||||
|
||||
return map;
|
||||
}
|
||||
@ -174,6 +177,7 @@ QString Data::formats()
|
||||
+ qApp->translate("Data", "SML files") + " (*.sml);;"
|
||||
+ qApp->translate("Data", "TCX files") + " (*.tcx);;"
|
||||
+ qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;"
|
||||
+ qApp->translate("Data", "GPSDump files") + " (*.wpt);;"
|
||||
+ qApp->translate("Data", "All files") + " (*)";
|
||||
}
|
||||
|
||||
|
161
src/data/gpsdumpparser.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
#include <QRegularExpression>
|
||||
#include "map/pcs.h"
|
||||
#include "map/gcs.h"
|
||||
#include "map/utm.h"
|
||||
#include "gpsdumpparser.h"
|
||||
|
||||
static double dms2dd(const QStringList &dms)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
int deg = dms.at(1).toInt(&ok);
|
||||
if (!ok)
|
||||
return NAN;
|
||||
int min = dms.at(2).toInt(&ok);
|
||||
if (!ok)
|
||||
return NAN;
|
||||
double sec = dms.at(3).toDouble(&ok);
|
||||
if (!ok)
|
||||
return NAN;
|
||||
|
||||
return deg + min/60.0 + sec/3600.0;
|
||||
}
|
||||
|
||||
static double parseLon(const QString &str)
|
||||
{
|
||||
QStringList dms(str.split(' '));
|
||||
if (dms.size() < 4)
|
||||
return NAN;
|
||||
|
||||
double dd = dms2dd(dms);
|
||||
if (std::isnan(dd))
|
||||
return NAN;
|
||||
|
||||
if (dms.at(0) == 'W')
|
||||
return -dd;
|
||||
else if (dms.at(0) == 'E')
|
||||
return dd;
|
||||
else
|
||||
return NAN;
|
||||
}
|
||||
|
||||
static double parseLat(const QString &str)
|
||||
{
|
||||
QStringList dms(str.split(' '));
|
||||
if (dms.size() < 4)
|
||||
return NAN;
|
||||
|
||||
double dd = dms2dd(dms);
|
||||
if (std::isnan(dd))
|
||||
return NAN;
|
||||
|
||||
if (dms.at(0) == 'S')
|
||||
return -dd;
|
||||
else if (dms.at(0) == 'N')
|
||||
return dd;
|
||||
else
|
||||
return NAN;
|
||||
}
|
||||
|
||||
static Coordinates parseGEO(const QString &lat, const QString &lon)
|
||||
{
|
||||
return Coordinates(parseLon(lon), parseLat(lat));
|
||||
}
|
||||
|
||||
static Coordinates parseUTM(const QString &zone, const QString &easting,
|
||||
const QString &northing)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
int z = zone.left(zone.size() - 1).toInt(&ok);
|
||||
if (!ok)
|
||||
return Coordinates();
|
||||
if (zone.right(1) < 'N')
|
||||
z = -z;
|
||||
|
||||
int x = easting.toInt(&ok);
|
||||
if (!ok)
|
||||
return Coordinates();
|
||||
int y = northing.toInt(&ok);
|
||||
if (!ok)
|
||||
return Coordinates();
|
||||
|
||||
Projection proj(PCS(GCS::WGS84(), Conversion(9807, UTM::setup(z), 9001)));
|
||||
|
||||
return proj.xy2ll(PointD(x, y));
|
||||
}
|
||||
|
||||
bool GPSDumpParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(tracks);
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(polygons);
|
||||
|
||||
_errorLine = 1;
|
||||
_errorString.clear();
|
||||
Type type = Unknown;
|
||||
QRegularExpression dm("[ ]{2,}");
|
||||
|
||||
while (!file->atEnd()) {
|
||||
QByteArray ba(file->readLine(4096).trimmed());
|
||||
|
||||
if (_errorLine == 1) {
|
||||
if (ba == "$FormatGEO")
|
||||
type = GEO;
|
||||
else if (ba == "$FormatUTM")
|
||||
type = UTM;
|
||||
else {
|
||||
_errorString = "Not a GPSDump waypoint file";
|
||||
return false;
|
||||
}
|
||||
} else if (!ba.isEmpty()) {
|
||||
QString line(ba);
|
||||
QStringList fields(line.split(dm));
|
||||
Coordinates c;
|
||||
double ele = NAN;
|
||||
QString desc;
|
||||
bool ok;
|
||||
|
||||
if (type == UTM) {
|
||||
if (fields.size() < 5) {
|
||||
_errorString = "Parse error";
|
||||
return false;
|
||||
}
|
||||
|
||||
c = parseUTM(fields.at(1), fields.at(2), fields.at(3));
|
||||
ele = fields.at(4).toDouble(&ok);
|
||||
if (fields.size() > 5)
|
||||
desc = fields.at(5);
|
||||
} else {
|
||||
if (fields.size() < 4) {
|
||||
_errorString = "Parse error";
|
||||
return false;
|
||||
}
|
||||
|
||||
c = parseGEO(fields.at(1), fields.at(2));
|
||||
ele = fields.at(3).toDouble(&ok);
|
||||
if (fields.size() > 4)
|
||||
desc = fields.at(4);
|
||||
}
|
||||
|
||||
if (!c.isValid()) {
|
||||
_errorString = "Invalid coordinates";
|
||||
return false;
|
||||
}
|
||||
|
||||
Waypoint w(c);
|
||||
w.setName(fields.at(0));
|
||||
if (ok)
|
||||
w.setElevation(ele);
|
||||
if (!desc.isEmpty())
|
||||
w.setDescription(desc);
|
||||
|
||||
waypoints.append(w);
|
||||
}
|
||||
|
||||
_errorLine++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
27
src/data/gpsdumpparser.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef GPSDUMPPARSER_H
|
||||
#define GPSDUMPPARSER_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
class GPSDumpParser : public Parser
|
||||
{
|
||||
public:
|
||||
GPSDumpParser() : _errorLine(0) {}
|
||||
|
||||
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||
QString errorString() const {return _errorString;}
|
||||
int errorLine() const {return _errorLine;}
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
Unknown,
|
||||
GEO,
|
||||
UTM
|
||||
};
|
||||
|
||||
int _errorLine;
|
||||
QString _errorString;
|
||||
};
|
||||
|
||||
#endif // GPSDUMPPARSER_H
|
@ -347,20 +347,14 @@ void AQMMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
Q_UNUSED(flags);
|
||||
const Zoom &z = _zooms.at(_zoom);
|
||||
qreal scale = OSM::zoom2scale(z.zoom, z.tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * _mapRatio, z.zoom);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, z.zoom));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
|
||||
QList<RenderTile> tiles;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
@ -371,13 +365,11 @@ void AQMMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||
|
||||
if (QPixmapCache::find(key, &pm)) {
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (t.y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (t.x() - tile.x()) * tileSize(),
|
||||
tl.y() + (t.y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
} else {
|
||||
} else
|
||||
tiles.append(RenderTile(t, tileData(t), key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,9 +384,8 @@ void AQMMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (mt.xy().x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (mt.xy().y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + (mt.xy().y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
}
|
||||
}
|
||||
|
@ -243,20 +243,14 @@ void GEMFMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
Q_UNUSED(flags);
|
||||
const Zoom &z = _zooms.at(_zi);
|
||||
qreal scale = OSM::zoom2scale(z.level, _tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * _mapRatio, z.level);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, z.level));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
|
||||
QList<RenderTile> tiles;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
@ -267,13 +261,11 @@ void GEMFMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||
|
||||
if (QPixmapCache::find(key, &pm)) {
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (t.y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (t.x() - tile.x()) * tileSize(),
|
||||
tl.y() + (t.y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
} else {
|
||||
} else
|
||||
tiles.append(RenderTile(t, tileData(t), key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,9 +280,8 @@ void GEMFMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (mt.xy().x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (mt.xy().y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + (mt.xy().y() - tile.y())* tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,6 @@
|
||||
#include <QSqlError>
|
||||
#include <QPainter>
|
||||
#include <QPixmapCache>
|
||||
#include <QImageReader>
|
||||
#include <QBuffer>
|
||||
#include <QtConcurrent>
|
||||
#include "common/util.h"
|
||||
#include "osm.h"
|
||||
@ -14,36 +12,169 @@
|
||||
|
||||
#define META_TYPE(type) static_cast<QMetaType::Type>(type)
|
||||
|
||||
class MBTile
|
||||
static RectC str2bounds(const QString &str)
|
||||
{
|
||||
public:
|
||||
MBTile(int zoom, int scaledSize, const QPoint &xy, const QByteArray &data,
|
||||
const QString &key) : _zoom(zoom), _scaledSize(scaledSize), _xy(xy),
|
||||
_data(data), _key(key) {}
|
||||
QStringList list(str.split(','));
|
||||
if (list.size() != 4)
|
||||
return RectC();
|
||||
|
||||
const QPoint &xy() const {return _xy;}
|
||||
const QString &key() const {return _key;}
|
||||
QPixmap pixmap() const {return QPixmap::fromImage(_image);}
|
||||
bool lok, rok, bok, tok;
|
||||
double left = list.at(0).toDouble(&lok);
|
||||
double bottom = list.at(1).toDouble(&bok);
|
||||
double right = list.at(2).toDouble(&rok);
|
||||
double top = list.at(3).toDouble(&tok);
|
||||
|
||||
void load() {
|
||||
QByteArray z(QString::number(_zoom).toLatin1());
|
||||
return (lok && rok && bok && tok)
|
||||
? RectC(Coordinates(left, top), Coordinates(right, bottom))
|
||||
: RectC();
|
||||
}
|
||||
|
||||
QBuffer buffer(&_data);
|
||||
QImageReader reader(&buffer, z);
|
||||
if (_scaledSize)
|
||||
reader.setScaledSize(QSize(_scaledSize, _scaledSize));
|
||||
reader.read(&_image);
|
||||
bool MBTilesMap::getMinZoom(int &zoom)
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'minzoom'", _db);
|
||||
|
||||
if (query.first()) {
|
||||
bool ok;
|
||||
zoom = query.value(0).toString().toInt(&ok);
|
||||
if (!ok || zoom < 0) {
|
||||
_errorString = "Invalid minzoom metadata";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qWarning("%s: missing minzoom metadata", qPrintable(path()));
|
||||
zoom = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int _zoom;
|
||||
int _scaledSize;
|
||||
QPoint _xy;
|
||||
QByteArray _data;
|
||||
QString _key;
|
||||
QImage _image;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MBTilesMap::getMaxZoom(int &zoom)
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'maxzoom'", _db);
|
||||
|
||||
if (query.first()) {
|
||||
bool ok;
|
||||
zoom = query.value(0).toString().toInt(&ok);
|
||||
if (!ok && zoom < 0) {
|
||||
_errorString = "Invalid maxzoom metadata";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qWarning("%s: missing maxzoom metadata", qPrintable(path()));
|
||||
zoom = 20;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MBTilesMap::getZooms()
|
||||
{
|
||||
int minZoom, maxZoom;
|
||||
|
||||
if (!(getMinZoom(minZoom) && getMaxZoom(maxZoom)))
|
||||
return false;
|
||||
|
||||
for (int i = minZoom; i <= maxZoom; i++) {
|
||||
QString sql = QString("SELECT zoom_level FROM tiles"
|
||||
" WHERE zoom_level = %1 LIMIT 1").arg(i);
|
||||
QSqlQuery query(sql, _db);
|
||||
if (query.first())
|
||||
_zooms.append(i);
|
||||
}
|
||||
|
||||
_zi = _zooms.size() - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MBTilesMap::getBounds()
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'bounds'", _db);
|
||||
if (query.first()) {
|
||||
RectC b(str2bounds(query.value(0).toString()));
|
||||
if (!b.isValid()) {
|
||||
_errorString = "Invalid bounds metadata";
|
||||
return false;
|
||||
}
|
||||
_bounds = b;
|
||||
} else {
|
||||
qWarning("%s: missing bounds metadata", qPrintable(path()));
|
||||
|
||||
int z = _zooms.first();
|
||||
QString sql = QString("SELECT min(tile_column), min(tile_row), "
|
||||
"max(tile_column), max(tile_row) FROM tiles WHERE zoom_level = %1")
|
||||
.arg(z);
|
||||
QSqlQuery query(sql, _db);
|
||||
query.first();
|
||||
|
||||
int minX = qMin((1<<z) - 1, qMax(0, query.value(0).toInt()));
|
||||
int minY = qMin((1<<z) - 1, qMax(0, query.value(1).toInt()));
|
||||
int maxX = qMin((1<<z) - 1, qMax(0, query.value(2).toInt())) + 1;
|
||||
int maxY = qMin((1<<z) - 1, qMax(0, query.value(3).toInt())) + 1;
|
||||
Coordinates tl(OSM::tile2ll(QPoint(minX, maxY), z));
|
||||
Coordinates br(OSM::tile2ll(QPoint(maxX, minY), z));
|
||||
// Workaround of broken zoom levels 0 and 1 due to numerical instability
|
||||
tl.rlat() = qMin(tl.lat(), OSM::BOUNDS.top());
|
||||
br.rlat() = qMax(br.lat(), OSM::BOUNDS.bottom());
|
||||
_bounds = RectC(tl, br);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MBTilesMap::getTileSize()
|
||||
{
|
||||
QString sql("SELECT tile_data FROM tiles LIMIT 1");
|
||||
QSqlQuery query(sql, _db);
|
||||
query.first();
|
||||
|
||||
QByteArray data = query.value(0).toByteArray();
|
||||
QBuffer buffer(&data);
|
||||
QImageReader reader(&buffer);
|
||||
QSize tileSize(reader.size());
|
||||
|
||||
if (!tileSize.isValid() || tileSize.width() != tileSize.height()) {
|
||||
_errorString = "Unsupported/invalid tile images";
|
||||
return false;
|
||||
}
|
||||
|
||||
_tileSize = tileSize.width();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MBTilesMap::getTileFormat()
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'format'", _db);
|
||||
if (query.first()) {
|
||||
if (query.value(0).toString() == "pbf")
|
||||
_scalable = true;
|
||||
} else
|
||||
qWarning("%s: missing tiles format metadata", qPrintable(path()));
|
||||
}
|
||||
|
||||
void MBTilesMap::getTilePixelRatio()
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'tilepixelratio'",
|
||||
_db);
|
||||
if (query.first()) {
|
||||
bool ok;
|
||||
double ratio = query.value(0).toString().toDouble(&ok);
|
||||
if (ok)
|
||||
_tileRatio = ratio;
|
||||
}
|
||||
}
|
||||
|
||||
void MBTilesMap::getName()
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'name'", _db);
|
||||
if (query.first())
|
||||
_name = query.value(0).toString();
|
||||
else {
|
||||
qWarning("%s: missing map name", qPrintable(path()));
|
||||
_name = Util::file2name(path());
|
||||
}
|
||||
}
|
||||
|
||||
MBTilesMap::MBTilesMap(const QString &fileName, QObject *parent)
|
||||
: Map(fileName, parent), _mapRatio(1.0), _tileRatio(1.0), _scalable(false),
|
||||
@ -75,90 +206,15 @@ MBTilesMap::MBTilesMap(const QString &fileName, QObject *parent)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
QSqlQuery query("SELECT DISTINCT zoom_level FROM tiles"
|
||||
" ORDER BY zoom_level", _db);
|
||||
while (query.next())
|
||||
_zooms.append(query.value(0).toInt());
|
||||
if (_zooms.isEmpty()) {
|
||||
_errorString = "Empty tile set";
|
||||
return;
|
||||
}
|
||||
if (_zooms.first() < 0) {
|
||||
_errorString = "Invalid zoom levels";
|
||||
return;
|
||||
}
|
||||
}
|
||||
_zi = _zooms.size() - 1;
|
||||
|
||||
{
|
||||
int z = _zooms.first();
|
||||
QString sql = QString("SELECT min(tile_column), min(tile_row), "
|
||||
"max(tile_column), max(tile_row) FROM tiles WHERE zoom_level = %1")
|
||||
.arg(z);
|
||||
QSqlQuery query(sql, _db);
|
||||
query.first();
|
||||
|
||||
int minX = qMin((1<<z) - 1, qMax(0, query.value(0).toInt()));
|
||||
int minY = qMin((1<<z) - 1, qMax(0, query.value(1).toInt()));
|
||||
int maxX = qMin((1<<z) - 1, qMax(0, query.value(2).toInt())) + 1;
|
||||
int maxY = qMin((1<<z) - 1, qMax(0, query.value(3).toInt())) + 1;
|
||||
Coordinates tl(OSM::tile2ll(QPoint(minX, maxY), z));
|
||||
Coordinates br(OSM::tile2ll(QPoint(maxX, minY), z));
|
||||
// Workaround of broken zoom levels 0 and 1 due to numerical instability
|
||||
tl.rlat() = qMin(tl.lat(), OSM::BOUNDS.top());
|
||||
br.rlat() = qMax(br.lat(), OSM::BOUNDS.bottom());
|
||||
_bounds = RectC(tl, br);
|
||||
}
|
||||
|
||||
{
|
||||
QString sql = QString("SELECT tile_data FROM tiles LIMIT 1");
|
||||
QSqlQuery query(sql, _db);
|
||||
query.first();
|
||||
|
||||
QByteArray data = query.value(0).toByteArray();
|
||||
QBuffer buffer(&data);
|
||||
QImageReader reader(&buffer);
|
||||
QSize tileSize(reader.size());
|
||||
|
||||
if (!tileSize.isValid() || tileSize.width() != tileSize.height()) {
|
||||
_errorString = "Unsupported/invalid tile images";
|
||||
return;
|
||||
}
|
||||
_tileSize = tileSize.width();
|
||||
}
|
||||
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'format'", _db);
|
||||
if (query.first()) {
|
||||
if (query.value(0).toString() == "pbf")
|
||||
_scalable = true;
|
||||
} else
|
||||
qWarning("%s: missing tiles format", qPrintable(fileName));
|
||||
}
|
||||
|
||||
{
|
||||
QSqlQuery query("SELECT value FROM metadata WHERE name = 'name'", _db);
|
||||
if (query.first())
|
||||
_name = query.value(0).toString();
|
||||
else {
|
||||
qWarning("%s: missing map name", qPrintable(fileName));
|
||||
_name = Util::file2name(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QSqlQuery query(
|
||||
"SELECT value FROM metadata WHERE name = 'tilepixelratio'", _db);
|
||||
if (query.first()) {
|
||||
bool ok;
|
||||
_tileRatio = query.value(0).toString().toDouble(&ok);
|
||||
if (!ok) {
|
||||
_errorString = "Invalid tile pixel ratio";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!getZooms())
|
||||
return;
|
||||
if (!getBounds())
|
||||
return;
|
||||
if (!getTileSize())
|
||||
return;
|
||||
getTileFormat();
|
||||
getTilePixelRatio();
|
||||
getName();
|
||||
|
||||
_db.close();
|
||||
|
||||
@ -183,6 +239,7 @@ void MBTilesMap::load(const Projection &in, const Projection &out,
|
||||
|
||||
void MBTilesMap::unload()
|
||||
{
|
||||
cancelJobs(true);
|
||||
_db.close();
|
||||
}
|
||||
|
||||
@ -219,12 +276,16 @@ qreal MBTilesMap::resolution(const QRectF &rect)
|
||||
|
||||
int MBTilesMap::zoomIn()
|
||||
{
|
||||
cancelJobs(false);
|
||||
|
||||
_zi = qMin(_zi + 1, _zooms.size() - 1);
|
||||
return _zi;
|
||||
}
|
||||
|
||||
int MBTilesMap::zoomOut()
|
||||
{
|
||||
cancelJobs(false);
|
||||
|
||||
_zi = qMax(_zi - 1, 0);
|
||||
return _zi;
|
||||
}
|
||||
@ -260,25 +321,65 @@ QByteArray MBTilesMap::tileData(int zoom, const QPoint &tile) const
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool MBTilesMap::isRunning(const QString &key) const
|
||||
{
|
||||
for (int i = 0; i < _jobs.size(); i++) {
|
||||
const QList<MBTile> &tiles = _jobs.at(i)->tiles();
|
||||
for (int j = 0; j < tiles.size(); j++)
|
||||
if (tiles.at(j).key() == key)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MBTilesMap::runJob(MBTilesMapJob *job)
|
||||
{
|
||||
_jobs.append(job);
|
||||
|
||||
connect(job, &MBTilesMapJob::finished, this, &MBTilesMap::jobFinished);
|
||||
job->run();
|
||||
}
|
||||
|
||||
void MBTilesMap::removeJob(MBTilesMapJob *job)
|
||||
{
|
||||
_jobs.removeOne(job);
|
||||
job->deleteLater();
|
||||
}
|
||||
|
||||
void MBTilesMap::jobFinished(MBTilesMapJob *job)
|
||||
{
|
||||
const QList<MBTile> &tiles = job->tiles();
|
||||
|
||||
for (int i = 0; i < tiles.size(); i++) {
|
||||
const MBTile &mt = tiles.at(i);
|
||||
if (!mt.pixmap().isNull())
|
||||
QPixmapCache::insert(mt.key(), mt.pixmap());
|
||||
}
|
||||
|
||||
removeJob(job);
|
||||
|
||||
emit tilesLoaded();
|
||||
}
|
||||
|
||||
void MBTilesMap::cancelJobs(bool wait)
|
||||
{
|
||||
for (int i = 0; i < _jobs.size(); i++)
|
||||
_jobs.at(i)->cancel(wait);
|
||||
}
|
||||
|
||||
void MBTilesMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
{
|
||||
Q_UNUSED(flags);
|
||||
int zoom = _zooms.at(_zi);
|
||||
qreal scale = OSM::zoom2scale(zoom, _tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * coordinatesRatio(), zoom);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, zoom));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
|
||||
QList<MBTile> tiles;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
@ -288,10 +389,12 @@ void MBTilesMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
QString key = path() + "-" + QString::number(zoom) + "_"
|
||||
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||
|
||||
if (isRunning(key))
|
||||
continue;
|
||||
|
||||
if (QPixmapCache::find(key, &pm)) {
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (t.y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (t.x() - tile.x()) * tileSize(),
|
||||
tl.y() + (t.y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
} else {
|
||||
tiles.append(MBTile(zoom, _scaledSize, t, tileData(zoom, t),
|
||||
@ -300,21 +403,25 @@ void MBTilesMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<void> future = QtConcurrent::map(tiles, &MBTile::load);
|
||||
future.waitForFinished();
|
||||
if (!tiles.isEmpty()) {
|
||||
if (flags & Map::Block || !_scalable) {
|
||||
QFuture<void> future = QtConcurrent::map(tiles, &MBTile::load);
|
||||
future.waitForFinished();
|
||||
|
||||
for (int i = 0; i < tiles.size(); i++) {
|
||||
const MBTile &mt = tiles.at(i);
|
||||
QPixmap pm(mt.pixmap());
|
||||
if (pm.isNull())
|
||||
continue;
|
||||
for (int i = 0; i < tiles.size(); i++) {
|
||||
const MBTile &mt = tiles.at(i);
|
||||
QPixmap pm(mt.pixmap());
|
||||
if (pm.isNull())
|
||||
continue;
|
||||
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (mt.xy().x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (mt.xy().y() - tile.y())
|
||||
* tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + (mt.xy().y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
}
|
||||
} else
|
||||
runJob(new MBTilesMapJob(tiles));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,80 @@
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QVector>
|
||||
#include <QImageReader>
|
||||
#include <QBuffer>
|
||||
#include <QPixmap>
|
||||
#include <QtConcurrent>
|
||||
#include "map.h"
|
||||
|
||||
class MBTile
|
||||
{
|
||||
public:
|
||||
MBTile(int zoom, int scaledSize, const QPoint &xy, const QByteArray &data,
|
||||
const QString &key) : _zoom(zoom), _scaledSize(scaledSize), _xy(xy),
|
||||
_data(data), _key(key) {}
|
||||
|
||||
const QPoint &xy() const {return _xy;}
|
||||
const QString &key() const {return _key;}
|
||||
const QPixmap &pixmap() const {return _pixmap;}
|
||||
|
||||
void load() {
|
||||
QByteArray z(QString::number(_zoom).toLatin1());
|
||||
|
||||
QBuffer buffer(&_data);
|
||||
QImageReader reader(&buffer, z);
|
||||
if (_scaledSize)
|
||||
reader.setScaledSize(QSize(_scaledSize, _scaledSize));
|
||||
_pixmap = QPixmap::fromImage(reader.read());
|
||||
}
|
||||
|
||||
private:
|
||||
int _zoom;
|
||||
int _scaledSize;
|
||||
QPoint _xy;
|
||||
QByteArray _data;
|
||||
QString _key;
|
||||
QPixmap _pixmap;
|
||||
};
|
||||
|
||||
class MBTilesMapJob : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MBTilesMapJob(const QList<MBTile> &tiles) : _tiles(tiles) {}
|
||||
|
||||
void run()
|
||||
{
|
||||
connect(&_watcher, &QFutureWatcher<void>::finished, this,
|
||||
&MBTilesMapJob::handleFinished);
|
||||
_future = QtConcurrent::map(_tiles, &MBTile::load);
|
||||
_watcher.setFuture(_future);
|
||||
}
|
||||
void cancel(bool wait)
|
||||
{
|
||||
_future.cancel();
|
||||
if (wait)
|
||||
_future.waitForFinished();
|
||||
}
|
||||
const QList<MBTile> &tiles() const {return _tiles;}
|
||||
|
||||
signals:
|
||||
void finished(MBTilesMapJob *job);
|
||||
|
||||
private slots:
|
||||
void handleFinished() {emit finished(this);}
|
||||
|
||||
private:
|
||||
QFutureWatcher<void> _watcher;
|
||||
QFuture<void> _future;
|
||||
QList<MBTile> _tiles;
|
||||
};
|
||||
|
||||
class MBTilesMap : public Map
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MBTilesMap(const QString &fileName, QObject *parent = 0);
|
||||
|
||||
@ -36,12 +106,27 @@ public:
|
||||
|
||||
static Map *create(const QString &path, const Projection &proj, bool *isDir);
|
||||
|
||||
private slots:
|
||||
void jobFinished(MBTilesMapJob *job);
|
||||
|
||||
private:
|
||||
bool getMinZoom(int &zoom);
|
||||
bool getMaxZoom(int &zoom);
|
||||
bool getZooms();
|
||||
bool getBounds();
|
||||
bool getTileSize();
|
||||
void getTileFormat();
|
||||
void getTilePixelRatio();
|
||||
void getName();
|
||||
qreal tileSize() const;
|
||||
qreal coordinatesRatio() const;
|
||||
qreal imageRatio() const;
|
||||
QByteArray tileData(int zoom, const QPoint &tile) const;
|
||||
void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp);
|
||||
bool isRunning(const QString &key) const;
|
||||
void runJob(MBTilesMapJob *job);
|
||||
void removeJob(MBTilesMapJob *job);
|
||||
void cancelJobs(bool wait);
|
||||
|
||||
QSqlDatabase _db;
|
||||
|
||||
@ -54,6 +139,8 @@ private:
|
||||
bool _scalable;
|
||||
int _scaledSize;
|
||||
|
||||
QList<MBTilesMapJob*> _jobs;
|
||||
|
||||
bool _valid;
|
||||
QString _errorString;
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <QtCore>
|
||||
#include <QPainter>
|
||||
#include <QDir>
|
||||
#include "common/rectc.h"
|
||||
@ -101,15 +100,11 @@ qreal OnlineMap::tileSize() const
|
||||
void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
{
|
||||
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * coordinatesRatio(), _zoom);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, _zoom));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
@ -127,9 +122,10 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
for (int i = 0; i < tiles.count(); i++) {
|
||||
FetchTile &t = tiles[i];
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.xy().x() - tile.x()) * tileSize(),
|
||||
qMax(tl.y(), b.top()) + ((_invertY ? (1<<_zoom) - t.xy().y() - 1 :
|
||||
t.xy().y()) - tile.y()) * tileSize());
|
||||
QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + ((_invertY
|
||||
? (1<<_zoom) - t.xy().y() - 1
|
||||
: t.xy().y()) - tile.y()) * tileSize());
|
||||
|
||||
if (!t.pixmap().isNull()) {
|
||||
t.pixmap().setDevicePixelRatio(imageRatio());
|
||||
|
@ -238,20 +238,14 @@ void OsmdroidMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
{
|
||||
Q_UNUSED(flags);
|
||||
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * _mapRatio, _zoom);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, _zoom));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
|
||||
QList<RenderTile> tiles;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
@ -262,13 +256,11 @@ void OsmdroidMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||
|
||||
if (QPixmapCache::find(key, &pm)) {
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (t.y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (t.x() - tile.x()) * tileSize(),
|
||||
tl.y() + (t.y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
} else {
|
||||
} else
|
||||
tiles.append(RenderTile(t, tileData(_zoom, t), key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,9 +275,8 @@ void OsmdroidMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (mt.xy().x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (mt.xy().y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + (mt.xy().y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
}
|
||||
}
|
||||
|
@ -185,20 +185,14 @@ void SqliteMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
{
|
||||
Q_UNUSED(flags);
|
||||
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||
QRectF b(bounds());
|
||||
|
||||
|
||||
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||
-rect.topLeft().y() * scale) * _mapRatio, _zoom);
|
||||
QPointF tl(floor(rect.left() / tileSize())
|
||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||
|
||||
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||
qMin(rect.bottom() - tl.y(), b.height()));
|
||||
Coordinates ctl(OSM::tile2ll(tile, _zoom));
|
||||
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
|
||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||
int width = ceil(s.width() / tileSize());
|
||||
int height = ceil(s.height() / tileSize());
|
||||
|
||||
|
||||
QList<RenderTile> tiles;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
@ -209,13 +203,11 @@ void SqliteMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||
|
||||
if (QPixmapCache::find(key, &pm)) {
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (t.y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (t.x() - tile.x()) * tileSize(),
|
||||
tl.y() + (t.y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
} else {
|
||||
} else
|
||||
tiles.append(RenderTile(t, tileData(_zoom, t), key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,9 +222,8 @@ void SqliteMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
QPixmapCache::insert(mt.key(), pm);
|
||||
|
||||
QPointF tp(qMax(tl.x(), b.left()) + (mt.xy().x() - tile.x())
|
||||
* tileSize(), qMax(tl.y(), b.top()) + (mt.xy().y() - tile.y())
|
||||
* tileSize());
|
||||
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize(),
|
||||
tl.y() + (mt.xy().y() - tile.y()) * tileSize());
|
||||
drawTile(painter, pm, tp);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons/GPXSee">
|
||||
<file alias="actions/22x22/document-open.svg">icons/GUI/FlatColor/actions/22x22/document-open.svg</file>
|
||||
<file alias="actions/22x22/document-open-recent.svg">icons/GUI/FlatColor/actions/22x22/document-open-recent.svg</file>
|
||||
<file alias="actions/22x22/document-open-folder.svg">icons/GUI/FlatColor/actions/22x22/document-open-folder.svg</file>
|
||||
<file alias="actions/22x22/document-export.svg">icons/GUI/FlatColor/actions/22x22/document-export.svg</file>
|
||||
<file alias="actions/22x22/document-print.svg">icons/GUI/FlatColor/actions/22x22/document-print.svg</file>
|
||||
|
@ -1,6 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons/GPXSee">
|
||||
<file alias="actions/22x22/document-open.svg">icons/GUI/Papirus/actions/22x22/document-open.svg</file>
|
||||
<file alias="actions/22x22/document-open-recent.svg">icons/GUI/Papirus/actions/22x22/document-open-recent.svg</file>
|
||||
<file alias="actions/22x22/document-open-folder.svg">icons/GUI/Papirus/actions/22x22/document-open-folder.svg</file>
|
||||
<file alias="actions/22x22/document-export.svg">icons/GUI/Papirus/actions/22x22/document-export.svg</file>
|
||||
<file alias="actions/22x22/document-print.svg">icons/GUI/Papirus/actions/22x22/document-print.svg</file>
|
||||
|