1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 06:43:22 +02:00

Added initial map support part #2

This commit is contained in:
Martin Tůma 2015-11-23 02:37:08 +01:00
parent 69095ca9eb
commit c639c6deac
13 changed files with 305 additions and 69 deletions

View File

@ -1,6 +1,7 @@
TARGET = GPXSee
QT += core \
gui
gui \
network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += printsupport
HEADERS += src/config.h \
@ -23,7 +24,9 @@ HEADERS += src/config.h \
src/elevationgraph.h \
src/speedgraph.h \
src/sliderinfoitem.h \
src/filebrowser.h
src/filebrowser.h \
src/map.h \
src/downloader.h
SOURCES += src/main.cpp \
src/gui.cpp \
src/gpx.cpp \
@ -41,7 +44,9 @@ SOURCES += src/main.cpp \
src/elevationgraph.cpp \
src/speedgraph.cpp \
src/sliderinfoitem.cpp \
src/filebrowser.cpp
src/filebrowser.cpp \
src/map.cpp \
src/downloader.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts
macx:ICON = icons/gpxsee.icns

View File

@ -7,6 +7,7 @@
<file>icons/flag.png</file>
<file>icons/gpxsee.png</file>
<file>icons/application-exit.png</file>
<file>icons/applications-internet.png</file>
<file>icons/view-refresh.png</file>
<file>lang/gpxsee_cs.qm</file>
</qresource>

View File

@ -150,12 +150,8 @@ void GPX::speedGraph(QVector<QPointF> &graph) const
void GPX::track(QVector<QPointF> &track) const
{
QPointF p;
for (int i = 0; i < _data.size(); i++) {
ll2mercator(_data.at(i).coordinates, p);
track.append(p);
}
for (int i = 0; i < _data.size(); i++)
track.append(ll2mercator(_data.at(i).coordinates));
}
qreal GPX::distance() const

View File

