1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-04 14:49:30 +02:00

Compare commits

...

39 Commits
5.17 ... 5.18

Author SHA1 Message Date
7432459c93 Improved dateline crossing handling 2018-09-15 13:40:21 +02:00
eda5046518 Show the path marker on the great circle segment line 2018-09-15 10:41:00 +02:00
b867ce9a7f Code cleanup 2018-09-15 08:40:37 +02:00
c89137204e Use the GreatCircle for all segments longer than 1 arc minute 2018-09-15 00:22:27 +02:00
e707cc30ad Weblate import 2018-09-14 00:09:50 +02:00
df104b16c6 Yet another optimization 2018-09-13 01:45:17 +02:00
8f9049a8d4 Code cleanup/optimization 2018-09-13 01:15:43 +02:00
9957e1834e Now drawing path segments > 1 arc minute as great circle curves instead of rhumb lines 2018-09-13 00:43:28 +02:00
8d1be76043 Fixed Garmin CSV reader coordinates order (correct is lon, lat) 2018-09-12 20:13:09 +02:00
09a5f57109 Fixed POI selection when the POI radius is not >> trackpoint distance
Fixes #153
2018-09-12 19:55:32 +02:00
3291ea86ef Localization update 2018-09-11 01:01:09 +02:00
672df4255e Version++ 2018-09-11 00:36:11 +02:00
89f384feed Made the HiDPI display mode (of non-HiDPI maps) configurable 2018-09-11 00:33:20 +02:00
d58322b412 Map API cleanup 2018-09-10 21:22:57 +02:00
70222f4ae2 Fixed overlapping scale numbers 2018-09-10 21:22:01 +02:00
fe1aaa73a0 Fixed compile warning 2018-09-10 21:21:40 +02:00
2501f834c8 Display numbers according to the locale settings
Closes #150
2018-09-09 18:46:43 +02:00
3f4b70ee48 Localization update 2018-09-09 15:34:34 +02:00
384d20b1a5 Changed 1/min to more convenient bpm/rpm
Closes #135
2018-09-09 15:27:44 +02:00
b4a06057f8 Fixed copy&paste error 2018-09-09 15:26:45 +02:00
9f14eb7e70 Added weblate info 2018-09-09 14:51:27 +02:00
dcf1c686e5 Added support for new IGC date header format
Fixes #152
2018-09-09 14:38:37 +02:00
a8d183639e Fixed broken zoom 0 handling
Fixes #151
2018-09-09 09:41:04 +02:00
d9e025a18c String handling optimization 2018-08-27 22:25:55 +02:00
0a9077545b Make huge images work under OpenGL (at least memory-ineficient) 2018-08-24 12:26:32 +02:00
bbc1d43290 Fixed QT4 build 2018-08-24 00:46:06 +02:00
524d72ce3c Merge branch 'master' of https://github.com/tumic0/GPXSee 2018-08-24 00:15:12 +02:00
9f74bbb27a Some more code cleanup 2018-08-24 00:14:40 +02:00
ce34d449c2 Translations update (#149) 2018-08-23 23:58:06 +02:00
21dbd3958d Removed obsolete method 2018-08-23 23:56:23 +02:00
92ac7c0c10 Removed obsolete define 2018-08-23 20:33:14 +02:00
1f71b3a3b2 Code/API cleanup 2018-08-23 20:26:10 +02:00
27886ea96a Update gpxsee_sv.ts (#148)
new string translated
2018-08-23 09:10:55 +02:00
3176271955 Only create/copy the sub-images when OpenGL is used 2018-08-23 09:08:59 +02:00
d4b46a4bb6 Broken OpenGL image part drawing workaround 2018-08-22 00:14:07 +02:00
3b2d4dcd31 Update README.md 2018-08-21 22:40:38 +02:00
de196e8281 Splited the OfflineMap class to separate OziMap and GeoTIFF map classes 2018-08-21 20:01:47 +02:00
f376f7139b Report an error on HiDPI maps when HiDPI support is not enabled 2018-08-20 18:46:44 +02:00
9fe10f10b8 Fixed compiler warning 2018-08-19 10:44:12 +02:00
78 changed files with 3414 additions and 2740 deletions

View File

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

View File

@ -10,6 +10,7 @@ KML, FIT, IGC, NMEA, SLF, LOC and OziExplorer files.
* Support for POI files.
* Print/export to PDF.
* Full-screen mode.
* HiDPI/Retina displays & maps support.
* Native GUI for Windows, Mac OS X and Linux.
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT, RTE, WPT) and Garmin CSV files.
@ -31,3 +32,6 @@ make
## Homepage
http://www.gpxsee.org
## Translations
GPXSee uses [Weblate](https://hosted.weblate.org/projects/gpxsee) for translations.

View File

@ -1,5 +1,5 @@
TARGET = GPXSee
VERSION = 5.17
VERSION = 5.18
QT += core \
gui \
@ -89,7 +89,7 @@ HEADERS += src/config.h \
src/map/downloader.h \
src/map/tile.h \
src/map/emptymap.h \
src/map/offlinemap.h \
src/map/ozimap.h \
src/map/tar.h \
src/map/ozf.h \
src/map/atlas.h \
@ -139,7 +139,10 @@ HEADERS += src/config.h \
src/map/krovak.h \
src/GUI/kv.h \
src/data/locparser.h \
src/data/slfparser.h
src/data/slfparser.h \
src/map/geotiffmap.h \
src/map/image.h \
src/common/greatcircle.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -192,7 +195,7 @@ SOURCES += src/main.cpp \
src/map/onlinemap.cpp \
src/map/downloader.cpp \
src/map/emptymap.cpp \
src/map/offlinemap.cpp \
src/map/ozimap.cpp \
src/map/tar.cpp \
src/map/atlas.cpp \
src/map/ozf.cpp \
@ -242,7 +245,10 @@ SOURCES += src/main.cpp \
src/map/krovak.cpp \
src/map/map.cpp \
src/data/locparser.cpp \
src/data/slfparser.cpp
src/data/slfparser.cpp \
src/map/geotiffmap.cpp \
src/map/image.cpp \
src/common/greatcircle.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts \
@ -299,3 +305,4 @@ win32 {
}
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
DEFINES *= QT_USE_QSTRINGBUILDER

View File

@ -40,5 +40,7 @@
<file>icons/document-print_32@2x.png</file>
<file>icons/view-filter.png</file>
<file>icons/view-filter@2x.png</file>
<file>icons/applications-internet_32.png</file>
<file>icons/applications-internet_32@2x.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -36,7 +36,8 @@ Ticks::Ticks(double minValue, double maxValue, int maxCount)
}
AxisItem::AxisItem(Type type, QGraphicsItem *parent) : QGraphicsItem(parent)
AxisItem::AxisItem(Type type, QGraphicsItem *parent)
: QGraphicsItem(parent), _locale(QLocale::system())
{
_type = type;
_size = 0;
@ -56,7 +57,7 @@ void AxisItem::setRange(const RangeF &range)
for (int i = 0; i < ticks.count(); i++) {
Tick &t = _ticks[i];
t.value = ticks.val(i);
t.boundingBox = fm.tightBoundingRect(QString::number(t.value));
t.boundingBox = fm.tightBoundingRect(_locale.toString(t.value));
}
updateBoundingRect();
@ -126,7 +127,7 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
TICK/2, (_size/_range.size()) * (val - _range.min()), -TICK/2);
painter->drawText(((_size/_range.size()) * (val - _range.min()))
- (ts.width()/2), ts.height() + TICK/2 + PADDING,
QString::number(val));
_locale.toString(val));
}
painter->drawText(_size/2 - _labelBB.width()/2, _labelBB.height()
@ -145,7 +146,7 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
* (val - _range.min())));
painter->drawText(-(ts.width() + PADDING + TICK/2),
-((_size/_range.size()) * (val - _range.min())) + (ts.height()/2),
QString::number(val));
_locale.toString(val));
}
painter->rotate(-90);

View File

@ -3,6 +3,7 @@
#include <QGraphicsItem>
#include <QVector>
#include <QLocale>
#include "common/range.h"
class AxisItem : public QGraphicsItem
@ -39,6 +40,7 @@ private:
QVector<Tick> _ticks;
QRectF _boundingRect;
QFont _font;
QLocale _locale;
};
#endif // AXISITEM_H

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "cadencegraphitem.h"
#include "cadencegraph.h"
@ -7,7 +8,7 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
{
_showTracks = true;
GraphView::setYUnits(tr("1/min"));
GraphView::setYUnits(tr("rpm"));
setYLabel(tr("Cadence"));
setSliderPrecision(1);
@ -16,9 +17,11 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
void CadenceGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
QLocale l(QLocale::system());
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
} else
clearInfo();

View File

@ -1,6 +1,8 @@
#include <QLocale>
#include "tooltip.h"
#include "cadencegraphitem.h"
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -16,11 +18,12 @@ CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
QString CadenceGraphItem::toolTip() const
{
ToolTip tt;
QLocale l(QLocale::system());
tt.insert(tr("Maximum"), QString::number(max(), 'f', 1)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Average"), QString::number(avg(), 'f', 1)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Maximum"), l.toString(max(), 'f', 1)
+ UNIT_SPACE + tr("rpm"));
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
+ UNIT_SPACE + tr("rpm"));
return tt.toString();
}

View File

@ -1,4 +1,5 @@
#include <cmath>
#include <QLocale>
#include "data/data.h"
#include "config.h"
#include "tooltip.h"
@ -54,13 +55,15 @@ void ElevationGraph::setInfo()
if (std::isnan(max()) || std::isnan(min()))
clearInfo();
else {
GraphView::addInfo(tr("Ascent"), QString::number(ascent() * yScale(),
QLocale l(QLocale::system());
GraphView::addInfo(tr("Ascent"), l.toString(ascent() * yScale(),
'f', 0) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Descent"), QString::number(descent() * yScale(),
GraphView::addInfo(tr("Descent"), l.toString(descent() * yScale(),
'f', 0) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
0) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale(), 'f',
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale(), 'f',
0) + UNIT_SPACE + yUnits());
}
}

View File

