1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-01 05:19:15 +02:00

Compare commits

..

78 Commits
5.0 ... 5.4

Author SHA1 Message Date
309fdb675c Removed unused definitions 2018-03-11 20:53:16 +01:00
e0daf367fb Added support for WGS84 GeoTIFF images with the GCS defined using the ellipsoid only 2018-03-11 20:11:42 +01:00
32d8672698 REST variables (dimensions) are apparently case-insensitive 2018-03-11 19:23:40 +01:00
0ef89e200d Translations update 2018-03-11 16:28:30 +01:00
6d6c232dba Version++ 2018-03-11 10:49:02 +01:00
8132ff722d Added support for WMTS dimensions 2018-03-11 10:31:41 +01:00
49792064d7 Fixed error handling 2018-03-11 09:24:04 +01:00
7aef81d823 Added support for EPSG 21781 PCS (Swiss grid)
Fixed swapped LCC1 and LCC2 GeoTIFF coordinate transformation codes
2018-03-11 01:10:24 +01:00
1d3d1aa5b7 Fixed broken zoom rectangle computation 2018-03-10 21:04:14 +01:00
bcd14726f3 Added pace info 2018-03-10 20:25:13 +01:00
fd15799114 Includes cleanup 2018-03-10 09:25:52 +01:00
a8bc2ae4c4 Fixed wrong data type 2018-03-10 08:40:55 +01:00
67aba4703b Some more code cleanup 2018-03-09 23:24:08 +01:00
a64e5e13c3 Remove the 1px offset workaround as it does not work properly anyway... 2018-03-09 21:53:06 +01:00
60fcff7658 Code cleanup 2018-03-09 18:57:23 +01:00
bc881836ac Improved map index caching 2018-03-09 18:56:54 +01:00
de05f5e64b Some more offline map code cleanup 2018-03-08 19:08:39 +01:00
16476dbf74 Offline map code cleanup/refactoring 2018-03-08 02:24:10 +01:00
a21464d98d Added missing virtual destructors 2018-03-08 00:57:09 +01:00
d6746bc444 Code cleanup 2018-03-06 19:28:07 +01:00
e4d8af2040 Update README.md 2018-03-01 20:30:02 +01:00
b40e0d3bbf Fixed accessing of un-initialized variable 2018-03-01 19:06:55 +01:00
9300d671a1 Fixed invalid memory access 2018-03-01 19:06:34 +01:00
b9ed0c3933 Improved scale computation on offline & WMTS maps 2018-02-28 22:19:46 +01:00
46cefada94 Code cleanup 2018-02-27 21:50:29 +01:00
e1e49b32e6 Added some more map definition checking 2018-02-27 01:02:22 +01:00
fa99d01a77 Extended error checking 2018-02-26 22:35:58 +01:00
688e309ef7 Update gpxsee_sv.ts (#79)
Change shortcut letter for "Data"
2018-02-26 19:22:34 +01:00
ae4723acb1 Added GCS 4178 and related PCSs 2018-02-26 19:21:00 +01:00
8c6f70d837 Code cleanup 2018-02-26 19:13:57 +01:00
d1b0e2ef73 Improved error reporting 2018-02-26 19:05:53 +01:00
962310df7d Fixed single point zoom fit on WMTS maps 2018-02-25 19:33:12 +01:00
f8c031e931 Translation update/cleanup 2018-02-25 09:31:19 +01:00
8022a9efbe Update gpxsee_sv.ts (#78) 2018-02-25 09:18:10 +01:00
fbab4b0097 Made the axis order an attribute of the set rather than a separate element 2018-02-25 08:58:40 +01:00
5e5ff6d96f Added support for REST WMTS maps 2018-02-25 02:31:01 +01:00
55e967673c Use image/png as the default image format 2018-02-24 22:31:37 +01:00
757ba6a566 Fixed QT4 build 2018-02-24 16:48:38 +01:00
ee80260e46 Improved capabilities xml parsing
Improved bounds handling
2018-02-24 16:44:30 +01:00
fa3e6d8550 Added error checking 2018-02-24 11:40:54 +01:00
6e95d484cd Added support for OGC:CRS84 CRS to WMTS maps 2018-02-24 11:20:29 +01:00
376587202b Properly handling non-integer tile matrix ids 2018-02-24 10:34:27 +01:00
d11ffc9ea4 Added tile matrix set limits handling
Added axis order setting
2018-02-24 01:59:03 +01:00
bf6ebdc088 Translations update (#77) 2018-02-23 00:13:49 +01:00
619df591e2 Added support for geographic2d "projected" WMTS maps 2018-02-22 21:02:56 +01:00
10aa7d3945 Code cleanup 2018-02-22 18:12:47 +01:00
12319fd8fd Cleanup 2018-02-22 18:07:51 +01:00
ccb7336e3f Added menu accelerator keys 2018-02-22 08:18:10 +01:00
a7fea3878c Version++ 2018-02-22 00:56:49 +01:00
a6cf88aa92 Fixed visual artefacts on transparent tiles 2018-02-22 00:50:45 +01:00
b054cf9046 Using the correct projection for Lambert azimuthal equal area 2018-02-22 00:46:05 +01:00
9c5153f89a Fixed QT4 build 2018-02-21 00:13:11 +01:00
2ebcdeeeff Added ETRS89 data 2018-02-20 23:38:29 +01:00
1bc4833a81 Added initial WMTS support 2018-02-20 23:37:19 +01:00
3202fc4c15 Version++ 2018-02-17 14:23:00 +01:00
5852a9dc09 Removed copy&paste junk 2018-02-17 14:20:23 +01:00
c587d8cd9a Added AppData file 2018-02-17 14:18:40 +01:00
586f30a337 Improved time sequence checking 2018-02-17 13:40:25 +01:00
da06c032bc Added map copyrights info 2018-02-16 22:55:35 +01:00
3def9f95b0 Fixed broken GeoTIFF Mercator coordinates transformation 2018-02-16 19:37:04 +01:00
dc25290637 Added time missing sequence check 2018-02-15 23:03:20 +01:00
9fd5b1b80a Fixed broken map show setting
Code cleanup
2018-02-15 01:44:03 +01:00
94ee5b6e67 Fixed crash on tracks with less than window size points 2018-02-15 01:43:04 +01:00
9556476f1b Merge branch 'master' of https://github.com/tumic0/GPXSee 2018-02-13 23:03:52 +01:00
b6e798f5c3 Removed debug stuff from release builds 2018-02-13 23:03:18 +01:00
e82f2a02c2 Updated Finnish translations (#67) 2018-02-12 23:24:16 +01:00
361ffacc35 Updated Russian translations (#65) 2018-02-12 23:23:38 +01:00
18fc6cc3e2 Fixed nmi conversion issues 2018-02-12 08:23:38 +01:00
9815f0bff2 Version++ 2018-02-12 07:46:20 +01:00
805cbe921c Updated Czech translations 2018-02-12 07:44:00 +01:00
d529055ea3 Update gpxsee_sv.ts (#64)
Latest strings translated
2018-02-12 07:37:58 +01:00
5d590b7c86 Fixed object init loop issue 2018-02-12 01:20:21 +01:00
1003c7b56f ts files update 2018-02-11 23:54:17 +01:00
820f967bd6 Added support for nautical units 2018-02-11 23:51:57 +01:00
27632bf07e Code cleanup 2018-02-11 20:49:26 +01:00
ee5b8fa333 Merge branch 'master' of https://github.com/tumic0/GPXSee 2018-02-11 20:41:21 +01:00
7e42b57d73 Added coordinates format settings
+ Fixed units settings issues
2018-02-11 20:39:39 +01:00
292fc9b433 Added GeoTIFF support info 2018-02-10 23:15:22 +01:00
116 changed files with 5800 additions and 3734 deletions

View File

@ -1,4 +1,4 @@
version: 5.0.{build}
version: 5.4.{build}
configuration: Release
platform: Any CPU
environment:

View File

@ -3,8 +3,8 @@ GPXSee is a Qt-based GPS log file viewer and analyzer that supports GPX, TCX,
KML, FIT, IGC and NMEA files.
## Features
* User-definable online maps.
* Offline maps (OziExplorer maps and TrekBuddy maps/atlases).
* User-definable online maps (OSM/Google tiles, WMTS).
* Offline maps (OziExplorer maps, TrekBuddy maps/atlases, GeoTIFF images).
* Elevation, speed, heart rate, cadence, power and temperature graphs.
* Support for multiple tracks in one view.
* Support for POI files.

View File

@ -1,5 +1,5 @@
TARGET = GPXSee
VERSION = 5.0
VERSION = 5.4
QT += core \
gui \
network
@ -116,7 +116,10 @@ HEADERS += src/config.h \
src/map/primemeridian.h \
src/map/linearunits.h \
src/map/ct.h \
src/map/mapsource.h
src/map/mapsource.h \
src/map/tileloader.h \
src/map/wmtsmap.h \
src/map/wmts.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -202,7 +205,10 @@ SOURCES += src/main.cpp \
src/map/angularunits.cpp \
src/map/primemeridian.cpp \
src/map/linearunits.cpp \
src/map/mapsource.cpp
src/map/mapsource.cpp \
src/map/tileloader.cpp \
src/map/wmtsmap.cpp \
src/map/wmts.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts \
lang/gpxsee_sv.ts \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

58
pkg/appdata.xml Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>gpxsee.desktop</id>
<metadata_license>MIT</metadata_license>
<project_license>GPL-3.0</project_license>
<name>GPXSee</name>
<summary>GPS log file viewer and analyzer</summary>
<description>
<p>GPXSee is a GPS log file viewer and analyzer that supports GPX, TCX,
KML, FIT, IGC and NMEA files.</p>
<p>Features:</p>
<ul>
<li>User-definable online maps.</li>
<li>Offline maps (OziExplorer maps, TrekBuddy maps/atlases, GeoTIFF
images).</li>
<li>Elevation, speed, heart rate, cadence, power and temperature
graphs.</li>
<li>Support for multiple tracks in one view.</li>
<li>Support for POI files.</li>
<li>Print/export to PDF.</li>
<li>Full-screen mode.</li>
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA and Garmin CSV files.</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<image>http://www.gpxsee.org/gallery/lin1.png</image>
</screenshot>
<screenshot>
<image>http://www.gpxsee.org/gallery/lin2.png</image>
</screenshot>
</screenshots>
<categories>
<category>Graphics</category>
<category>Viewer</category>
</categories>
<url type="homepage">http://www.gpxsee.org</url>
<launchable type="desktop-id">gpxsee.desktop</launchable>
<provides>
<binary>gpxsee</binary>
</provides>
<mimetypes>
<mimetype>application/gpx+xml</mimetype>
<mimetype>application/tcx+xml</mimetype>
<mimetype>application/vnd.ant.fit</mimetype>
<mimetype>application/vnd.google-earth.kml+xml</mimetype>
<mimetype>application/vnd.fai.igc</mimetype>
<mimetype>application/vnd.nmea.nmea</mimetype>
</mimetypes>
</component>

View File

@ -21,7 +21,7 @@ Canton Astro 1966,4716,6716,9122,7022,8901,9603,298,-304,-375
Cape,4222,6222,9122,7012,8901,9603,-136,-108,-292
Cape Canaveral,4717,6717,9122,7008,8901,9603,-2,150,181
Carthage,4223,6223,9122,7012,8901,9603,-263,6,431
CH-1903,4149,6149,9122,7004,8901,9603,674,15,405
CH-1903,4149,6149,9122,7004,8901,9603,674.374,15.056,405.343
Chatham 1971,4672,6672,9122,7022,8901,9603,175,-38,113
Chua Astro,4224,6224,9122,7022,8901,9603,-134,229,-29
Corrego Alegre,4225,6225,9122,7022,8901,9603,-206,172,-6
@ -29,6 +29,7 @@ Djakarta (Batavia),4211,6211,9122,7004,8901,9603,-377,681,-50
DOS 1968,,,9122,7022,8901,9603,230,-199,-752
Easter Island 1967,4719,6719,9122,7022,8901,9603,211,147,111
Egypt,4199,6199,9122,7022,8901,9603,-130,-117,-151
ETRS 89,4258,6258,9122,7019,8901,9603,0,0,0
European 1950,4230,6230,9122,7022,8901,9603,-87,-98,-121
European 1950 (Mean France),,,9122,7022,8901,9603,-87,-96,-120
European 1950 (Spain and Portugal),,,9122,7022,8901,9603,-84,-107,-120
@ -104,6 +105,7 @@ Rijksdriehoeksmeting,4289,6289,9122,7004,8901,9603,593,26,478
Rome 1940,4806,6806,9122,7022,8906,9603,-225,-65,9
RT 90,4124,6124,9122,7004,8901,9603,498,-36,568
S42,4179,6179,9122,7024,8901,9603,28,-121,-77
S42 (83),4178,6178,9122,7024,8901,9603,26,-121,-78
Santo (DOS),4730,6730,9122,7022,8901,9603,170,42,84
Sao Braz,4184,6184,9122,7022,8901,9603,-203,141,53
Sapper Hill 1943,4292,6292,9122,7022,8901,9603,-355,16,74

1 Adindan 4201 6201 9122 7012 8901 9603 -162 -12 206
21 Cape 4222 6222 9122 7012 8901 9603 -136 -108 -292
22 Cape Canaveral 4717 6717 9122 7008 8901 9603 -2 150 181
23 Carthage 4223 6223 9122 7012 8901 9603 -263 6 431
24 CH-1903 4149 6149 9122 7004 8901 9603 674 674.374 15 15.056 405 405.343
25 Chatham 1971 4672 6672 9122 7022 8901 9603 175 -38 113
26 Chua Astro 4224 6224 9122 7022 8901 9603 -134 229 -29
27 Corrego Alegre 4225 6225 9122 7022 8901 9603 -206 172 -6
29 DOS 1968 9122 7022 8901 9603 230 -199 -752
30 Easter Island 1967 4719 6719 9122 7022 8901 9603 211 147 111
31 Egypt 4199 6199 9122 7022 8901 9603 -130 -117 -151
32 ETRS 89 4258 6258 9122 7019 8901 9603 0 0 0
33 European 1950 4230 6230 9122 7022 8901 9603 -87 -98 -121
34 European 1950 (Mean France) 9122 7022 8901 9603 -87 -96 -120
35 European 1950 (Spain and Portugal) 9122 7022 8901 9603 -84 -107 -120
105 Rome 1940 4806 6806 9122 7022 8906 9603 -225 -65 9
106 RT 90 4124 6124 9122 7004 8901 9603 498 -36 568
107 S42 4179 6179 9122 7024 8901 9603 28 -121 -77
108 S42 (83) 4178 6178 9122 7024 8901 9603 26 -121 -78
109 Santo (DOS) 4730 6730 9122 7022 8901 9603 170 42 84
110 Sao Braz 4184 6184 9122 7022 8901 9603 -203 141 53
111 Sapper Hill 1943 4292 6292 9122 7022 8901 9603 -355 16 74

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "5.0"
!define VERSION "5.4"
; The file to write
OutFile "GPXSee-${VERSION}.exe"

View File

@ -5,7 +5,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "5.0"
!define VERSION "5.4"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -4,4 +4,5 @@
<url>http://4umaps.eu/$z/$x/$y.png</url>
<zoom min="2" max="15"/>
<bounds bottom="-65"/>
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
</map>

View File

@ -2,4 +2,5 @@
<map>
<name>Open Street Map</name>
<url>http://tile.openstreetmap.org/$z/$x/$y.png</url>
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
</map>

View File

@ -3,4 +3,5 @@
<name>Open Topo Map</name>
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
<zoom max="17"/>
<copyright>Map data: © OpenStreetMap contributors (ODbL), SRTM | Rendering: © OpenTopoMap (CC-BY-SA)</copyright>
</map>

View File

@ -4,4 +4,5 @@
<url>https://navigator.er.usgs.gov/tiles/aerial_Imagery.cgi/$z/$x/$y</url>
<zoom min="2" max="15"/>
<bounds bottom="0" top="74"/>
<copyright>Map services and data available from U.S. Geological Survey, National Geospatial Program.</copyright>
</map>

View File

@ -3,4 +3,5 @@
<name>USGS Topo</name>
<url>https://navigator.er.usgs.gov/tiles/tcr.cgi/$z/$x/$y.png</url>
<zoom min="2" max="15"/>
<copyright>Map services and data available from U.S. Geological Survey, National Geospatial Program.</copyright>
</map>

View File

@ -4,7 +4,8 @@
#include <QFileOpenEvent>
#include <QNetworkProxyFactory>
#include <QLibraryInfo>
#include "map/onlinemap.h"
#include "map/wmts.h"
#include "map/tileloader.h"
#include "map/downloader.h"
#include "map/ellipsoid.h"
#include "map/gcs.h"
@ -36,7 +37,9 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
#endif // Q_OS_MAC
QNetworkProxyFactory::setUseSystemConfiguration(true);
OnlineMap::setDownloader(new Downloader(this));
Downloader *dl = new Downloader(this);
TileLoader::setDownloader(dl);
WMTS::setDownloader(dl);
OPENGL_SET_SAMPLES(4);
loadDatums();
loadPCSs();

View File

@ -62,12 +62,17 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
_bottomMargin = new QDoubleSpinBox();
_leftMargin = new QDoubleSpinBox();
_rightMargin = new QDoubleSpinBox();
QString us = (_export->units == Imperial) ? tr("in") : tr("mm");
QString us = (_export->units == Metric) ? tr("mm") : tr("in");
_topMargin->setSuffix(UNIT_SPACE + us);
_bottomMargin->setSuffix(UNIT_SPACE + us);
_leftMargin->setSuffix(UNIT_SPACE + us);
_rightMargin->setSuffix(UNIT_SPACE + us);
if (_export->units == Imperial) {
if (_export->units == Metric) {
_topMargin->setValue(_export->margins.top());
_bottomMargin->setValue(_export->margins.bottom());
_leftMargin->setValue(_export->margins.left());
_rightMargin->setValue(_export->margins.right());
} else {
_topMargin->setValue(_export->margins.top() * MM2IN);
_bottomMargin->setValue(_export->margins.bottom() * MM2IN);
_leftMargin->setValue(_export->margins.left() * MM2IN);
@ -76,11 +81,6 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
_bottomMargin->setSingleStep(0.1);
_leftMargin->setSingleStep(0.1);
_rightMargin->setSingleStep(0.1);
} else {
_topMargin->setValue(_export->margins.top());
_bottomMargin->setValue(_export->margins.bottom());
_leftMargin->setValue(_export->margins.left());
_rightMargin->setValue(_export->margins.right());
}
QGridLayout *marginsLayout = new QGridLayout();

View File

@ -2,6 +2,32 @@
#include "common/coordinates.h"
#include "format.h"
static QString deg2DMS(double val)
{
int deg = val;
double r1 = val - deg;
int min = r1 * 60.0;
double r2 = r1 - (min / 60.0);
double sec = r2 * 3600.0;
return QString("%1°%2'%3\"").arg(deg).arg(min, 2, 10, QChar('0'))
.arg(sec, 4, 'f', 1, QChar('0'));
}
static QString deg2DMM(double val)
{
int deg = val;
double r1 = val - deg;
double min = r1 * 60.0;
return QString("%1°%2'").arg(deg).arg(min, 6, 'f', 3, QChar('0'));
}
QString Format::timeSpan(qreal time, bool full)
{
unsigned h, m, s;
@ -27,6 +53,13 @@ QString Format::distance(qreal value, Units units)
else
return QString::number(value * M2MI, 'f', 1) + UNIT_SPACE
+ qApp->translate("Format", "mi");
} else if (units == Nautical) {
if (value < NMIINM)
return QString::number(value * M2FT, 'f', 0) + UNIT_SPACE
+ qApp->translate("Format", "ft");
else
return QString::number(value * M2NMI, 'f', 1) + UNIT_SPACE
+ qApp->translate("Format", "nmi");
} else {
if (value < KMINM)
return QString::number(value, 'f', 0) + UNIT_SPACE
@ -47,11 +80,22 @@ QString Format::elevation(qreal value, Units units)
+ qApp->translate("Format", "ft");
}
QString Format::coordinates(const Coordinates &value)
QString Format::coordinates(const Coordinates &value, CoordinatesFormat type)
{
QChar yH = (value.lat() < 0) ? 'S' : 'N';
QChar xH = (value.lon() < 0) ? 'W' : 'E';
return QString::number(qAbs(value.lat()), 'f', 5) + yH + "," + QChar(0x00A0)
+ QString::number(qAbs(value.lon()), 'f', 5) + xH;
switch (type) {
case DegreesMinutes:
return deg2DMM(qAbs(value.lat())) + yH + "," + QChar(0x00A0)
+ deg2DMM(qAbs(value.lon())) + xH;
break;
case DMS:
return deg2DMS(qAbs(value.lat())) + yH + "," + QChar(0x00A0)
+ deg2DMS(qAbs(value.lon())) + xH;
break;
default:
return QString::number(qAbs(value.lat()), 'f', 5) + yH + ","
+ QChar(0x00A0) + QString::number(qAbs(value.lon()), 'f', 5) + xH;
}
}

View File

@ -6,12 +6,18 @@
class Coordinates;
enum CoordinatesFormat {
DecimalDegrees,
DegreesMinutes,
DMS
};
namespace Format
{
QString timeSpan(qreal time, bool full = true);
QString distance(qreal value, Units units);
QString elevation(qreal value, Units units);
QString coordinates(const Coordinates &value);
QString coordinates(const Coordinates &value, CoordinatesFormat type);
}
#endif // FORMAT_H

View File

@ -12,6 +12,7 @@ class GraphItem : public QGraphicsObject
public:
GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent = 0);
virtual ~GraphItem() {}
QPainterPath shape() const {return _shape;}
QRectF boundingRect() const {return _shape.boundingRect();}

View File

@ -16,6 +16,7 @@ class GraphTab : public GraphView
public:
GraphTab(QWidget *parent = 0) : GraphView(parent)
{setFrameShape(QFrame::NoFrame);}
virtual ~GraphTab() {}
virtual QString label() const = 0;
virtual void loadData(const Data &data, const QList<PathItem *> &paths) = 0;

View File

@ -104,15 +104,7 @@ void GraphView::setYUnits(const QString &units)
void GraphView::setXUnits()
{
if (_graphType == Distance) {
if (_units == Metric) {
if (bounds().width() < KMINM) {
_xUnits = tr("m");
_xScale = 1;
} else {
_xUnits = tr("km");
_xScale = M2KM;
}
} else {
if (_units == Imperial) {
if (bounds().width() < MIINM) {
_xUnits = tr("ft");
_xScale = M2FT;
@ -120,6 +112,22 @@ void GraphView::setXUnits()
_xUnits = tr("mi");
_xScale = M2MI;
}
} else if (_units == Nautical) {
if (bounds().width() < NMIINM) {
_xUnits = tr("ft");
_xScale = M2FT;
} else {
_xUnits = tr("nmi");
_xScale = M2NMI;
}
} else {
if (bounds().width() < KMINM) {
_xUnits = tr("m");
_xScale = 1;
} else {
_xUnits = tr("km");
_xScale = M2KM;
}
}
} else {
if (bounds().width() < MININS) {

View File

@ -40,7 +40,6 @@
#include "filebrowser.h"
#include "cpuarch.h"
#include "graphtab.h"
#include "format.h"
#include "gui.h"
@ -373,6 +372,28 @@ void GUI::createActions()
_imperialUnitsAction->setActionGroup(ag);
connect(_imperialUnitsAction, SIGNAL(triggered()), this,
SLOT(setImperialUnits()));
_nauticalUnitsAction = new QAction(tr("Nautical"), this);
_nauticalUnitsAction->setCheckable(true);
_nauticalUnitsAction->setActionGroup(ag);
connect(_nauticalUnitsAction, SIGNAL(triggered()), this,
SLOT(setNauticalUnits()));
ag = new QActionGroup(this);
ag->setExclusive(true);
_decimalDegreesAction = new QAction(tr("Decimal degrees (DD)"), this);
_decimalDegreesAction->setCheckable(true);
_decimalDegreesAction->setActionGroup(ag);
connect(_decimalDegreesAction, SIGNAL(triggered()), this,
SLOT(setDecimalDegrees()));
_degreesMinutesAction = new QAction(tr("Degrees and decimal minutes (DMM)"),
this);
_degreesMinutesAction->setCheckable(true);
_degreesMinutesAction->setActionGroup(ag);
connect(_degreesMinutesAction, SIGNAL(triggered()), this,
SLOT(setDegreesMinutes()));
_DMSAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
_DMSAction->setCheckable(true);
_DMSAction->setActionGroup(ag);
connect(_DMSAction, SIGNAL(triggered()), this, SLOT(setDMS()));
_fullscreenAction = new QAction(QIcon(QPixmap(FULLSCREEN_ICON)),
tr("Fullscreen mode"), this);
_fullscreenAction->setCheckable(true);
@ -404,7 +425,7 @@ void GUI::createActions()
void GUI::createMenus()
{
QMenu *fileMenu = menuBar()->addMenu(tr("File"));
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(_openFileAction);
fileMenu->addSeparator();
fileMenu->addAction(_printFileAction);
@ -418,7 +439,7 @@ void GUI::createMenus()
fileMenu->addAction(_exitAction);
#endif // Q_OS_MAC
_mapMenu = menuBar()->addMenu(tr("Map"));
_mapMenu = menuBar()->addMenu(tr("&Map"));
_mapMenu->addActions(_mapActions);
_mapsEnd = _mapMenu->addSeparator();
_mapMenu->addAction(_loadMapAction);
@ -426,7 +447,7 @@ void GUI::createMenus()
_mapMenu->addSeparator();
_mapMenu->addAction(_showMapAction);
QMenu *graphMenu = menuBar()->addMenu(tr("Graph"));
QMenu *graphMenu = menuBar()->addMenu(tr("&Graph"));
graphMenu->addAction(_distanceGraphAction);
graphMenu->addAction(_timeGraphAction);
graphMenu->addSeparator();
@ -435,7 +456,7 @@ void GUI::createMenus()
graphMenu->addSeparator();
graphMenu->addAction(_showGraphsAction);
QMenu *poiMenu = menuBar()->addMenu(tr("POI"));
QMenu *poiMenu = menuBar()->addMenu(tr("&POI"));
_poiFilesMenu = poiMenu->addMenu(tr("POI files"));
_poiFilesMenu->addActions(_poiFilesActions);
poiMenu->addSeparator();
@ -447,7 +468,7 @@ void GUI::createMenus()
poiMenu->addSeparator();
poiMenu->addAction(_showPOIAction);
QMenu *dataMenu = menuBar()->addMenu(tr("Data"));
QMenu *dataMenu = menuBar()->addMenu(tr("&Data"));
QMenu *displayMenu = dataMenu->addMenu(tr("Display"));
displayMenu->addAction(_showWaypointLabelsAction);
displayMenu->addAction(_showRouteWaypointsAction);
@ -456,20 +477,25 @@ void GUI::createMenus()
dataMenu->addAction(_showRoutesAction);
dataMenu->addAction(_showWaypointsAction);
QMenu *settingsMenu = menuBar()->addMenu(tr("Settings"));
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
QMenu *timeMenu = settingsMenu->addMenu(tr("Time"));
timeMenu->addAction(_totalTimeAction);
timeMenu->addAction(_movingTimeAction);
QMenu *unitsMenu = settingsMenu->addMenu(tr("Units"));
unitsMenu->addAction(_metricUnitsAction);
unitsMenu->addAction(_imperialUnitsAction);
unitsMenu->addAction(_nauticalUnitsAction);
QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
coordinatesMenu->addAction(_decimalDegreesAction);
coordinatesMenu->addAction(_degreesMinutesAction);
coordinatesMenu->addAction(_DMSAction);
settingsMenu->addSeparator();
settingsMenu->addAction(_showToolbarsAction);
settingsMenu->addAction(_fullscreenAction);
settingsMenu->addSeparator();
settingsMenu->addAction(_openOptionsAction);
QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(_pathsAction);
helpMenu->addAction(_keysAction);
helpMenu->addSeparator();
@ -1121,7 +1147,7 @@ bool GUI::loadMap(const QString &fileName)
_mapMenu->insertAction(_mapsEnd, a);
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
_mapActions.last()->activate(QAction::Trigger);
_mapActions.last()->trigger();
return true;
} else {
@ -1293,6 +1319,11 @@ void GUI::setUnits(Units units)
updateStatusBarInfo();
}
void GUI::setCoordinatesFormat(CoordinatesFormat format)
{
_mapView->setCoordinatesFormat(format);
}
void GUI::setGraphType(GraphType type)
{
_sliderPos = 0;
@ -1363,15 +1394,15 @@ void GUI::keyPressEvent(QKeyEvent *event)
case TOGGLE_GRAPH_TYPE_KEY:
if (_timeGraphAction->isChecked())
_distanceGraphAction->activate(QAction::Trigger);
_distanceGraphAction->trigger();
else
_timeGraphAction->activate(QAction::Trigger);
_timeGraphAction->trigger();
break;
case TOGGLE_TIME_TYPE_KEY:
if (_movingTimeAction->isChecked())
_totalTimeAction->activate(QAction::Trigger);
_totalTimeAction->trigger();
else
_movingTimeAction->activate(QAction::Trigger);
_movingTimeAction->trigger();
break;
case Qt::Key_Escape:
@ -1437,11 +1468,15 @@ void GUI::writeSettings()
if ((_movingTimeAction->isChecked() ? Moving : Total) !=
TIME_TYPE_DEFAULT)
settings.setValue(TIME_TYPE_SETTING, _movingTimeAction->isChecked()
? Moving : Total);
if ((_imperialUnitsAction->isChecked() ? Imperial : Metric) !=
UNITS_DEFAULT)
settings.setValue(UNITS_SETTING, _imperialUnitsAction->isChecked()
? Imperial : Metric);
? Moving : Total);
Units units = _imperialUnitsAction->isChecked() ? Imperial
: _nauticalUnitsAction->isChecked() ? Nautical : Metric;
if (units != UNITS_DEFAULT)
settings.setValue(UNITS_SETTING, units);
CoordinatesFormat format = _DMSAction->isChecked() ? DMS
: _degreesMinutesAction->isChecked() ? DegreesMinutes : DecimalDegrees;
if (format != COORDINATES_DEFAULT)
settings.setValue(COORDINATES_SETTING, format);
if (_showToolbarsAction->isChecked() != SHOW_TOOLBARS_DEFAULT)
settings.setValue(SHOW_TOOLBARS_SETTING,
_showToolbarsAction->isChecked());
@ -1601,6 +1636,7 @@ void GUI::writeSettings()
void GUI::readSettings()
{
int value;
QSettings settings(APP_NAME, APP_NAME);
settings.beginGroup(WINDOW_SETTINGS_GROUP);
@ -1610,20 +1646,27 @@ void GUI::readSettings()
settings.beginGroup(SETTINGS_SETTINGS_GROUP);
if (settings.value(TIME_TYPE_SETTING, TIME_TYPE_DEFAULT).toInt()
== Moving) {
setTimeType(Moving);
_movingTimeAction->setChecked(true);
} else {
setTimeType(Total);
_totalTimeAction->setChecked(true);
}
if (settings.value(UNITS_SETTING, UNITS_DEFAULT).toInt() == Imperial) {
setUnits(Imperial);
_imperialUnitsAction->setChecked(true);
} else {
setUnits(Metric);
_metricUnitsAction->setChecked(true);
}
== Moving)
_movingTimeAction->trigger();
else
_totalTimeAction->trigger();
value = settings.value(UNITS_SETTING, UNITS_DEFAULT).toInt();
if (value == Imperial)
_imperialUnitsAction->trigger();
else if (value == Nautical)
_nauticalUnitsAction->trigger();
else
_metricUnitsAction->trigger();
value = settings.value(COORDINATES_SETTING, COORDINATES_DEFAULT).toInt();
if (value == DMS)
_DMSAction->trigger();
else if (value == DegreesMinutes)
_degreesMinutesAction->trigger();
else
_decimalDegreesAction->trigger();
if (!settings.value(SHOW_TOOLBARS_SETTING, SHOW_TOOLBARS_DEFAULT).toBool())
showToolbars(false);
else
@ -1633,6 +1676,8 @@ void GUI::readSettings()
settings.beginGroup(MAP_SETTINGS_GROUP);
if (settings.value(SHOW_MAP_SETTING, SHOW_MAP_DEFAULT).toBool())
_showMapAction->setChecked(true);
else
_mapView->showMap(false);
if (_ml->maps().count()) {
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
_mapActions.at(index)->trigger();
@ -1867,7 +1912,8 @@ int GUI::mapIndex(const QString &name)
Units GUI::units() const
{
return _imperialUnitsAction->isChecked() ? Imperial : Metric;
return _imperialUnitsAction->isChecked() ? Imperial
: _nauticalUnitsAction->isChecked() ? Nautical : Metric;
}
qreal GUI::distance() const

View File

@ -10,6 +10,7 @@
#include "data/poi.h"
#include "units.h"
#include "timetype.h"
#include "format.h"
#include "exportdialog.h"
#include "optionsdialog.h"
@ -73,8 +74,12 @@ private slots:
void setMovingTime() {setTimeType(Moving);}
void setMetricUnits() {setUnits(Metric);}
void setImperialUnits() {setUnits(Imperial);}
void setNauticalUnits() {setUnits(Nautical);}
void setDistanceGraph() {setGraphType(Distance);}
void setTimeGraph() {setGraphType(Time);}
void setDecimalDegrees() {setCoordinatesFormat(DecimalDegrees);}
void setDegreesMinutes() {setCoordinatesFormat(DegreesMinutes);}
void setDMS() {setCoordinatesFormat(DMS);}
void sliderPositionChanged(qreal pos);
@ -111,6 +116,7 @@ private:
Units units() const;
void setTimeType(TimeType type);
void setUnits(Units units);
void setCoordinatesFormat(CoordinatesFormat format);
void setGraphType(GraphType type);
qreal distance() const;
@ -165,6 +171,10 @@ private:
QAction *_firstAction;
QAction *_metricUnitsAction;
QAction *_imperialUnitsAction;
QAction *_nauticalUnitsAction;
QAction *_decimalDegreesAction;
QAction *_degreesMinutesAction;
QAction *_DMSAction;
QAction *_totalTimeAction;
QAction *_movingTimeAction;
QAction *_nextMapAction;

View File

@ -49,6 +49,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
_units = Metric;
_coordinatesFormat = DecimalDegrees;
_opacity = 1.0;
_backgroundColor = Qt::white;
_markerColor = Qt::red;
@ -75,6 +76,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
_digitalZoom = 0;
_map->setBackgroundColor(_backgroundColor);
_res = _map->resolution(_map->bounds());
_scene->setSceneRect(_map->bounds());
centerOn(_scene->sceneRect().center());
@ -83,18 +85,8 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
void MapView::centerOn(const QPointF &pos)
{
QGraphicsView::centerOn(pos);
/* Fix the offset caused by QGraphicsView::centerOn() approximation */
QPointF center = mapToScene(viewport()->rect().center());
QPoint offset((int)(pos.x() - center.x()), (int)(pos.y() - center.y()));
if (qAbs(offset.x()) == 1)
horizontalScrollBar()->setValue(horizontalScrollBar()->value()
+ offset.x());
if (qAbs(offset.y()) == 1)
verticalScrollBar()->setValue(verticalScrollBar()->value()
+ offset.y());
_res = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
_res = _map->resolution(vr);
_mapScale->setResolution(_res);
}
@ -137,6 +129,7 @@ PathItem *MapView::addRoute(const Route &route)
ri->setWidth(_routeWidth);
ri->setStyle(_routeStyle);
ri->setUnits(_units);
ri->setCoordinatesFormat(_coordinatesFormat);
ri->setVisible(_showRoutes);
ri->showWaypoints(_showRouteWaypoints);
ri->showWaypointLabels(_showWaypointLabels);
@ -162,7 +155,7 @@ void MapView::addWaypoints(const QList<Waypoint> &waypoints)
wi->setSize(_waypointSize);
wi->setColor(_waypointColor);
wi->showLabel(_showWaypointLabels);
wi->setUnits(_units);
wi->setToolTipFormat(_units, _coordinatesFormat);
wi->setVisible(_showWaypoints);
wi->setDigitalZoom(_digitalZoom);
_scene->addItem(wi);
@ -175,7 +168,7 @@ void MapView::addWaypoints(const QList<Waypoint> &waypoints)
QList<PathItem *> MapView::loadData(const Data &data)
{
QList<PathItem *> paths;
qreal zoom = _map->zoom();
int zoom = _map->zoom();
for (int i = 0; i < data.tracks().count(); i++)
paths.append(addTrack(*(data.tracks().at(i))));
@ -196,7 +189,7 @@ QList<PathItem *> MapView::loadData(const Data &data)
return paths;
}
qreal MapView::mapZoom() const
int MapView::mapZoom() const
{
RectC br = _tr | _rr | _wr;
@ -265,9 +258,9 @@ void MapView::setPalette(const Palette &palette)
void MapView::setMap(Map *map)
{
QPointF pos = mapToScene(viewport()->rect().center());
Coordinates center = _map->xy2ll(pos);
qreal resolution = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
_map->unload();
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
@ -279,7 +272,7 @@ void MapView::setMap(Map *map)
digitalZoom(0);
_map->zoomFit(resolution, center);
_map->zoomFit(viewport()->rect().size(), cr);
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
@ -294,7 +287,7 @@ void MapView::setMap(Map *map)
it.value()->setMap(_map);
updatePOIVisibility();
centerOn(_map->ll2xy(center));
centerOn(_map->ll2xy(cr.center()));
resetCachedContent();
QPixmapCache::clear();
@ -348,28 +341,49 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
pi->showLabel(_showPOILabels);
pi->setVisible(_showPOI);
pi->setDigitalZoom(_digitalZoom);
pi->setToolTipFormat(_units, _coordinatesFormat);
_scene->addItem(pi);
_pois.insert(SearchPointer<Waypoint>(&(pi->waypoint())), pi);
}
}
void MapView::setUnits(enum Units units)
void MapView::setUnits(Units units)
{
if (_units == units)
return;
_units = units;
_mapScale->setUnits(units);
_mapScale->setUnits(_units);
for (int i = 0; i < _tracks.count(); i++)
_tracks[i]->setUnits(units);
_tracks[i]->setUnits(_units);
for (int i = 0; i < _routes.count(); i++)
_routes[i]->setUnits(units);
_routes[i]->setUnits(_units);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setUnits(units);
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setUnits(units);
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
void MapView::setCoordinatesFormat(CoordinatesFormat format)
{
if (_coordinatesFormat == format)
return;
_coordinatesFormat = format;
for (int i = 0; i < _waypoints.count(); i++)
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
for (int i = 0; i < _routes.count(); i++)
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
void MapView::clearMapCache()
@ -476,9 +490,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
bool hires)
{
QRect orig, adj;
qreal ratio, diff, origRes, q;
qreal ratio, diff, q;
QPointF origScene, origPos;
Coordinates origLL;
RectC origC;
// Enter plot mode
@ -503,9 +517,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Adjust the view for printing
if (hires) {
origScene = mapToScene(orig.center());
origLL = _map->xy2ll(origScene);
origRes = _map->resolution(origScene);
QRectF vr(mapToScene(orig).boundingRect());
origC = RectC(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
origScene = vr.center();
QPointF s(painter->device()->logicalDpiX()
/ (qreal)metric(QPaintDevice::PdmDpiX),
@ -535,7 +549,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Revert view changes to display mode
if (hires) {
_map->zoomFit(origRes, origLL);
_map->zoomFit(orig.size(), origC);
rescale();
centerOn(origScene);
}
@ -738,24 +752,21 @@ void MapView::setBackgroundColor(const QColor &color)
void MapView::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->fillRect(rect, _backgroundColor);
if (_showMap) {
QRectF ir = rect.intersected(_map->bounds());
if (_opacity < 1.0 || ir != rect)
painter->fillRect(rect, _backgroundColor);
if (_opacity < 1.0)
painter->setOpacity(_opacity);
_map->draw(painter, ir);
} else
painter->fillRect(rect, _backgroundColor);
}
}
void MapView::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
qreal zoom = _map->zoom();
int zoom = _map->zoom();
if (mapZoom() != zoom)
rescale();
@ -777,8 +788,8 @@ void MapView::scrollContentsBy(int dx, int dy)
{
QGraphicsView::scrollContentsBy(dx, dy);
QPointF center = mapToScene(viewport()->rect().center());
qreal res = _map->resolution(center);
QRectF sr(mapToScene(viewport()->rect()).boundingRect());
qreal res = _map->resolution(sr);
if (qMax(res, _res) / qMin(res, _res) > 1.1) {
_mapScale->setResolution(res);

View File

@ -9,6 +9,7 @@
#include "data/waypoint.h"
#include "searchpointer.h"
#include "units.h"
#include "format.h"
#include "palette.h"
class Data;
@ -34,12 +35,13 @@ public:
void setPalette(const Palette &palette);
void setPOI(POI *poi);
void setMap(Map *map);
void setUnits(enum Units units);
void plot(QPainter *painter, const QRectF &target, qreal scale, bool hires);
void clear();
void setUnits(Units units);
void setMarkerColor(const QColor &color);
void setTrackWidth(int width);
void setRouteWidth(int width);
void setTrackStyle(Qt::PenStyle style);
@ -52,7 +54,6 @@ public:
void setBackgroundColor(const QColor &color);
void useOpenGL(bool use);
void useAntiAliasing(bool use);
void setMarkerColor(const QColor &color);
public slots:
void showMap(bool show);
@ -65,6 +66,7 @@ public slots:
void showWaypoints(bool show);
void showRouteWaypoints(bool show);
void clearMapCache();
void setCoordinatesFormat(CoordinatesFormat format);
private slots:
void updatePOI();
@ -78,7 +80,7 @@ private:
void loadPOI();
void clearPOI();
qreal mapZoom() const;
int mapZoom() const;
QPointF contentCenter() const;
void rescale();
void centerOn(const QPointF &pos);
@ -108,6 +110,7 @@ private:
POI *_poi;
Palette _palette;
Units _units;
CoordinatesFormat _coordinatesFormat;
qreal _opacity;
QColor _backgroundColor;

View File

@ -25,11 +25,13 @@ private:
qreal _left, _top, _right, _bottom;
};
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const MarginsF &margins)
{
dbg.nospace() << "MarginsF(" << margins.left() << ", " << margins.top()
<< ", " << margins.right() << margins.bottom() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // MARGINS_H

View File

@ -291,6 +291,9 @@ QWidget *OptionsDialog::createDataPage()
if (_options->units == Imperial) {
_pauseSpeed->setValue(_options->pauseSpeed * MS2MIH);
_pauseSpeed->setSuffix(UNIT_SPACE + tr("mi/h"));
} else if (_options->units == Nautical) {
_pauseSpeed->setValue(_options->pauseSpeed * MS2KN);
_pauseSpeed->setSuffix(UNIT_SPACE + tr("kn"));
} else {
_pauseSpeed->setValue(_options->pauseSpeed * MS2KMH);
_pauseSpeed->setSuffix(UNIT_SPACE + tr("km/h"));
@ -323,6 +326,9 @@ QWidget *OptionsDialog::createPOIPage()
if (_options->units == Imperial) {
_poiRadius->setValue(_options->poiRadius / MIINM);
_poiRadius->setSuffix(UNIT_SPACE + tr("mi"));
} else if (_options->units == Nautical) {
_poiRadius->setValue(_options->poiRadius / NMIINM);
_poiRadius->setSuffix(UNIT_SPACE + tr("nmi"));
} else {
_poiRadius->setValue(_options->poiRadius / KMINM);
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
@ -525,13 +531,15 @@ void OptionsDialog::accept()
_options->powerFilter = _powerFilter->value();
_options->outlierEliminate = _outlierEliminate->isChecked();
qreal pauseSpeed = (_options->units == Imperial)
? _pauseSpeed->value() / MS2MIH : _pauseSpeed->value() / MS2KMH;
? _pauseSpeed->value() / MS2MIH : (_options->units == Nautical)
? _pauseSpeed->value() / MS2KN : _pauseSpeed->value() / MS2KMH;
if (qAbs(pauseSpeed - _options->pauseSpeed) > 0.01)
_options->pauseSpeed = pauseSpeed;
_options->pauseInterval = _pauseInterval->value();
qreal poiRadius = (_options->units == Imperial)
? _poiRadius->value() * MIINM : _poiRadius->value() * KMINM;
? _poiRadius->value() * MIINM : (_options->units == Nautical)
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
_options->poiRadius = poiRadius;

View File

@ -37,9 +37,11 @@ void Palette::reset()
_state = _h;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Palette &palette)
{
dbg.nospace() << "Palette(" << palette.color() << ", " << palette.shift()
<< ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -28,6 +28,8 @@ private:
qreal _state;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Palette &palette);
#endif // QT_NO_DEBUG
#endif // PALLETE_H

View File

@ -30,6 +30,8 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
_name = route.name();
_desc = route.description();
_units = Metric;
_coordinatesFormat = DecimalDegrees;
setToolTip(toolTip(Metric));
}
@ -47,9 +49,38 @@ void RouteItem::setMap(Map *map)
PathItem::setMap(map);
}
void RouteItem::setUnits(enum Units units)
void RouteItem::setUnits(Units units)
{
setToolTip(toolTip(units));
if (_units == units)
return;
_units = units;
setToolTip(toolTip(_units));
QList<QGraphicsItem *> childs = childItems();
for (int i = 0; i < childs.count(); i++) {
if (childs.at(i) != _marker) {
WaypointItem *wi = static_cast<WaypointItem*>(childs.at(i));
wi->setToolTipFormat(_units, _coordinatesFormat);
}
}
}
void RouteItem::setCoordinatesFormat(CoordinatesFormat format)
{
if (_coordinatesFormat == format)
return;
_coordinatesFormat = format;
QList<QGraphicsItem *> childs = childItems();
for (int i = 0; i < childs.count(); i++) {
if (childs.at(i) != _marker) {
WaypointItem *wi = static_cast<WaypointItem*>(childs.at(i));
wi->setToolTipFormat(_units, _coordinatesFormat);
}
}
}
void RouteItem::showWaypoints(bool show)

View File

@ -4,6 +4,7 @@
#include "data/route.h"
#include "pathitem.h"
#include "units.h"
#include "format.h"
class Map;
@ -17,6 +18,7 @@ public:
void setMap(Map *map);
void setUnits(Units units);
void setCoordinatesFormat(CoordinatesFormat format);
void showWaypoints(bool show);
void showWaypointLabels(bool show);
@ -25,6 +27,8 @@ private:
QString _name;
QString _desc;
Units _units;
CoordinatesFormat _coordinatesFormat;
};
#endif // ROUTEITEM_H

View File

@ -82,6 +82,9 @@ QString ScaleItem::units() const
if (_units == Imperial)
return _scale ? qApp->translate("ScaleItem", "mi")
: qApp->translate("ScaleItem", "ft");
else if (_units == Nautical)
return _scale ? qApp->translate("ScaleItem", "nmi")
: qApp->translate("ScaleItem", "ft");
else
return _scale ? qApp->translate("ScaleItem", "km")
: qApp->translate("ScaleItem", "m");
@ -94,8 +97,18 @@ void ScaleItem::computeScale()
if (_units == Imperial) {
_length = niceNum((res * M2FT * SCALE_WIDTH) / SEGMENTS, 1);
if (_length >= MIINFT) {
_length = niceNum((res * M2FT * FT2MI * SCALE_WIDTH) / SEGMENTS, 1);
_width = (_length / (res * M2FT * FT2MI));
_length = niceNum((res * M2MI * SCALE_WIDTH) / SEGMENTS, 1);
_width = (_length / (res * M2MI));
_scale = true;
} else {
_width = (_length / (res * M2FT));
_scale = false;
}
} else if (_units == Nautical) {
_length = niceNum((res * M2FT * SCALE_WIDTH) / SEGMENTS, 1);
if (_length >= NMIINFT) {
_length = niceNum((res * M2NMI * SCALE_WIDTH) / SEGMENTS, 1);
_width = (_length / (res * M2NMI));
_scale = true;
} else {
_width = (_length / (res * M2FT));

View File

@ -15,6 +15,8 @@
#define TIME_TYPE_DEFAULT Total
#define UNITS_SETTING "units"
#define UNITS_DEFAULT (IMPERIAL_UNITS() ? Imperial : Metric)
#define COORDINATES_SETTING "coordinates"
#define COORDINATES_DEFAULT DecimalDegrees
#define SHOW_TOOLBARS_SETTING "toolbar"
#define SHOW_TOOLBARS_DEFAULT true

View File

@ -1,16 +1,18 @@
#include "data/data.h"
#include "config.h"
#include "tooltip.h"
#include "format.h"
#include "speedgraphitem.h"
#include "speedgraph.h"
SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
{
_units = Metric;
_timeType = Total;
_showTracks = true;
setYUnits(Metric);
setYUnits();
setYLabel(tr("Speed"));
setSliderPrecision(1);
@ -19,10 +21,15 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
void SpeedGraph::setInfo()
{
if (_showTracks) {
QString pace = Format::timeSpan((3600.0 / (avg() * yScale())), false);
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
tr("min/mi") : tr("min/nmi");
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Pace"), pace + UNIT_SPACE + pu);
} else
clearInfo();
}
@ -77,20 +84,25 @@ void SpeedGraph::clear()
GraphView::clear();
}
void SpeedGraph::setYUnits(Units units)
void SpeedGraph::setYUnits()
{
if (units == Metric) {
GraphView::setYUnits(tr("km/h"));
setYScale(MS2KMH);
} else {
if (_units == Nautical) {
GraphView::setYUnits(tr("kn"));
setYScale(MS2KN);
} else if (_units == Imperial) {
GraphView::setYUnits(tr("mi/h"));
setYScale(MS2MIH);
} else {
GraphView::setYUnits(tr("km/h"));
setYScale(MS2KMH);
}
}
void SpeedGraph::setUnits(Units units)
{
setYUnits(units);
_units = units;
setYUnits();
setInfo();
GraphView::setUnits(units);

View File

@ -21,13 +21,14 @@ public:
private:
qreal avg() const;
qreal max() const {return bounds().bottom();}
void setYUnits(Units units);
void setYUnits();
void setInfo();
QList<QPointF> _avg;
QList<QPointF> _mavg;
enum TimeType _timeType;
Units _units;
TimeType _timeType;
bool _showTracks;
};

View File

@ -1,4 +1,5 @@
#include "tooltip.h"
#include "format.h"
#include "speedgraphitem.h"
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
@ -16,13 +17,20 @@ SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
QString SpeedGraphItem::toolTip() const
{
ToolTip tt;
qreal scale = (_units == Metric) ? MS2KMH : MS2MIH;
QString su = (_units == Metric) ? tr("km/h") : tr("mi/h");
qreal scale = (_units == Imperial) ? MS2MIH : (_units == Nautical)
? MS2KN : MS2KMH;
QString su = (_units == Imperial) ? tr("mi/h") : (_units == Nautical)
? tr("kn") : tr("km/h");
QString pace = Format::timeSpan((3600.0 / ((_timeType == Total)
? avg() * scale : mavg() * scale)), false);
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
tr("min/mi") : tr("min/nmi");
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 1)
+ UNIT_SPACE + su);
tt.insert(tr("Average"), QString::number((_timeType == Total)
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);
return tt.toString();
}

View File

@ -3,24 +3,29 @@
enum Units {
Metric,
Imperial
Imperial,
Nautical
};
#define M2KM 0.001000000000 // m -> km
#define M2MI 0.000621371192 // m -> mi
#define M2NMI 0.000539956803 // m -> nmi
#define M2FT 3.280839900000 // m -> ft
#define MS2KMH 3.600000000000 // m/s -> km/h
#define MS2MIH 2.236936290000 // m/s -> mi/h
#define MS2KN 1.943844490000 // m/s -> kn
#define FT2MI 0.000189393939 // ft -> mi
#define MM2IN 0.039370100000 // mm -> in
#define H2S 0.000277777778 // h -> s
#define MIN2S 0.016666666667 // min -> s
#define KMINM 1000.0 // 1 km in m
#define MIINFT 5280.0 // 1 mi in ft
#define MIINM 1609.344 // 1 mi in m
#define MININS 60.0 // 1 min in s
#define HINS 3600.0 // 1 hins
#define KMINM 1000.0 // 1 km in m
#define MIINFT 5280.0 // 1 mi in ft
#define NMIINFT 6076.11549 // 1 nm in ft
#define MIINM 1609.344 // 1 mi in m
#define NMIINM 1852.0 // 1 nmi in m
#define MININS 60.0 // 1 min in s
#define HINS 3600.0 // 1 hins
#define C2FS 1.8 // Celsius to Farenheit - scale
#define C2FO 32.0 // Celsius to Farenheit - offset

View File

@ -1,7 +1,6 @@
#include <QApplication>
#include <QPainter>
#include "config.h"
#include "format.h"
#include "tooltip.h"
#include "waypointitem.h"
@ -11,14 +10,14 @@
#define FS(size) \
((int)((qreal)size * 1.41))
QString WaypointItem::toolTip(Units units)
QString WaypointItem::toolTip(Units units, CoordinatesFormat format)
{
ToolTip tt;
if (!_waypoint.name().isEmpty())
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
Format::coordinates(_waypoint.coordinates()));
Format::coordinates(_waypoint.coordinates(), format));
if (!std::isnan(_waypoint.elevation()))
tt.insert(qApp->translate("WaypointItem", "Elevation"),
Format::elevation(_waypoint.elevation(), units));
@ -44,7 +43,7 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, Map *map,
updateShape();
setPos(map->ll2xy(waypoint.coordinates()));
setToolTip(toolTip(Metric));
setToolTip(toolTip(Metric, DecimalDegrees));
setCursor(Qt::ArrowCursor);
setAcceptHoverEvents(true);
}
@ -108,6 +107,9 @@ void WaypointItem::paint(QPainter *painter,
void WaypointItem::setSize(int size)
{
if (_size == size)
return;
prepareGeometryChange();
_size = size;
updateShape();
@ -115,17 +117,23 @@ void WaypointItem::setSize(int size)
void WaypointItem::setColor(const QColor &color)
{
if (_color == color)
return;
_color = color;
update();
}
void WaypointItem::setUnits(enum Units units)
void WaypointItem::setToolTipFormat(Units units, CoordinatesFormat format)
{
setToolTip(toolTip(units));
setToolTip(toolTip(units, format));
}
void WaypointItem::showLabel(bool show)
{
if (_showLabel == show)
return;
prepareGeometryChange();
_showLabel = show;
updateShape();

View File

@ -6,6 +6,7 @@
#include "data/waypoint.h"
#include "map/map.h"
#include "units.h"
#include "format.h"
class WaypointItem : public QGraphicsItem
{
@ -15,7 +16,7 @@ public:
const Waypoint &waypoint() const {return _waypoint;}
void setMap(Map *map) {setPos(map->ll2xy(_waypoint.coordinates()));}
void setUnits(Units units);
void setToolTipFormat(Units units, CoordinatesFormat format);
void setSize(int size);
void setColor(const QColor &color);
void showLabel(bool show);
@ -31,7 +32,7 @@ private:
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
void updateShape();
QString toolTip(Units units);
QString toolTip(Units units, CoordinatesFormat format);
QPainterPath _shape;
Waypoint _waypoint;

View File

@ -16,12 +16,6 @@ qreal Coordinates::distanceTo(const Coordinates &c) const
return (WGS84_RADIUS * (2.0 * atan2(sqrt(a), sqrt(1.0 - a))));
}
QDebug operator<<(QDebug dbg, const Coordinates &c)
{
dbg.nospace() << "Coordinates(" << c.lon() << ", " << c.lat() << ")";
return dbg.space();
}
QPair<Coordinates, Coordinates> Coordinates::boundingRect(qreal distance) const
{
qreal radDist = distance / WGS84_RADIUS;
@ -50,3 +44,11 @@ QPair<Coordinates, Coordinates> Coordinates::boundingRect(qreal distance) const
maxLon)), rad2deg(qMin(minLat, maxLat))), Coordinates(rad2deg(qMax(minLon,
maxLon)), rad2deg(qMax(minLat, maxLat))));
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Coordinates &c)
{
dbg.nospace() << "Coordinates(" << c.lon() << ", " << c.lat() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -43,6 +43,8 @@ inline bool operator==(const Coordinates &c1, const Coordinates &c2)
inline bool operator!=(const Coordinates &c1, const Coordinates &c2)
{return !(c1 == c2);}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Coordinates &c);
#endif // QT_NO_DEBUG
#endif // COORDINATES_H

View File

@ -8,6 +8,7 @@ void RangeF::resize(qreal size)
_max += adj;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Range &range)
{
dbg.nospace() << "Range(" << range.min() << ", " << range.max() << ")";
@ -19,3 +20,4 @@ QDebug operator<<(QDebug dbg, const RangeF &range)
dbg.nospace() << "RangeF(" << range.min() << ", " << range.max() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -14,6 +14,8 @@ public:
int max() const {return _max;}
int size() const {return (_max - _min);}
bool isValid() const {return size() >= 0;}
private:
int _min, _max;
};
@ -28,13 +30,17 @@ public:
qreal max() const {return _max;}
qreal size() const {return (_max - _min);}
bool isValid() const {return size() >= 0;}
void resize(qreal size);
private:
qreal _min, _max;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Range &range);
QDebug operator<<(QDebug dbg, const RangeF &range);
#endif // QT_NO_DEBUG
#endif // RANGE_H

View File

@ -61,8 +61,10 @@ void RectC::unite(const Coordinates &c)
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RectC &rect)
{
dbg.nospace() << "RectC(" << rect.topLeft() << ", " << rect.size() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -37,6 +37,8 @@ private:
Coordinates _tl, _br;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RectC &rect);
#endif // QT_NO_DEBUG
#endif // RECTC_H

View File

@ -23,13 +23,13 @@ static QHash<QString, Parser*> parsers()
{
QHash<QString, Parser*> hash;
hash.insert("gpx", &gpx);
hash.insert("tcx", &tcx);
hash.insert("kml", &kml);
hash.insert("fit", &fit);
hash.insert("csv", &csv);
hash.insert("igc", &igc);
hash.insert("nmea", &nmea);
hash.insert("gpx", &gpx);
hash.insert("tcx", &tcx);
hash.insert("kml", &kml);
hash.insert("fit", &fit);
hash.insert("csv", &csv);
hash.insert("igc", &igc);
hash.insert("nmea", &nmea);
return hash;
}

View File

@ -30,12 +30,14 @@ private:
Q_DECLARE_TYPEINFO(GraphPoint, Q_PRIMITIVE_TYPE);
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const GraphPoint &point)
{
dbg.nospace() << "GraphPoint(" << point.s() << ", " << point.t() << ", "
<< point.y() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
typedef QVector<GraphPoint> Graph;

View File

@ -13,9 +13,11 @@ RectC Path::boundingRect() const
return ret;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PathPoint &point)
{
dbg.nospace() << "PathPoint(" << point.distance() << ", "
<< point.coordinates() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -23,7 +23,9 @@ private:
};
Q_DECLARE_TYPEINFO(PathPoint, Q_PRIMITIVE_TYPE);
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PathPoint &point);
#endif // QT_NO_DEBUG
class Path : public QVector<PathPoint>

View File

@ -49,9 +49,7 @@ static QSet<int> eliminate(const QVector<qreal> &v, int window)
static Graph filter(const Graph &g, int window)
{
if (g.size() < window)
return Graph();
if (window < 2)
if (g.size() < window || window < 2)
return Graph(g);
qreal acc = 0;
@ -77,27 +75,32 @@ static Graph filter(const Graph &g, int window)
Track::Track(const TrackData &data) : _data(data)
{
qreal dt, ds, total;
int last;
_time.append(0);
_distance.append(0);
_speed.append(0);
for (int i = 1; i < data.count(); i++) {
ds = data.at(i).coordinates().distanceTo(data.at(i-1).coordinates());
last = 0;
for (int i = 1; i < _data.count(); i++) {
ds = _data.at(i).coordinates().distanceTo(_data.at(i-1).coordinates());
_distance.append(ds);
if (data.first().hasTimestamp() && data.at(i).hasTimestamp())
if (_data.first().hasTimestamp() && _data.at(i).hasTimestamp()
&& _data.at(i).timestamp() > _data.at(last).timestamp()) {
_time.append(_data.first().timestamp().msecsTo(
_data.at(i).timestamp()) / 1000.0);
else
last = i;
} else
_time.append(NAN);
if (std::isnan(_time.at(i)) || std::isnan(_time.at(i-1)))
_speed.append(NAN);
else {
dt = _time.at(i) - _time.at(i-1);
if (!dt) {
if (dt < 1e-3) {
_speed.append(_speed.at(i-1));
continue;
}
@ -106,7 +109,7 @@ Track::Track(const TrackData &data) : _data(data)
}
_pause = 0;
for (int i = 1; i < data.count(); i++) {
for (int i = 1; i < _data.count(); i++) {
if (_time.at(i) > _time.at(i-1) + _pauseInterval
&& _speed.at(i) < _pauseSpeed) {
_pause += _time.at(i) - _time.at(i-1);

View File

@ -57,6 +57,7 @@ private:
Q_DECLARE_TYPEINFO(Trackpoint, Q_MOVABLE_TYPE);
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint)
{
dbg.nospace() << "Trackpoint(" << trackpoint.coordinates() << ", "
@ -65,5 +66,6 @@ inline QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint)
<< trackpoint.temperature() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // TRACKPOINT_H

View File

@ -48,12 +48,14 @@ inline uint qHash(const Waypoint &key)
return ::qHash(key.name());
}
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
{
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
<< waypoint.name() << ", " << waypoint.description() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
Q_DECLARE_TYPEINFO(Waypoint, Q_MOVABLE_TYPE);

View File

@ -41,6 +41,7 @@ Defense.
*/
#include "ellipsoid.h"
#include "albersequal.h"

View File

@ -1,9 +1,10 @@
#ifndef ALBERSEQUAL_H
#define ALBERSEQUAL_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class AlbersEqual : public CT
{
public:

View File

@ -8,7 +8,8 @@ static double sDMS2deg(double val)
const char *decimal;
QString qstr(QString::number(qAbs(val), 'f', 7));
const char *str = qstr.toLatin1().constData();
QByteArray ba = qstr.toLatin1();
const char *str = ba.constData();
decimal = strrchr(str, '.');
int deg = str2int(str, decimal - str);
int min = str2int(decimal + 1, 2);
@ -83,8 +84,10 @@ double AngularUnits::fromDegrees(double val) const
return (_code == 9110) ? deg2sDMS(val) : val / _f;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const AngularUnits &au)
{
dbg.nospace() << "AngularUnits(" << deg2rad(au._f) << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -17,8 +17,9 @@ public:
double fromDegrees(double val) const;
friend bool operator==(const AngularUnits &au1, const AngularUnits &au2);
#ifndef QT_NO_DEBUG
friend QDebug operator<<(QDebug dbg, const AngularUnits &au);
#endif // QT_NO_DEBUG
private:
int _code;
double _f;
@ -27,6 +28,8 @@ private:
inline bool operator==(const AngularUnits &au1, const AngularUnits &au2)
{return (au1._f == au2._f);}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const AngularUnits &au);
#endif // QT_NO_DEBUG
#endif // ANGULARUNITS_H

View File

@ -2,6 +2,7 @@
#include <QtAlgorithms>
#include <QPainter>
#include "common/rectc.h"
#include "offlinemap.h"
#include "tar.h"
#include "atlas.h"
@ -15,8 +16,8 @@ static bool resCmp(const OfflineMap *m1, const OfflineMap *m2)
{
qreal r1, r2;
r1 = m1->resolution(m1->bounds().center());
r2 = m2->resolution(m2->bounds().center());
r1 = m1->resolution(m1->bounds());
r2 = m2->resolution(m2->bounds());
return r1 > r2;
}
@ -37,8 +38,8 @@ void Atlas::computeZooms()
_zooms.append(QPair<int, int>(0, _maps.count() - 1));
for (int i = 1; i < _maps.count(); i++) {
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds().center());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds().center());
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds());
if (cur < last * ZOOM_THRESHOLD) {
_zooms.last().second = i-1;
_zooms.append(QPair<int, int>(i, _maps.count() - 1));
@ -78,21 +79,19 @@ void Atlas::computeBounds()
BR(_maps.at(i))), QRectF(offsets.at(i), _maps.at(i)->bounds().size())));
}
Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
Atlas::Atlas(const QString &fileName, QObject *parent)
: Map(parent), _zoom(0), _mapIndex(-1), _valid(false)
{
QFileInfo fi(fileName);
QByteArray ba;
QString suffix = fi.suffix().toLower();
Tar tar;
Tar tar(fileName);
_valid = false;
_zoom = 0;
_name = fi.dir().dirName();
_ci = -1; _cz = -1;
if (suffix == "tar") {
if (!tar.load(fileName)) {
if (!tar.open()) {
_errorString = "Error reading tar file";
return;
}
@ -112,7 +111,6 @@ Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
return;
}
QDir dir(fi.absolutePath());
QFileInfoList layers = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (int n = 0; n < layers.count(); n++) {
@ -149,12 +147,6 @@ Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
_valid = true;
}
Atlas::~Atlas()
{
for (int i = 0; i < _maps.size(); i++)
delete _maps.at(i);
}
QRectF Atlas::bounds() const
{
QSizeF s(0, 0);
@ -169,28 +161,24 @@ QRectF Atlas::bounds() const
return QRectF(QPointF(0, 0), s);
}
qreal Atlas::resolution(const QPointF &p) const
qreal Atlas::resolution(const QRectF &rect) const
{
int idx = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(p))) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(rect.center()))) {
idx = i;
break;
}
}
return _maps.at(idx)->resolution(p);
return _maps.at(idx)->resolution(rect);
}
qreal Atlas::zoom() const
{
return _zoom;
}
qreal Atlas::zoomFit(const QSize &size, const RectC &br)
int Atlas::zoomFit(const QSize &size, const RectC &br)
{
_zoom = 0;
_mapIndex = -1;
if (!br.isValid()) {
_zoom = _zooms.size() - 1;
@ -217,35 +205,19 @@ qreal Atlas::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal Atlas::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = 0;
for (int z = 0; z < _zooms.count(); z++) {
for (int i = _zooms.at(z).first; i <= _zooms.at(z).second; i++) {
if (!_bounds.at(i).first.contains(_maps.at(i)->ll2pp(c)))
continue;
if (_maps.at(i)->resolution(_maps.at(i)->ll2xy(c)) < resolution)
return _zoom;
_zoom = z;
break;
}
}
return _zoom;
}
qreal Atlas::zoomIn()
int Atlas::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
_mapIndex = -1;
return _zoom;
}
qreal Atlas::zoomOut()
int Atlas::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
_mapIndex = -1;
return _zoom;
}
@ -253,26 +225,21 @@ QPointF Atlas::ll2xy(const Coordinates &c)
{
QPointF pp;
if (_cz != _zoom) {
_ci = -1;
_cz = _zoom;
}
if (_ci >= 0)
pp = _maps.at(_ci)->ll2pp(c);
if (_ci < 0 || !_bounds.at(_ci).first.contains(pp)) {
_ci = _zooms.at(_zoom).first;
if (_mapIndex >= 0)
pp = _maps.at(_mapIndex)->ll2pp(c);
if (_mapIndex < 0 || !_bounds.at(_mapIndex).first.contains(pp)) {
_mapIndex = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
pp = _maps.at(i)->ll2pp(c);
if (_bounds.at(i).first.contains(pp)) {
_ci = i;
_mapIndex = i;
break;
}
}
}
QPointF p = _maps.at(_ci)->pp2xy(pp);
return p + _bounds.at(_ci).second.topLeft();
QPointF p = _maps.at(_mapIndex)->pp2xy(pp);
return p + _bounds.at(_mapIndex).second.topLeft();
}
Coordinates Atlas::xy2ll(const QPointF &p)
@ -332,10 +299,10 @@ bool Atlas::isAtlas(const QString &path)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
Tar tar;
Tar tar(path);
if (suffix == "tar") {
if (!tar.load(path))
if (!tar.open())
return false;
QString tbaFileName = fi.completeBaseName() + ".tba";
return tar.contains(tbaFileName);

View File

@ -1,10 +1,9 @@
#ifndef ATLAS_H
#define ATLAS_H
#include <QFileInfoList>
#include "map.h"
#include "offlinemap.h"
class OfflineMap;
class Atlas : public Map
{
@ -12,18 +11,16 @@ class Atlas : public Map
public:
Atlas(const QString &fileName, QObject *parent = 0);
~Atlas();
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const;
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
@ -33,7 +30,7 @@ public:
void unload();
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
QString errorString() const {return _errorString;}
static bool isAtlas(const QString &path);
@ -43,15 +40,15 @@ private:
void computeBounds();
QString _name;
bool _valid;
QString _errorString;
QList<OfflineMap*> _maps;
QVector<QPair<int, int> > _zooms;
QVector<QPair<QRectF, QRectF> > _bounds;
int _zoom;
int _mapIndex;
int _ci, _cz;
bool _valid;
QString _errorString;
};
#endif // ATLAS_H

View File

@ -43,11 +43,12 @@ static Coordinates molodensky(const Coordinates &c, const Datum &from,
return Coordinates(c.lon() + rad2deg(dlon), c.lat() + rad2deg(dlat));
}
Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy,
double dz) : _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz)
Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz)
: _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz)
{
_WGS84 = (*_ellipsoid == *WGS84.ellipsoid() && _dx == WGS84.dx()
&& _dy == WGS84.dy() && _dz == WGS84.dz()) ? true : false;
_WGS84 = (_ellipsoid->radius() == WGS84_RADIUS
&& _ellipsoid->flattening() == WGS84_FLATTENING && _dx == 0.0
&& _dy == 0.0 && _dz == 0.0) ? true : false;
}
Coordinates Datum::toWGS84(const Coordinates &c) const
@ -60,9 +61,11 @@ Coordinates Datum::fromWGS84(const Coordinates &c) const
return _WGS84 ? c : molodensky(c, WGS84, *this);
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Datum &datum)
{
dbg.nospace() << "Datum(" << *datum.ellipsoid() << ", " << datum.dx()
<< ", " << datum.dy() << ", " << datum.dz() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -39,6 +39,8 @@ inline bool operator==(const Datum &d1, const Datum &d2)
{return (d1.ellipsoid() == d2.ellipsoid() && d1.dx() == d2.dx()
&& d1.dy() == d2.dy() && d1.dz() == d2.dz());}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Datum &datum);
#endif // QT_NO_DEBUG
#endif // DATUM_H

View File

@ -61,7 +61,7 @@ bool Downloader::saveToDisk(const QString &filename, QIODevice *data)
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
qWarning("Error writing map tile: %s: %s\n",
qWarning("Error writing file: %s: %s\n",
qPrintable(filename), qPrintable(file.errorString()));
return false;
}
@ -80,11 +80,11 @@ void Downloader::downloadFinished(QNetworkReply *reply)
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
if (origin.isEmpty()) {
_errorDownloads.insert(url);
qWarning("Error downloading map tile: %s: %s\n",
qWarning("Error downloading file: %s: %s\n",
url.toEncoded().constData(), qPrintable(reply->errorString()));
} else {
_errorDownloads.insert(origin);
qWarning("Error downloading map tile: %s -> %s: %s\n",
qWarning("Error downloading file: %s -> %s: %s\n",
origin.toEncoded().constData(), url.toEncoded().constData(),
qPrintable(reply->errorString()));
}
@ -99,11 +99,11 @@ void Downloader::downloadFinished(QNetworkReply *reply)
if (location == url) {
_errorDownloads.insert(url);
qWarning("Error downloading map tile: %s: "
qWarning("Error downloading file: %s: "
"redirect loop\n", url.toEncoded().constData());
} else if (level >= MAX_REDIRECT_LEVEL) {
_errorDownloads.insert(origin);
qWarning("Error downloading map tile: %s: "
qWarning("Error downloading file: %s: "
"redirect level limit reached\n",
origin.toEncoded().constData());
} else {

View File

@ -66,9 +66,11 @@ void Ellipsoid::loadList(const QString &path)
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Ellipsoid &ellipsoid)
{
dbg.nospace() << "Ellipsoid(" << ellipsoid.radius() << ", "
<< 1.0 / ellipsoid.flattening() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -35,6 +35,8 @@ private:
inline bool operator==(const Ellipsoid &e1, const Ellipsoid &e2)
{return (e1.radius() == e2.radius() && e1.flattening() == e2.flattening());}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Ellipsoid &ellipsoid);
#endif // QT_NO_DEBUG
#endif // ELLIPSOID_H

View File

@ -3,16 +3,47 @@
#include "common/coordinates.h"
#include "common/rectc.h"
#include "common/wgs84.h"
#include "mercator.h"
#include "emptymap.h"
#define SCALE_MIN 0.5
#define SCALE_MAX 1.0E-6
#define ZOOM_MIN 0
#define ZOOM_MAX 19
#define TILE_SIZE 256
static QPointF ll2m(const Coordinates &c)
{
return QPointF(c.lon(), rad2deg(log(tan(M_PI/4.0 + deg2rad(c.lat())/2.0))));
}
static Coordinates m2ll(const QPointF &p)
{
return Coordinates(p.x(), rad2deg(2 * atan(exp(deg2rad(p.y()))) - M_PI/2));
}
static qreal zoom2scale(int zoom)
{
return (360.0/(qreal)((1<<zoom) * TILE_SIZE));
}
static int scale2zoom(qreal scale)
{
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}
static int limitZoom(int zoom)
{
if (zoom < ZOOM_MIN)
return ZOOM_MIN;
if (zoom > ZOOM_MAX)
return ZOOM_MAX;
return zoom;
}
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
{
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
}
QRectF EmptyMap::bounds() const
@ -20,50 +51,38 @@ QRectF EmptyMap::bounds() const
return QRectF(ll2xy(Coordinates(-180, 85)), ll2xy(Coordinates(180, -85)));
}
qreal EmptyMap::zoomFit(const QSize &size, const RectC &br)
int EmptyMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
else {
QRectF tbr(Mercator().ll2xy(br.topLeft()),
Mercator().ll2xy(br.bottomRight()));
QRectF tbr(ll2m(br.topLeft()), ll2m(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
_scale = qMax(sc.x(), sc.y());
_zoom = limitZoom(scale2zoom(qMax(sc.x(), sc.y())));
}
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return _zoom;
}
qreal EmptyMap::zoomFit(qreal resolution, const Coordinates &c)
qreal EmptyMap::resolution(const QRectF &rect) const
{
_scale = (360.0 * resolution) / (WGS84_RADIUS * 2 * M_PI
* cos(deg2rad(c.lat())));
qreal scale = zoom2scale(_zoom);
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal EmptyMap::resolution(const QPointF &p) const
int EmptyMap::zoomIn()
{
return (WGS84_RADIUS * 2 * M_PI * _scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * _scale))) - M_PI/2));
_zoom = qMin(_zoom + 1, ZOOM_MAX);
return _zoom;
}
qreal EmptyMap::zoomIn()
int EmptyMap::zoomOut()
{
_scale = qMax(_scale / 2.0, SCALE_MAX);
return _scale;
}
qreal EmptyMap::zoomOut()
{
_scale = qMin(_scale * 2.0, SCALE_MIN);
return _scale;
_zoom = qMax(_zoom - 1, ZOOM_MIN);
return _zoom;
}
void EmptyMap::draw(QPainter *painter, const QRectF &rect)
@ -73,12 +92,13 @@ void EmptyMap::draw(QPainter *painter, const QRectF &rect)
QPointF EmptyMap::ll2xy(const Coordinates &c) const
{
QPointF m = Mercator().ll2xy(c);
return QPointF(m.x() / _scale, m.y() / -_scale);
qreal scale = zoom2scale(_zoom);
QPointF m = ll2m(c);
return QPointF(m.x() / scale, m.y() / -scale);
}
Coordinates EmptyMap::xy2ll(const QPointF &p) const
{
QPointF m(p.x() * _scale, -p.y() * _scale);
return Mercator().xy2ll(m);
qreal scale = zoom2scale(_zoom);
return m2ll(QPointF(p.x() * scale, -p.y() * scale));
}

View File

@ -1,7 +1,6 @@
#ifndef EMPTYMAP_H
#define EMPTYMAP_H
#include "common/coordinates.h"
#include "map.h"
class EmptyMap : public Map
@ -14,13 +13,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _scale;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const EmptyMap &>(*this).ll2xy(c);}
@ -34,7 +32,7 @@ private:
Coordinates xy2ll(const QPointF &p) const;
QString _name;
qreal _scale;
int _zoom;
};
#endif // EMPTYMAP_H