@ -7,10 +7,12 @@
#include <QPrinter>
#include <QPainter>
#include <QKeyEvent>
#include <QSignalMapper>
#include "config.h"
#include "icons.h"
#include "keys.h"
#include "gpx.h"
#include "map.h"
#include "elevationgraph.h"
#include "speedgraph.h"
#include "track.h"
@ -36,6 +38,8 @@ static QString timeSpan(qreal time)
GUI::GUI()
{
loadMaps();
createActions();
createMenus();
createToolBars();
@ -68,6 +72,40 @@ GUI::GUI()
resize(600, 800);
}
void GUI::loadMaps()
{
_maps.append(new Map("Google maps",
"http://mts1.google.com/vt/x=$x&y=$y&z=$z"));
_maps.append(new Map("Mapy.cz",
"http://m1.mapserver.mapy.cz/wturist-m/$z-$x-$y"));
_maps.append(new Map("OSM",
"http://tile.mtbmap.cz/mtbmap_tiles/$z/$x/$y.png"));
}
void GUI::createMapActions()
{
QActionGroup *ag = new QActionGroup(this);
ag->setExclusive(true);
QSignalMapper *sm = new QSignalMapper(this);
for (int i = 0; i < _maps.count(); i++) {
QAction *a = new QAction(_maps.at(i)->name(), this);
a->setCheckable(true);
a->setActionGroup(ag);
sm->setMapping(a, i);
connect(a, SIGNAL(triggered()), sm, SLOT(map()));
_mapActions.append(a);
}
connect(sm, SIGNAL(mapped(int)), this, SLOT(mapChanged(int)));
_mapActions.at(0)->setChecked(true);
_currentMap = _maps.at(0);
}
void GUI::createActions()
{
// Action Groups
@ -118,12 +156,22 @@ void GUI::createActions()
// POI actions
_openPOIAction = new QAction(QIcon(QPixmap(OPEN_FILE_ICON)),
tr("Load file"), this);
tr("Load POI file"), this);
connect(_openPOIAction, SIGNAL(triggered()), this, SLOT(openPOIFile()));
_showPOIAction = new QAction(QIcon(QPixmap(SHOW_POI_ICON)),
tr("Show"), this);
tr("Show POIs"), this);
_showPOIAction->setCheckable(true);
connect(_showPOIAction, SIGNAL(triggered()), this, SLOT(showPOI()));
// Map actions
_showMapAction = new QAction(QIcon(QPixmap(SHOW_MAP_ICON)), tr("Show map"),
this);
_showMapAction->setCheckable(true);
connect(_showMapAction, SIGNAL(triggered()), this, SLOT(showMap()));
if (_maps.empty())
_showMapAction->setEnabled(false);
else
createMapActions();
}
void GUI::createMenus()
@ -142,6 +190,11 @@ void GUI::createMenus()
_fileMenu->addAction(_exitAction);
#endif // __APPLE__
_mapMenu = menuBar()->addMenu(tr("Map"));
_mapMenu->addActions(_mapActions);
_mapMenu->addSeparator();
_mapMenu->addAction(_showMapAction);
_poiMenu = menuBar()->addMenu(tr("POI"));
_poiMenu->addAction(_openPOIAction);
_poiMenu->addAction(_showPOIAction);
@ -164,10 +217,11 @@ void GUI::createToolBars()
_fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
#endif // __APPLE__
_poiToolBar = addToolBar(tr("POI"));
_poiToolBar->addAction(_showPOIAction);
_showToolBar = addToolBar(tr("Show"));
_showToolBar->addAction(_showPOIAction);
_showToolBar->addAction(_showMapAction);
#ifdef __APPLE__
_poiToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
_showToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
#endif // __APPLE__
}
@ -402,6 +456,13 @@ void GUI::showPOI()
_track->clearPOI();
}
void GUI::showMap()
{
if (_showMapAction->isChecked())
_track->setMap(_currentMap);
else
_track->setMap(0);
}
void GUI::updateStatusBarInfo()
{
@ -422,6 +483,14 @@ void GUI::updateStatusBarInfo()
_timeLabel->setText(timeSpan(_time));
}
void GUI::mapChanged(int index)
{
_currentMap = _maps.at(index);
if (_showMapAction->isChecked())
_track->setMap(_currentMap);
}
void GUI::graphChanged(int index)
{
if (_trackGraphs->widget(index) == _elevationGraph)

View File

@ -16,6 +16,7 @@ class FileBrowser;
class ElevationGraph;
class SpeedGraph;
class Track;
class Map;
class GUI : public QMainWindow
{
@ -36,10 +37,15 @@ private slots:
void reloadFile();
void openPOIFile();
void showPOI();
void showMap();
void mapChanged(int);
void graphChanged(int);
private:
void loadMaps();
void createMapActions();
void createActions();
void createMenus();
void createToolBars();
@ -56,9 +62,10 @@ private:
QMenu *_fileMenu;
QMenu *_helpMenu;
QMenu *_poiMenu;
QMenu *_mapMenu;
QToolBar *_fileToolBar;
QToolBar *_poiToolBar;
QToolBar *_showToolBar;
QTabWidget *_trackGraphs;
QActionGroup *_fileActionGroup;
@ -73,6 +80,8 @@ private:
QAction *_reloadFileAction;
QAction *_openPOIAction;
QAction *_showPOIAction;
QAction *_showMapAction;
QList<QAction*> _mapActions;
QLabel *_fileNameLabel;
QLabel *_distanceLabel;
@ -83,10 +92,12 @@ private:
Track *_track;
POI _poi;
QList<Map*> _maps;
FileBrowser *_browser;
QList<QString> _files;
QString _saveFileName;
Map *_currentMap;
qreal _distance;
qreal _time;

View File

@ -9,6 +9,7 @@
#define SAVE_AS_ICON ":/icons/document-save-as.png"
#define CLOSE_FILE_ICON ":/icons/dialog-close.png"
#define SHOW_POI_ICON ":/icons/flag.png"
#define SHOW_MAP_ICON ":/icons/applications-internet.png"
#define QUIT_ICON ":/icons/application-exit.png"
#define RELOAD_FILE_ICON ":/icons/view-refresh.png"

View File

@ -20,8 +20,38 @@ qreal llDistance(const QPointF &p1, const QPointF &p2)
return (WGS84_RADIUS * c);
}
void ll2mercator(const QPointF &src, QPointF &dst)
QPointF ll2mercator(const QPointF &ll)
{
dst.setX(src.x());
dst.setY(rad2deg(log(tan(M_PI/4.0 + deg2rad(src.y())/2.0))));
QPointF m;
m.setX(ll.x());
m.setY(rad2deg(log(tan(M_PI/4.0 + deg2rad(ll.y())/2.0))));
return m;
}
QPoint mercator2tile(const QPointF &m, int z)
{
QPoint tile;
tile.setX((int)(floor((m.x() + 180.0) / 360.0 * pow(2.0, z))));
tile.setY((int)(floor((1.0 - (m.y() / 180.0)) / 2.0 * pow(2.0, z))));
return tile;
}
QPointF tile2mercator(const QPoint &tile, int z)
{
QPointF m;
m.setX(tile.x() / pow(2.0, z) * 360.0 - 180);
qreal n = M_PI - 2.0 * M_PI * tile.y() / pow(2.0, z);
m.setY(rad2deg(atan(0.5 * (exp(n) - exp(-n)))));
return ll2mercator(m);
}
int scale2zoom(qreal scale)
{
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}

View File

@ -3,7 +3,12 @@
#include <QPointF>
void ll2mercator(const QPointF &src, QPointF &dst);
#define TILE_SIZE 256
QPointF ll2mercator(const QPointF &ll);
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);
#endif // LL_H