@ -1,6 +1,8 @@
#include <QLocale>
#include "tooltip.h"
#include "elevationgraphitem.h"
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -24,14 +26,15 @@ QString ElevationGraphItem::toolTip(Units units) const
ToolTip tt;
qreal scale = (units == Metric) ? 1.0 : M2FT;
QString su = (units == Metric) ? tr("m") : tr("ft");
QLocale l(QLocale::system());
tt.insert(tr("Ascent"), QString::number(ascent() * scale, 'f', 0)
tt.insert(tr("Ascent"), l.toString(ascent() * scale, 'f', 0)
+ UNIT_SPACE + su);
tt.insert(tr("Descent"), QString::number(descent() * scale, 'f', 0)
tt.insert(tr("Descent"), l.toString(descent() * scale, 'f', 0)
+ UNIT_SPACE + su);
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 0)
tt.insert(tr("Maximum"), l.toString(max() * scale, 'f', 0)
+ UNIT_SPACE + su);
tt.insert(tr("Minimum"), QString::number(min() * scale, 'f', 0)
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
+ UNIT_SPACE + su);
return tt.toString();

View File

@ -46,37 +46,41 @@ QString Format::timeSpan(qreal time, bool full)
QString Format::distance(qreal value, Units units)
{
QLocale l(QLocale::system());
if (units == Imperial) {
if (value < MIINM)
return QString::number(value * M2FT, 'f', 0) + UNIT_SPACE
return l.toString(value * M2FT, 'f', 0) + UNIT_SPACE
+ qApp->translate("Format", "ft");
else
return QString::number(value * M2MI, 'f', 1) + UNIT_SPACE
return l.toString(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
return l.toString(value * M2FT, 'f', 0) + UNIT_SPACE
+ qApp->translate("Format", "ft");
else
return QString::number(value * M2NMI, 'f', 1) + UNIT_SPACE
return l.toString(value * M2NMI, 'f', 1) + UNIT_SPACE
+ qApp->translate("Format", "nmi");
} else {
if (value < KMINM)
return QString::number(value, 'f', 0) + UNIT_SPACE
return l.toString(value, 'f', 0) + UNIT_SPACE
+ qApp->translate("Format", "m");
else
return QString::number(value * M2KM, 'f', 1) + UNIT_SPACE
return l.toString(value * M2KM, 'f', 1) + UNIT_SPACE
+ qApp->translate("Format", "km");
}
}
QString Format::elevation(qreal value, Units units)
{
QLocale l(QLocale::system());
if (units == Metric)
return QString::number(qRound(value)) + UNIT_SPACE
return l.toString(qRound(value)) + UNIT_SPACE
+ qApp->translate("Format", "m");
else
return QString::number(qRound(value * M2FT)) + UNIT_SPACE
return l.toString(qRound(value * M2FT)) + UNIT_SPACE
+ qApp->translate("Format", "ft");
}
@ -95,7 +99,8 @@ QString Format::coordinates(const Coordinates &value, CoordinatesFormat type)
+ 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;
QLocale l(QLocale::system());
return l.toString(qAbs(value.lat()), 'f', 5) + yH + ","
+ QChar(0x00A0) + l.toString(qAbs(value.lon()), 'f', 5) + xH;
}
}

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "gearratiographitem.h"
#include "gearratiograph.h"
@ -16,11 +17,13 @@ GearRatioGraph::GearRatioGraph(QWidget *parent) : GraphTab(parent)
void GearRatioGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Most used"), QString::number(top() * yScale(),
QLocale l(QLocale::system());
GraphView::addInfo(tr("Most used"), l.toString(top() * yScale(),
'f', 2) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale(), 'f',
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale(), 'f',
2) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
2) + UNIT_SPACE + yUnits());
} else
clearInfo();

View File

@ -1,7 +1,9 @@
#include <QMap>
#include <QLocale>
#include "tooltip.h"
#include "gearratiographitem.h"
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
{
@ -30,10 +32,11 @@ GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
QString GearRatioGraphItem::toolTip() const
{
ToolTip tt;
QLocale l(QLocale::system());
tt.insert(tr("Minimum"), QString::number(min(), 'f', 2));
tt.insert(tr("Maximum"), QString::number(max(), 'f', 2));
tt.insert(tr("Most used"), QString::number(top(), 'f', 2));
tt.insert(tr("Minimum"), l.toString(min(), 'f', 2));
tt.insert(tr("Maximum"), l.toString(max(), 'f', 2));
tt.insert(tr("Most used"), l.toString(top(), 'f', 2));
return tt.toString();
}

View File

@ -5,6 +5,7 @@
#include <QPaintDevice>
#include <QGraphicsSimpleTextItem>
#include <QPalette>
#include <QLocale>
#include "data/graph.h"
#include "opengl.h"
#include "config.h"
@ -413,8 +414,10 @@ void GraphView::updateSliderPosition()
void GraphView::updateSliderInfo()
{
QLocale l(QLocale::system());
qreal r, y;
if (_visible.count() > 1) {
r = 0;
y = 0;
@ -435,9 +438,9 @@ void GraphView::updateSliderInfo()
_sliderInfo->setSide(s);
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
bounds().width() > 3600) : QString::number(_sliderPos * _xScale, 'f', 1)
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
+ UNIT_SPACE + _xUnits, (_visible.count() > 1) ? QString()
: QString::number(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
+ _yUnits);
}

View File

@ -931,6 +931,11 @@ void GUI::openOptions()
if (options.enableHTTP2 != _options.enableHTTP2)
Downloader::enableHTTP2(options.enableHTTP2);
#endif // ENABLE_HTTP2
#ifdef ENABLE_HIDPI
if (options.hidpiMap != _options.hidpiMap)
_mapView->setDevicePixelRatio(options.hidpiMap ? devicePixelRatioF()
: 1.0);
#endif // ENABLE_HIDPI
if (reload)
reloadFile();
@ -971,6 +976,8 @@ void GUI::exportFile()
void GUI::statistics()
{
QLocale l(QLocale::system());
#ifdef Q_OS_WIN32
QString text = "<style>td {white-space: pre; padding-right: 4em;}"
"th {text-align: left; padding-top: 0.5em;}</style><table>";
@ -981,21 +988,21 @@ void GUI::statistics()
if (_showTracksAction->isChecked() && _trackCount > 1)
text.append("<tr><td>" + tr("Tracks") + ":</td><td>"
+ QString::number(_trackCount) + "</td></tr>");
+ l.toString(_trackCount) + "</td></tr>");
if (_showRoutesAction->isChecked() && _routeCount > 1)
text.append("<tr><td>" + tr("Routes") + ":</td><td>"
+ QString::number(_routeCount) + "</td></tr>");
+ l.toString(_routeCount) + "</td></tr>");
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
text.append("<tr><td>" + tr("Waypoints") + ":</td><td>"
+ QString::number(_waypointCount) + "</td></tr>");
+ l.toString(_waypointCount) + "</td></tr>");
if (_dateRange.first.isValid()) {
if (_dateRange.first == _dateRange.second) {
QString format = QLocale::system().dateFormat(QLocale::LongFormat);
QString format = l.dateFormat(QLocale::LongFormat);
text.append("<tr><td>" + tr("Date") + ":</td><td>"
+ _dateRange.first.toString(format) + "</td></tr>");
} else {
QString format = QLocale::system().dateFormat(QLocale::ShortFormat);
QString format = l.dateFormat(QLocale::ShortFormat);
text.append("<tr><td>" + tr("Date") + ":</td><td>"
+ QString("%1 - %2").arg(_dateRange.first.toString(format),
_dateRange.second.toString(format)) + "</td></tr>");
@ -1037,6 +1044,7 @@ void GUI::statistics()
void GUI::plot(QPrinter *printer)
{
QLocale l(QLocale::system());
QPainter p(printer);
TrackInfo info;
qreal ih, gh, mh, ratio;
@ -1047,19 +1055,19 @@ void GUI::plot(QPrinter *printer)
if (_options.printItemCount) {
if (_showTracksAction->isChecked() && _trackCount > 1)
info.insert(tr("Tracks"), QString::number(_trackCount));
info.insert(tr("Tracks"), l.toString(_trackCount));
if (_showRoutesAction->isChecked() && _routeCount > 1)
info.insert(tr("Routes"), QString::number(_routeCount));
info.insert(tr("Routes"), l.toString(_routeCount));
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
info.insert(tr("Waypoints"), QString::number(_waypointCount));
info.insert(tr("Waypoints"), l.toString(_waypointCount));
}
if (_dateRange.first.isValid() && _options.printDate) {
if (_dateRange.first == _dateRange.second) {
QString format = QLocale::system().dateFormat(QLocale::LongFormat);
QString format = l.dateFormat(QLocale::LongFormat);
info.insert(tr("Date"), _dateRange.first.toString(format));
} else {
QString format = QLocale::system().dateFormat(QLocale::ShortFormat);
QString format = l.dateFormat(QLocale::ShortFormat);
info.insert(tr("Date"), QString("%1 - %2")
.arg(_dateRange.first.toString(format),
_dateRange.second.toString(format)));
@ -1795,6 +1803,10 @@ void GUI::writeSettings()
settings.setValue(SLIDER_COLOR_SETTING, _options.sliderColor);
if (_options.alwaysShowMap != ALWAYS_SHOW_MAP_DEFAULT)
settings.setValue(ALWAYS_SHOW_MAP_SETTING, _options.alwaysShowMap);
#ifdef ENABLE_HIDPI
if (_options.hidpiMap != HIDPI_MAP_DEFAULT)
settings.setValue(HIDPI_MAP_SETTING, _options.hidpiMap);
#endif // ENABLE_HIDPI
settings.endGroup();
}
@ -2030,6 +2042,10 @@ void GUI::readSettings()
SLIDER_COLOR_DEFAULT).value<QColor>();
_options.alwaysShowMap = settings.value(ALWAYS_SHOW_MAP_SETTING,
ALWAYS_SHOW_MAP_DEFAULT).toBool();
#ifdef ENABLE_HIDPI
_options.hidpiMap = settings.value(HIDPI_MAP_SETTING, HIDPI_MAP_SETTING)
.toBool();
#endif // ENABLE_HIDPI
_mapView->setPalette(_options.palette);
_mapView->setMapOpacity(_options.mapOpacity);
@ -2046,6 +2062,9 @@ void GUI::readSettings()
_mapView->setMarkerColor(_options.sliderColor);
if (_options.useOpenGL)
_mapView->useOpenGL(true);
#ifdef ENABLE_HIDPI
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
#endif // ENABLE_HIDPI
for (int i = 0; i < _tabs.count(); i++) {
_tabs.at(i)->setPalette(_options.palette);
@ -2131,7 +2150,7 @@ void GUI::show()
void GUI::screenChanged(QScreen *screen)
{
#ifdef ENABLE_HIDPI
_mapView->updateDevicePixelRatio();
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
disconnect(SIGNAL(logicalDotsPerInchChanged(qreal)), this,
SLOT(logicalDotsPerInchChanged(qreal)));
@ -2147,6 +2166,6 @@ void GUI::logicalDotsPerInchChanged(qreal dpi)
Q_UNUSED(dpi)
#ifdef ENABLE_HIDPI
_mapView->updateDevicePixelRatio();
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
#endif // ENBLE_HIDPI
}

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "heartrategraphitem.h"
#include "heartrategraph.h"
@ -7,7 +8,7 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
{
_showTracks = true;
GraphView::setYUnits(tr("1/min"));
GraphView::setYUnits(tr("bpm"));
setYLabel(tr("Heart rate"));
setSliderPrecision(0);
@ -16,9 +17,11 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
void HeartRateGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f',
QLocale l(QLocale::system());
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale(), 'f',
0) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
0) + UNIT_SPACE + yUnits());
} else
clearInfo();

View File

@ -1,6 +1,8 @@
#include <QLocale>
#include "tooltip.h"
#include "heartrategraphitem.h"
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -16,11 +18,12 @@ HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
QString HeartRateGraphItem::toolTip() const
{
ToolTip tt;
QLocale l(QLocale::system());
tt.insert(tr("Maximum"), QString::number(max(), 'f', 0)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Average"), QString::number(avg(), 'f', 0)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Maximum"), l.toString(max(), 'f', 0)
+ UNIT_SPACE + tr("bpm"));
tt.insert(tr("Average"), l.toString(avg(), 'f', 0)
+ UNIT_SPACE + tr("bpm"));
return tt.toString();
}

View File

@ -25,5 +25,6 @@
#define SYSTEM_ICON ":/icons/preferences-system.png"
#define PRINT_EXPORT_ICON ":/icons/document-print_32.png"
#define DATA_ICON ":/icons/view-filter.png"
#define MAPS_ICON ":/icons/applications-internet_32.png"
#endif /* ICONS_H */

View File