View File

@ -183,9 +183,11 @@ Coordinates GCS::fromWGS84(const Coordinates &c) const
return Coordinates(_primeMeridian.fromGreenwich(ds.lon()), ds.lat());
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const GCS &gcs)
{
dbg.nospace() << "GCS(" << gcs.datum() << ", " << gcs.primeMeridian()
<< ", " << gcs.angularUnits() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -25,7 +25,6 @@ public:
Coordinates toWGS84(const Coordinates &c) const;
Coordinates fromWGS84(const Coordinates &c) const;
static const GCS *gcs(int id);
static const GCS *gcs(int geodeticDatum, int primeMeridian,
int angularUnits);
@ -50,6 +49,8 @@ inline bool operator==(const GCS &gcs1, const GCS &gcs2)
&& gcs1.primeMeridian() == gcs2.primeMeridian()
&& gcs1.angularUnits() == gcs2.angularUnits());}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const GCS &gcs);
#endif // QT_NO_DEBUG
#endif // GCS_H

View File

@ -1,7 +1,7 @@
#include <QFileInfo>
#include <QtEndian>
#include "pcs.h"
#include "latlon.h"
#include "tifffile.h"
#include "geotiff.h"
@ -9,38 +9,55 @@
#define TIFF_SHORT 3
#define TIFF_LONG 4
#define ModelPixelScaleTag 33550
#define ModelTiepointTag 33922
#define ModelTransformationTag 34264
#define GeoKeyDirectoryTag 34735
#define GeoDoubleParamsTag 34736
#define ImageWidth 256
#define ImageHeight 257
#define ModelPixelScaleTag 33550
#define ModelTiepointTag 33922
#define ModelTransformationTag 34264
#define GeoKeyDirectoryTag 34735
#define GeoDoubleParamsTag 34736
#define GTModelTypeGeoKey 1024
#define GTRasterTypeGeoKey 1025
#define GeographicTypeGeoKey 2048
#define GeogGeodeticDatumGeoKey 2050
#define GeogPrimeMeridianGeoKey 2051
#define GeogAngularUnitsGeoKey 2054
#define ProjectedCSTypeGeoKey 3072
#define ProjectionGeoKey 3074
#define ProjCoordTransGeoKey 3075
#define ProjLinearUnitsGeoKey 3076
#define ProjStdParallel1GeoKey 3078
#define ProjStdParallel2GeoKey 3079
#define ProjNatOriginLongGeoKey 3080
#define ProjNatOriginLatGeoKey 3081
#define ProjFalseEastingGeoKey 3082
#define ProjFalseNorthingGeoKey 3083
#define ProjScaleAtNatOriginGeoKey 3092
#define GTModelTypeGeoKey 1024
#define GTRasterTypeGeoKey 1025
#define GeographicTypeGeoKey 2048
#define GeogGeodeticDatumGeoKey 2050
#define GeogPrimeMeridianGeoKey 2051
#define GeogAngularUnitsGeoKey 2054
#define GeogEllipsoidGeoKey 2056
#define ProjectedCSTypeGeoKey 3072
#define ProjectionGeoKey 3074
#define ProjCoordTransGeoKey 3075
#define ProjLinearUnitsGeoKey 3076
#define ProjStdParallel1GeoKey 3078
#define ProjStdParallel2GeoKey 3079
#define ProjNatOriginLongGeoKey 3080
#define ProjNatOriginLatGeoKey 3081
#define ProjFalseEastingGeoKey 3082
#define ProjFalseNorthingGeoKey 3083
#define ProjCenterLongGeoKey 3088
#define ProjCenterLatGeoKey 3089
#define ProjScaleAtNatOriginGeoKey 3092
#define ProjScaleAtCenterGeoKey 3093
#define ProjAzimuthAngleGeoKey 3094
#define ProjRectifiedGridAngleGeoKey 3096
#define ModelTypeProjected 1
#define ModelTypeGeographic 2
#define ModelTypeGeocentric 3
#define CT_TransverseMercator 1
#define CT_ObliqueMercator 3
#define CT_Mercator 7
#define CT_LambertConfConic_2SP 8
#define CT_LambertConfConic_1SP 9
#define CT_LambertAzimEqualArea 10
#define CT_AlbersEqualArea 11
#define ModelTypeProjected 1
#define ModelTypeGeographic 2
#define ModelTypeGeocentric 3
#define IS_SET(map, key) \
((map).contains(key) && (map).value(key).SHORT != 32767)
#define TO_M(lu, val) \
(std::isnan(val) ? val : (lu).toMeters(val))
#define TO_DEG(au, val) \
(std::isnan(val) ? val : (au).toDegrees(val))
#define ARRAY_SIZE(a) \
(sizeof(a) / sizeof(*a))
@ -223,6 +240,7 @@ bool GeoTIFF::readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv) const
case ProjectionGeoKey:
case ProjCoordTransGeoKey:
case ProjLinearUnitsGeoKey:
case GeogEllipsoidGeoKey:
if (entry.TIFFTagLocation != 0 || entry.Count != 1)
return false;
value.SHORT = entry.ValueOffset;
@ -235,6 +253,11 @@ bool GeoTIFF::readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv) const
case ProjFalseNorthingGeoKey:
case ProjStdParallel1GeoKey:
case ProjStdParallel2GeoKey:
case ProjCenterLongGeoKey:
case ProjCenterLatGeoKey:
case ProjScaleAtCenterGeoKey:
case ProjAzimuthAngleGeoKey:
case ProjRectifiedGridAngleGeoKey:
if (!readGeoValue(file, ctx.values, entry.ValueOffset,
value.DOUBLE))
return false;
@ -272,13 +295,19 @@ const GCS *GeoTIFF::gcs(QMap<quint16, Value> &kv)
if (!(gcs = GCS::gcs(kv.value(GeographicTypeGeoKey).SHORT)))
_errorString = QString("%1: unknown GCS")
.arg(kv.value(GeographicTypeGeoKey).SHORT);
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey)) {
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey)
|| kv.value(GeogEllipsoidGeoKey).SHORT == 7019) {
int pm = IS_SET(kv, GeogPrimeMeridianGeoKey)
? kv.value(GeogPrimeMeridianGeoKey).SHORT : 8901;
int au = IS_SET(kv, GeogAngularUnitsGeoKey)
? kv.value(GeogAngularUnitsGeoKey).SHORT : 9102;
if (!(gcs = GCS::gcs(kv.value(GeogGeodeticDatumGeoKey).SHORT, pm, au)))
/* If only the ellipsoid is defined and it is GRS80, handle such
definition as a WGS84 geodetic datum. */
int gd = IS_SET(kv, GeogGeodeticDatumGeoKey)
? kv.value(GeogGeodeticDatumGeoKey).SHORT : 6326;
if (!(gcs = GCS::gcs(gd, pm, au)))
_errorString = QString("%1+%2: unknown geodetic datum + prime"
" meridian combination")
.arg(kv.value(GeogGeodeticDatumGeoKey).SHORT)
@ -297,17 +326,19 @@ Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
}
switch (kv.value(ProjCoordTransGeoKey).SHORT) {
case 1:
case CT_TransverseMercator:
return Projection::Method(9807);
case 7:
case CT_ObliqueMercator:
return Projection::Method(9815);
case CT_Mercator:
return Projection::Method(1024);
case 8:
return Projection::Method(9801);
case 9:
case CT_LambertConfConic_2SP:
return Projection::Method(9802);
case 10:
case CT_LambertConfConic_1SP:
return Projection::Method(9801);
case CT_LambertAzimEqualArea:
return Projection::Method(9820);
case 11:
case CT_AlbersEqualArea:
return Projection::Method(9822);
default:
_errorString = QString("%1: unknown coordinate transformation method")
@ -341,6 +372,8 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
_projection = Projection(pcs->gcs(), pcs->method(), pcs->setup(),
pcs->units());
} else {
double lat0, lon0, scale, fe, fn, sp1, sp2;
const GCS *g = gcs(kv);
if (!g)
return false;
@ -358,15 +391,47 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
return false;
}
Projection::Setup setup(
au.toDegrees(kv.value(ProjNatOriginLatGeoKey).DOUBLE),
au.toDegrees(kv.value(ProjNatOriginLongGeoKey).DOUBLE),
kv.value(ProjScaleAtNatOriginGeoKey).DOUBLE,
lu.toMeters(kv.value(ProjFalseEastingGeoKey).DOUBLE),
lu.toMeters(kv.value(ProjFalseNorthingGeoKey).DOUBLE),
au.toDegrees(kv.value(ProjStdParallel1GeoKey).DOUBLE),
au.toDegrees(kv.value(ProjStdParallel2GeoKey).DOUBLE)
);
if (kv.contains(ProjNatOriginLatGeoKey))
lat0 = kv.value(ProjNatOriginLatGeoKey).DOUBLE;
else if (kv.contains(ProjCenterLatGeoKey))
lat0 = kv.value(ProjCenterLatGeoKey).DOUBLE;
else
lat0 = NAN;
if (kv.contains(ProjNatOriginLongGeoKey))
lon0 = kv.value(ProjNatOriginLongGeoKey).DOUBLE;
else if (kv.contains(ProjCenterLongGeoKey))
lon0 = kv.value(ProjCenterLongGeoKey).DOUBLE;
else
lon0 = NAN;
if (kv.contains(ProjScaleAtNatOriginGeoKey))
scale = kv.value(ProjScaleAtNatOriginGeoKey).DOUBLE;
else if (kv.contains(ProjScaleAtCenterGeoKey))
scale = kv.value(ProjScaleAtCenterGeoKey).DOUBLE;
else
scale = NAN;
if (kv.contains(ProjStdParallel1GeoKey))
sp1 = kv.value(ProjStdParallel1GeoKey).DOUBLE;
else if (kv.contains(ProjAzimuthAngleGeoKey))
sp1 = kv.value(ProjAzimuthAngleGeoKey).DOUBLE;
else
sp1 = NAN;
if (kv.contains(ProjStdParallel2GeoKey))
sp2 = kv.value(ProjStdParallel2GeoKey).DOUBLE;
else if (kv.contains(ProjRectifiedGridAngleGeoKey))
sp2 = kv.value(ProjRectifiedGridAngleGeoKey).DOUBLE;
else
sp2 = NAN;
if (kv.contains(ProjFalseNorthingGeoKey))
fn = kv.value(ProjFalseNorthingGeoKey).DOUBLE;
else
fn = NAN;
if (kv.contains(ProjFalseEastingGeoKey))
fe = kv.value(ProjFalseEastingGeoKey).DOUBLE;
else
fe = NAN;
Projection::Setup setup(TO_DEG(au, lat0), TO_DEG(au, lon0), scale,
TO_M(lu, fe), TO_M(lu, fn), TO_DEG(au, sp1), TO_DEG(au, sp2));
_projection = Projection(g, m, setup, lu);
}