View File

@ -38,11 +38,9 @@ bool POI::loadFile(const QString &fileName)
}
QByteArray ba = list[2].trimmed();
QPointF p;
Entry entry;
ll2mercator(QPointF(lon, lat), p);
entry.description = QString::fromUtf8(ba.data(), ba.size());
entry.coordinates = p;
entry.coordinates = ll2mercator(QPointF(lon, lat));
_data.append(entry);
ln++;

View File

@ -7,10 +7,10 @@
#define POINT_SIZE 8
POIItem::POIItem(const QString &text, QGraphicsItem *parent)
POIItem::POIItem(const Entry &entry, QGraphicsItem *parent)
: QGraphicsItem(parent)
{
_text = text;
_entry = entry;
updateBoundingRect();
}
@ -20,7 +20,7 @@ void POIItem::updateBoundingRect()
font.setPixelSize(FONT_SIZE);
font.setFamily(FONT_FAMILY);
QFontMetrics fm(font);
QRect ts = fm.tightBoundingRect(_text);
QRect ts = fm.tightBoundingRect(_entry.description);
_boundingRect = QRectF(0, 0, ts.width() + POINT_SIZE,
ts.height() + fm.descent() + POINT_SIZE);
@ -35,11 +35,11 @@ void POIItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
font.setPixelSize(FONT_SIZE);
font.setFamily(FONT_FAMILY);
QFontMetrics fm(font);
QRect ts = fm.tightBoundingRect(_text);
QRect ts = fm.tightBoundingRect(_entry.description);
painter->setFont(font);
painter->drawText(POINT_SIZE - qMax(ts.x(), 0), POINT_SIZE + ts.height(),
_text);
_entry.description);
painter->setBrush(Qt::SolidPattern);
painter->drawEllipse(0, 0, POINT_SIZE, POINT_SIZE);

View File

@ -2,11 +2,13 @@
#define POIITEM_H
#include <QGraphicsItem>
#include "poi.h"
class POIItem : public QGraphicsItem
{
public:
POIItem(const QString &text, QGraphicsItem *parent = 0);
POIItem(const Entry &entry, QGraphicsItem *parent = 0);
const Entry &entry() const {return _entry;}
QRectF boundingRect() const {return _boundingRect;}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
@ -15,7 +17,7 @@ public:
private:
void updateBoundingRect();
QString _text;
Entry _entry;
QRectF _boundingRect;
};

View File

