From c2391929d32b748107c1a5e330489f8e06119f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 14 Jan 2016 00:37:51 +0100 Subject: [PATCH] Added track scale info --- gpxsee.pro | 8 ++- src/axisitem.cpp | 36 ++------------ src/gui.cpp | 2 + src/ll.cpp | 6 +++ src/ll.h | 1 + src/nicenum.cpp | 34 +++++++++++++ src/nicenum.h | 6 +++ src/scaleitem.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++++ src/scaleitem.h | 32 ++++++++++++ src/track.cpp | 34 +++++++++++++ src/track.h | 5 ++ src/units.h | 4 ++ 12 files changed, 256 insertions(+), 35 deletions(-) create mode 100644 src/nicenum.cpp create mode 100644 src/nicenum.h create mode 100644 src/scaleitem.cpp create mode 100644 src/scaleitem.h diff --git a/gpxsee.pro b/gpxsee.pro index 122d5ff5..b735c778 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -28,7 +28,9 @@ HEADERS += src/config.h \ src/map.h \ src/maplist.h \ src/downloader.h \ - src/units.h + src/units.h \ + src/scaleitem.h \ + src/nicenum.h SOURCES += src/main.cpp \ src/gui.cpp \ src/gpx.cpp \ @@ -49,7 +51,9 @@ SOURCES += src/main.cpp \ src/filebrowser.cpp \ src/map.cpp \ src/maplist.cpp \ - src/downloader.cpp + src/downloader.cpp \ + src/scaleitem.cpp \ + src/nicenum.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts macx:ICON = icons/gpxsee.icns diff --git a/src/axisitem.cpp b/src/axisitem.cpp index 25270b32..4a0d8e8a 100644 --- a/src/axisitem.cpp +++ b/src/axisitem.cpp @@ -1,6 +1,7 @@ #include #include #include "config.h" +#include "nicenum.h" #include "axisitem.h" @@ -15,38 +16,6 @@ struct Label { double d; }; -static double niceNum(double x, int round) -{ - int expv; - double f; - double nf; - - expv = floor(log10(x)); - f = x / pow(10.0, expv); - - if (round) { - if (f < 1.5) - nf = 1.0; - else if (f < 3.0) - nf = 2.0; - else if (f < 7.0) - nf = 5.0; - else - nf = 10.0; - } else { - if (f <= 1.0) - nf = 1.; - else if (f <= 2.0) - nf = 2.0; - else if (f <= 5.0) - nf = 5.0; - else - nf = 10.0; - } - - return nf * pow(10.0, expv); -} - static struct Label label(double min, double max, int ticks) { double range; @@ -123,7 +92,6 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QFont font; font.setPixelSize(FONT_SIZE); font.setFamily(FONT_FAMILY); - painter->setFont(font); QFontMetrics fm(font); QRect ts, ls; struct Label l; @@ -131,6 +99,8 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, qreal val; + painter->setFont(font); + ls = fm.tightBoundingRect(_label); if (_type == X) { diff --git a/src/gui.cpp b/src/gui.cpp index c522749c..c429f33e 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -670,6 +670,7 @@ void GUI::updateNavigationActions() void GUI::setMetricUnits() { + _track->setUnits(Metric); _elevationGraph->setUnits(Metric); _speedGraph->setUnits(Metric); updateStatusBarInfo(); @@ -677,6 +678,7 @@ void GUI::setMetricUnits() void GUI::setImperialUnits() { + _track->setUnits(Imperial); _elevationGraph->setUnits(Imperial); _speedGraph->setUnits(Imperial); updateStatusBarInfo(); diff --git a/src/ll.cpp b/src/ll.cpp index 6354cf10..98536f85 100644 --- a/src/ll.cpp +++ b/src/ll.cpp @@ -68,3 +68,9 @@ int scale2zoom(qreal scale) return ZOOM_MAX; return zoom; } + +qreal zoom2resolution(int zoom, qreal y) +{ + return (WGS84_RADIUS * 2 * M_PI / 256 * cos(2 * atan(exp(deg2rad(y))) + - M_PI/2)) / pow(2.0, zoom); +} diff --git a/src/ll.h b/src/ll.h index 94c36542..0b99094b 100644 --- a/src/ll.h +++ b/src/ll.h @@ -12,5 +12,6 @@ qreal llDistance(const QPointF &p1, const QPointF &p2); QPoint mercator2tile(const QPointF &m, int zoom); QPointF tile2mercator(const QPoint &tile, int zoom); int scale2zoom(qreal scale); +qreal zoom2resolution(int zoom, qreal y); #endif // LL_H diff --git a/src/nicenum.cpp b/src/nicenum.cpp new file mode 100644 index 00000000..e4f1dabc --- /dev/null +++ b/src/nicenum.cpp @@ -0,0 +1,34 @@ +#include +#include "nicenum.h" + +double niceNum(double x, int round) +{ + int expv; + double f; + double nf; + + expv = floor(log10(x)); + f = x / pow(10.0, expv); + + if (round) { + if (f < 1.5) + nf = 1.0; + else if (f < 3.0) + nf = 2.0; + else if (f < 7.0) + nf = 5.0; + else + nf = 10.0; + } else { + if (f <= 1.0) + nf = 1.0; + else if (f <= 2.0) + nf = 2.0; + else if (f <= 5.0) + nf = 5.0; + else + nf = 10.0; + } + + return nf * pow(10.0, expv); +} diff --git a/src/nicenum.h b/src/nicenum.h new file mode 100644 index 00000000..7be831b8 --- /dev/null +++ b/src/nicenum.h @@ -0,0 +1,6 @@ +#ifndef NICENUM_H +#define NICENUM_H + +double niceNum(double x, int round); + +#endif // NICENUM_H diff --git a/src/scaleitem.cpp b/src/scaleitem.cpp new file mode 100644 index 00000000..a40a1898 --- /dev/null +++ b/src/scaleitem.cpp @@ -0,0 +1,123 @@ +#include +#include "config.h" +#include "ll.h" +#include "nicenum.h" +#include "scaleitem.h" + + +#define SCALE_WIDTH 132 +#define SCALE_HEIGHT 5 +#define SEGMENTS 3 + +#define PADDING 4 + + +ScaleItem::ScaleItem(QGraphicsItem *parent) : QGraphicsItem(parent) +{ + _units = Metric; +} + +QRectF ScaleItem::boundingRect() const +{ + QFont font; + font.setPixelSize(FONT_SIZE); + font.setFamily(FONT_FAMILY); + QFontMetrics fm(font); + QRect ss, es, us; + + ss = fm.tightBoundingRect(QString::number(0)); + es = fm.tightBoundingRect(QString::number(_length * SEGMENTS)); + us = fm.tightBoundingRect(units()); + + return QRectF(-ss.width()/2, -(PADDING + ss.height() + fm.descent()), + _width * SEGMENTS + ss.width()/2 + qMax(us.width() + PADDING, es.width()/2), + SCALE_HEIGHT + PADDING + ss.height() + 2*fm.descent()); +} + +void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + QFont font; + font.setPixelSize(FONT_SIZE); + font.setFamily(FONT_FAMILY); + QFontMetrics fm(font); + + + painter->setFont(font); + + for (int i = 0; i <= SEGMENTS; i++) { + QString label = QString::number(_length * i); + QRect br = fm.tightBoundingRect(label); + painter->drawText(_width * i - br.width()/2, -PADDING, label); + } + painter->drawText(_width * SEGMENTS + PADDING, SCALE_HEIGHT + fm.descent(), + units()); + + painter->drawRect(QRectF(0, 0, SEGMENTS * _width, SCALE_HEIGHT)); + for (int i = 0; i < SEGMENTS; i += 2) + painter->fillRect(QRectF(i * _width, 0, _width, SCALE_HEIGHT), + Qt::black); + +/* + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); +*/ +} + +QString ScaleItem::units() const +{ + if (_units == Imperial) + return _scale ? QObject::tr("mi") : QObject::tr("ft"); + else + return _scale ? QObject::tr("km") : QObject::tr("m"); +} + +void ScaleItem::computeScale() +{ + qreal res = zoom2resolution(_zoom, _lat); + + if (_units == Imperial) { + _length = niceNum((res * M2FT * SCALE_WIDTH) / SEGMENTS, 1); + if (_length >= MIINFT) { + _length = niceNum((res * M2FT * FT2MI * SCALE_WIDTH) / SEGMENTS, 1); + _width = (_length / (res * M2FT * FT2MI)); + _scale = true; + } else { + _width = (_length / (res * M2FT)); + _scale = false; + } + } else { + _length = niceNum((res * SCALE_WIDTH) / SEGMENTS, 1); + if (_length >= KMINM) { + _length *= M2KM; + _width = (_length / (res * M2KM)); + _scale = true; + } else { + _width = (_length / res); + _scale = false; + } + } +} + +void ScaleItem::setLatitude(qreal lat) +{ + _lat = lat; + computeScale(); + prepareGeometryChange(); +} + +void ScaleItem::setZoom(int z) +{ + _zoom = z; + computeScale(); + prepareGeometryChange(); +} + +void ScaleItem::setUnits(enum Units units) +{ + _units = units; + computeScale(); + prepareGeometryChange(); +} diff --git a/src/scaleitem.h b/src/scaleitem.h new file mode 100644 index 00000000..059e9f0e --- /dev/null +++ b/src/scaleitem.h @@ -0,0 +1,32 @@ +#ifndef SCALEITEM_H +#define SCALEITEM_H + +#include +#include "units.h" + +class ScaleItem : public QGraphicsItem +{ +public: + ScaleItem(QGraphicsItem *parent = 0); + + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + void setLatitude(qreal lat); + void setZoom(int z); + void setUnits(enum Units units); + +private: + void computeScale(); + QString units() const; + + int _zoom; + qreal _lat; + qreal _width; + qreal _length; + Units _units; + bool _scale; +}; + +#endif // SCALEITEM_H diff --git a/src/track.cpp b/src/track.cpp index ad2aac6f..7d9f8753 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -5,9 +5,12 @@ #include #include "poiitem.h" #include "markeritem.h" +#include "scaleitem.h" #include "ll.h" #include "track.h" +#include + #define MARGIN 10.0 #define TRACK_WIDTH 3 @@ -22,6 +25,9 @@ Track::Track(QWidget *parent) setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + _mapScale = new ScaleItem(); + _mapScale->setZValue(2.0); + _zoom = -1; _scale = 1.0; _map = 0; @@ -79,6 +85,12 @@ void Track::loadGPX(const GPX &gpx) QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE); _scene->setSceneRect(ba); centerOn(ba.center()); + + if (_mapScale->scene() != _scene) + _scene->addItem(_mapScale); + + _mapScale->setLatitude(track.at(track.size() / 2).y()); + _mapScale->setZoom(_zoom); } QRectF Track::trackBoundingRect() const @@ -198,6 +210,11 @@ void Track::setMap(Map *map) resetCachedContent(); } +void Track::setUnits(enum Units units) +{ + _mapScale->setUnits(units); +} + void Track::redraw() { resetCachedContent(); @@ -225,6 +242,8 @@ void Track::wheelEvent(QWheelEvent *event) else centerOn(pos * scale/_scale); + _mapScale->setZoom(_zoom); + resetCachedContent(); } @@ -245,6 +264,8 @@ void Track::setTrackLineWidth(qreal width) void Track::plot(QPainter *painter, const QRectF &target) { + _scene->removeItem(_mapScale); + QRectF orig = _scene->itemsBoundingRect(); QRectF adj; qreal ratio, diff; @@ -264,6 +285,8 @@ void Track::plot(QPainter *painter, const QRectF &target) _scene->render(painter, target, adj, Qt::KeepAspectRatioByExpanding); setTrackLineWidth(TRACK_WIDTH * _scale); showMarkers(true); + + _scene->addItem(_mapScale); } enum QPrinter::Orientation Track::orientation() const @@ -286,6 +309,9 @@ void Track::clearPOI() void Track::clear() { + if (_mapScale->scene() == _scene) + _scene->removeItem(_mapScale); + _pois.clear(); _tracks.clear(); _trackPaths.clear(); @@ -362,3 +388,11 @@ void Track::resizeEvent(QResizeEvent *e) centerOn(br.center()); resetCachedContent(); } + +void Track::paintEvent(QPaintEvent *e) +{ + QPointF scenePos = mapToScene(rect().bottomLeft() + QPoint(10, -15)); + _mapScale->setPos(scenePos); + + QGraphicsView::paintEvent(e); +} diff --git a/src/track.h b/src/track.h index c30acd67..e8072799 100644 --- a/src/track.h +++ b/src/track.h @@ -9,11 +9,13 @@ #include "poi.h" #include "gpx.h" #include "map.h" +#include "units.h" #include "colorshop.h" class POIItem; class MarkerItem; +class ScaleItem; class Track : public QGraphicsView { @@ -30,6 +32,7 @@ public: void clear(); void setMap(Map *map); + void setUnits(enum Units units); void plot(QPainter *painter, const QRectF &target); enum QPrinter::Orientation orientation() const; @@ -52,6 +55,7 @@ private: void wheelEvent(QWheelEvent *event); void drawBackground(QPainter *painter, const QRectF &rect); void resizeEvent(QResizeEvent *e); + void paintEvent(QPaintEvent *e); QGraphicsScene *_scene; QList > _tracks; @@ -59,6 +63,7 @@ private: QList _markers; QHash _pois; Map *_map; + ScaleItem *_mapScale; ColorShop _colorShop; qreal _maxLen; diff --git a/src/units.h b/src/units.h index 59f68dd4..0910ac9e 100644 --- a/src/units.h +++ b/src/units.h @@ -11,5 +11,9 @@ enum Units { #define M2FT 3.280839900000 // m -> ft #define MS2KMH 3.600000000000 // m/s -> km/h #define MS2MIH 2.236936290000 // m/s -> mi/h +#define FT2MI 0.000189393939 // ft -> mi + +#define MIINFT 5280 // 1 mi in ft +#define KMINM 1000 // 1 km in m #endif // UNITS_H