View File

@ -1,14 +1,14 @@
#ifndef GEOTIFF_H
#define GEOTIFF_H
#include <QTransform>
#include <QFile>
#include <QMap>
#include "gcs.h"
#include "projection.h"
#include "tifffile.h"
#include <QList>
#include <QTransform>
#include "transform.h"
#include "linearunits.h"
#include "projection.h"
class TIFFFile;
class GCS;
class GeoTIFF
{

View File

@ -1,193 +1,72 @@
/*
* Based on libgeotrans with the following Source Code Disclaimer:
1. The GEOTRANS source code ("the software") is provided free of charge by
the National Imagery and Mapping Agency (NIMA) of the United States
Department of Defense. Although NIMA makes no copyright claim under Title 17
U.S.C., NIMA claims copyrights in the source code under other legal regimes.
NIMA hereby grants to each user of the software a license to use and
distribute the software, and develop derivative works.
2. Warranty Disclaimer: The software was developed to meet only the internal
requirements of the U.S. National Imagery and Mapping Agency. The software
is provided "as is," and no warranty, express or implied, including but not
limited to the implied warranties of merchantability and fitness for
particular purpose or arising by statute or otherwise in law or from a
course of dealing or usage in trade, is made by NIMA as to the accuracy and
functioning of the software.
3. NIMA and its personnel are not required to provide technical support or
general assistance with respect to the software.
4. Neither NIMA nor its personnel will be liable for any claims, losses, or
damages arising from or connected with the use of the software. The user
agrees to hold harmless the United States National Imagery and Mapping
Agency. The user's sole and exclusive remedy is to stop using the software.
5. NIMA requests that products developed using the software credit the
source of the software with the following statement, "The product was
developed using GEOTRANS, a product of the National Imagery and Mapping
Agency and U.S. Army Engineering Research and Development Center."
6. For any products developed using the software, NIMA requires a disclaimer
that use of the software does not indicate endorsement or approval of the
product by the Secretary of Defense or the National Imagery and Mapping
Agency. Pursuant to the United States Code, 10 U.S.C. Sec. 2797, the name of
the National Imagery and Mapping Agency, the initials "NIMA", the seal of
the National Imagery and Mapping Agency, or any colorable imitation thereof
shall not be used to imply approval, endorsement, or authorization of a
product without prior written permission from United States Secretary of
Defense.
*/
#include <cmath>
#include "ellipsoid.h"
#include "lambertazimuthal.h"
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif // M_PI_2
#define sin2(x) (sin(x) * sin(x))
#define sqr(x) ((x) * (x))
LambertAzimuthal::LambertAzimuthal(const Ellipsoid *ellipsoid,
double latitudeOrigin, double longitudeOrigin, double falseEasting,
double falseNorthing)
{
double es2, es4, es6;
double lat0 = deg2rad(latitudeOrigin);
es2 = 2 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
es4 = es2 * es2;
es6 = es4 * es2;
_ra = ellipsoid->radius() * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0
* es6 / 3024.0);
_latOrigin = deg2rad(latitudeOrigin);
_sinLatOrigin = sin(_latOrigin);
_cosLatOrigin = cos(_latOrigin);
_absLatOrigin = fabs(_latOrigin);
_lonOrigin = deg2rad(longitudeOrigin);
if (_lonOrigin > M_PI)
_lonOrigin -= 2.0 * M_PI;
_falseNorthing = falseNorthing;
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
_lon0 = deg2rad(longitudeOrigin);
_a = ellipsoid->radius();
_es2 = 2.0 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
_es = sqrt(_es2);
double q0 = (1.0 - _es2) * ((sin(lat0) / (1.0 - _es2 * sin2(lat0)))
- ((1.0/(2.0*_es)) * log((1.0 - _es * sin(lat0)) / (1.0 + _es
* sin(lat0)))));
_qP = (1.0 - _es2) * ((1.0 / (1.0 - _es2)) - ((1.0/(2.0*_es))
* log((1.0 - _es) / (1.0 + _es))));
_beta0 = asin(q0 / _qP);
_Rq = _a * sqrt(_qP / 2.0);
_D = _a * (cos(lat0) / sqrt(1.0 - _es2 * sin2(lat0))) / (_Rq * cos(_beta0));
}
QPointF LambertAzimuthal::ll2xy(const Coordinates &c) const
{
double dlam;
double k_prime;
double cd;
double rlat = deg2rad(c.lat());
double slat = sin(rlat);
double clat = cos(rlat);
double cos_c;
double sin_dlam, cos_dlam;
double Ra_kprime;
double Ra_PI_OVER_2_Lat;
QPointF p;
double lon = deg2rad(c.lon());
double lat = deg2rad(c.lat());
double q = (1.0 - _es2) * ((sin(lat) / (1.0 - _es2 * sin2(lat)))
- ((1.0/(2.0*_es)) * log((1.0 - _es * sin(lat)) / (1.0 + _es
* sin(lat)))));
double beta = asin(q / _qP);
double B = _Rq * sqrt(2.0 / (1.0 + sin(_beta0) * sin(beta) + (cos(_beta0)
* cos(beta) * cos(lon - _lon0))));
dlam = deg2rad(c.lon()) - _lonOrigin;
if (dlam > M_PI)
dlam -= 2.0 * M_PI;
if (dlam < -M_PI)
dlam += 2.0 * M_PI;
double x = _falseEasting + ((B * _D) * (cos(beta) * sin(lon - _lon0)));
double y = _falseNorthing + (B / _D) * ((cos(_beta0) * sin(beta))
- (sin(_beta0) * cos(beta) * cos(lon - _lon0)));
sin_dlam = sin(dlam);
cos_dlam = cos(dlam);
if (fabs(_absLatOrigin - M_PI_2) < 1.0e-10) {
if (_latOrigin >= 0.0) {
Ra_PI_OVER_2_Lat = _ra * (M_PI_2 - rlat);
p.rx() = Ra_PI_OVER_2_Lat * sin_dlam + _falseEasting;
p.ry() = -1.0 * (Ra_PI_OVER_2_Lat * cos_dlam) + _falseNorthing;
} else {
Ra_PI_OVER_2_Lat = _ra * (M_PI_2 + rlat);
p.rx() = Ra_PI_OVER_2_Lat * sin_dlam + _falseEasting;
p.ry() = Ra_PI_OVER_2_Lat * cos_dlam + _falseNorthing;
}
} else if (_absLatOrigin <= 1.0e-10) {
cos_c = clat * cos_dlam;
if (fabs(fabs(cos_c) - 1.0) < 1.0e-14) {
if (cos_c >= 0.0) {
p.rx() = _falseEasting;
p.ry() = _falseNorthing;
} else
return QPointF(NAN, NAN);
} else {
cd = acos(cos_c);
k_prime = cd / sin(cd);
Ra_kprime = _ra * k_prime;
p.rx() = Ra_kprime * clat * sin_dlam + _falseEasting;
p.ry() = Ra_kprime * slat + _falseNorthing;
}
} else {
cos_c = (_sinLatOrigin * slat) + (_cosLatOrigin * clat * cos_dlam);
if (fabs(fabs(cos_c) - 1.0) < 1.0e-14) {
if (cos_c >= 0.0) {
p.rx() = _falseEasting;
p.ry() = _falseNorthing;
} else
return QPointF(NAN, NAN);
} else {
cd = acos(cos_c);
k_prime = cd / sin(cd);
Ra_kprime = _ra * k_prime;
p.rx() = Ra_kprime * clat * sin_dlam + _falseEasting;
p.ry() = Ra_kprime * (_cosLatOrigin * slat - _sinLatOrigin * clat
* cos_dlam) + _falseNorthing;
}
}
return p;
return QPointF(x, y);
}
Coordinates LambertAzimuthal::xy2ll(const QPointF &p) const
{
double dx, dy;
double rho;
double cd;
double sin_c, cos_c, dy_sinc;
double lat, lon;
double es4 = _es2 * _es2;
double es6 = _es2 * es4;
double rho = sqrt(sqr((p.x() - _falseEasting) / _D) + sqr(_D * (p.y()
- _falseNorthing)));
double C = 2.0 * asin(rho / (2.0*_Rq));
double betaS = asin((cos(C) * sin(_beta0)) + ((_D * (p.y() -_falseNorthing)
* sin(C) * cos(_beta0)) / rho));
dy = p.y() - _falseNorthing;
dx = p.x() - _falseEasting;
rho = sqrt(dx * dx + dy * dy);
if (fabs(rho) <= 1.0e-10) {
lat = _latOrigin;
lon = _lonOrigin;
} else {
cd = rho / _ra;
sin_c = sin(cd);
cos_c = cos(cd);
dy_sinc = dy * sin_c;
lat = asin((cos_c * _sinLatOrigin) + ((dy_sinc * _cosLatOrigin) / rho));
if (fabs(_absLatOrigin - M_PI_2) < 1.0e-10) {
if (_latOrigin >= 0.0)
lon = _lonOrigin + atan2(dx, -dy);
else
lon = _lonOrigin + atan2(dx, dy);
}
else
lon = _lonOrigin + atan2((dx * sin_c), ((rho * _cosLatOrigin
* cos_c) - (dy_sinc * _sinLatOrigin)));
}
if (lat > M_PI_2)
lat = M_PI_2;
else if (lat < -M_PI_2)
lat = -M_PI_2;
if (lon > M_PI)
lon -= 2.0 * M_PI;
if (lon < -M_PI)
lon += 2.0 * M_PI;
if (lon > M_PI)
lon = M_PI;
else if (lon < -M_PI)
lon = -M_PI;
double lon = _lon0 + atan((p.x() - _falseEasting) * sin(C) / (_D * rho
* cos(_beta0) * cos(C) - sqr(_D) * (p.y() - _falseNorthing) * sin(_beta0)
* sin(C)));
double lat = betaS + ((_es2/3.0 + 31.0*es4/180.0 + 517.0*es6/5040.0)
* sin(2.0*betaS)) + ((23.0*es4/360.0 + 251.0*es6/3780.0) * sin(4.0*betaS))
+ ((761.0*es6/45360.0)*sin(6.0*betaS));
return Coordinates(rad2deg(lon), rad2deg(lat));
}