@ -6,18 +6,29 @@
#include <QGraphicsEllipseItem>
#include "poiitem.h"
#include "markeritem.h"
#include "ll.h"
#include "track.h"
#include <QDebug>
#define MARGIN 10.0
#define TRACK_WIDTH 3
#define ZOOM_MAX 19
#define ZOOM_MIN 0
Track::Track(QWidget *parent)
: QGraphicsView(parent)
{
_scene = new QGraphicsScene(this);
setScene(_scene);
setResizeAnchor(QGraphicsView::AnchorViewCenter);
setCacheMode(QGraphicsView::CacheBackground);
_zoom = -1;
_scale = 1.0;
_map = 0;
_maxLen = 0;
}
@ -33,6 +44,7 @@ void Track::loadGPX(const GPX &gpx)
QGraphicsPathItem *pi;
MarkerItem *mi;
QColor color = _colorShop.color();
qreal prevScale = _scale;
gpx.track(track);
@ -48,41 +60,72 @@ void Track::loadGPX(const GPX &gpx)
_maxLen = qMax(path.length(), _maxLen);
for (int i = 0; i < _trackPaths.size(); i++) {
_trackPaths.at(i)->resetTransform();
_scene->removeItem(_markers.at(i));
}
pi = new QGraphicsPathItem(path);
QBrush brush(color, Qt::SolidPattern);
QPen pen(brush, 0);
pi->setPen(pen);
_scene->addItem(pi);
_trackPaths.append(pi);
_zoom = scale2zoom(trackScale());
_scale = mapScale();
QBrush brush(color, Qt::SolidPattern);
QPen pen(brush, TRACK_WIDTH * _scale);
pi->setPen(pen);
pi->setScale(1.0/_scale);
_scene->addItem(pi);
QTransform t = transform();
mi = new MarkerItem();
mi->setPos(pi->path().pointAtPercent(0));
mi = new MarkerItem(pi);
_markers.append(mi);
mi->setPos(pi->path().pointAtPercent(0));
mi->setScale(_scale);
for (int i = 0; i < _trackPaths.size(); i++) {
_markers.at(i)->setTransform(t);
_scene->addItem(_markers.at(i));
}
if (_trackPaths.size() > 1 && prevScale != _scale)
rescale(_scale);
_scene->setSceneRect(_scene->itemsBoundingRect());
fitInView(_scene->sceneRect(), Qt::KeepAspectRatio);
}
QTransform Track::transform() const
qreal Track::trackScale() const
{
QPointF scale(_scene->itemsBoundingRect().width() / viewport()->width(),
_scene->itemsBoundingRect().height() / viewport()->height());
QTransform transform;
transform.scale(qMax(scale.x(), scale.y()), qMax(scale.x(), scale.y()));
qreal bottom, top, left, right;
return transform;
bottom = _trackPaths.at(0)->boundingRect().bottom();
top = _trackPaths.at(0)->boundingRect().top();
left = _trackPaths.at(0)->boundingRect().left();
right = _trackPaths.at(0)->boundingRect().right();
for (int i = 1; i < _trackPaths.size(); i++) {
bottom = qMax(bottom, _trackPaths.at(i)->boundingRect().bottom());
top = qMin(top, _trackPaths.at(i)->boundingRect().top());
right = qMax(right, _trackPaths.at(i)->boundingRect().right());
left = qMin(left, _trackPaths.at(i)->boundingRect().left());
}
QRectF br(QPointF(left, top), QPointF(right, bottom));
QPointF sc(br.width() / (viewport()->width() - MARGIN/2),
br.height() / (viewport()->height() - MARGIN/2));
return qMax(sc.x(), sc.y());
}
qreal Track::mapScale() const
{
return ((360.0/(qreal)(1<<_zoom))/(qreal)TILE_SIZE);
}
void Track::rescale(qreal scale)
{
for (int i = 0; i < _trackPaths.size(); i++) {
_markers.at(i)->setScale(scale);
_trackPaths.at(i)->setScale(1.0/scale);
QPen pen(_trackPaths.at(i)->pen());
pen.setWidthF(TRACK_WIDTH * scale);
_trackPaths.at(i)->setPen(pen);
}
QHash<Entry, POIItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setPos(QPointF(it.value()->entry().coordinates.x()
* 1.0/scale, -it.value()->entry().coordinates.y() * 1.0/scale));
_scale = scale;
}
void Track::loadPOI(const POI &poi)
@ -96,9 +139,9 @@ void Track::loadPOI(const POI &poi)
if (_pois.contains(p.at(i)))
continue;
POIItem *pi = new POIItem(p.at(i).description);
pi->setPos(p.at(i).coordinates.x(), -p.at(i).coordinates.y());
pi->setTransform(transform());
POIItem *pi = new POIItem(p.at(i));
pi->setPos(p.at(i).coordinates.x() * 1.0/_scale,
-p.at(i).coordinates.y() * 1.0/_scale);
pi->setZValue(1);
_scene->addItem(pi);
@ -106,9 +149,6 @@ void Track::loadPOI(const POI &poi)
}
}
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setTransform(transform());
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
for (jt = _pois.constBegin(); jt != _pois.constEnd(); jt++) {
if (it != jt && it.value()->isVisible() && jt.value()->isVisible()
@ -118,15 +158,44 @@ void Track::loadPOI(const POI &poi)
}
_scene->setSceneRect(_scene->itemsBoundingRect());
fitInView(_scene->sceneRect(), Qt::KeepAspectRatio);
}
void Track::setMap(Map *map)
{
_map = map;
if (_map)
connect(_map, SIGNAL(loaded()), this, SLOT(redraw()));
resetCachedContent();
}
void Track::redraw()
{
resetCachedContent();
}
void Track::wheelEvent(QWheelEvent *event)
{
float factor;
_zoom = (event->delta() > 0) ?
qMin(_zoom + 1, ZOOM_MAX) : qMax(_zoom - 1, ZOOM_MIN);
factor = pow(2.0, -event->delta() / 400.0);
scale(factor, factor);
rescale(mapScale());
_scene->setSceneRect(_scene->itemsBoundingRect());
resetCachedContent();
}
void Track::showMarkers(bool show)
{
for (int i = 0; i < _markers.size(); i++)
_markers.at(i)->setVisible(show);
}
void Track::setTrackLineWidth(qreal width)
{
for (int i = 0; i < _trackPaths.size(); i++) {
QPen pen(_trackPaths.at(i)->pen());
pen.setWidthF(width);
_trackPaths.at(i)->setPen(pen);
}
}
void Track::plot(QPainter *painter, const QRectF &target)
@ -145,11 +214,11 @@ void Track::plot(QPainter *painter, const QRectF &target)
adj = orig.adjusted(0, -diff/2, 0, diff/2);
}
for (int i = 0; i < _markers.size(); i++)
_markers.at(i)->setVisible(false);
showMarkers(false);
setTrackLineWidth(0);
_scene->render(painter, target, adj, Qt::KeepAspectRatioByExpanding);
for (int i = 0; i < _markers.size(); i++)
_markers.at(i)->setVisible(true);
setTrackLineWidth(TRACK_WIDTH * _scale);
showMarkers(true);
}
enum QPrinter::Orientation Track::orientation() const
@ -193,3 +262,35 @@ void Track::movePositionMarker(qreal val)
_markers.at(i)->setPos(pos);
}
}
void Track::drawBackground(QPainter *painter, const QRectF &rect)
{
if (_tracks.isEmpty() || !_map) {
painter->fillRect(rect, Qt::white);
return;
}
painter->setWorldMatrixEnabled(false);
QRectF rr(rect.topLeft() * _scale, rect.size());
QPoint tile = mercator2tile(QPointF(rr.topLeft().x(), -rr.topLeft().y()),
_zoom);
QPointF tm = tile2mercator(tile, _zoom);
QPoint tl = mapFromScene(QPointF(tm.x() / _scale, -tm.y() / _scale));
QList<Tile> tiles;
for (int i = 0; i <= rr.size().width() / TILE_SIZE + 1; i++) {
for (int j = 0; j <= rr.size().height() / TILE_SIZE + 1; j++) {
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
}
}
_map->loadTiles(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPoint tp(tl.x() + (t.xy().rx() - tile.rx()) * TILE_SIZE,
tl.y() + (t.xy().ry() - tile.ry()) * TILE_SIZE);
painter->drawPixmap(tp, t.pixmap());
}
}

View File

@ -8,6 +8,7 @@
#include <QPrinter>
#include "poi.h"
#include "gpx.h"
#include "map.h"
#include "colorshop.h"
@ -23,29 +24,45 @@ public:
~Track();
void loadGPX(const GPX &gpx);
void loadPOI(const POI &poi);
void loadPOI(const POI &poi);
void clearPOI();
void clear();
void setMap(Map *map);
void plot(QPainter *painter, const QRectF &target);
enum QPrinter::Orientation orientation() const;
public slots:
void movePositionMarker(qreal val);
private slots:
void redraw();
private:
QTransform transform() const;
qreal trackScale() const;
qreal mapScale() const;
void rescale(qreal scale);
void showMarkers(bool show);
void setTrackLineWidth(qreal width);
void wheelEvent(QWheelEvent *event);
void drawBackground(QPainter *painter, const QRectF &rect);
QGraphicsScene *_scene;
QList<QVector<QPointF> > _tracks;
QList<QGraphicsPathItem*> _trackPaths;
QList<MarkerItem*> _markers;
QHash<Entry, POIItem*> _pois;
Map *_map;
ColorShop _colorShop;
qreal _maxLen;
qreal _scale;
int _zoom;
};
#endif // TRACK_H