1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/track.cpp

400 lines
9.5 KiB
C++
Raw Normal View History

2015-10-05 01:43:48 +02:00
#include <cmath>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPainterPath>
#include <QWheelEvent>
#include "poiitem.h"
#include "markeritem.h"
2016-01-14 00:37:51 +01:00
#include "scaleitem.h"
2015-11-23 02:37:08 +01:00
#include "ll.h"
2015-10-05 01:43:48 +02:00
#include "track.h"
2016-01-14 00:37:51 +01:00
2016-01-19 09:04:54 +01:00
#define MARGIN 10.0
#define TRACK_WIDTH 3
#define SCALE_OFFSET_X 7
#define SCALE_OFFSET_Y 15
2015-11-23 02:37:08 +01:00
2015-10-05 01:43:48 +02:00
Track::Track(QWidget *parent)
: QGraphicsView(parent)
{
_scene = new QGraphicsScene(this);
setScene(_scene);
2015-11-23 02:37:08 +01:00
setCacheMode(QGraphicsView::CacheBackground);
2015-11-25 23:17:39 +01:00
setDragMode(QGraphicsView::ScrollHandDrag);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2015-10-05 01:43:48 +02:00
2016-01-14 00:37:51 +01:00
_mapScale = new ScaleItem();
_mapScale->setZValue(2.0);
2015-11-23 02:37:08 +01:00
_zoom = -1;
_scale = 1.0;
_map = 0;
2015-10-05 01:43:48 +02:00
_maxLen = 0;
}
Track::~Track()
{
delete _scene;
}
2015-10-17 12:08:30 +02:00
void Track::loadGPX(const GPX &gpx)
2015-10-05 01:43:48 +02:00
{
2015-10-17 12:08:30 +02:00
QVector<QPointF> track;
2015-10-05 01:43:48 +02:00
QPainterPath path;
QGraphicsPathItem *pi;
MarkerItem *mi;
QColor color = _colorShop.color();
2015-11-23 02:37:08 +01:00
qreal prevScale = _scale;
2015-10-05 01:43:48 +02:00
2015-10-17 12:08:30 +02:00
gpx.track(track);
2015-10-05 01:43:48 +02:00
if (track.size() < 2)
return;
_tracks.append(track);
path.moveTo(track.at(0).x(), -track.at(0).y());
for (int i = 1; i < track.size(); i++)
path.lineTo(track.at(i).x(), -track.at(i).y());
_maxLen = qMax(path.length(), _maxLen);
pi = new QGraphicsPathItem(path);
2015-11-23 02:37:08 +01:00
_trackPaths.append(pi);
_zoom = scale2zoom(trackScale());
_scale = mapScale();
2015-10-22 10:27:27 +02:00
QBrush brush(color, Qt::SolidPattern);
2015-11-23 02:37:08 +01:00
QPen pen(brush, TRACK_WIDTH * _scale);
2015-10-22 10:27:27 +02:00
pi->setPen(pen);
2015-11-23 02:37:08 +01:00
pi->setScale(1.0/_scale);
2015-10-05 01:43:48 +02:00
_scene->addItem(pi);
2015-11-23 02:37:08 +01:00
mi = new MarkerItem(pi);
2015-10-05 01:43:48 +02:00
_markers.append(mi);
2015-11-23 02:37:08 +01:00
mi->setPos(pi->path().pointAtPercent(0));
mi->setScale(_scale);
2015-10-05 01:43:48 +02:00
2015-11-23 02:37:08 +01:00
if (_trackPaths.size() > 1 && prevScale != _scale)
rescale(_scale);
2015-12-06 00:51:02 +01:00
QRectF br = trackBoundingRect();
QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE);
_scene->setSceneRect(ba);
centerOn(ba.center());
2016-01-14 00:37:51 +01:00
if (_mapScale->scene() != _scene)
_scene->addItem(_mapScale);
_mapScale->setLatitude(track.at(track.size() / 2).y());
_mapScale->setZoom(_zoom);
2015-12-06 00:51:02 +01:00
}
QRectF Track::trackBoundingRect() const
{
qreal bottom, top, left, right;
bottom = _trackPaths.at(0)->sceneBoundingRect().bottom();
top = _trackPaths.at(0)->sceneBoundingRect().top();
left = _trackPaths.at(0)->sceneBoundingRect().left();
right = _trackPaths.at(0)->sceneBoundingRect().right();
for (int i = 1; i < _trackPaths.size(); i++) {
bottom = qMax(bottom, _trackPaths.at(i)->sceneBoundingRect().bottom());
top = qMin(top, _trackPaths.at(i)->sceneBoundingRect().top());
right = qMax(right, _trackPaths.at(i)->sceneBoundingRect().right());
left = qMin(left, _trackPaths.at(i)->sceneBoundingRect().left());
}
return QRectF(QPointF(left, top), QPointF(right, bottom));
2015-11-23 02:37:08 +01:00
}
qreal Track::trackScale() const
{
qreal bottom, top, left, right;
2015-11-25 00:10:11 +01:00
bottom = _trackPaths.at(0)->path().boundingRect().bottom();
top = _trackPaths.at(0)->path().boundingRect().top();
left = _trackPaths.at(0)->path().boundingRect().left();
right = _trackPaths.at(0)->path().boundingRect().right();
2015-11-23 02:37:08 +01:00
for (int i = 1; i < _trackPaths.size(); i++) {
2015-11-25 00:10:11 +01:00
bottom = qMax(bottom, _trackPaths.at(i)->path().boundingRect().bottom());
top = qMin(top, _trackPaths.at(i)->path().boundingRect().top());
right = qMax(right, _trackPaths.at(i)->path().boundingRect().right());
left = qMin(left, _trackPaths.at(i)->path().boundingRect().left());
2015-10-05 01:43:48 +02:00
}
2015-11-23 02:37:08 +01:00
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);
2015-10-05 01:43:48 +02:00
}
2015-11-23 02:37:08 +01:00
void Track::rescale(qreal scale)
2015-10-05 01:43:48 +02:00
{
2015-11-23 02:37:08 +01:00
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);
}
2015-10-05 01:43:48 +02:00
2015-11-25 23:17:39 +01:00
QHash<Entry, POIItem*>::const_iterator it, jt;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
2015-11-23 02:37:08 +01:00
it.value()->setPos(QPointF(it.value()->entry().coordinates.x()
* 1.0/scale, -it.value()->entry().coordinates.y() * 1.0/scale));
2015-11-25 23:17:39 +01:00
it.value()->show();
}
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()
&& it.value()->collidesWithItem(jt.value()))
jt.value()->hide();
}
}
2015-11-23 02:37:08 +01:00
_scale = scale;
2015-10-05 01:43:48 +02:00
}
void Track::loadPOI(const POI &poi)
{
QHash<Entry, POIItem*>::const_iterator it,jt;
2015-12-06 00:51:02 +01:00
if (!_tracks.size())
return;
2015-10-05 01:43:48 +02:00
for (int i = 0; i < _tracks.size(); i++) {
QVector<Entry> p = poi.points(_tracks.at(i));
for (int i = 0; i < p.size(); i++) {
if (_pois.contains(p.at(i)))
continue;
2015-11-23 02:37:08 +01:00
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);
2015-10-05 01:43:48 +02:00
pi->setZValue(1);
_scene->addItem(pi);
_pois.insert(p.at(i), pi);
}
}
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()
&& it.value()->collidesWithItem(jt.value()))
jt.value()->hide();
}
}
2015-11-23 02:37:08 +01:00
}
void Track::setMap(Map *map)
{
_map = map;
if (_map)
connect(_map, SIGNAL(loaded()), this, SLOT(redraw()));
resetCachedContent();
}
2016-01-14 00:37:51 +01:00
void Track::setUnits(enum Units units)
{
_mapScale->setUnits(units);
}
2015-11-23 02:37:08 +01:00
void Track::redraw()
{
resetCachedContent();
2015-10-05 01:43:48 +02:00
}
void Track::wheelEvent(QWheelEvent *event)
{
if (_tracks.isEmpty())
return;
2015-11-25 23:17:39 +01:00
QPointF pos = mapToScene(event->pos());
qreal scale = _scale;
2015-11-23 02:37:08 +01:00
_zoom = (event->delta() > 0) ?
qMin(_zoom + 1, ZOOM_MAX) : qMax(_zoom - 1, ZOOM_MIN);
2015-10-05 01:43:48 +02:00
2015-11-23 02:37:08 +01:00
rescale(mapScale());
2015-12-06 00:51:02 +01:00
QRectF br = trackBoundingRect();
QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE);
_scene->setSceneRect(ba);
if (br.width() < viewport()->size().width()
&& br.height() < viewport()->size().height())
centerOn(br.center());
else
centerOn(pos * scale/_scale);
2016-01-14 00:37:51 +01:00
_mapScale->setZoom(_zoom);
2015-11-23 02:37:08 +01:00
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);
}
2015-10-05 01:43:48 +02:00
}
void Track::plot(QPainter *painter, const QRectF &target)
{
2016-01-14 00:37:51 +01:00
_scene->removeItem(_mapScale);
2015-12-06 00:51:02 +01:00
QRectF orig = _scene->itemsBoundingRect();
2015-10-05 01:43:48 +02:00
QRectF adj;
qreal ratio, diff;
if (target.width()/target.height() > orig.width()/orig.height()) {
ratio = target.width()/target.height();
diff = qAbs((orig.height() * ratio) - orig.width());
adj = orig.adjusted(-diff/2, 0, diff/2, 0);
} else {
ratio = target.height()/target.width();
diff = fabs((orig.width() * ratio) - orig.height());
adj = orig.adjusted(0, -diff/2, 0, diff/2);
}
2015-11-23 02:37:08 +01:00
showMarkers(false);
setTrackLineWidth(0);
2015-10-05 01:43:48 +02:00
_scene->render(painter, target, adj, Qt::KeepAspectRatioByExpanding);
2015-11-23 02:37:08 +01:00
setTrackLineWidth(TRACK_WIDTH * _scale);
showMarkers(true);
2016-01-14 00:37:51 +01:00
_scene->addItem(_mapScale);
2015-10-05 01:43:48 +02:00
}
enum QPrinter::Orientation Track::orientation() const
{
return (sceneRect().width() > sceneRect().height())
? QPrinter::Landscape : QPrinter::Portrait;
}
void Track::clearPOI()
{
QHash<Entry, POIItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
_scene->removeItem(it.value());
delete it.value();
}
_pois.clear();
}
void Track::clear()
{
2016-01-14 00:37:51 +01:00
if (_mapScale->scene() == _scene)
_scene->removeItem(_mapScale);
2015-10-05 01:43:48 +02:00
_pois.clear();
_tracks.clear();
_trackPaths.clear();
_markers.clear();
_scene->clear();
_colorShop.reset();
_maxLen = 0;
_scene->setSceneRect(0, 0, 0, 0);
}
void Track::movePositionMarker(qreal val)
{
for (int i = 0; i < _trackPaths.size(); i++) {
qreal f = _maxLen / _trackPaths.at(i)->path().length();
QPointF pos = _trackPaths.at(i)->path().pointAtPercent(qMin(val * f,
1.0));
_markers.at(i)->setPos(pos);
}
}
2015-11-23 02:37:08 +01:00
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());
}
}
2015-12-20 09:33:40 +01:00
void Track::resizeEvent(QResizeEvent *e)
{
if (_tracks.isEmpty())
return;
QRectF br = trackBoundingRect();
QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE);
if (ba.width() < e->size().width()) {
qreal diff = e->size().width() - ba.width();
ba.adjust(-diff/2, 0, diff/2, 0);
}
if (ba.height() < e->size().height()) {
qreal diff = e->size().height() - ba.height();
ba.adjust(0, -diff/2, 0, diff/2);
}
_scene->setSceneRect(ba);
centerOn(br.center());
resetCachedContent();
}
2016-01-14 00:37:51 +01:00
void Track::paintEvent(QPaintEvent *e)
{
2016-01-19 09:04:54 +01:00
QPointF scenePos = mapToScene(rect().bottomLeft() + QPoint(SCALE_OFFSET_X,
-SCALE_OFFSET_Y));
2016-01-14 00:37:51 +01:00
_mapScale->setPos(scenePos);
QGraphicsView::paintEvent(e);
}