View File

@ -1,9 +1,10 @@
#ifndef LAMBERTAZIMUTHAL_H
#define LAMBERTAZIMUTHAL_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class LambertAzimuthal : public CT
{
public:
@ -16,15 +17,10 @@ public:
virtual Coordinates xy2ll(const QPointF &p) const;
private:
double _ra;
double _sinLatOrigin;
double _cosLatOrigin;
double _absLatOrigin;
double _latOrigin;
double _lonOrigin;
double _lon0;
double _falseNorthing;
double _falseEasting;
double _a, _es, _es2, _qP, _beta0, _Rq, _D;
};
#endif // LAMBERTAZIMUTHAL_H

View File

@ -42,6 +42,7 @@ Defense.
*/
#include <cmath>
#include "ellipsoid.h"
#include "lambertconic.h"
#ifndef M_PI_2

View File

@ -1,9 +1,10 @@
#ifndef LAMBERTCONIC_H
#define LAMBERTCONIC_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class LambertConic1 : public CT
{
public:

View File

@ -20,8 +20,10 @@ LinearUnits::LinearUnits(int code)
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const LinearUnits &lu)
{
dbg.nospace() << "LinearUnits(" << lu._f << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -22,7 +22,9 @@ public:
{return QPointF(p.x() / _f, p.y() /_f);}
friend bool operator==(const LinearUnits &lu1, const LinearUnits &lu2);
#ifndef QT_NO_DEBUG
friend QDebug operator<<(QDebug dbg, const LinearUnits &lu);
#endif // QT_NO_DEBUG
private:
double _f;
@ -31,6 +33,8 @@ private:
inline bool operator==(const LinearUnits &lu1, const LinearUnits &lu2)
{return (lu1._f == lu2._f);}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const LinearUnits &lu);
#endif // QT_NO_DEBUG
#endif // LINEARUNITS_H