@ -41,10 +41,6 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
_scene->addItem(_mapScale);
_map = map;
#ifdef ENABLE_HIDPI
_ratio = devicePixelRatioF();
_map->setDevicePixelRatio(_ratio);
#endif // ENABLE_HIDPI
_map->load();
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
@ -75,6 +71,10 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
_poiSize = 8;
_poiColor = Qt::black;
#ifdef ENABLE_HIDPI
_ratio = 1.0;
#endif // ENABLE_HIDPI
_opengl = false;
_plot = false;
_digitalZoom = 0;
@ -268,10 +268,10 @@ void MapView::setMap(Map *map)
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
_map = map;
_map->load();
#ifdef ENABLE_HIDPI
_map->setDevicePixelRatio(_ratio);
#endif // ENABLE_HIDPI
_map->load();
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
digitalZoom(0);
@ -765,9 +765,17 @@ void MapView::drawBackground(QPainter *painter, const QRectF &rect)
if (_showMap) {
QRectF ir = rect.intersected(_map->bounds());
Map::Flags flags = Map::NoFlags;
if (_opacity < 1.0)
painter->setOpacity(_opacity);
_map->draw(painter, ir, _plot);
if (_plot)
flags = Map::Block;
else if (_opengl)
flags = Map::OpenGL;
_map->draw(painter, ir, flags);
}
}
@ -808,6 +816,8 @@ void MapView::scrollContentsBy(int dx, int dy)
void MapView::useOpenGL(bool use)
{
_opengl = use;
if (use)
setViewport(new OPENGL_WIDGET);
else
@ -834,23 +844,19 @@ void MapView::reloadMap()
_scene->invalidate();
}
void MapView::updateDevicePixelRatio()
void MapView::setDevicePixelRatio(qreal ratio)
{
#ifdef ENABLE_HIDPI
if (_ratio == devicePixelRatioF())
if (_ratio == ratio)
return;
_ratio = devicePixelRatioF();
_ratio = ratio;
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
_map->setDevicePixelRatio(_ratio);
digitalZoom(0);
_map->zoomFit(viewport()->rect().size(), cr);
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
@ -870,5 +876,7 @@ void MapView::updateDevicePixelRatio()
centerOn(nc);
reloadMap();
#else // ENABLE_HIDPI
Q_UNUSED(ratio);
#endif // ENABLE_HIDPI
}

View File

@ -69,7 +69,7 @@ public slots:
void showRouteWaypoints(bool show);
void clearMapCache();
void setCoordinatesFormat(CoordinatesFormat format);
void updateDevicePixelRatio();
void setDevicePixelRatio(qreal ratio);
private slots:
void updatePOI();
@ -142,6 +142,7 @@ private:
#ifdef ENABLE_HIDPI
qreal _ratio;
#endif // ENABLE_HIDPI
bool _opengl;
};
#endif // MAPVIEW_H

View File

@ -34,26 +34,61 @@ static QFrame *line()
}
#endif
QWidget *OptionsDialog::createGeneralPage()
QWidget *OptionsDialog::createMapPage()
{
_alwaysShowMap = new QCheckBox(tr("Always show the map"));
_alwaysShowMap->setChecked(_options->alwaysShowMap);
_alwaysShowMap->setToolTip("<p>" +
tr("Show the map even when no files are loaded.") + "</p>");
#ifdef ENABLE_HIDPI
_hidpi = new QRadioButton(tr("High-resolution"));
_lodpi = new QRadioButton(tr("Standard"));
if (_options->hidpiMap)
_hidpi->setChecked(true);
else
_lodpi->setChecked(true);
QLabel *lhi = new QLabel(tr("Non-HiDPI maps are loaded as HiDPI maps. "
"The map is sharp but map objects are small/hard to read."));
QLabel *llo = new QLabel(tr("Non-HiDPI maps are loaded such as they are. "
"Map objects have the expected size but the map is blurry."));
QFont f = lhi->font();
f.setPointSize(f.pointSize() - 1);
lhi->setWordWrap(true);
llo->setWordWrap(true);
lhi->setFont(f);
llo->setFont(f);
#endif // ENABLE_HIDPI
QFormLayout *showMapLayout = new QFormLayout();
showMapLayout->addWidget(_alwaysShowMap);
QWidget *generalTab = new QWidget();
QVBoxLayout *generalTabLayout = new QVBoxLayout();
generalTabLayout->addLayout(showMapLayout);
generalTabLayout->addStretch();
generalTab->setLayout(generalTabLayout);
QWidget *mapTab = new QWidget();
QVBoxLayout *mapTabLayout = new QVBoxLayout();
mapTabLayout->addLayout(showMapLayout);
mapTabLayout->addStretch();
mapTab->setLayout(mapTabLayout);
QTabWidget *generalPage = new QTabWidget();
generalPage->addTab(generalTab, tr("General"));
#ifdef ENABLE_HIDPI
QVBoxLayout *hidpiTabLayout = new QVBoxLayout();
hidpiTabLayout->addWidget(_lodpi);
hidpiTabLayout->addWidget(llo);
hidpiTabLayout->addSpacing(10);
hidpiTabLayout->addWidget(_hidpi);
hidpiTabLayout->addWidget(lhi);
hidpiTabLayout->addStretch();
return generalPage;
QWidget *hidpiTab = new QWidget();
hidpiTab->setLayout(hidpiTabLayout);
#endif // ENABLE_HIDPI
QTabWidget *mapPage = new QTabWidget();
mapPage->addTab(mapTab, tr("General"));
#ifdef ENABLE_HIDPI
mapPage->addTab(hidpiTab, tr("HiDPI display mode"));
#endif // ENABLE_HIDPI
return mapPage;
}
QWidget *OptionsDialog::createAppearancePage()
@ -483,8 +518,8 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
: QDialog(parent), _options(options)
{
QStackedWidget *pages = new QStackedWidget();
pages->addWidget(createGeneralPage());
pages->addWidget(createAppearancePage());
pages->addWidget(createMapPage());
pages->addWidget(createDataPage());
pages->addWidget(createPOIPage());
pages->addWidget(createExportPage());
@ -492,9 +527,9 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
QListWidget *menu = new QListWidget();
menu->setIconSize(QSize(MENU_ICON_SIZE, MENU_ICON_SIZE));
new QListWidgetItem(QIcon(APP_ICON), tr("General"), menu);
new QListWidgetItem(QIcon(APPEARANCE_ICON), tr("Appearance"),
menu);
new QListWidgetItem(QIcon(MAPS_ICON), tr("Maps"), menu);
new QListWidgetItem(QIcon(DATA_ICON), tr("Data"), menu);
new QListWidgetItem(QIcon(POI_ICON), tr("POI"), menu);
new QListWidgetItem(QIcon(PRINT_EXPORT_ICON), tr("Print & Export"),
@ -532,8 +567,6 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
void OptionsDialog::accept()
{
_options->alwaysShowMap = _alwaysShowMap->isChecked();
_options->palette.setColor(_baseColor->color());
_options->palette.setShift(_colorOffset->value());
_options->mapOpacity = _mapOpacity->value();
@ -553,6 +586,11 @@ void OptionsDialog::accept()
_options->sliderColor = _sliderColor->color();
_options->graphAntiAliasing = _graphAA->isChecked();
_options->alwaysShowMap = _alwaysShowMap->isChecked();
#ifdef ENABLE_HIDPI
_options->hidpiMap = _hidpi->isChecked();
#endif // ENABLE_HIDPI
_options->elevationFilter = _elevationFilter->value();
_options->speedFilter = _speedFilter->value();
_options->heartRateFilter = _heartRateFilter->value();

View File

@ -18,8 +18,6 @@ class QRadioButton;
class PercentSlider;
struct Options {
// General
bool alwaysShowMap;
// Appearance
Palette palette;
int trackWidth;
@ -36,6 +34,11 @@ struct Options {
bool graphAntiAliasing;
int mapOpacity;
QColor backgroundColor;
// Map
bool alwaysShowMap;
#ifdef ENABLE_HIDPI
bool hidpiMap;
#endif // ENABLE_HIDPI
// Data
int elevationFilter;
int speedFilter;
@ -79,7 +82,7 @@ public slots:
void accept();
private:
QWidget *createGeneralPage();
QWidget *createMapPage();
QWidget *createAppearancePage();
QWidget *createDataPage();
QWidget *createPOIPage();
@ -88,8 +91,6 @@ private:
Options *_options;
// General
QCheckBox *_alwaysShowMap;
// Appearance
ColorBox *_baseColor;
QDoubleSpinBox *_colorOffset;
@ -107,6 +108,12 @@ private:
QSpinBox *_graphWidth;
ColorBox *_sliderColor;
QCheckBox *_graphAA;
// Map
QCheckBox *_alwaysShowMap;
#ifdef ENABLE_HIDPI
QRadioButton *_hidpi;
QRadioButton *_lodpi;
#endif // ENABLE_HIDPI
// Data
OddSpinBox *_elevationFilter;
OddSpinBox *_speedFilter;

View File

@ -2,12 +2,20 @@
#include <QApplication>
#include <QCursor>
#include <QPainter>
#include "common/greatcircle.h"
#include "map/map.h"
#include "tooltip.h"
#include "nicenum.h"
#include "pathitem.h"
#define GEOGRAPHICAL_MILE 1855.3248
static unsigned segments(qreal distance)
{
return ceil(distance / GEOGRAPHICAL_MILE);
}
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
: QGraphicsObject(parent)
{
@ -21,7 +29,7 @@ PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
QBrush brush(Qt::SolidPattern);
_pen = QPen(brush, _width);
updatePainterPath(map);
updatePainterPath();
updateShape();
_marker = new MarkerItem(this);
@ -39,13 +47,36 @@ void PathItem::updateShape()
_shape = s.createStroke(_painterPath);
}
void PathItem::updatePainterPath(Map *map)
void PathItem::addSegment(const Coordinates &c1, const Coordinates &c2)
{
if (fabs(c1.lon() - c2.lon()) > 180.0)
_painterPath.moveTo(_map->ll2xy(c2));
else
_painterPath.lineTo(_map->ll2xy(c2));
}
void PathItem::updatePainterPath()
{
_painterPath = QPainterPath();
_painterPath.moveTo(map->ll2xy(_path.first().coordinates()));
for (int i = 1; i < _path.size(); i++)
_painterPath.lineTo(map->ll2xy(_path.at(i).coordinates()));
_painterPath.moveTo(_map->ll2xy(_path.first().coordinates()));
for (int i = 1; i < _path.size(); i++) {
const PathPoint &p1 = _path.at(i-1);
const PathPoint &p2 = _path.at(i);
unsigned n = segments(p2.distance() - p1.distance());
if (n > 1) {
GreatCircle gc(p1.coordinates(), p2.coordinates());
Coordinates last = p1.coordinates();
for (unsigned j = 1; j <= n; j++) {
Coordinates c(gc.pointAt(j/(double)n));
addSegment(last, c);
last = c;
}
} else
addSegment(p1.coordinates(), p2.coordinates());
}
}
void PathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
@ -70,7 +101,7 @@ void PathItem::setMap(Map *map)
_map = map;
updatePainterPath(map);
updatePainterPath();
updateShape();
_marker->setPos(position(_markerDistance));
@ -141,19 +172,40 @@ QPointF PathItem::position(qreal x) const
return _map->ll2xy(_path.at(mid).coordinates());
}
QLineF l;
Coordinates c1, c2;
qreal p1, p2;
if (_path.at(mid).distance() < x) {
l = QLineF(_map->ll2xy(_path.at(mid).coordinates()),
_map->ll2xy(_path.at(mid+1).coordinates()));
c1 = _path.at(mid).coordinates(); c2 = _path.at(mid+1).coordinates();
p1 = _path.at(mid).distance(); p2 = _path.at(mid+1).distance();
} else {
l = QLineF(_map->ll2xy(_path.at(mid-1).coordinates()),
_map->ll2xy(_path.at(mid).coordinates()));
c1 = _path.at(mid-1).coordinates(); c2 = _path.at(mid).coordinates();
p1 = _path.at(mid-1).distance(); p2 = _path.at(mid).distance();
}
return l.pointAt((x - p1) / (p2 - p1));
unsigned n = segments(p2 - p1);
if (n > 1) {
GreatCircle gc(c1, c2);
// Great circle point
double f = (x - p1) / (p2 - p1);
QPointF p(_map->ll2xy(gc.pointAt(f)));
// Segment line of the great circle path
double f1 = floor(n * f) / n;
double f2 = ceil(n * f) / n;
QLineF l(_map->ll2xy(gc.pointAt(f1)), _map->ll2xy(gc.pointAt(f2)));
// Project the great circle point to the segment line
QLineF u = l.unitVector();
double lambda = (u.dx() * (p.x() - l.p1().x())) + (u.dy() * (p.y()
- l.p1().y()));
return QPointF((u.dx() * lambda) + l.p1().x(), (u.dy() * lambda)
+ l.p1().y());
} else {
QLineF l(_map->ll2xy(c1), _map->ll2xy(c2));
return l.pointAt((x - p1) / (p2 - p1));
}
}
void PathItem::moveMarker(qreal distance)

View File

@ -43,8 +43,10 @@ protected:
private:
QPointF position(qreal distance) const;
void updatePainterPath(Map *map);
void updatePainterPath();
void updateShape();
void addSegment(const Coordinates &c1, const Coordinates &c2);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);

View File

@ -1,13 +1,14 @@
#include <QSlider>
#include <QLabel>
#include <QHBoxLayout>
#include <QLocale>
#include "units.h"
#include "percentslider.h"
static QString format(int value)
{
return QString::number(value) + UNIT_SPACE + QString("%");
return QLocale::system().toString(value) + UNIT_SPACE + QString("%");
}
PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "powergraphitem.h"
#include "powergraph.h"
@ -16,9 +17,11 @@ PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
void PowerGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
QLocale l(QLocale::system());
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
} else
clearInfo();

View File

@ -1,6 +1,8 @@
#include <QLocale>
#include "tooltip.h"
#include "powergraphitem.h"
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -16,11 +18,12 @@ PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
QString PowerGraphItem::toolTip() const
{
ToolTip tt;
QLocale l(QLocale::system());
tt.insert(tr("Maximum"), QString::number(max(), 'f', 1)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Average"), QString::number(avg(), 'f', 1)
+ UNIT_SPACE + tr("1/min"));
tt.insert(tr("Maximum"), l.toString(max(), 'f', 1)
+ UNIT_SPACE + tr("W"));
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
+ UNIT_SPACE + tr("W"));
return tt.toString();
}

