2016-02-11 20:58:52 +01:00
|
|
|
#include <QGraphicsView>
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
#include <QWheelEvent>
|
2016-12-06 01:48:26 +01:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
|
|
#include <QGLWidget>
|
|
|
|
#else // QT 5
|
|
|
|
#include <QOpenGLWidget>
|
|
|
|
#endif // QT 5
|
|
|
|
#include <QSysInfo>
|
2016-10-24 00:21:40 +02:00
|
|
|
#include "rd.h"
|
2016-02-12 10:23:14 +01:00
|
|
|
#include "poi.h"
|
2016-10-23 11:09:20 +02:00
|
|
|
#include "data.h"
|
2016-02-12 10:09:17 +01:00
|
|
|
#include "map.h"
|
2016-07-28 00:23:22 +02:00
|
|
|
#include "trackitem.h"
|
2016-08-09 01:16:19 +02:00
|
|
|
#include "routeitem.h"
|
2016-02-19 21:34:55 +01:00
|
|
|
#include "waypointitem.h"
|
2016-02-11 20:58:52 +01:00
|
|
|
#include "scaleitem.h"
|
2016-09-26 21:01:58 +02:00
|
|
|
#include "pathview.h"
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
|
2016-10-24 00:21:40 +02:00
|
|
|
#define ZOOM_MAX 18
|
|
|
|
#define ZOOM_MIN 3
|
|
|
|
#define MARGIN 10.0
|
|
|
|
#define SCALE_OFFSET 7
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QPointF tile2mercator(const QPoint &tile, int z)
|
|
|
|
{
|
|
|
|
Coordinates m;
|
|
|
|
|
|
|
|
m.setLon(tile.x() / pow(2.0, z) * 360.0 - 180);
|
|
|
|
qreal n = M_PI - 2.0 * M_PI * tile.y() / pow(2.0, z);
|
|
|
|
m.setLat(rad2deg(atan(0.5 * (exp(n) - exp(-n)))));
|
|
|
|
|
|
|
|
return m.toMercator();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int scale2zoom(qreal scale)
|
|
|
|
{
|
|
|
|
int zoom = (int)log2(360.0/(scale * (qreal)Tile::size()));
|
|
|
|
|
|
|
|
if (zoom < ZOOM_MIN)
|
|
|
|
return ZOOM_MIN;
|
|
|
|
if (zoom > ZOOM_MAX)
|
|
|
|
return ZOOM_MAX;
|
|
|
|
|
|
|
|
return zoom;
|
|
|
|
}
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal mapScale(int zoom)
|
|
|
|
{
|
|
|
|
return ((360.0/(qreal)(1<<zoom))/(qreal)Tile::size());
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRectF qrectf(const QPointF &p1, const QPointF &p2)
|
|
|
|
{
|
|
|
|
return QRectF(QPointF(qMin(p1.x(), p2.x()), qMin(p1.y(), p2.y())),
|
|
|
|
QPointF(qMax(p1.x(), p2.x()), qMax(p1.y(), p2.y())));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unite(QRectF &rect, const QPointF &p)
|
|
|
|
{
|
|
|
|
if (p.x() < rect.left())
|
|
|
|
rect.setLeft(p.x());
|
|
|
|
if (p.x() > rect.right())
|
|
|
|
rect.setRight(p.x());
|
|
|
|
if (p.y() > rect.bottom())
|
|
|
|
rect.setBottom(p.y());
|
|
|
|
if (p.y() < rect.top())
|
|
|
|
rect.setTop(p.y());
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRectF scaled(const QRectF &rect, qreal factor)
|
|
|
|
{
|
|
|
|
return QRectF(QPointF(rect.left() * factor, rect.top() * factor),
|
|
|
|
QSizeF(rect.width() * factor, rect.height() * factor));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
PathView::PathView(QWidget *parent)
|
2016-02-11 20:58:52 +01:00
|
|
|
: QGraphicsView(parent)
|
|
|
|
{
|
|
|
|
_scene = new QGraphicsScene(this);
|
|
|
|
setScene(_scene);
|
|
|
|
setCacheMode(QGraphicsView::CacheBackground);
|
|
|
|
setDragMode(QGraphicsView::ScrollHandDrag);
|
|
|
|
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
|
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
2016-12-06 01:48:26 +01:00
|
|
|
setRenderHint(QPainter::Antialiasing, true);
|
2016-10-04 10:16:46 +02:00
|
|
|
setAcceptDrops(false);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
_mapScale = new ScaleItem();
|
|
|
|
_mapScale->setZValue(2.0);
|
|
|
|
|
2016-03-15 01:20:24 +01:00
|
|
|
_zoom = ZOOM_MAX;
|
2016-02-11 20:58:52 +01:00
|
|
|
_map = 0;
|
2016-10-08 14:53:10 +02:00
|
|
|
_poi = 0;
|
2016-05-19 01:10:40 +02:00
|
|
|
|
2016-07-25 19:32:36 +02:00
|
|
|
_units = Metric;
|
2016-08-09 01:16:19 +02:00
|
|
|
|
|
|
|
_showTracks = true;
|
|
|
|
_showRoutes = true;
|
|
|
|
_showWaypoints = true;
|
|
|
|
_showWaypointLabels = true;
|
2016-10-08 14:53:10 +02:00
|
|
|
_showPOI = true;
|
2016-08-09 01:16:19 +02:00
|
|
|
_showPOILabels = true;
|
|
|
|
_overlapPOIs = true;
|
2016-08-09 10:47:49 +02:00
|
|
|
_showRouteWaypoints = true;
|
2016-12-06 01:48:26 +01:00
|
|
|
_trackWidth = 3;
|
|
|
|
_routeWidth = 3;
|
|
|
|
_trackStyle = Qt::SolidLine;
|
|
|
|
_routeStyle = Qt::DashLine;
|
2016-08-09 01:16:19 +02:00
|
|
|
|
|
|
|
_plot = false;
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
PathView::~PathView()
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-05-12 09:03:05 +02:00
|
|
|
if (_mapScale->scene() != _scene)
|
|
|
|
delete _mapScale;
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
PathItem *PathView::addTrack(const Track &track)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-07-28 00:23:22 +02:00
|
|
|
if (track.isNull()) {
|
2016-12-06 01:48:26 +01:00
|
|
|
_palette.nextColor();
|
2016-09-19 00:56:10 +02:00
|
|
|
return 0;
|
2016-03-23 20:49:40 +01:00
|
|
|
}
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-08-09 01:16:19 +02:00
|
|
|
TrackItem *ti = new TrackItem(track);
|
|
|
|
_tracks.append(ti);
|
2016-11-11 17:58:18 +01:00
|
|
|
_tr |= ti->path().boundingRect();
|
|
|
|
_zoom = scale2zoom(contentsScale());
|
|
|
|
ti->setScale(1.0/mapScale(_zoom));
|
2016-12-06 01:48:26 +01:00
|
|
|
ti->setColor(_palette.nextColor());
|
|
|
|
ti->setWidth(_trackWidth);
|
|
|
|
ti->setStyle(_trackStyle);
|
2016-08-09 01:16:19 +02:00
|
|
|
ti->setVisible(_showTracks);
|
|
|
|
_scene->addItem(ti);
|
2016-09-19 00:56:10 +02:00
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
if (_poi)
|
|
|
|
addPOI(_poi->points(ti));
|
|
|
|
|
2016-09-19 00:56:10 +02:00
|
|
|
return ti;
|
2016-03-03 09:15:56 +01:00
|
|
|
}
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
PathItem *PathView::addRoute(const Route &route)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
if (route.isNull()) {
|
2016-12-06 01:48:26 +01:00
|
|
|
_palette.nextColor();
|
2016-09-19 00:56:10 +02:00
|
|
|
return 0;
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
RouteItem *ri = new RouteItem(route);
|
|
|
|
_routes.append(ri);
|
2016-11-11 17:58:18 +01:00
|
|
|
_rr |= ri->path().boundingRect();
|
|
|
|
_zoom = scale2zoom(contentsScale());
|
|
|
|
ri->setScale(1.0/mapScale(_zoom));
|
2016-12-06 01:48:26 +01:00
|
|
|
ri->setColor(_palette.nextColor());
|
|
|
|
ri->setWidth(_routeWidth);
|
|
|
|
ri->setStyle(_routeStyle);
|
2016-08-09 01:16:19 +02:00
|
|
|
ri->setVisible(_showRoutes);
|
2016-08-09 10:47:49 +02:00
|
|
|
ri->showWaypoints(_showRouteWaypoints);
|
2016-08-09 23:08:49 +02:00
|
|
|
ri->showWaypointLabels(_showWaypointLabels);
|
2016-08-09 01:16:19 +02:00
|
|
|
_scene->addItem(ri);
|
2016-09-19 00:56:10 +02:00
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
if (_poi)
|
|
|
|
addPOI(_poi->points(ri));
|
|
|
|
|
2016-09-19 00:56:10 +02:00
|
|
|
return ri;
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::addWaypoints(const QList<Waypoint> &waypoints)
|
2016-03-15 01:20:24 +01:00
|
|
|
{
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal scale = mapScale(_zoom);
|
|
|
|
|
2016-03-15 01:20:24 +01:00
|
|
|
for (int i = 0; i < waypoints.count(); i++) {
|
2016-03-19 09:06:43 +01:00
|
|
|
const Waypoint &w = waypoints.at(i);
|
2016-03-15 01:20:24 +01:00
|
|
|
|
2016-07-28 00:23:22 +02:00
|
|
|
WaypointItem *wi = new WaypointItem(w);
|
2016-11-11 17:58:18 +01:00
|
|
|
wi->setScale(1.0/scale);
|
2016-03-15 01:20:24 +01:00
|
|
|
wi->setZValue(1);
|
2016-08-09 01:16:19 +02:00
|
|
|
wi->showLabel(_showWaypointLabels);
|
|
|
|
wi->setVisible(_showWaypoints);
|
2016-03-15 01:20:24 +01:00
|
|
|
_scene->addItem(wi);
|
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
if (_wr.isNull()) {
|
|
|
|
if (_wp.isNull())
|
|
|
|
_wp = wi->coordinates();
|
|
|
|
else
|
|
|
|
_wr = qrectf(_wp, wi->coordinates());
|
|
|
|
} else
|
2016-11-11 17:58:18 +01:00
|
|
|
unite(_wr, wi->coordinates());
|
|
|
|
|
2016-07-28 00:23:22 +02:00
|
|
|
_waypoints.append(wi);
|
2016-03-15 01:20:24 +01:00
|
|
|
}
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
if (_poi)
|
|
|
|
addPOI(_poi->points(waypoints));
|
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
_zoom = scale2zoom(contentsScale());
|
2016-03-15 01:20:24 +01:00
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
QList<PathItem *> PathView::loadData(const Data &data)
|
2016-03-03 09:15:56 +01:00
|
|
|
{
|
2016-09-19 00:56:10 +02:00
|
|
|
QList<PathItem *> paths;
|
2016-03-15 01:20:24 +01:00
|
|
|
int zoom = _zoom;
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-09-27 10:19:39 +02:00
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
for (int i = 0; i < data.tracks().count(); i++)
|
|
|
|
paths.append(addTrack(*(data.tracks().at(i))));
|
|
|
|
for (int i = 0; i < data.routes().count(); i++)
|
|
|
|
paths.append(addRoute(*(data.routes().at(i))));
|
|
|
|
addWaypoints(data.waypoints());
|
2016-03-15 01:20:24 +01:00
|
|
|
|
2016-08-09 01:16:19 +02:00
|
|
|
if (_tracks.empty() && _routes.empty() && _waypoints.empty())
|
2016-09-19 00:56:10 +02:00
|
|
|
return paths;
|
2016-03-15 01:20:24 +01:00
|
|
|
|
2016-09-26 10:09:56 +02:00
|
|
|
if ((_tracks.size() + _routes.size() > 1 && _zoom < zoom)
|
2016-07-28 00:23:22 +02:00
|
|
|
|| (_waypoints.size() && _zoom < zoom))
|
2016-11-11 17:58:18 +01:00
|
|
|
rescale(_zoom);
|
2016-10-08 14:53:10 +02:00
|
|
|
else
|
|
|
|
updatePOIVisibility();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
QRectF sr = contentsSceneRect();
|
|
|
|
_scene->setSceneRect(sr);
|
|
|
|
centerOn(sr.center());
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
_mapScale->setZoom(_zoom, -(sr.center().ry() * mapScale(_zoom)));
|
2016-03-03 09:15:56 +01:00
|
|
|
if (_mapScale->scene() != _scene)
|
|
|
|
_scene->addItem(_mapScale);
|
2016-09-19 00:56:10 +02:00
|
|
|
|
|
|
|
return paths;
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal PathView::contentsScale() const
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-11-11 17:58:18 +01:00
|
|
|
QRectF br = _tr | _rr | _wr;
|
2016-03-15 01:20:24 +01:00
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
if (br.isNull())
|
2016-03-15 01:20:24 +01:00
|
|
|
return mapScale(ZOOM_MAX);
|
|
|
|
|
|
|
|
QPointF sc(br.width() / (viewport()->width() - MARGIN/2),
|
|
|
|
br.height() / (viewport()->height() - MARGIN/2));
|
|
|
|
|
|
|
|
return qMax(sc.x(), sc.y());
|
|
|
|
}
|
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
QRectF PathView::contentsSceneRect() const
|
|
|
|
{
|
|
|
|
qreal scale = mapScale(_zoom);
|
|
|
|
QRectF br = scaled(_tr | _rr | _wr, 1.0/scale);
|
|
|
|
|
|
|
|
if (br.isNull())
|
|
|
|
return QRectF(QPointF(_wp.x() / scale - Tile::size()/2,
|
|
|
|
_wp.y() /scale - Tile::size()/2), QSizeF(Tile::size(), Tile::size()));
|
|
|
|
else
|
|
|
|
return br.adjusted(-Tile::size(), -Tile::size(), Tile::size(),
|
|
|
|
Tile::size());
|
|
|
|
}
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
void PathView::updatePOIVisibility()
|
2016-08-02 20:46:22 +02:00
|
|
|
{
|
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it, jt;
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
if (!_showPOI)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
|
|
|
|
it.value()->show();
|
|
|
|
|
|
|
|
if (!_overlapPOIs) {
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
|
|
|
|
for (jt = _pois.constBegin(); jt != _pois.constEnd(); jt++) {
|
|
|
|
if (it.value()->isVisible() && jt.value()->isVisible()
|
|
|
|
&& it != jt && it.value()->collidesWithItem(jt.value()))
|
|
|
|
jt.value()->hide();
|
|
|
|
}
|
2016-08-02 20:46:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
void PathView::rescale(int zoom)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-11-11 17:58:18 +01:00
|
|
|
_zoom = zoom;
|
|
|
|
qreal scale = mapScale(zoom);
|
2016-10-08 14:53:10 +02:00
|
|
|
|
2016-08-09 01:16:19 +02:00
|
|
|
for (int i = 0; i < _tracks.size(); i++)
|
|
|
|
_tracks.at(i)->setScale(1.0/scale);
|
|
|
|
|
|
|
|
for (int i = 0; i < _routes.size(); i++)
|
|
|
|
_routes.at(i)->setScale(1.0/scale);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-07-28 00:23:22 +02:00
|
|
|
for (int i = 0; i < _waypoints.size(); i++)
|
2016-08-02 00:28:56 +02:00
|
|
|
_waypoints.at(i)->setScale(1.0/scale);
|
2016-03-15 01:20:24 +01:00
|
|
|
|
2016-08-02 20:46:22 +02:00
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it;
|
2016-10-08 14:53:10 +02:00
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
|
2016-08-02 00:28:56 +02:00
|
|
|
it.value()->setScale(1.0/scale);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
updatePOIVisibility();
|
|
|
|
}
|
|
|
|
|
2016-12-06 01:48:26 +01:00
|
|
|
void PathView::setPalette(const Palette &palette)
|
|
|
|
{
|
|
|
|
_palette = palette;
|
|
|
|
_palette.reset();
|
|
|
|
|
|
|
|
for (int i = 0; i < _tracks.count(); i++)
|
|
|
|
_tracks.at(i)->setColor(_palette.nextColor());
|
|
|
|
for (int i = 0; i < _routes.count(); i++)
|
|
|
|
_routes.at(i)->setColor(_palette.nextColor());
|
|
|
|
}
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
void PathView::setPOI(POI *poi)
|
|
|
|
{
|
2016-10-09 23:46:30 +02:00
|
|
|
if (_poi)
|
2016-10-11 00:19:42 +02:00
|
|
|
disconnect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
2016-10-09 23:46:30 +02:00
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
_poi = poi;
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-10-09 23:46:30 +02:00
|
|
|
if (_poi)
|
2016-10-11 00:19:42 +02:00
|
|
|
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
2016-10-09 23:58:24 +02:00
|
|
|
|
|
|
|
updatePOI();
|
2016-10-08 14:53:10 +02:00
|
|
|
}
|
|
|
|
|
2016-10-09 23:46:30 +02:00
|
|
|
void PathView::updatePOI()
|
2016-10-08 14:53:10 +02:00
|
|
|
{
|
2016-10-09 23:46:30 +02:00
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it;
|
|
|
|
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
|
|
|
|
_scene->removeItem(it.value());
|
|
|
|
delete it.value();
|
|
|
|
}
|
|
|
|
_pois.clear();
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
if (!_poi)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = 0; i < _tracks.size(); i++)
|
|
|
|
addPOI(_poi->points(_tracks.at(i)));
|
|
|
|
for (int i = 0; i < _routes.size(); i++)
|
|
|
|
addPOI(_poi->points(_routes.at(i)));
|
|
|
|
addPOI(_poi->points(_waypoints));
|
|
|
|
|
|
|
|
updatePOIVisibility();
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::addPOI(const QVector<Waypoint> &waypoints)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal scale = mapScale(_zoom);
|
|
|
|
|
2016-03-17 20:56:40 +01:00
|
|
|
for (int i = 0; i < waypoints.size(); i++) {
|
2016-03-19 09:06:43 +01:00
|
|
|
const Waypoint &w = waypoints.at(i);
|
|
|
|
|
|
|
|
if (_pois.contains(w))
|
2016-03-17 20:56:40 +01:00
|
|
|
continue;
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-07-28 00:23:22 +02:00
|
|
|
WaypointItem *pi = new WaypointItem(w);
|
2016-11-11 17:58:18 +01:00
|
|
|
pi->setScale(1.0/scale);
|
2016-03-17 20:56:40 +01:00
|
|
|
pi->setZValue(1);
|
2016-08-09 01:16:19 +02:00
|
|
|
pi->showLabel(_showPOILabels);
|
2016-10-08 14:53:10 +02:00
|
|
|
pi->setVisible(_showPOI);
|
2016-03-17 20:56:40 +01:00
|
|
|
_scene->addItem(pi);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-03-19 09:06:43 +01:00
|
|
|
_pois.insert(w, pi);
|
2016-03-17 20:56:40 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::setMap(Map *map)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-10-09 23:58:24 +02:00
|
|
|
if (_map)
|
|
|
|
disconnect(_map, SIGNAL(loaded()), this, SLOT(redraw()));
|
|
|
|
|
2016-02-11 20:58:52 +01:00
|
|
|
_map = map;
|
2016-10-09 23:58:24 +02:00
|
|
|
|
2016-02-11 20:58:52 +01:00
|
|
|
if (_map)
|
2016-10-09 23:58:24 +02:00
|
|
|
connect(_map, SIGNAL(loaded()), this, SLOT(redraw()));
|
|
|
|
|
2016-02-11 20:58:52 +01:00
|
|
|
resetCachedContent();
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::setUnits(enum Units units)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-07-25 19:32:36 +02:00
|
|
|
_units = units;
|
|
|
|
|
2016-02-11 20:58:52 +01:00
|
|
|
_mapScale->setUnits(units);
|
2016-07-25 19:32:36 +02:00
|
|
|
|
2016-08-09 01:16:19 +02:00
|
|
|
for (int i = 0; i < _tracks.count(); i++)
|
|
|
|
_tracks[i]->setUnits(units);
|
2016-08-30 21:26:28 +02:00
|
|
|
for (int i = 0; i < _routes.count(); i++)
|
|
|
|
_routes[i]->setUnits(units);
|
2016-08-02 00:28:56 +02:00
|
|
|
for (int i = 0; i < _waypoints.size(); i++)
|
|
|
|
_waypoints.at(i)->setUnits(units);
|
|
|
|
|
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it;
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
|
|
|
|
it.value()->setUnits(units);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::redraw()
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
|
|
|
resetCachedContent();
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::rescale()
|
2016-04-05 09:10:19 +02:00
|
|
|
{
|
2016-11-12 09:09:42 +01:00
|
|
|
int zoom = scale2zoom(contentsScale());
|
|
|
|
|
|
|
|
if (zoom != _zoom) {
|
|
|
|
rescale(zoom);
|
|
|
|
_mapScale->setZoom(zoom);
|
|
|
|
}
|
2016-04-05 09:10:19 +02:00
|
|
|
}
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
void PathView::zoom(int z, const QPoint &pos)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-08-09 01:16:19 +02:00
|
|
|
if (_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty())
|
2016-02-11 20:58:52 +01:00
|
|
|
return;
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
QPoint offset = pos - viewport()->rect().center();
|
|
|
|
QPointF spos = mapToScene(pos);
|
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal os = mapScale(_zoom);
|
2016-07-21 22:39:53 +02:00
|
|
|
_zoom = z;
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
rescale(_zoom);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
QRectF sr = contentsSceneRect();
|
|
|
|
_scene->setSceneRect(sr);
|
|
|
|
|
|
|
|
if (sr.width() < viewport()->size().width()
|
|
|
|
&& sr.height() < viewport()->size().height())
|
|
|
|
centerOn(sr.center());
|
2016-02-11 20:58:52 +01:00
|
|
|
else
|
2016-11-11 23:48:38 +01:00
|
|
|
centerOn((spos * (os/mapScale(_zoom))) - offset);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
_mapScale->setZoom(_zoom);
|
|
|
|
|
|
|
|
resetCachedContent();
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::wheelEvent(QWheelEvent *event)
|
2016-07-21 22:39:53 +02:00
|
|
|
{
|
2016-10-29 21:22:26 +02:00
|
|
|
int z = (event->delta() > 0) ?
|
|
|
|
qMin(_zoom + 1, ZOOM_MAX) : qMax(_zoom - 1, ZOOM_MIN);
|
|
|
|
|
|
|
|
zoom(z, event->pos());
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathView::mouseDoubleClickEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
if (event->button() != Qt::LeftButton && event->button() != Qt::RightButton)
|
2016-07-21 22:39:53 +02:00
|
|
|
return;
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
int z = (event->button() == Qt::LeftButton) ?
|
2016-07-21 22:39:53 +02:00
|
|
|
qMin(_zoom + 1, ZOOM_MAX) : qMax(_zoom - 1, ZOOM_MIN);
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
zoom(z, event->pos());
|
2016-07-21 22:39:53 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::keyPressEvent(QKeyEvent *event)
|
2016-07-21 22:39:53 +02:00
|
|
|
{
|
|
|
|
int z = -1;
|
|
|
|
|
|
|
|
if (event->matches(QKeySequence::ZoomIn))
|
|
|
|
z = qMin(_zoom + 1, ZOOM_MAX);
|
|
|
|
if (event->matches(QKeySequence::ZoomOut))
|
|
|
|
z = qMax(_zoom - 1, ZOOM_MIN);
|
|
|
|
|
|
|
|
if (z >= 0)
|
2016-10-29 21:22:26 +02:00
|
|
|
zoom(z, QRect(QPoint(), size()).center());
|
2016-07-21 22:39:53 +02:00
|
|
|
else
|
|
|
|
QWidget::keyPressEvent(event);
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::plot(QPainter *painter, const QRectF &target)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-05-19 01:10:40 +02:00
|
|
|
QRect orig, adj;
|
2016-02-11 20:58:52 +01:00
|
|
|
qreal ratio, diff;
|
|
|
|
|
2016-05-20 22:44:03 +02:00
|
|
|
|
2016-05-15 13:19:07 +02:00
|
|
|
orig = viewport()->rect();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-05-27 22:45:58 +02:00
|
|
|
if (orig.height() * (target.width() / target.height()) - orig.width() < 0) {
|
2016-02-11 20:58:52 +01:00
|
|
|
ratio = target.height()/target.width();
|
2016-05-27 22:45:58 +02:00
|
|
|
diff = (orig.width() * ratio) - orig.height();
|
2016-02-11 20:58:52 +01:00
|
|
|
adj = orig.adjusted(0, -diff/2, 0, diff/2);
|
2016-05-27 22:45:58 +02:00
|
|
|
} else {
|
|
|
|
ratio = target.width() / target.height();
|
|
|
|
diff = (orig.height() * ratio) - orig.width();
|
|
|
|
adj = orig.adjusted(-diff/2, 0, diff/2, 0);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-05-20 22:44:03 +02:00
|
|
|
setUpdatesEnabled(false);
|
2016-05-19 01:10:40 +02:00
|
|
|
_plot = true;
|
2016-05-20 22:44:03 +02:00
|
|
|
|
|
|
|
QPointF pos = _mapScale->pos();
|
|
|
|
_mapScale->setPos(mapToScene(QPoint(adj.bottomRight() + QPoint(
|
|
|
|
-(SCALE_OFFSET + _mapScale->boundingRect().width()),
|
|
|
|
-(SCALE_OFFSET + _mapScale->boundingRect().height())))));
|
|
|
|
|
2016-05-19 01:10:40 +02:00
|
|
|
render(painter, target, adj);
|
2016-05-20 22:44:03 +02:00
|
|
|
|
|
|
|
_mapScale->setPos(pos);
|
|
|
|
|
2016-05-19 01:10:40 +02:00
|
|
|
_plot = false;
|
2016-05-20 22:44:03 +02:00
|
|
|
setUpdatesEnabled(true);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::clear()
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
|
|
|
if (_mapScale->scene() == _scene)
|
|
|
|
_scene->removeItem(_mapScale);
|
|
|
|
|
|
|
|
_pois.clear();
|
2016-08-09 01:16:19 +02:00
|
|
|
_tracks.clear();
|
|
|
|
_routes.clear();
|
2016-07-28 00:23:22 +02:00
|
|
|
_waypoints.clear();
|
2016-02-11 20:58:52 +01:00
|
|
|
_scene->clear();
|
2016-03-02 09:34:39 +01:00
|
|
|
_palette.reset();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-03-15 01:20:24 +01:00
|
|
|
_zoom = ZOOM_MAX;
|
2016-11-11 17:58:18 +01:00
|
|
|
_tr = QRectF(); _rr = QRectF(); _wr = QRectF();
|
2016-11-11 23:48:38 +01:00
|
|
|
_wp = QPointF();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-03-03 09:15:56 +01:00
|
|
|
_scene->setSceneRect(QRectF());
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showTracks(bool show)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
_showTracks = show;
|
|
|
|
|
|
|
|
for (int i = 0; i < _tracks.count(); i++)
|
|
|
|
_tracks.at(i)->setVisible(show);
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showRoutes(bool show)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
_showRoutes = show;
|
|
|
|
|
|
|
|
for (int i = 0; i < _routes.count(); i++)
|
|
|
|
_routes.at(i)->setVisible(show);
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showWaypoints(bool show)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
_showWaypoints = show;
|
|
|
|
|
|
|
|
for (int i = 0; i < _waypoints.count(); i++)
|
|
|
|
_waypoints.at(i)->setVisible(show);
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showWaypointLabels(bool show)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
_showWaypointLabels = show;
|
|
|
|
|
|
|
|
for (int i = 0; i < _waypoints.size(); i++)
|
|
|
|
_waypoints.at(i)->showLabel(show);
|
2016-08-09 23:08:49 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < _routes.size(); i++)
|
|
|
|
_routes.at(i)->showWaypointLabels(show);
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showRouteWaypoints(bool show)
|
2016-08-09 10:47:49 +02:00
|
|
|
{
|
|
|
|
_showRouteWaypoints = show;
|
|
|
|
|
|
|
|
for (int i = 0; i < _routes.size(); i++)
|
|
|
|
_routes.at(i)->showWaypoints(show);
|
|
|
|
}
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
void PathView::showPOI(bool show)
|
|
|
|
{
|
|
|
|
_showPOI = show;
|
|
|
|
|
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it;
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
|
|
|
|
it.value()->setVisible(show);
|
|
|
|
|
|
|
|
updatePOIVisibility();
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::showPOILabels(bool show)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
_showPOILabels = show;
|
|
|
|
|
|
|
|
QHash<Waypoint, WaypointItem*>::const_iterator it;
|
|
|
|
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
|
|
|
|
it.value()->showLabel(show);
|
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
updatePOIVisibility();
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::setPOIOverlap(bool overlap)
|
2016-08-02 20:46:22 +02:00
|
|
|
{
|
2016-08-09 01:16:19 +02:00
|
|
|
_overlapPOIs = overlap;
|
2016-08-02 20:46:22 +02:00
|
|
|
|
2016-10-08 14:53:10 +02:00
|
|
|
updatePOIVisibility();
|
2016-08-02 20:46:22 +02:00
|
|
|
}
|
|
|
|
|
2016-12-06 01:48:26 +01:00
|
|
|
void PathView::setTrackWidth(int width)
|
|
|
|
{
|
|
|
|
_trackWidth = width;
|
|
|
|
|
|
|
|
for (int i = 0; i < _tracks.count(); i++)
|
|
|
|
_tracks.at(i)->setWidth(width);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathView::setRouteWidth(int width)
|
|
|
|
{
|
|
|
|
_routeWidth = width;
|
|
|
|
|
|
|
|
for (int i = 0; i < _routes.count(); i++)
|
|
|
|
_routes.at(i)->setWidth(width);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathView::setTrackStyle(Qt::PenStyle style)
|
|
|
|
{
|
|
|
|
_trackStyle = style;
|
|
|
|
|
|
|
|
for (int i = 0; i < _tracks.count(); i++)
|
|
|
|
_tracks.at(i)->setStyle(style);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathView::setRouteStyle(Qt::PenStyle style)
|
|
|
|
{
|
|
|
|
_routeStyle = style;
|
|
|
|
|
|
|
|
for (int i = 0; i < _routes.count(); i++)
|
|
|
|
_routes.at(i)->setStyle(style);
|
|
|
|
}
|
|
|
|
|
2016-09-26 21:01:58 +02:00
|
|
|
void PathView::drawBackground(QPainter *painter, const QRectF &rect)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-08-09 01:16:19 +02:00
|
|
|
if ((_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty())
|
|
|
|
|| !_map) {
|
2016-02-11 20:58:52 +01:00
|
|
|
painter->fillRect(rect, Qt::white);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-11 17:58:18 +01:00
|
|
|
qreal scale = mapScale(_zoom);
|
|
|
|
QRectF rr(rect.topLeft() * scale, rect.size());
|
2016-02-11 20:58:52 +01:00
|
|
|
QPoint tile = mercator2tile(QPointF(rr.topLeft().x(), -rr.topLeft().y()),
|
|
|
|
_zoom);
|
|
|
|
QPointF tm = tile2mercator(tile, _zoom);
|
2016-11-11 17:58:18 +01:00
|
|
|
QPoint tl = mapToScene(mapFromScene(QPointF(tm.x() / scale,
|
|
|
|
-tm.y() / scale))).toPoint();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
QList<Tile> tiles;
|
2016-10-24 00:21:40 +02:00
|
|
|
for (int i = 0; i <= rr.size().width() / Tile::size() + 1; i++) {
|
|
|
|
for (int j = 0; j <= rr.size().height() / Tile::size() + 1; j++) {
|
2016-02-11 20:58:52 +01:00
|
|
|
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 01:10:40 +02:00
|
|
|
_map->loadTiles(tiles, _plot);
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < tiles.count(); i++) {
|
|
|
|
Tile &t = tiles[i];
|
2016-10-24 00:21:40 +02:00
|
|
|
QPoint tp(tl.x() + (t.xy().x() - tile.x()) * Tile::size(),
|
|
|
|
tl.y() + (t.xy().y() - tile.y()) * Tile::size());
|
2016-02-11 20:58:52 +01:00
|
|
|
painter->drawPixmap(tp, t.pixmap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
void PathView::resizeEvent(QResizeEvent *event)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-08-09 01:16:19 +02:00
|
|
|
if (_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty())
|
2016-02-11 20:58:52 +01:00
|
|
|
return;
|
|
|
|
|
2016-04-05 09:10:19 +02:00
|
|
|
rescale();
|
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
QRectF sr = contentsSceneRect();
|
2016-02-11 20:58:52 +01:00
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
if (sr.width() < event->size().width()) {
|
|
|
|
qreal diff = event->size().width() - sr.width();
|
|
|
|
sr.adjust(-diff/2, 0, diff/2, 0);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
2016-11-11 23:48:38 +01:00
|
|
|
if (sr.height() < event->size().height()) {
|
|
|
|
qreal diff = event->size().height() - sr.height();
|
|
|
|
sr.adjust(0, -diff/2, 0, diff/2);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-11-11 23:48:38 +01:00
|
|
|
_scene->setSceneRect(sr);
|
|
|
|
centerOn(sr.center());
|
2016-02-11 20:58:52 +01:00
|
|
|
|
|
|
|
resetCachedContent();
|
|
|
|
}
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
void PathView::paintEvent(QPaintEvent *event)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-05-20 22:44:03 +02:00
|
|
|
QPointF scenePos = mapToScene(rect().bottomRight() + QPoint(
|
|
|
|
-(SCALE_OFFSET + _mapScale->boundingRect().width()),
|
2016-02-11 20:58:52 +01:00
|
|
|
-(SCALE_OFFSET + _mapScale->boundingRect().height())));
|
2016-05-19 01:10:40 +02:00
|
|
|
if (_mapScale->pos() != scenePos && !_plot)
|
2016-02-11 20:58:52 +01:00
|
|
|
_mapScale->setPos(scenePos);
|
|
|
|
|
2016-10-29 21:22:26 +02:00
|
|
|
QGraphicsView::paintEvent(event);
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
2016-12-06 01:48:26 +01:00
|
|
|
|
|
|
|
void PathView::useOpenGL(bool use)
|
|
|
|
{
|
|
|
|
if (use) {
|
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
|
|
|
|
#endif // Q_OS_WIN32
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
|
|
setViewport(new QGLWidget);
|
|
|
|
#else // QT 5
|
|
|
|
setViewport(new QOpenGLWidget);
|
|
|
|
#endif // QT 5
|
|
|
|
} else
|
|
|
|
setViewport(new QWidget);
|
|
|
|
}
|