View File

@ -5,9 +5,9 @@
#include <QString>
#include <QRectF>
#include <QColor>
#include "common/coordinates.h"
class QPainter;
class Coordinates;
class RectC;
class Map : public QObject
@ -15,18 +15,18 @@ class Map : public QObject
Q_OBJECT
public:
Map(QObject *parent = 0) : QObject(parent) {_backgroundColor = Qt::white;}
Map(QObject *parent = 0) : QObject(parent), _backgroundColor(Qt::white) {}
virtual ~Map() {}
virtual const QString &name() const = 0;
virtual QRectF bounds() const = 0;
virtual qreal resolution(const QPointF &p) const = 0;
virtual qreal resolution(const QRectF &rect) const = 0;
virtual qreal zoom() const = 0;
virtual qreal zoomFit(const QSize &size, const RectC &br) = 0;
virtual qreal zoomFit(qreal resolution, const Coordinates &c) = 0;
virtual qreal zoomIn() = 0;
virtual qreal zoomOut() = 0;
virtual int zoom() const = 0;
virtual int zoomFit(const QSize &size, const RectC &br) = 0;
virtual int zoomIn() = 0;
virtual int zoomOut() = 0;
virtual QPointF ll2xy(const Coordinates &c) = 0;
virtual Coordinates xy2ll(const QPointF &p) = 0;
@ -40,6 +40,9 @@ public:
void setBackgroundColor(const QColor &color) {_backgroundColor = color;}
virtual bool isValid() const {return true;}
virtual QString errorString() const {return QString();}
signals:
void loaded();