View File

@ -6,7 +6,7 @@
#define BORDER_WIDTH 1
#define SCALE_WIDTH 132
#define SCALE_WIDTH 135
#define SCALE_HEIGHT 5
#define SEGMENTS 3
#define PADDING 4

View File

@ -156,5 +156,7 @@
#define SLIDER_COLOR_DEFAULT QColor(Qt::red)
#define ALWAYS_SHOW_MAP_SETTING "alwaysShowMap"
#define ALWAYS_SHOW_MAP_DEFAULT true
#define HIDPI_MAP_SETTING "HiDPIMap"
#define HIDPI_MAP_DEFAULT true
#endif // SETTINGS_H

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "config.h"
#include "tooltip.h"
@ -21,13 +22,14 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
void SpeedGraph::setInfo()
{
if (_showTracks) {
QLocale l(QLocale::system());
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',
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Pace"), pace + UNIT_SPACE + pu);
} else

View File

@ -1,7 +1,9 @@
#include <QLocale>
#include "tooltip.h"
#include "format.h"
#include "speedgraphitem.h"
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -25,10 +27,11 @@ QString SpeedGraphItem::toolTip() const
? avg() * scale : mavg() * scale)), false);
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
tr("min/mi") : tr("min/nmi");
QLocale l(QLocale::system());
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 1)
tt.insert(tr("Maximum"), l.toString(max() * scale, 'f', 1)
+ UNIT_SPACE + su);
tt.insert(tr("Average"), QString::number((_timeType == Total)
tt.insert(tr("Average"), l.toString((_timeType == Total)
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);

View File

@ -1,3 +1,4 @@
#include <QLocale>
#include "data/data.h"
#include "temperaturegraphitem.h"
#include "temperaturegraph.h"
@ -16,11 +17,13 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
void TemperatureGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
QLocale l(QLocale::system());
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale()
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
} else
clearInfo();

View File

@ -1,6 +1,8 @@
#include <QLocale>
#include "tooltip.h"
#include "temperaturegraphitem.h"
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
@ -20,12 +22,13 @@ QString TemperatureGraphItem::toolTip(Units units) const
qreal offset = (units == Metric) ? 0 : C2FO;
QString su = (units == Metric) ?
QChar(0x00B0) + tr("C") : QChar(0x00B0) + tr("F");
QLocale l(QLocale::system());
tt.insert(tr("Average"), QString::number(avg() * scale + offset, 'f', 1)
tt.insert(tr("Average"), l.toString(avg() * scale + offset, 'f', 1)
+ UNIT_SPACE + su);
tt.insert(tr("Maximum"), QString::number(max() * scale + offset, 'f', 1)
tt.insert(tr("Maximum"), l.toString(max() * scale + offset, 'f', 1)
+ UNIT_SPACE + su);
tt.insert(tr("Minimum"), QString::number(min() * scale + offset, 'f', 1)
tt.insert(tr("Minimum"), l.toString(min() * scale + offset, 'f', 1)
+ UNIT_SPACE + su);
return tt.toString();

View File

@ -0,0 +1,34 @@
#include "greatcircle.h"
GreatCircle::GreatCircle(const Coordinates &c1, const Coordinates &c2)
{
double lat1 = deg2rad(c1.lat());
double lon1 = deg2rad(c1.lon());
double lat2 = deg2rad(c2.lat());
double lon2 = deg2rad(c2.lon());
double cosLat1 = cos(lat1);
double cosLat2 = cos(lat2);
_sinLat1 = sin(lat1);
_sinLat2 = sin(lat2);
_xA = cosLat1 * cos(lon1);
_xB = cosLat2 * cos(lon2);
_yA = cosLat1 * sin(lon1);
_yB = cosLat2 * sin(lon2);
_d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cosLat1 * cosLat2
* pow(sin((lon1 - lon2) / 2), 2)));
_sinD = sin(_d);
}
Coordinates GreatCircle::pointAt(double f) const
{
double A = sin((1.0 - f) * _d) / _sinD;
double B = sin(f * _d) / _sinD;
double x = A * _xA + B * _xB;
double y = A * _yA + B * _yB;
double z = A * _sinLat1 + B * _sinLat2;
return Coordinates(rad2deg(atan2(y, x)), rad2deg(atan2(z, sqrt(x*x + y*y))));
}

20
src/common/greatcircle.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef GREATCIRCLE_H
#define GREATCIRCLE_H
#include "coordinates.h"
class GreatCircle
{
public:
GreatCircle(const Coordinates &c1, const Coordinates &c2);
Coordinates pointAt(double f) const;
private:
double _xA, _xB, _yA, _yB;
double _d;
double _sinD;
double _sinLat1, _sinLat2;
};
#endif // GREATCIRCLE_H

View File

@ -18,16 +18,16 @@ bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
return false;
}
qreal lat = list[0].trimmed().toDouble(&res);
if (!res || (lat < -90.0 || lat > 90.0)) {
_errorString = "Invalid latitude";
return false;
}
qreal lon = list[1].trimmed().toDouble(&res);
qreal lon = list[0].trimmed().toDouble(&res);
if (!res || (lon < -180.0 || lon > 180.0)) {
_errorString = "Invalid longitude";
return false;
}
qreal lat = list[1].trimmed().toDouble(&res);
if (!res || (lat < -90.0 || lat > 90.0)) {
_errorString = "Invalid latitude";
return false;
}
Waypoint wp(Coordinates(lon, lat));
QByteArray ba = list[2].trimmed();

View File

@ -98,7 +98,7 @@ template<class T> bool FITParser::readValue(CTX &ctx, T &val)
return true;
}
bool FITParser::skipValue(CTX &ctx, size_t size)
bool FITParser::skipValue(CTX &ctx, quint8 size)
{
ctx.len -= size;
return ctx.file->seek(ctx.file->pos() + size);

View File

@ -20,7 +20,7 @@ private:
bool readData(QFile *file, char *data, size_t size);
template<class T> bool readValue(CTX &ctx, T &val);
bool skipValue(CTX &ctx, size_t size);
bool skipValue(CTX &ctx, quint8 size);
bool readField(CTX &ctx, Field *field, quint32 &val);
bool parseHeader(CTX &ctx);

View File

@ -54,7 +54,7 @@ Coordinates GPXParser::coordinates()
void GPXParser::rpExtension(TrackData *autoRoute)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "rpt")
if (_reader.name() == QLatin1String("rpt"))
autoRoute->append(Trackpoint(coordinates()));
_reader.skipCurrentElement();
}
@ -63,9 +63,9 @@ void GPXParser::rpExtension(TrackData *autoRoute)
void GPXParser::tpExtension(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "hr")
if (_reader.name() == QLatin1String("hr"))
trackpoint.setHeartRate(number());
else if (_reader.name() == "atemp")
else if (_reader.name() == QLatin1String("atemp"))
trackpoint.setTemperature(number());
else
_reader.skipCurrentElement();
@ -75,7 +75,7 @@ void GPXParser::tpExtension(Trackpoint &trackpoint)
void GPXParser::rteptExtensions(TrackData *autoRoute)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "RoutePointExtension")
if (_reader.name() == QLatin1String("RoutePointExtension"))
rpExtension(autoRoute);
else
_reader.skipCurrentElement();
@ -85,17 +85,18 @@ void GPXParser::rteptExtensions(TrackData *autoRoute)
void GPXParser::trkptExtensions(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "speed")
if (_reader.name() == QLatin1String("speed"))
trackpoint.setSpeed(number());
else if (_reader.name() == "hr" || _reader.name() == "heartrate")
else if (_reader.name() == QLatin1String("hr")
|| _reader.name() == QLatin1String("heartrate"))
trackpoint.setHeartRate(number());
else if (_reader.name() == "temp")
else if (_reader.name() == QLatin1String("temp"))
trackpoint.setTemperature(number());
else if (_reader.name() == "cadence")
else if (_reader.name() == QLatin1String("cadence"))
trackpoint.setCadence(number());
else if (_reader.name() == "power")
else if (_reader.name() == QLatin1String("power"))
trackpoint.setPower(number());
else if (_reader.name() == "TrackPointExtension")
else if (_reader.name() == QLatin1String("TrackPointExtension"))
tpExtension(trackpoint);
else
_reader.skipCurrentElement();
@ -107,13 +108,13 @@ void GPXParser::trackpointData(Trackpoint &trackpoint)
qreal gh = NAN;
while (_reader.readNextStartElement()) {
if (_reader.name() == "ele")
if (_reader.name() == QLatin1String("ele"))
trackpoint.setElevation(number());
else if (_reader.name() == "time")
else if (_reader.name() == QLatin1String("time"))
trackpoint.setTimestamp(time());
else if (_reader.name() == "geoidheight")
else if (_reader.name() == QLatin1String("geoidheight"))
gh = number();
else if (_reader.name() == "extensions")
else if (_reader.name() == QLatin1String("extensions"))
trkptExtensions(trackpoint);
else
_reader.skipCurrentElement();
@ -128,17 +129,17 @@ void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
qreal gh = NAN;
while (_reader.readNextStartElement()) {
if (_reader.name() == "name")
if (_reader.name() == QLatin1String("name"))
waypoint.setName(_reader.readElementText());
else if (_reader.name() == "desc")
else if (_reader.name() == QLatin1String("desc"))
waypoint.setDescription(_reader.readElementText());
else if (_reader.name() == "ele")
else if (_reader.name() == QLatin1String("ele"))
waypoint.setElevation(number());
else if (_reader.name() == "geoidheight")
else if (_reader.name() == QLatin1String("geoidheight"))
gh = number();
else if (_reader.name() == "time")
else if (_reader.name() == QLatin1String("time"))
waypoint.setTimestamp(time());
else if (autoRoute && _reader.name() == "extensions")
else if (autoRoute && _reader.name() == QLatin1String("extensions"))
rteptExtensions(autoRoute);
else
_reader.skipCurrentElement();
@ -151,7 +152,7 @@ void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
void GPXParser::trackpoints(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "trkpt") {
if (_reader.name() == QLatin1String("trkpt")) {
track.append(Trackpoint(coordinates()));
trackpointData(track.last());
} else
@ -164,12 +165,12 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
TrackData autoRoute;
while (_reader.readNextStartElement()) {
if (_reader.name() == "rtept") {
if (_reader.name() == QLatin1String("rtept")) {
route.append(Waypoint(coordinates()));
waypointData(route.last(), &autoRoute);
} else if (_reader.name() == "name")
} else if (_reader.name() == QLatin1String("name"))
route.setName(_reader.readElementText());
else if (_reader.name() == "desc")
else if (_reader.name() == QLatin1String("desc"))
route.setDescription(_reader.readElementText());
else
_reader.skipCurrentElement();
@ -185,11 +186,11 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
void GPXParser::track(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "trkseg")
if (_reader.name() == QLatin1String("trkseg"))
trackpoints(track);
else if (_reader.name() == "name")
else if (_reader.name() == QLatin1String("name"))
track.setName(_reader.readElementText());
else if (_reader.name() == "desc")
else if (_reader.name() == QLatin1String("desc"))
track.setDescription(_reader.readElementText());
else
_reader.skipCurrentElement();
@ -200,13 +201,13 @@ void GPXParser::gpx(QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "trk") {
if (_reader.name() == QLatin1String("trk")) {
tracks.append(TrackData());
track(tracks.back());
} else if (_reader.name() == "rte") {
} else if (_reader.name() == QLatin1String("rte")) {
routes.append(RouteData());
routepoints(routes.back(), tracks);
} else if (_reader.name() == "wpt") {
} else if (_reader.name() == QLatin1String("wpt")) {
waypoints.append(Waypoint(coordinates()));
waypointData(waypoints.last());
} else
@ -222,7 +223,7 @@ bool GPXParser::parse(QFile *file, QList<TrackData> &tracks,
_reader.setNamespaceProcessing(false);
if (_reader.readNextStartElement()) {
if (_reader.name() == "gpx")
if (_reader.name() == QLatin1String("gpx"))
gpx(tracks, routes, waypoints);
else
_reader.raiseError("Not a GPX file");

View File

@ -98,12 +98,14 @@ static bool readARecord(const char *line, qint64 len)
bool IGCParser::readHRecord(const char *line, int len)
{
if (len < 10 || ::strncmp(line, "HFDTE", 5))
if (len < 11 || ::strncmp(line, "HFDTE", 5))
return true;
int d = str2int(line + 5, 2);
int m = str2int(line + 7, 2);
int y = str2int(line + 9, 2);
int offset = (len < 16 || ::strncmp(line + 5, "DATE:", 5)) ? 5 : 10;
int d = str2int(line + offset, 2);
int m = str2int(line + offset + 2, 2);
int y = str2int(line + offset + 4, 2);
if (y < 0 || m < 0 || d < 0) {
_errorString = "Invalid date header format";

View File

@ -191,7 +191,7 @@ QDateTime KMLParser::timeStamp()
QDateTime ts;
while (_reader.readNextStartElement()) {
if (_reader.name() == "when")
if (_reader.name() == QLatin1String("when"))
ts = time();
else
_reader.skipCurrentElement();
@ -203,7 +203,7 @@ QDateTime KMLParser::timeStamp()
void KMLParser::lineString(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "coordinates") {
if (_reader.name() == QLatin1String("coordinates")) {
if (!lineCoordinates(track))
_reader.raiseError("Invalid coordinates");
} else
@ -214,7 +214,7 @@ void KMLParser::lineString(TrackData &track)
void KMLParser::point(Waypoint &waypoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "coordinates") {
if (_reader.name() == QLatin1String("coordinates")) {
if (!pointCoordinates(waypoint))
_reader.raiseError("Invalid coordinates");
} else
@ -231,7 +231,7 @@ void KMLParser::heartRate(TrackData &track, int start)
const char error[] = "Heartrate data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == "value") {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setHeartRate(number());
else {
@ -252,7 +252,7 @@ void KMLParser::cadence(TrackData &track, int start)
const char error[] = "Cadence data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == "value") {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setCadence(number());
else {
@ -273,7 +273,7 @@ void KMLParser::speed(TrackData &track, int start)
const char error[] = "Speed data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == "value") {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setSpeed(number());
else {
@ -294,7 +294,7 @@ void KMLParser::temperature(TrackData &track, int start)
const char error[] = "Temperature data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == "value") {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setTemperature(number());
else {
@ -312,17 +312,17 @@ void KMLParser::temperature(TrackData &track, int start)
void KMLParser::schemaData(TrackData &track, int start)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "SimpleArrayData") {
if (_reader.name() == QLatin1String("SimpleArrayData")) {
QXmlStreamAttributes attr = _reader.attributes();
QStringRef name = attr.value("name");
if (name == "Heartrate")
if (name == QLatin1String("Heartrate"))
heartRate(track, start);
else if (name == "Cadence")
else if (name == QLatin1String("Cadence"))
cadence(track, start);
else if (name == "Speed")
else if (name == QLatin1String("Speed"))
speed(track, start);
else if (name == "Temperature")
else if (name == QLatin1String("Temperature"))
temperature(track, start);
else
_reader.skipCurrentElement();
@ -334,7 +334,7 @@ void KMLParser::schemaData(TrackData &track, int start)
void KMLParser::extendedData(TrackData &track, int start)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "SchemaData")
if (_reader.name() == QLatin1String("SchemaData"))
schemaData(track, start);
else
_reader.skipCurrentElement();
@ -348,10 +348,10 @@ void KMLParser::track(TrackData &track)
int i = first;
while (_reader.readNextStartElement()) {
if (_reader.name() == "when") {
if (_reader.name() == QLatin1String("when")) {
track.append(Trackpoint());
track.last().setTimestamp(time());
} else if (_reader.name() == "coord") {
} else if (_reader.name() == QLatin1String("coord")) {
if (i == track.size()) {
_reader.raiseError(error);
return;
@ -360,7 +360,7 @@ void KMLParser::track(TrackData &track)
return;
}
i++;
} else if (_reader.name() == "ExtendedData")
} else if (_reader.name() == QLatin1String("ExtendedData"))
extendedData(track, first);
else
_reader.skipCurrentElement();
@ -373,7 +373,7 @@ void KMLParser::track(TrackData &track)
void KMLParser::multiTrack(TrackData &t)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Track")
if (_reader.name() == QLatin1String("Track"))
track(t);
else
_reader.skipCurrentElement();
@ -385,14 +385,14 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks,
const QDateTime timestamp)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Point") {
if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
w.setName(name);
w.setDescription(desc);
w.setTimestamp(timestamp);
point(w);
} else if (_reader.name() == "LineString") {
} else if (_reader.name() == QLatin1String("LineString")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
@ -409,35 +409,35 @@ void KMLParser::placemark(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
QDateTime timestamp;
while (_reader.readNextStartElement()) {
if (_reader.name() == "name")
if (_reader.name() == QLatin1String("name"))
name = _reader.readElementText();
else if (_reader.name() == "description")
else if (_reader.name() == QLatin1String("description"))
desc = _reader.readElementText();
else if (_reader.name() == "TimeStamp")
else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp();
else if (_reader.name() == "MultiGeometry")
else if (_reader.name() == QLatin1String("MultiGeometry"))
multiGeometry(tracks, waypoints, name, desc, timestamp);
else if (_reader.name() == "Point") {
else if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
w.setName(name);
w.setDescription(desc);
w.setTimestamp(timestamp);
point(w);
} else if (_reader.name() == "LineString"
|| _reader.name() == "LinearRing") {
} else if (_reader.name() == QLatin1String("LineString")
|| _reader.name() == QLatin1String("LinearRing")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
t.setDescription(desc);
lineString(t);
} else if (_reader.name() == "Track") {
} else if (_reader.name() == QLatin1String("Track")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
t.setDescription(desc);
track(t);
} else if (_reader.name() == "MultiTrack") {
} else if (_reader.name() == QLatin1String("MultiTrack")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
@ -451,9 +451,9 @@ void KMLParser::placemark(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
void KMLParser::folder(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Placemark")
if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
else if (_reader.name() == "Folder")
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
else
_reader.skipCurrentElement();
@ -463,9 +463,9 @@ void KMLParser::folder(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
void KMLParser::document(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Placemark")
if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
else if (_reader.name() == "Folder")
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
else
_reader.skipCurrentElement();
@ -475,11 +475,11 @@ void KMLParser::document(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
void KMLParser::kml(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Document")
if (_reader.name() == QLatin1String("Document"))
document(tracks, waypoints);
else if (_reader.name() == "Placemark")
else if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
else if (_reader.name() == "Folder")
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
else
_reader.skipCurrentElement();
@ -495,7 +495,7 @@ bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
if (_reader.name() == "kml")
if (_reader.name() == QLatin1String("kml"))
kml(tracks, waypoints);
else
_reader.raiseError("Not a KML file");

View File

@ -31,11 +31,11 @@ Coordinates LOCParser::coordinates()
void LOCParser::waypoint(Waypoint &waypoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "name") {
if (_reader.name() == QLatin1String("name")) {
const QXmlStreamAttributes &attr = _reader.attributes();
waypoint.setName(attr.value("id").toString());
waypoint.setDescription(_reader.readElementText());
} else if (_reader.name() == "coord") {
} else if (_reader.name() == QLatin1String("coord")) {
waypoint.setCoordinates(coordinates());
_reader.skipCurrentElement();
} else
@ -49,7 +49,7 @@ void LOCParser::waypoint(Waypoint &waypoint)
void LOCParser::loc(QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "waypoint") {
if (_reader.name() == QLatin1String("waypoint")) {
waypoints.append(Waypoint());
waypoint(waypoints.last());
} else
@ -67,7 +67,7 @@ bool LOCParser::parse(QFile *file, QList<TrackData> &tracks,
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
if (_reader.name() == "loc")
if (_reader.name() == QLatin1String("loc"))
loc(waypoints);
else
_reader.raiseError("Not a LOC file");

View File

@ -1,6 +1,7 @@
#include <QFile>
#include <QDir>
#include "common/rectc.h"
#include "common/greatcircle.h"
#include "data.h"
#include "poi.h"
@ -94,23 +95,45 @@ static bool cb(size_t data, void* context)
return true;
}
void POI::search(const RectC &rect, QSet<int> &set) const
{
qreal min[2], max[2];
min[0] = rect.topLeft().lon();
min[1] = rect.bottomRight().lat();
max[0] = rect.bottomRight().lon();
max[1] = rect.topLeft().lat();
_tree.Search(min, max, cb, &set);
}
QList<Waypoint> POI::points(const Path &path) const
{
QList<Waypoint> ret;
QSet<int> set;
qreal min[2], max[2];
QSet<int>::const_iterator it;
for (int i = 0; i < path.count(); i++) {
RectC br(path.at(i).coordinates(), _radius);
min[0] = br.topLeft().lon();
min[1] = br.bottomRight().lat();
max[0] = br.bottomRight().lon();
max[1] = br.topLeft().lat();
_tree.Search(min, max, cb, &set);
for (int i = 1; i < path.count(); i++) {
double ds = path.at(i).distance() - path.at(i-1).distance();
unsigned n = (unsigned)ceil(ds / _radius);
if (n > 1) {
GreatCircle gc(path.at(i-1).coordinates(), path.at(i).coordinates());
for (unsigned j = 0; j < n; j++) {
RectC br(gc.pointAt((double)j/n), _radius);
search(br, set);
}
} else {
RectC br(path.at(i-1).coordinates(), _radius);
search(br, set);
}
}
RectC br(path.last().coordinates(), _radius);
search(br, set);
for (it = set.constBegin(); it != set.constEnd(); ++it)
ret.append(_data.at(*it));

View File

@ -45,6 +45,7 @@ private:
};
bool loadFile(const QString &path, bool dir);
void search(const RectC &rect, QSet<int> &set) const;
POITree _tree;
QVector<Waypoint> _data;

View File

@ -29,7 +29,7 @@ bool SLFParser::data(const QXmlStreamAttributes &attr, const char *name,
void SLFParser::entries(const QDateTime &date, TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Entry") {
if (_reader.name() == QLatin1String("Entry")) {
qreal val, lat, lon;
QXmlStreamAttributes attr(_reader.attributes());
@ -70,11 +70,11 @@ void SLFParser::entries(const QDateTime &date, TrackData &track)
void SLFParser::generalInformation(QDateTime &date, TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "name")
if (_reader.name() == QLatin1String("name"))
track.setName(_reader.readElementText());
else if (_reader.name() == "description")
else if (_reader.name() == QLatin1String("description"))
track.setDescription(_reader.readElementText());
else if (_reader.name() == "startDate") {
else if (_reader.name() == QLatin1String("startDate")) {
QString ds(_reader.readElementText());
QLocale locale(QLocale::English);
date = locale.toDateTime(ds.mid(0, ds.indexOf("GMT"))
@ -89,9 +89,9 @@ void SLFParser::activity(TrackData &track)
QDateTime date;
while (_reader.readNextStartElement()) {
if (_reader.name() == "Entries")
if (_reader.name() == QLatin1String("Entries"))
entries(date, track);
else if (_reader.name() == "GeneralInformation")
else if (_reader.name() == QLatin1String("GeneralInformation"))
generalInformation(date, track);
else
_reader.skipCurrentElement();
@ -108,7 +108,7 @@ bool SLFParser::parse(QFile *file, QList<TrackData> &tracks,
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
if (_reader.name() == "Activity") {
if (_reader.name() == QLatin1String("Activity")) {
tracks.append(TrackData());
activity(tracks.last());
} else

View File

@ -37,13 +37,13 @@ Coordinates TCXParser::position()
bool res;
while (_reader.readNextStartElement()) {
if (_reader.name() == "LatitudeDegrees") {
if (_reader.name() == QLatin1String("LatitudeDegrees")) {
val = _reader.readElementText().toDouble(&res);
if (!res || (val < -90.0 || val > 90.0))
_reader.raiseError("Invalid LatitudeDegrees");
else
pos.setLat(val);
} else if (_reader.name() == "LongitudeDegrees") {
} else if (_reader.name() == QLatin1String("LongitudeDegrees")) {
val = _reader.readElementText().toDouble(&res);
if (!res || (val < -180.0 || val > 180.0))
_reader.raiseError("Invalid LongitudeDegrees");
@ -59,7 +59,7 @@ Coordinates TCXParser::position()
void TCXParser::heartRateBpm(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Value")
if (_reader.name() == QLatin1String("Value"))
trackpoint.setHeartRate(number());
else
_reader.skipCurrentElement();
@ -69,9 +69,9 @@ void TCXParser::heartRateBpm(Trackpoint &trackpoint)
void TCXParser::extensions(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "RunCadence")
if (_reader.name() == QLatin1String("RunCadence"))
trackpoint.setCadence(number());
else if (_reader.name() == "Watts")
else if (_reader.name() == QLatin1String("Watts"))
trackpoint.setPower(number());
else
_reader.skipCurrentElement();
@ -81,17 +81,17 @@ void TCXParser::extensions(Trackpoint &trackpoint)
void TCXParser::trackpointData(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Position")
if (_reader.name() == QLatin1String("Position"))
trackpoint.setCoordinates(position());
else if (_reader.name() == "AltitudeMeters")
else if (_reader.name() == QLatin1String("AltitudeMeters"))
trackpoint.setElevation(number());
else if (_reader.name() == "Time")
else if (_reader.name() == QLatin1String("Time"))
trackpoint.setTimestamp(time());
else if (_reader.name() == "HeartRateBpm")
else if (_reader.name() == QLatin1String("HeartRateBpm"))
heartRateBpm(trackpoint);
else if (_reader.name() == "Cadence")
else if (_reader.name() == QLatin1String("Cadence"))
trackpoint.setCadence(number());
else if (_reader.name() == "Extensions")
else if (_reader.name() == QLatin1String("Extensions"))
extensions(trackpoint);
else
_reader.skipCurrentElement();
@ -101,15 +101,15 @@ void TCXParser::trackpointData(Trackpoint &trackpoint)
void TCXParser::waypointData(Waypoint &waypoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Position")
if (_reader.name() == QLatin1String("Position"))
waypoint.setCoordinates(position());
else if (_reader.name() == "Name")
else if (_reader.name() == QLatin1String("Name"))
waypoint.setName(_reader.readElementText());
else if (_reader.name() == "Notes")
else if (_reader.name() == QLatin1String("Notes"))
waypoint.setDescription(_reader.readElementText());
else if (_reader.name() == "AltitudeMeters")
else if (_reader.name() == QLatin1String("AltitudeMeters"))
waypoint.setElevation(number());
else if (_reader.name() == "Time")
else if (_reader.name() == QLatin1String("Time"))
waypoint.setTimestamp(time());
else
_reader.skipCurrentElement();
@ -119,7 +119,7 @@ void TCXParser::waypointData(Waypoint &waypoint)
void TCXParser::trackpoints(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Trackpoint") {
if (_reader.name() == QLatin1String("Trackpoint")) {
Trackpoint t;
trackpointData(t);
if (t.coordinates().isValid())
@ -134,7 +134,7 @@ void TCXParser::trackpoints(TrackData &track)
void TCXParser::lap(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Track")
if (_reader.name() == QLatin1String("Track"))
trackpoints(track);
else
_reader.skipCurrentElement();
@ -144,13 +144,13 @@ void TCXParser::lap(TrackData &track)
void TCXParser::course(QList<Waypoint> &waypoints, TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Track")
if (_reader.name() == QLatin1String("Track"))
trackpoints(track);
else if (_reader.name() == "Name")
else if (_reader.name() == QLatin1String("Name"))
track.setName(_reader.readElementText());
else if (_reader.name() == "Notes")
else if (_reader.name() == QLatin1String("Notes"))
track.setDescription(_reader.readElementText());
else if (_reader.name() == "CoursePoint") {
else if (_reader.name() == QLatin1String("CoursePoint")) {
Waypoint w;
waypointData(w);
if (w.coordinates().isValid())
@ -165,7 +165,7 @@ void TCXParser::course(QList<Waypoint> &waypoints, TrackData &track)
void TCXParser::activity(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Lap")
if (_reader.name() == QLatin1String("Lap"))
lap(track);
else
_reader.skipCurrentElement();
@ -175,7 +175,7 @@ void TCXParser::activity(TrackData &track)
void TCXParser::courses(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Course") {
if (_reader.name() == QLatin1String("Course")) {
tracks.append(TrackData());
course(waypoints, tracks.back());
} else
@ -186,7 +186,7 @@ void TCXParser::courses(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
void TCXParser::sport(QList<TrackData> &tracks)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Activity") {
if (_reader.name() == QLatin1String("Activity")) {
tracks.append(TrackData());
activity(tracks.back());
} else
@ -197,7 +197,8 @@ void TCXParser::sport(QList<TrackData> &tracks)
void TCXParser::multiSportSession(QList<TrackData> &tracks)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "FirstSport" || _reader.name() == "NextSport")
if (_reader.name() == QLatin1String("FirstSport")
|| _reader.name() == QLatin1String("NextSport"))
sport(tracks);
else
_reader.skipCurrentElement();
@ -207,10 +208,10 @@ void TCXParser::multiSportSession(QList<TrackData> &tracks)
void TCXParser::activities(QList<TrackData> &tracks)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Activity") {
if (_reader.name() == QLatin1String("Activity")) {
tracks.append(TrackData());
activity(tracks.back());
} else if (_reader.name() == "MultiSportSession")
} else if (_reader.name() == QLatin1String("MultiSportSession"))
multiSportSession(tracks);
else
_reader.skipCurrentElement();
@ -220,9 +221,9 @@ void TCXParser::activities(QList<TrackData> &tracks)
void TCXParser::tcx(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "Courses")
if (_reader.name() == QLatin1String("Courses"))
courses(tracks, waypoints);
else if (_reader.name() == "Activities")
else if (_reader.name() == QLatin1String("Activities"))
activities(tracks);
else
_reader.skipCurrentElement();
@ -238,7 +239,7 @@ bool TCXParser::parse(QFile *file, QList<TrackData> &tracks,
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
if (_reader.name() == "TrainingCenterDatabase")
if (_reader.name() == QLatin1String("TrainingCenterDatabase"))
tcx(tracks, waypoints);
else
_reader.raiseError("Not a TCX file");

View File

@ -2,7 +2,7 @@
#include <QtAlgorithms>
#include <QPainter>
#include "common/rectc.h"
#include "offlinemap.h"
#include "ozimap.h"
#include "tar.h"
#include "atlas.h"
@ -12,7 +12,7 @@
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
static bool resCmp(OfflineMap *m1, OfflineMap *m2)
static bool resCmp(OziMap *m1, OziMap *m2)
{
qreal r1, r2;
@ -22,12 +22,12 @@ static bool resCmp(OfflineMap *m1, OfflineMap *m2)
return r1 > r2;
}
static bool xCmp(OfflineMap *m1, OfflineMap *m2)
static bool xCmp(OziMap *m1, OziMap *m2)
{
return TL(m1).x() < TL(m2).x();
}
static bool yCmp(OfflineMap *m1, OfflineMap *m2)
static bool yCmp(OziMap *m1, OziMap *m2)
{
return TL(m1).y() > TL(m2).y();
}
@ -52,7 +52,7 @@ void Atlas::computeBounds()
QVector<QPointF> offsets(_maps.count());
for (int z = 0; z < _zooms.count(); z++) {
QList<OfflineMap*> m;
QList<OziMap*> m;
for (int i = _zooms.at(z).first; i <= _zooms.at(z).last; i++)
m.append(_maps.at(i));
@ -119,11 +119,11 @@ Atlas::Atlas(const QString &fileName, QObject *parent)
QString mapFile = maps.at(i).absoluteFilePath() + "/"
+ maps.at(i).fileName() + ".map";
OfflineMap *map;
OziMap *map;
if (tar.isOpen())
map = new OfflineMap(mapFile, tar, this);
map = new OziMap(mapFile, tar, this);
else
map = new OfflineMap(mapFile, this);
map = new OziMap(mapFile, this);
if (map->isValid())
_maps.append(map);
@ -255,14 +255,12 @@ Coordinates Atlas::xy2ll(const QPointF &p)
return _maps.at(idx)->xy2ll(p2);
}
void Atlas::draw(QPainter *painter, const QRectF &rect, bool block)
void Atlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
Q_UNUSED(block);
// All in one map
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
if (_bounds.at(i).xy.contains(rect)) {
draw(painter, rect, i);
draw(painter, rect, i, flags);
return;
}
}
@ -271,20 +269,21 @@ void Atlas::draw(QPainter *painter, const QRectF &rect, bool block)
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
QRectF ir = rect.intersected(_bounds.at(i).xy);
if (!ir.isNull())
draw(painter, ir, i);
draw(painter, ir, i, flags);
}
}
void Atlas::draw(QPainter *painter, const QRectF &rect, int mapIndex)
void Atlas::draw(QPainter *painter, const QRectF &rect, int mapIndex,
Flags flags)
{
OfflineMap *map = _maps.at(mapIndex);
OziMap *map = _maps.at(mapIndex);
const QPointF offset = _bounds.at(mapIndex).xy.topLeft();
QRectF pr = QRectF(rect.topLeft() - offset, rect.size());
map->load();
painter->translate(offset);
map->draw(painter, pr, true);
map->draw(painter, pr, flags);
painter->translate(-offset);
}

View File

@ -4,7 +4,7 @@
#include "map.h"
#include "rectd.h"
class OfflineMap;
class OziMap;
class Atlas : public Map
{
@ -26,7 +26,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio);
void unload();
@ -53,13 +53,13 @@ private:
Bounds(const RectD &pp, const QRectF &xy) : pp(pp), xy(xy) {}
};
void draw(QPainter *painter, const QRectF &rect, int mapIndex);
void draw(QPainter *painter, const QRectF &rect, int mapIndex, Flags flags);
void computeZooms();
void computeBounds();
QString _name;
QList<OfflineMap*> _maps;
QList<OziMap*> _maps;
QVector<Zoom> _zooms;
QVector<Bounds> _bounds;
int _zoom;

View File

@ -85,11 +85,11 @@ int EmptyMap::zoomOut()
return _zoom;
}
void EmptyMap::draw(QPainter *painter, const QRectF &rect, bool block)
void EmptyMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
Q_UNUSED(painter);
Q_UNUSED(rect);
Q_UNUSED(block);
Q_UNUSED(flags);
}
QPointF EmptyMap::ll2xy(const Coordinates &c)

View File

@ -24,7 +24,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
private:
int _zoom;

81
src/map/geotiffmap.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <QFileInfo>
#include <QPainter>
#include <QImageReader>
#include "config.h"
#include "geotiff.h"
#include "image.h"
#include "geotiffmap.h"
GeoTIFFMap::GeoTIFFMap(const QString &fileName, QObject *parent)
: Map(parent), _fileName(fileName), _img(0), _ratio(1.0), _valid(false)
{
QImageReader ir(fileName);
if (!ir.canRead()) {
_errorString = "Unsupported/invalid image file";
return;
}
_size = ir.size();
GeoTIFF gt(fileName);
if (!gt.isValid()) {
_errorString = gt.errorString();
return;
} else {
_projection = gt.projection();
_transform = gt.transform();
}
_valid = true;
}
GeoTIFFMap::~GeoTIFFMap()
{
delete _img;
}
QString GeoTIFFMap::name() const
{
QFileInfo fi(_fileName);
return fi.fileName();
}
QPointF GeoTIFFMap::ll2xy(const Coordinates &c)
{
return QPointF(_transform.proj2img(_projection.ll2xy(c))) / _ratio;
}
Coordinates GeoTIFFMap::xy2ll(const QPointF &p)
{
return _projection.xy2ll(_transform.img2proj(p * _ratio));
}
QRectF GeoTIFFMap::bounds()
{
return QRectF(QPointF(0, 0), _size / _ratio);
}
void GeoTIFFMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
if (_img)
_img->draw(painter, rect, flags);
}
void GeoTIFFMap::setDevicePixelRatio(qreal ratio)
{
_ratio = ratio;
if (_img)
_img->setDevicePixelRatio(_ratio);
}
void GeoTIFFMap::load()
{
if (!_img)
_img = new Image(_fileName);
}
void GeoTIFFMap::unload()
{
delete _img;
_img = 0;
}

45
src/map/geotiffmap.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef GEOTIFFMAP_H
#define GEOTIFFMAP_H
#include "transform.h"
#include "projection.h"
#include "map.h"
class Image;
class GeoTIFFMap : public Map
{
Q_OBJECT
public:
GeoTIFFMap(const QString &fileName, QObject *parent = 0);
~GeoTIFFMap();
QString name() const;
QRectF bounds();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void load();
void unload();
void setDevicePixelRatio(qreal ratio);
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private:
QString _fileName;
Projection _projection;
Transform _transform;
Image *_img;
QSize _size;
qreal _ratio;
bool _valid;
QString _errorString;
};
#endif // GEOTIFFMAP_H

53
src/map/image.cpp Normal file
View File

@ -0,0 +1,53 @@
#include <QPainter>
#include <QPixmapCache>
#include "config.h"
#include "image.h"
#define TILE_SIZE 256
Image::Image(const QString &fileName) : _img(fileName), _fileName(fileName)
{
}
void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
{
#ifdef ENABLE_HIDPI
qreal ratio = _img.devicePixelRatioF();
#else // ENABLE_HIDPI
qreal ratio = 1.0;
#endif // ENABLE_HIDPI
QRectF sr(rect.topLeft() * ratio, rect.size() * ratio);
if (flags & Map::OpenGL) {
for (int i = sr.left()/TILE_SIZE; i <= sr.right()/TILE_SIZE; i++) {
for (int j = sr.top()/TILE_SIZE; j <= sr.bottom()/TILE_SIZE; j++) {
QString key = _fileName + "-" + QString::number(i) + "_"
+ QString::number(j);
QPoint tl(i * TILE_SIZE, j * TILE_SIZE);
QPixmap pm;
if (!QPixmapCache::find(key, &pm)) {
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
pm = QPixmap::fromImage(_img.copy(tile));
if (!pm.isNull())
QPixmapCache::insert(key, pm);
}
#ifdef ENABLE_HIDPI
pm.setDevicePixelRatio(ratio);
#endif // ENABLE_HIDPI
painter->drawPixmap(tl/ratio, pm);
}
}
} else
painter->drawImage(rect.topLeft(), _img, sr);
}
void Image::setDevicePixelRatio(qreal ratio)
{
#ifdef ENABLE_HIDPI
_img.setDevicePixelRatio(ratio);
#else // ENABLE_HIDPI
Q_UNUSED(ratio);
#endif // ENABLE_HIDPI
}

22
src/map/image.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef IMAGE_H
#define IMAGE_H
#include <QImage>
#include "map.h"
class QPainter;
class Image
{
public:
Image(const QString &fileName);
void draw(QPainter *painter, const QRectF &rect, Map::Flags flags);
void setDevicePixelRatio(qreal ratio);
private:
QImage _img;
QString _fileName;
};
#endif // IMAGE_H

View File

@ -245,9 +245,9 @@ bool JNXMap::cb(Tile *tile, void *context)
return true;
}
void JNXMap::draw(QPainter *painter, const QRectF &rect, bool block)
void JNXMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
Q_UNUSED(block);
Q_UNUSED(flags);
const RTree<Tile*, qreal, 2> &tree = _zooms.at(_zoom).tree;
Ctx ctx(painter, &_file, _ratio);
QRectF rr(rect.topLeft() * _ratio, rect.size() * _ratio);

View File

@ -30,7 +30,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}

View File

@ -4,6 +4,7 @@
#include <QObject>
#include <QString>
#include <QRectF>
#include <QFlags>
#include "common/coordinates.h"
class QPainter;
@ -14,6 +15,13 @@ class Map : public QObject
Q_OBJECT
public:
enum Flag {
NoFlags = 0,
Block = 1,
OpenGL = 2
};
Q_DECLARE_FLAGS(Flags, Flag)
Map(QObject *parent = 0) : QObject(parent) {}
virtual ~Map() {}
@ -22,21 +30,21 @@ public:
virtual QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect);
virtual int zoom() const = 0;
virtual void setZoom(int zoom) = 0;
virtual int zoomFit(const QSize &size, const RectC &rect) = 0;
virtual int zoomIn() = 0;
virtual int zoomOut() = 0;
virtual int zoom() const {return 0;}
virtual void setZoom(int) {}
virtual int zoomFit(const QSize &, const RectC &) {return 0;}
virtual int zoomIn() {return 0;}
virtual int zoomOut() {return 0;}
virtual QPointF ll2xy(const Coordinates &c) = 0;
virtual Coordinates xy2ll(const QPointF &p) = 0;
virtual void draw(QPainter *painter, const QRectF &rect, bool block) = 0;
virtual void draw(QPainter *painter, const QRectF &rect, Flags flags) = 0;
virtual void clearCache() {}
virtual void load() {}
virtual void unload() {}
virtual void setDevicePixelRatio(qreal ratio) {Q_UNUSED(ratio);}
virtual void setDevicePixelRatio(qreal) {}
virtual bool isValid() const {return true;}
virtual QString errorString() const {return QString();}
@ -45,4 +53,6 @@ signals:
void loaded();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Map::Flags)
#endif // MAP_H

View File

@ -1,9 +1,10 @@
#include <QFileInfo>
#include <QDir>
#include "atlas.h"
#include "offlinemap.h"
#include "ozimap.h"
#include "onlinemap.h"
#include "jnxmap.h"
#include "geotiffmap.h"
#include "mapsource.h"
#include "maplist.h"
@ -53,8 +54,10 @@ bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
return loadSource(path, dir);
else if (suffix == "jnx")
return loadMap(new JNXMap(path, this), path, dir);
else if (suffix == "tif" || suffix == "tiff")
return loadMap(new GeoTIFFMap(path, this), path, dir);
else
return loadMap(new OfflineMap(path, this), path, dir);
return loadMap(new OziMap(path, this), path, dir);
}
bool MapList::loadDirR(const QString &path)

View File

@ -1,5 +1,6 @@
#include <QFile>
#include <QXmlStreamReader>
#include "config.h"
#include "onlinemap.h"
#include "wmtsmap.h"
#include "wmsmap.h"
@ -160,12 +161,16 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
attr.value("password").toString());
reader.skipCurrentElement();
} else if (reader.name() == "tilePixelRatio") {
#ifdef ENABLE_HIDPI
bool res;
qreal val = reader.readElementText().toDouble(&res);
if (!res)
reader.raiseError("Invalid tilePixelRatio");
else
config.tileRatio = val;
#else // ENABLE_HIDPI
reader.raiseError("HiDPI maps not supported");
#endif // ENABLE_HIDPI
} else
reader.skipCurrentElement();
}

View File

@ -126,9 +126,10 @@ qreal OnlineMap::tileSize() const
return (TILE_SIZE / coordinatesRatio());
}
void OnlineMap::draw(QPainter *painter, const QRectF &rect, bool block)
void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
qreal scale = zoom2scale(_zoom);
QRectF b(bounds());
QPoint tile = mercator2tile(QPointF(rect.topLeft().x() * scale,
-rect.topLeft().y() * scale) * coordinatesRatio(), _zoom);
@ -136,20 +137,21 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect, bool block)
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
QList<Tile> tiles;
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
qMin(rect.bottom() - tl.y(), b.height()));
for (int i = 0; i < ceil(s.width() / tileSize()); i++)
for (int j = 0; j < ceil(s.height() / tileSize()); j++)
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
if (block)
if (flags & Map::Block)
_tileLoader->loadTilesSync(tiles);
else
_tileLoader->loadTilesAsync(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize(),
tl.y() + (t.xy().y() - tile.y()) * tileSize());
QPointF tp(qMax(tl.x(), b.left()) + (t.xy().x() - tile.x()) * tileSize(),
qMax(tl.y(), b.top()) + (t.xy().y() - tile.y()) * tileSize());
if (!t.pixmap().isNull()) {
#ifdef ENABLE_HIDPI
t.pixmap().setDevicePixelRatio(imageRatio());

View File

@ -29,7 +29,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio) {_deviceRatio = ratio;}
void clearCache() {_tileLoader->clearCache();}

View File

@ -3,20 +3,118 @@
#include <QMap>
#include <QDir>
#include <QBuffer>
#include <QImage>
#include <QImageReader>
#include <QPixmapCache>
#include "common/coordinates.h"
#include "common/rectc.h"
#include "tar.h"
#include "ozf.h"
#include "image.h"
#include "mapfile.h"
#include "geotiff.h"
#include "config.h"
#include "offlinemap.h"
#include "ozimap.h"
bool OfflineMap::setImageInfo(const QString &path)
OziMap::OziMap(const QString &fileName, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower();
if (suffix == "tar") {
_tar = new Tar(fileName);
if (!_tar->open()) {
_errorString = "Error reading tar file";
return;
}
QString mapFileName = fi.completeBaseName() + ".map";
QByteArray ba = _tar->file(mapFileName);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
if (!setTileInfo(_tar->files()))
return;
} else {
QFile file(fileName);
MapFile mf(file);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
QDir set(fi.absolutePath() + "/" + "set");
if (set.exists()) {
if (!setTileInfo(set.entryList(), set.absolutePath()))
return;
} else {
if (!setImageInfo(fi.absolutePath()))
return;
}
}
_valid = true;
}
OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QFileInfo map(fi.absolutePath());
QFileInfo layer(map.absolutePath());
QString mapFile = layer.fileName() + "/" + map.fileName() + "/"
+ fi.fileName();
QByteArray ba = tar.file(mapFile);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
}
_name = mf.name();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
_valid = true;
}
OziMap::~OziMap()
{
delete _img;
delete _tar;
delete _ozf;
}
bool OziMap::setImageInfo(const QString &path)
{
QFileInfo ii(_map.path);
@ -40,26 +138,25 @@ bool OfflineMap::setImageInfo(const QString &path)
if (OZF::isOZF(_map.path)) {
_ozf = new OZF(_map.path);
if (!_ozf->open()) {
_errorString = QString("%1: Error loading OZF file")
.arg(_ozf->fileName());
if (!_ozf || !_ozf->open()) {
_errorString = QString("%1: Error loading OZF file").arg(_map.path);
return false;
}
_scale = _ozf->scale(_zoom);
} else {
QImageReader img(_map.path);
_map.size = img.size();
if (!_map.size.isValid()) {
_errorString = QString("%1: Error reading map image")
.arg(QFileInfo(_map.path).fileName());
QImageReader ir(_map.path);
if (!ir.canRead()) {
_errorString = QString("%1: Unsupported/invalid image file")
.arg(_map.path);
return false;
}
_map.size = ir.size();
}
return true;
}
bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
bool OziMap::setTileInfo(const QStringList &tiles, const QString &path)
{
if (!_map.size.isValid()) {
_errorString = "Missing total image size (IWH)";
@ -94,122 +191,7 @@ bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
return false;
}
OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower();
if (suffix == "tar") {
_tar = new Tar(fileName);
if (!_tar->open()) {
_errorString = "Error reading tar file";
return;
}
QString mapFileName = fi.completeBaseName() + ".map";
QByteArray ba = _tar->file(mapFileName);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "map") {
QFile file(fileName);
MapFile mf(file);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "tif" || suffix == "tiff") {
GeoTIFF gt(fileName);
if (!gt.isValid()) {
_errorString = gt.errorString();
return;
} else {
_name = fi.fileName();
_map.path = fileName;
_projection = gt.projection();
_transform = gt.transform();
}
} else {
_errorString = "Not a map file";
return;
}
if (_tar) {
if (!setTileInfo(_tar->files()))
return;
} else {
QDir set(fi.absolutePath() + "/" + "set");
if (set.exists()) {
if (!setTileInfo(set.entryList(), set.absolutePath()))
return;
} else {
if (!setImageInfo(fi.absolutePath()))
return;
}
}
_valid = true;
}
OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QFileInfo map(fi.absolutePath());
QFileInfo layer(map.absolutePath());
QString mapFile = layer.fileName() + "/" + map.fileName() + "/"
+ fi.fileName();
QByteArray ba = tar.file(mapFile);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
}
_name = mf.name();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
_valid = true;
}
OfflineMap::~OfflineMap()
{
delete _img;
delete _tar;
delete _ozf;
}
void OfflineMap::load()
void OziMap::load()
{
if (_tar && !_tar->isOpen()) {
if (!_tar->open()) {
@ -223,25 +205,17 @@ void OfflineMap::load()
return;
}
if (!_ozf && !_img && _map.isValid()) {
_img = new QImage(_map.path);
if (!_img || _img->isNull()) {
qWarning("%s: error loading map image", qPrintable(_map.path));
return;
}
#ifdef ENABLE_HIDPI
_img->setDevicePixelRatio(_ratio);
#endif // ENABLE_HIDPI
}
if (!_tile.isValid() && !_ozf && !_img)
_img = new Image(_map.path);
}
void OfflineMap::unload()
void OziMap::unload()
{
delete _img;
_img = 0;
}
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
void OziMap::drawTiled(QPainter *painter, const QRectF &rect) const
{
QSizeF ts(_tile.size.width() / _ratio, _tile.size.height() / _ratio);
QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
@ -282,7 +256,7 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
}
}
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
void OziMap::drawOZF(QPainter *painter, const QRectF &rect) const
{
QSizeF ts(_ozf->tileSize().width() / _ratio, _ozf->tileSize().height()
/ _ratio);
@ -317,25 +291,19 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
}
}
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect) const
void OziMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
painter->drawImage(rect.topLeft(), *_img, QRectF(rect.topLeft() * _ratio,
rect.size() * _ratio));
}
void OfflineMap::draw(QPainter *painter, const QRectF &rect, bool block)
{
Q_UNUSED(block);
Q_UNUSED(flags);
if (_ozf)
drawOZF(painter, rect);
else if (_img)
_img->draw(painter, rect, flags);
else if (_tile.isValid())
drawTiled(painter, rect);
else if (_img && !_img->isNull())
drawImage(painter, rect);
}
QPointF OfflineMap::ll2xy(const Coordinates &c)
QPointF OziMap::ll2xy(const Coordinates &c)
{
QPointF p(_transform.proj2img(_projection.ll2xy(c)));
return _ozf
@ -343,7 +311,7 @@ QPointF OfflineMap::ll2xy(const Coordinates &c)
: p / _ratio;
}
Coordinates OfflineMap::xy2ll(const QPointF &p)
Coordinates OziMap::xy2ll(const QPointF &p)
{
return _ozf
? _projection.xy2ll(_transform.img2proj(QPointF(p.x() / _scale.x(),
@ -351,14 +319,14 @@ Coordinates OfflineMap::xy2ll(const QPointF &p)
: _projection.xy2ll(_transform.img2proj(p * _ratio));
}
QRectF OfflineMap::bounds()
QRectF OziMap::bounds()
{
return _ozf
? QRectF(QPointF(0, 0), _ozf->size(_zoom) / _ratio)
: QRectF(QPointF(0, 0), _map.size / _ratio);
}
int OfflineMap::zoomFit(const QSize &size, const RectC &rect)
int OziMap::zoomFit(const QSize &size, const RectC &rect)
{
if (!_ozf)
return _zoom;
@ -381,7 +349,7 @@ int OfflineMap::zoomFit(const QSize &size, const RectC &rect)
return _zoom;
}
int OfflineMap::zoomIn()
int OziMap::zoomIn()
{
if (_ozf)
rescale(qMax(_zoom - 1, 0));
@ -389,7 +357,7 @@ int OfflineMap::zoomIn()
return _zoom;
}
int OfflineMap::zoomOut()
int OziMap::zoomOut()
{
if (_ozf)
rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
@ -397,8 +365,15 @@ int OfflineMap::zoomOut()
return _zoom;
}
void OfflineMap::rescale(int zoom)
void OziMap::rescale(int zoom)
{
_zoom = zoom;
_scale = _ozf->scale(zoom);
}
void OziMap::setDevicePixelRatio(qreal ratio)
{
_ratio = ratio;
if (_img)
_img->setDevicePixelRatio(_ratio);
}

View File

@ -1,5 +1,5 @@
#ifndef OFFLINEMAP_H
#define OFFLINEMAP_H
#ifndef OZIMAP_H
#define OZIMAP_H
#include "transform.h"
#include "projection.h"
@ -7,16 +7,16 @@
class Tar;
class OZF;
class QImage;
class Image;
class OfflineMap : public Map
class OziMap : public Map
{
Q_OBJECT
public:
OfflineMap(const QString &fileName, QObject *parent = 0);
OfflineMap(const QString &fileName, Tar &tar, QObject *parent = 0);
~OfflineMap();
OziMap(const QString &fileName, QObject *parent = 0);
OziMap(const QString &fileName, Tar &tar, QObject *parent = 0);
~OziMap();
QString name() const {return _name;}
@ -31,9 +31,9 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}
void setDevicePixelRatio(qreal ratio);
void load();
void unload();
@ -60,14 +60,14 @@ private:
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 drawImage(QPainter *painter, const QRectF &rect, Flags flags) const;
void rescale(int zoom);
QString _name;
Projection _projection;
Transform _transform;
QImage *_img;
Image *_img;
Tar *_tar;
OZF *_ozf;
ImageInfo _map, _tile;
@ -79,4 +79,4 @@ private:
QString _errorString;
};
#endif // OFFLINEMAP_H
#endif // OZIMAP_H

View File

@ -192,7 +192,7 @@ qreal WMSMap::tileSize() const
return (TILE_SIZE / _ratio);
}
void WMSMap::draw(QPainter *painter, const QRectF &rect, bool block)
void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
QPoint tl = QPoint((int)floor(rect.left() / tileSize()),
(int)floor(rect.top() / tileSize()));
@ -214,7 +214,7 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, bool block)
}
}
if (block)
if (flags & Map::Block)
_tileLoader->loadTilesSync(tiles);
else
_tileLoader->loadTilesAsync(tiles);

View File

@ -29,7 +29,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}
void clearCache();

View File

@ -169,7 +169,7 @@ QSizeF WMTSMap::tileSize(const WMTS::Zoom &zoom) const
zoom.tile().height() / coordinatesRatio());
}
void WMTSMap::draw(QPainter *painter, const QRectF &rect, bool block)
void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
const WMTS::Zoom &z = _zooms.at(_zoom);
QSizeF ts(tileSize(z));
@ -184,7 +184,7 @@ void WMTSMap::draw(QPainter *painter, const QRectF &rect, bool block)
for (int j = tl.y(); j < br.y(); j++)
tiles.append(Tile(QPoint(i, j), z.id()));
if (block)
if (flags & Map::Block)
_tileLoader->loadTilesSync(tiles);
else
_tileLoader->loadTilesAsync(tiles);

View File

@ -29,7 +29,7 @@ public:
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, bool block);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void setDevicePixelRatio(qreal ratio) {_deviceRatio = ratio;}
void clearCache();