View File

@ -1,3 +1,4 @@
#include <QIODevice>
#include "utm.h"
#include "gcs.h"
#include "mapfile.h"

View File

@ -1,12 +1,13 @@
#ifndef MAPFILE_H
#define MAPFILE_H
#include <QIODevice>
#include <QTransform>
#include "gcs.h"
#include "transform.h"
#include "projection.h"
class QIODevice;
class MapFile
{
public:

View File

@ -1,6 +1,5 @@
#include <QFileInfo>
#include <QDir>
#include "common/range.h"
#include "atlas.h"
#include "offlinemap.h"
#include "onlinemap.h"
@ -13,7 +12,7 @@ bool MapList::loadSource(const QString &path, bool dir)
MapSource ms;
Map *map;
if (!ms.loadFile(path, &map)) {
if (!(map = ms.loadFile(path))) {
if (dir)
_errorString += path + ": " + ms.errorString() + "\n";
else

View File

@ -3,9 +3,8 @@
#include <QObject>
#include <QString>
#include "map.h"
class Tar;
class Map;
class MapList : public QObject
{

View File

@ -1,9 +1,9 @@
#include <QFile>
#include <QXmlStreamReader>
#include "onlinemap.h"
#include "wmtsmap.h"
#include "mapsource.h"
#define ZOOM_MAX 19
#define ZOOM_MIN 0
#define BOUNDS_LEFT -180
@ -11,6 +11,11 @@
#define BOUNDS_RIGHT 180
#define BOUNDS_BOTTOM -85.0511
MapSource::TMSConfig::TMSConfig()
: zooms(ZOOM_MIN, ZOOM_MAX), bounds(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM)) {}
Range MapSource::zooms(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
@ -43,7 +48,7 @@ Range MapSource::zooms(QXmlStreamReader &reader)
} else
max = ZOOM_MAX;
if (min > max || max < min) {
if (min > max) {
reader.raiseError("Invalid maximal/minimal zoom level combination");
return Range();
}
@ -109,11 +114,11 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
} else
right = BOUNDS_RIGHT;
if (bottom > top || top < bottom) {
if (bottom >= top) {
reader.raiseError("Invalid bottom/top bounds combination");
return RectC();
}
if (left > right || right < left) {
if (left >= right) {
reader.raiseError("Invalid left/right bounds combination");
return RectC();
}
@ -121,52 +126,109 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
void MapSource::map(QXmlStreamReader &reader, Map **map)
void MapSource::map(QXmlStreamReader &reader, Config &config)
{
QString name, url;
Range z(ZOOM_MIN, ZOOM_MAX);
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
config.type = (reader.attributes().value("type") == "WMTS") ? WMTS : TMS;
while (reader.readNextStartElement()) {
if (reader.name() == "name")
name = reader.readElementText();
else if (reader.name() == "url")
url = reader.readElementText();
else if (reader.name() == "zoom") {
z = zooms(reader);
config.name = reader.readElementText();
else if (reader.name() == "url") {
config.wmts.rest = (reader.attributes().value("type") == "REST")
? true : false;
config.url = reader.readElementText();
} else if (reader.name() == "zoom") {
config.tms.zooms = zooms(reader);
reader.skipCurrentElement();
} else if (reader.name() == "bounds") {
b = bounds(reader);
config.tms.bounds = bounds(reader);
reader.skipCurrentElement();
} else if (reader.name() == "format") {
config.wmts.format = reader.readElementText();
} else if (reader.name() == "layer")
config.wmts.layer = reader.readElementText();
else if (reader.name() == "style")
config.wmts.style = reader.readElementText();
else if (reader.name() == "set") {
config.wmts.yx = (reader.attributes().value("axis") == "yx")
? true : false;
config.wmts.set = reader.readElementText();
} else if (reader.name() == "dimension") {
QXmlStreamAttributes attr = reader.attributes();
if (!attr.hasAttribute("id"))
reader.raiseError("Missing dimension id");
else
config.wmts.dimensions.append(QPair<QString, QString>(
attr.value("id").toString(), reader.readElementText()));
} else
reader.skipCurrentElement();
}
*map = reader.error() ? 0 : new OnlineMap(name, url, z, b);
}
bool MapSource::loadFile(const QString &path, Map **map)
Map *MapSource::loadFile(const QString &path)
{
QFile file(path);
QXmlStreamReader reader;
Config config;
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
return false;
return 0;
}
reader.setDevice(&file);
if (reader.readNextStartElement()) {
if (reader.name() == "map")
MapSource::map(reader, map);
map(reader, config);
else
reader.raiseError("Not an online map source file");
}
if (reader.error()) {
_errorString = QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString());
return 0;
}
_errorString = reader.error() ? QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString()) : QString();
if (config.name.isEmpty()) {
_errorString = "Missing name definition";
return 0;
}
if (config.url.isEmpty()) {
_errorString = "Missing URL definition";
return 0;
}
if (config.type == WMTS) {
if (config.wmts.layer.isEmpty()) {
_errorString = "Missing layer definition";
return 0;
}
if (config.wmts.style.isEmpty()) {
_errorString = "Missing style definiton";
return 0;
}
if (config.wmts.set.isEmpty()) {
_errorString = "Missing set definiton";
return 0;
}
if (config.wmts.format.isEmpty()) {
_errorString = "Missing format definition";
return 0;
}
}
return !reader.error();
Map *m;
if (config.type == WMTS)
m = new WMTSMap(config.name, WMTS::Setup(config.url, config.wmts.layer,
config.wmts.set, config.wmts.style, config.wmts.format,
config.wmts.rest, config.wmts.yx, config.wmts.dimensions));
else
m = new OnlineMap(config.name, config.url, config.tms.zooms,
config.tms.bounds);
if (!m->isValid()) {
_errorString = m->errorString();
delete m;
return 0;
}
return m;
}

View File

@ -11,13 +11,47 @@ class QXmlStreamReader;
class MapSource
{
public:
bool loadFile(const QString &path, Map **map);
Map *loadFile(const QString &path);
const QString &errorString() const {return _errorString;}
private:
enum Type {
TMS,
WMTS
};
struct TMSConfig {
Range zooms;
RectC bounds;
TMSConfig();
};
struct WMTSConfig {
QString layer;
QString style;
QString set;
QString format;
bool rest;
bool yx;
QList<QPair<QString, QString> > dimensions;
WMTSConfig() : format("image/png"), rest(false), yx(false) {}
};
struct Config {
QString name;
QString url;
Type type;
WMTSConfig wmts;
TMSConfig tms;
Config() : type(TMS) {}
};
RectC bounds(QXmlStreamReader &reader);
Range zooms(QXmlStreamReader &reader);
void map(QXmlStreamReader &reader, Map **map);
void map(QXmlStreamReader &reader, Config &config);
QString _errorString;
};

View File

@ -116,6 +116,7 @@ void Matrix::zeroize()
_m[i] = 0;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Matrix &matrix)
{
dbg.nospace() << "Matrix(" << endl;
@ -128,3 +129,4 @@ QDebug operator<<(QDebug dbg, const Matrix &matrix)
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -5,7 +5,8 @@
#include <cfloat>
#include <QDebug>
class Matrix {
class Matrix
{
public:
Matrix() {_h = 0; _w = 0; _m = 0;}
Matrix(size_t h, size_t w);
@ -31,6 +32,8 @@ private:
size_t _w;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Matrix &matrix);
#endif // QT_NO_DEBUG
#endif // MATRIX_H

View File

@ -1,12 +1,16 @@
#include <cmath>
#include "common/coordinates.h"
#include "common/wgs84.h"
#include "mercator.h"
QPointF Mercator::ll2xy(const Coordinates &c) const
{
return QPointF(c.lon(), rad2deg(log(tan(M_PI/4.0 + deg2rad(c.lat())/2.0))));
return QPointF(deg2rad(c.lon()) * WGS84_RADIUS,
log(tan(M_PI/4.0 + deg2rad(c.lat())/2.0)) * WGS84_RADIUS);
}
Coordinates Mercator::xy2ll(const QPointF &p) const
{
return Coordinates(p.x(), rad2deg(2 * atan(exp(deg2rad(p.y()))) - M_PI/2));
return Coordinates(rad2deg(p.x() / WGS84_RADIUS),
rad2deg(2 * atan(exp(p.y() / WGS84_RADIUS)) - M_PI/2));
}

View File

@ -1,4 +1,3 @@
#include <QtGlobal>
#include <QPainter>
#include <QFileInfo>
#include <QMap>
@ -9,56 +8,49 @@
#include <QPixmapCache>
#include "common/coordinates.h"
#include "common/rectc.h"
#include "tar.h"
#include "ozf.h"
#include "mapfile.h"
#include "geotiff.h"
#include "offlinemap.h"
void OfflineMap::computeResolution()
bool OfflineMap::setImageInfo(const QString &path)
{
Coordinates tl = xy2ll((bounds().topLeft()));
Coordinates br = xy2ll(bounds().bottomRight());
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(bounds().topLeft(), bounds().bottomRight()).length();
_resolution = ds/ps;
}
bool OfflineMap::getImageInfo(const QString &path)
{
QFileInfo ii(_imgPath);
QFileInfo ii(_map.path);
if (ii.isRelative())
ii.setFile(path + "/" + _imgPath);
ii.setFile(path + "/" + _map.path);
if (!ii.exists()) {
int last = _imgPath.lastIndexOf('\\');
if (last >= 0 && last < _imgPath.length() - 1) {
QStringRef fn(&_imgPath, last + 1, _imgPath.length() - last - 1);
int last = _map.path.lastIndexOf('\\');
if (last >= 0 && last < _map.path.length() - 1) {
QStringRef fn(&_map.path, last + 1, _map.path.length() - last - 1);
ii.setFile(path + "/" + fn.toString());
}
}
if (ii.exists())
_imgPath = ii.absoluteFilePath();
_map.path = ii.absoluteFilePath();
else {
_errorString = QString("%1: No such image file").arg(_imgPath);
_errorString = QString("%1: No such image file").arg(_map.path);
return false;
}
if (OZF::isOZF(_imgPath)) {
if (!_ozf.load(_imgPath)) {
if (OZF::isOZF(_map.path)) {
_ozf = new OZF(_map.path);
if (!_ozf->open()) {
_errorString = QString("%1: Error loading OZF file")
.arg(QFileInfo(_imgPath).fileName());
.arg(_ozf->fileName());
return false;
}
_scale = _ozf->scale(_zoom);
} else {
QImageReader img(_imgPath);
_size = img.size();
if (!_size.isValid()) {
QImageReader img(_map.path);
_map.size = img.size();
if (!_map.size.isValid()) {
_errorString = QString("%1: Error reading map image")
.arg(QFileInfo(_imgPath).fileName());
.arg(QFileInfo(_map.path).fileName());
return false;
}
}
@ -66,27 +58,33 @@ bool OfflineMap::getImageInfo(const QString &path)
return true;
}
bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path)
bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
{
if (!_map.size.isValid()) {
_errorString = "Missing total image size (IWH)";
return false;
}
QRegExp rx("_[0-9]+_[0-9]+\\.");
for (int i = 0; i < tiles.size(); i++) {
if (tiles.at(i).contains(rx)) {
_tileName = QString(tiles.at(i)).replace(rx, "_%1_%2.");
_tile.path = QString(tiles.at(i)).replace(rx, "_%1_%2.");
if (path.isNull()) {
QByteArray ba = _tar.file(tiles.at(i));
if (_tar) {
QByteArray ba = _tar->file(tiles.at(i));
QBuffer buffer(&ba);
_tileSize = QImageReader(&buffer).size();
_tile.size = QImageReader(&buffer).size();
} else {
_tileName = path + "/" + _tileName;
_tileSize = QImageReader(path + "/" + tiles.at(i)).size();
_tile.path = path + "/" + _tile.path;
_tile.size = QImageReader(path + "/" + tiles.at(i)).size();
}
if (!_tileSize.isValid()) {
if (!_tile.size.isValid()) {
_errorString = QString("Error retrieving tile size: "
"%1: Invalid image").arg(QFileInfo(tiles.at(i)).fileName());
return false;
}
_map.path = QString();
return true;
}
}
@ -95,35 +93,22 @@ bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path)
return false;
}
bool OfflineMap::totalSizeSet()
{
if (!_size.isValid()) {
_errorString = "Missing total image size (IWH)";
return false;
} else
return true;
}
OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
: Map(parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _valid(false)
{
QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower();
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
if (suffix == "tar") {
if (!_tar.load(fileName)) {
_tar = new Tar(fileName);
if (!_tar->open()) {
_errorString = "Error reading tar file";
return;
}
QString mapFileName = fi.completeBaseName() + ".map";
QByteArray ba = _tar.file(mapFileName);
QByteArray ba = _tar->file(mapFileName);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
@ -135,8 +120,8 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return;
} else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
@ -148,8 +133,8 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return;
} else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
@ -160,7 +145,7 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return;
} else {
_name = fi.fileName();
_imgPath = fileName;
_map.path = fileName;
_projection = gt.projection();
_transform = gt.transform();
}
@ -169,43 +154,31 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return;
}
if (_tar.isOpen()) {
if (!totalSizeSet())
if (_tar) {
if (!setTileInfo(_tar->files()))
return;
if (!getTileInfo(_tar.files()))
return;
_imgPath = QString();
} else {
QDir set(fi.absolutePath() + "/" + "set");
if (set.exists()) {
if (!totalSizeSet())
if (!setTileInfo(set.entryList(), set.absolutePath()))
return;
if (!getTileInfo(set.entryList(), set.absolutePath()))
return;
_imgPath = QString();
} else {
if (!getImageInfo(fi.absolutePath()))
if (!setImageInfo(fi.absolutePath()))
return;
}
}
_inverted = _transform.inverted();
computeResolution();
_valid = true;
}
OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _valid(false)
{
QFileInfo fi(fileName);
MapFile mf;
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
QFileInfo map(fi.absolutePath());
QFileInfo layer(map.absolutePath());
@ -224,38 +197,40 @@ OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
}
_name = mf.name();
_size = mf.size();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_inverted = _transform.inverted();
computeResolution();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
_tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar";
_valid = true;
}
OfflineMap::~OfflineMap()
{
delete _img;
delete _tar;
delete _ozf;
}
void OfflineMap::load()
{
if (!_tarPath.isNull() && !_tileSize.isValid()) {
if (!_tar.load(_tarPath)) {
qWarning("%s: error loading tar file", qPrintable(_tarPath));
if (_tar && !_tar->isOpen()) {
if (!_tar->open()) {
qWarning("%s: error loading tar file",
qPrintable(_tar->fileName()));
return;
}
if (!getTileInfo(_tar.files()))
qWarning("%s: %s", qPrintable(_tarPath), qPrintable(_errorString));
if (!setTileInfo(_tar->files()))
qWarning("%s: %s", qPrintable(_tar->fileName()),
qPrintable(_errorString));
return;
}
if (!_img && !_imgPath.isNull() && !_ozf.isOpen()) {
_img = new QImage(_imgPath);
if (!_ozf && !_img && _map.isValid()) {
_img = new QImage(_map.path);
if (_img->isNull())
qWarning("%s: error loading map image", qPrintable(_imgPath));
qWarning("%s: error loading map image", qPrintable(_map.path));
}
}
@ -265,26 +240,26 @@ void OfflineMap::unload()
_img = 0;
}
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
{
QPoint tl = QPoint((int)floor(rect.left() / (qreal)_tileSize.width())
* _tileSize.width(), (int)floor(rect.top() / _tileSize.height())
* _tileSize.height());
QPoint tl = QPoint((int)floor(rect.left() / (qreal)_tile.size.width())
* _tile.size.width(), (int)floor(rect.top() / _tile.size.height())
* _tile.size.height());
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
for (int i = 0; i < ceil(s.width() / _tileSize.width()); i++) {
for (int j = 0; j < ceil(s.height() / _tileSize.height()); j++) {
int x = tl.x() + i * _tileSize.width();
int y = tl.y() + j * _tileSize.height();
for (int i = 0; i < ceil(s.width() / _tile.size.width()); i++) {
for (int j = 0; j < ceil(s.height() / _tile.size.height()); j++) {
int x = tl.x() + i * _tile.size.width();
int y = tl.y() + j * _tile.size.height();
QString tileName(_tileName.arg(QString::number(x),
QString tileName(_tile.path.arg(QString::number(x),
QString::number(y)));
QPixmap pixmap;
if (_tar.isOpen()) {
QString key = _tar.fileName() + "/" + tileName;
if (_tar) {
QString key = _tar->fileName() + "/" + tileName;
if (!QPixmapCache::find(key, &pixmap)) {
QByteArray ba = _tar.file(tileName);
QByteArray ba = _tar->file(tileName);
pixmap = QPixmap::fromImage(QImage::fromData(ba));
if (!pixmap.isNull())
QPixmapCache::insert(key, pixmap);
@ -294,8 +269,8 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
if (pixmap.isNull()) {
qWarning("%s: error loading tile image", qPrintable(
_tileName.arg(QString::number(x), QString::number(y))));
painter->fillRect(QRectF(QPoint(x, y), _tileSize),
_tile.path.arg(QString::number(x), QString::number(y))));
painter->fillRect(QRectF(QPoint(x, y), _tile.size),
_backgroundColor);
} else
painter->drawPixmap(QPoint(x, y), pixmap);
@ -303,30 +278,30 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
}
}
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
{
QPoint tl = QPoint((int)floor(rect.left() / _ozf.tileSize().width())
* _ozf.tileSize().width(), (int)floor(rect.top()
/ _ozf.tileSize().height()) * _ozf.tileSize().height());
QPoint tl = QPoint((int)floor(rect.left() / _ozf->tileSize().width())
* _ozf->tileSize().width(), (int)floor(rect.top()
/ _ozf->tileSize().height()) * _ozf->tileSize().height());
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
for (int i = 0; i < ceil(s.width() / _ozf.tileSize().width()); i++) {
for (int j = 0; j < ceil(s.height() / _ozf.tileSize().height()); j++) {
int x = tl.x() + i * _ozf.tileSize().width();
int y = tl.y() + j * _ozf.tileSize().height();
for (int i = 0; i < ceil(s.width() / _ozf->tileSize().width()); i++) {
for (int j = 0; j < ceil(s.height() / _ozf->tileSize().height()); j++) {
int x = tl.x() + i * _ozf->tileSize().width();
int y = tl.y() + j * _ozf->tileSize().height();
QPixmap pixmap;
QString key = _ozf.fileName() + "/" + QString::number(_zoom) + "_"
QString key = _ozf->fileName() + "/" + QString::number(_zoom) + "_"
+ QString::number(x) + "_" + QString::number(y);
if (!QPixmapCache::find(key, &pixmap)) {
pixmap = _ozf.tile(_zoom, x, y);
pixmap = _ozf->tile(_zoom, x, y);
if (!pixmap.isNull())
QPixmapCache::insert(key, pixmap);
}
if (pixmap.isNull()) {
qWarning("%s: error loading tile image", qPrintable(key));
painter->fillRect(QRectF(QPoint(x, y), _ozf.tileSize()),
painter->fillRect(QRectF(QPoint(x, y), _ozf->tileSize()),
_backgroundColor);
} else
painter->drawPixmap(QPoint(x, y), pixmap);
@ -334,7 +309,7 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
}
}
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect)
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect) const
{
QRect r(rect.toRect());
painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
@ -343,9 +318,9 @@ void OfflineMap::drawImage(QPainter *painter, const QRectF &rect)
void OfflineMap::draw(QPainter *painter, const QRectF &rect)
{
if (_ozf.isOpen())
if (_ozf)
drawOZF(painter, rect);
else if (_tileSize.isValid())
else if (_tile.isValid())
drawTiled(painter, rect);
else if (_img && !_img->isNull())
drawImage(painter, rect);
@ -353,18 +328,18 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
painter->fillRect(rect, _backgroundColor);
}
QPointF OfflineMap::ll2xy(const Coordinates &c)
QPointF OfflineMap::ll2xy(const Coordinates &c) const
{
if (_ozf.isOpen()) {
if (_ozf) {
QPointF p(_transform.map(_projection.ll2xy(c)));
return QPointF(p.x() * _scale.x(), p.y() * _scale.y());
} else
return _transform.map(_projection.ll2xy(c));
}
Coordinates OfflineMap::xy2ll(const QPointF &p)
Coordinates OfflineMap::xy2ll(const QPointF &p) const
{
if (_ozf.isOpen()) {
if (_ozf) {
return _projection.xy2ll(_inverted.map(QPointF(p.x() / _scale.x(),
p.y() / _scale.y())));
} else
@ -373,25 +348,26 @@ Coordinates OfflineMap::xy2ll(const QPointF &p)
QRectF OfflineMap::bounds() const
{
if (_ozf.isOpen())
return QRectF(QPointF(0, 0), _ozf.size(_zoom));
if (_ozf)
return QRectF(QPointF(0, 0), _ozf->size(_zoom));
else
return QRectF(QPointF(0, 0), _size);
return QRectF(QPointF(0, 0), _map.size);
}
qreal OfflineMap::resolution(const QPointF &p) const
qreal OfflineMap::resolution(const QRectF &rect) const
{
Q_UNUSED(p);
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
if (_ozf.isOpen())
return _resolution / ((_scale.x() + _scale.y()) / 2.0);
else
return _resolution;
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
return ds/ps;
}
qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
int OfflineMap::zoomFit(const QSize &size, const RectC &br)
{
if (_ozf.isOpen()) {
if (_ozf) {
if (!br.isValid())
rescale(0);
else {
@ -399,7 +375,7 @@ qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
_transform.map(_projection.ll2xy(br.bottomRight())))
.toRect().normalized());
for (int i = 0; i < _ozf.zooms(); i++) {
for (int i = 0; i < _ozf->zooms(); i++) {
rescale(i);
if (sbr.size().width() * _scale.x() <= size.width()
&& sbr.size().height() * _scale.y() <= size.height())
@ -411,34 +387,18 @@ qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal OfflineMap::zoomFit(qreal resolution, const Coordinates &c)
int OfflineMap::zoomIn()
{
Q_UNUSED(c);
if (_ozf.isOpen()) {
for (int i = 0; i < _ozf.zooms(); i++) {
rescale(i);
qreal sr = _resolution / ((_scale.x() + _scale.y()) / 2.0);
if (sr >= resolution)
break;
}
}
return _zoom;
}
qreal OfflineMap::zoomIn()
{
if (_ozf.isOpen())
if (_ozf)
rescale(qMax(_zoom - 1, 0));
return _zoom;
}
qreal OfflineMap::zoomOut()
int OfflineMap::zoomOut()
{
if (_ozf.isOpen())
rescale(qMin(_zoom + 1, _ozf.zooms() - 1));
if (_ozf)
rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
return _zoom;
}
@ -446,7 +406,5 @@ qreal OfflineMap::zoomOut()
void OfflineMap::rescale(int zoom)
{
_zoom = zoom;
_scale = QPointF(
(qreal)_ozf.size(_zoom).width() / (qreal)_ozf.size(0).width(),
(qreal)_ozf.size(_zoom).height() / (qreal)_ozf.size(0).height());
_scale = _ozf->scale(zoom);
}

View File

@ -3,13 +3,10 @@
#include <QTransform>
#include "projection.h"
#include "transform.h"
#include "linearunits.h"
#include "map.h"
#include "tar.h"
#include "ozf.h"
class QIODevice;
class Tar;
class OZF;
class QImage;
class OfflineMap : public Map
@ -24,16 +21,17 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OfflineMap &>(*this).ll2xy(c);}
Coordinates xy2ll(const QPointF &p)
{return static_cast<const OfflineMap &>(*this).xy2ll(p);}
void draw(QPainter *painter, const QRectF &rect);
@ -41,7 +39,7 @@ public:
void unload();
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
QString errorString() const {return _errorString;}
QPointF ll2pp(const Coordinates &c) const
{return _projection.ll2xy(c);}
@ -51,15 +49,23 @@ public:
{return _transform.map(p);}
private:
bool getTileInfo(const QStringList &tiles, const QString &path = QString());
bool getImageInfo(const QString &path);
bool totalSizeSet();
struct ImageInfo {
QSize size;
QString path;
void drawTiled(QPainter *painter, const QRectF &rect);
void drawOZF(QPainter *painter, const QRectF &rect);
void drawImage(QPainter *painter, const QRectF &rect);
bool isValid() const {return size.isValid() && !path.isEmpty();}
};
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
bool setTileInfo(const QStringList &tiles, const QString &path = QString());
bool setImageInfo(const QString &path);
void drawTiled(QPainter *painter, const QRectF &rect) const;
void drawOZF(QPainter *painter, const QRectF &rect) const;
void drawImage(QPainter *painter, const QRectF &rect) const;
void computeResolution();
void rescale(int zoom);
QString _name;
@ -67,17 +73,12 @@ private:
Projection _projection;
QTransform _transform, _inverted;
OZF _ozf;
Tar _tar;
QString _tarPath;
QImage *_img;
QString _imgPath;
QSize _tileSize;
QString _tileName;
QSize _size;
Tar *_tar;
OZF *_ozf;
ImageInfo _map, _tile;
int _zoom;
qreal _resolution;
QPointF _scale;
bool _valid;

View File

@ -1,10 +1,7 @@
#include <QFileInfo>
#include <QDir>
#include <QPainter>
#include "common/coordinates.h"
#include "common/rectc.h"
#include "common/wgs84.h"
#include "mercator.h"
#include "downloader.h"
#include "config.h"
#include "onlinemap.h"
@ -12,6 +9,16 @@
#define TILE_SIZE 256
static QPointF ll2m(const Coordinates &c)
{
return QPointF(c.lon(), rad2deg(log(tan(M_PI/4.0 + deg2rad(c.lat())/2.0))));
}
static Coordinates m2ll(const QPointF &p)
{
return Coordinates(p.x(), rad2deg(2 * atan(exp(deg2rad(p.y()))) - M_PI/2));
}
static QPoint mercator2tile(const QPointF &m, int z)
{
QPoint tile;
@ -32,45 +39,35 @@ static int scale2zoom(qreal scale)
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}
static bool loadTileFile(Tile &tile, const QString &file)
{
if (!tile.pixmap().load(file)) {
qWarning("%s: error loading tile file\n", qPrintable(file));
return false;
}
return true;
}
Downloader *OnlineMap::downloader;
OnlineMap::OnlineMap(const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, QObject *parent)
: Map(parent), _name(name), _url(url), _zooms(zooms), _bounds(bounds)
const Range &zooms, const RectC &bounds, QObject *parent) :
Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
_block(false), _valid(false)
{
_block = false;
_zoom = _zooms.max();
QString dir(TILES_DIR + "/" + _name);
QString path = TILES_DIR + QString("/") + name;
if (!QDir().mkpath(path))
qWarning("Error creating tiles dir: %s\n", qPrintable(path));
_zoom = _zooms.max();
_tileLoader = TileLoader(url, dir);
if (!QDir().mkpath(dir)) {
_errorString = "Error creating tiles dir";
return;
}
_valid = true;
}
void OnlineMap::load()
{
connect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
connect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void OnlineMap::unload()
{
disconnect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
}
void OnlineMap::fillTile(Tile &tile)
{
tile.pixmap() = QPixmap(TILE_SIZE, TILE_SIZE);
tile.pixmap().fill(_backgroundColor);
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void OnlineMap::emitLoaded()
@ -78,91 +75,6 @@ void OnlineMap::emitLoaded()
emit loaded();
}
void OnlineMap::loadTilesAsync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists()) {
fillTile(t);
dl.append(Download(tileUrl(t), file));
} else
loadTileFile(t, file);
}
if (!dl.empty())
downloader->get(dl);
}
void OnlineMap::loadTilesSync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists())
dl.append(Download(tileUrl(t), file));
else
loadTileFile(t, file);
}
if (dl.empty())
return;
QEventLoop wait;
connect(downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (downloader->get(dl))
wait.exec();
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
if (t.pixmap().isNull()) {
QString file = tileFile(t);
QFileInfo fi(file);
if (!(fi.exists() && loadTileFile(t, file)))
fillTile(t);
}
}
}
QString OnlineMap::tileUrl(const Tile &tile) const
{
QString url(_url);
url.replace("$z", QString::number(tile.zoom()));
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
return url;
}
QString OnlineMap::tileFile(const Tile &tile) const
{
QString file = TILES_DIR + QString("/%1/%2-%3-%4").arg(name())
.arg(tile.zoom()).arg(tile.xy().x()).arg(tile.xy().y());
return file;
}
void OnlineMap::clearCache()
{
QString path = TILES_DIR + QString("/") + name();
QDir dir = QDir(path);
QStringList list = dir.entryList();
for (int i = 0; i < list.count(); i++)
dir.remove(list.at(i));
}
QRectF OnlineMap::bounds() const
{
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
@ -178,13 +90,12 @@ int OnlineMap::limitZoom(int zoom) const
return zoom;
}
qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
int OnlineMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_zoom = _zooms.max();
else {
QRectF tbr(Mercator().ll2xy(br.topLeft()),
Mercator().ll2xy(br.bottomRight()));
QRectF tbr(ll2m(br.topLeft()), ll2m(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
_zoom = limitZoom(scale2zoom(qMax(sc.x(), sc.y())));
@ -193,29 +104,21 @@ qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal OnlineMap::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = limitZoom((int)log2((WGS84_RADIUS * 2.0 * M_PI
* cos(deg2rad(c.lat()))) / (resolution * TILE_SIZE)));
return _zoom;
}
qreal OnlineMap::resolution(const QPointF &p) const
qreal OnlineMap::resolution(const QRectF &rect) const
{
qreal scale = zoom2scale(_zoom);
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * scale))) - M_PI/2));
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal OnlineMap::zoomIn()
int OnlineMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.max());
return _zoom;
}
qreal OnlineMap::zoomOut()
int OnlineMap::zoomOut()
{
_zoom = qMax(_zoom - 1, _zooms.min());
return _zoom;
@ -237,28 +140,31 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect)
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
if (_block)
loadTilesSync(tiles);
_tileLoader.loadTilesSync(tiles);
else
loadTilesAsync(tiles);
_tileLoader.loadTilesAsync(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPoint tp(tl.x() + (t.xy().x() - tile.x()) * TILE_SIZE,
tl.y() + (t.xy().y() - tile.y()) * TILE_SIZE);
painter->drawPixmap(tp, t.pixmap());
if (t.pixmap().isNull())
painter->fillRect(QRect(tp, QSize(TILE_SIZE, TILE_SIZE)),
_backgroundColor);
else
painter->drawPixmap(tp, t.pixmap());
}
}
QPointF OnlineMap::ll2xy(const Coordinates &c) const
{
qreal scale = zoom2scale(_zoom);
QPointF m = Mercator().ll2xy(c);
QPointF m = ll2m(c);
return QPointF(m.x() / scale, m.y() / -scale);
}
Coordinates OnlineMap::xy2ll(const QPointF &p) const
{
qreal scale = zoom2scale(_zoom);
QPointF m(p.x() * scale, -p.y() * scale);
return Mercator().xy2ll(m);
return m2ll(QPointF(p.x() * scale, -p.y() * scale));
}

View File

@ -1,13 +1,10 @@
#ifndef ONLINEMAP_H
#define ONLINEMAP_H
#include "common/coordinates.h"
#include "common/range.h"
#include "common/rectc.h"
#include "map.h"
#include "tile.h"
class Downloader;
#include "tileloader.h"
class OnlineMap : public Map
{
@ -20,13 +17,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OnlineMap &>(*this).ll2xy(c);}
@ -36,36 +32,31 @@ public:
void draw(QPainter *painter, const QRectF &rect);
void setBlockingMode(bool block) {_block = block;}
void clearCache();
static void setDownloader(Downloader *downloader)
{OnlineMap::downloader = downloader;}
void clearCache() {_tileLoader.clearCache();}
void load();
void unload();
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private slots:
void emitLoaded();
private:
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
void fillTile(Tile &tile);
QString tileUrl(const Tile &tile) const;
QString tileFile(const Tile &tile) const;
void loadTilesAsync(QList<Tile> &list);
void loadTilesSync(QList<Tile> &list);
int limitZoom(int zoom) const;
TileLoader _tileLoader;
QString _name;
QString _url;
Range _zooms;
RectC _bounds;
int _zoom;
bool _block;
static Downloader *downloader;
bool _valid;
QString _errorString;
};
#endif // ONLINEMAP_H

View File

@ -185,12 +185,8 @@ bool OZF::readTileTable()
return _zooms.isEmpty() ? false : true;
}
bool OZF::load(const QString &path)
bool OZF::open()
{
if (_file.isOpen())
_file.close();
_file.setFileName(path);
if (!_file.open(QIODevice::ReadOnly))
return false;
@ -250,6 +246,12 @@ QSize OZF::size(int zoom) const
return _zooms.at(zoom).size;
}
QPointF OZF::scale(int zoom) const
{
return QPointF((qreal)size(zoom).width() / (qreal)size(0).width(),
(qreal)size(zoom).height() / (qreal)size(0).height());
}
bool OZF::isOZF(const QString &path)
{
QFile file(path);

View File

@ -12,15 +12,17 @@
class OZF
{
public:
OZF() : _tileSize(0), _decrypt(false), _key(0) {}
OZF(const QString &name) : _tileSize(0), _decrypt(false), _key(0),
_file(name) {}
bool load(const QString &path);
bool open();
QString fileName() const {return _file.fileName();}
bool isOpen() const {return _file.isOpen();}
int zooms() const {return _zooms.size();}
QSize size(int zoom) const;
QPointF scale(int zoom) const;
QSize tileSize() const {return QSize(_tileSize, _tileSize);}
QPixmap tile(int zoom, int x, int y);

View File

@ -22,6 +22,7 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
{
switch (key) {
case 8801:
case 8811:
case 8821:
{AngularUnits au(units);
if (au.isNull())
@ -29,6 +30,7 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setLatitudeOrigin(au.toDegrees(val));}
return true;
case 8802:
case 8812:
case 8822:
{AngularUnits au(units);
if (au.isNull())
@ -36,9 +38,11 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setLongitudeOrigin(au.toDegrees(val));}
return true;
case 8805:
case 8815:
setup.setScale(val);
return true;
case 8806:
case 8816:
case 8826:
{LinearUnits lu(units);
if (lu.isNull())
@ -46,18 +50,21 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setFalseEasting(lu.toMeters(val));}
return true;
case 8807:
case 8817:
case 8827:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseNorthing(lu.toMeters(val));}
return true;
case 8813:
case 8823:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel1(au.toDegrees(val));}
return true;
case 8814:
case 8824:
{AngularUnits au(units);
if (au.isNull())
@ -74,7 +81,7 @@ static int projectionSetup(const QList<QByteArray> &list,
{
bool r1, r2, r3;
for (int i = 6; i < 24; i += 3) {
for (int i = 6; i < 27; i += 3) {
QString ks = list[i].trimmed();
if (ks.isEmpty())
break;
@ -129,7 +136,7 @@ void PCS::loadList(const QString &path)
QByteArray line = file.readLine();
QList<QByteArray> list = line.split(',');
if (list.size() != 24) {
if (list.size() != 27) {
qWarning("%s: %d: Format error", qPrintable(path), ln);
continue;
}
@ -187,9 +194,11 @@ void PCS::loadList(const QString &path)
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PCS &pcs)
{
dbg.nospace() << "PCS(" << *pcs.gcs() << ", " << pcs.method() << ", "
<< pcs.units() << ", " << pcs.setup() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -40,9 +40,10 @@ private:
LinearUnits _units;
static QList<Entry> _pcss;
static GCS _nullGCS;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PCS &pcs);
#endif // QT_NO_DEBUG
#endif // PCS_H

View File

@ -66,8 +66,10 @@ double PrimeMeridian::fromGreenwich(double val) const
return shift(val, -_pm);
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PrimeMeridian &pm)
{
dbg.nospace() << "PrimeMeridian(" << pm._pm << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -17,7 +17,9 @@ public:
double fromGreenwich(double val) const;
friend bool operator==(const PrimeMeridian &pm1, const PrimeMeridian &pm2);
#ifndef QT_NO_DEBUG
friend QDebug operator<<(QDebug dbg, const PrimeMeridian &pm);
#endif // QT_NO_DEBUG
private:
double _pm;
@ -26,6 +28,8 @@ private:
inline bool operator==(const PrimeMeridian &pm1, const PrimeMeridian &pm2)
{return (pm1._pm == pm2._pm);}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PrimeMeridian &pm);
#endif // QT_NO_DEBUG
#endif // PRIMEMERIDIAN_H

Some files were not shown because too many files have changed in this diff Show More