1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 23:03:22 +02:00
GPXSee/src/GUI/mapview.cpp

976 lines
22 KiB
C++
Raw Normal View History

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QWheelEvent>
2017-04-05 22:53:25 +02:00
#include <QApplication>
2017-05-22 14:54:22 +02:00
#include <QPixmapCache>
#include <QScrollBar>
2017-11-26 18:54:03 +01:00
#include "data/poi.h"
#include "data/data.h"
#include "map/map.h"
2016-12-20 00:11:30 +01:00
#include "opengl.h"
#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"
2019-01-31 01:46:53 +01:00
#include "areaitem.h"
#include "scaleitem.h"
2017-04-05 22:53:25 +02:00
#include "keys.h"
#include "mapview.h"
2017-06-26 00:20:42 +02:00
#define MAX_DIGITAL_ZOOM 2
2017-06-26 00:20:42 +02:00
#define MIN_DIGITAL_ZOOM -3
2018-10-05 07:10:49 +02:00
#define MARGIN 10
2017-06-26 00:20:42 +02:00
#define SCALE_OFFSET 7
2018-10-15 01:15:00 +02:00
MapView::MapView(Map *map, POI *poi, QWidget *parent)
2017-07-27 19:47:46 +02:00
: QGraphicsView(parent)
{
Q_ASSERT(map != 0);
Q_ASSERT(poi != 0);
_scene = new QGraphicsScene(this);
setScene(_scene);
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);
_mapScale = new ScaleItem();
_mapScale->setZValue(2.0);
_scene->addItem(_mapScale);
_map = map;
2018-08-23 20:26:10 +02:00
_map->load();
2017-10-04 23:15:39 +02:00
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
2017-10-11 22:39:42 +02:00
_poi = poi;
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
2016-07-25 19:32:36 +02:00
_units = Metric;
_coordinatesFormat = DecimalDegrees;
2019-01-31 01:46:53 +01:00
_mapOpacity = 1.0;
2017-09-15 00:07:09 +02:00
_backgroundColor = Qt::white;
2017-12-03 00:36:52 +01:00
_markerColor = Qt::red;
2016-08-09 01:16:19 +02:00
_showMap = true;
2016-08-09 01:16:19 +02:00
_showTracks = true;
_showRoutes = true;
2019-01-31 01:46:53 +01:00
_showAreas = true;
2016-08-09 01:16:19 +02:00
_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;
2019-02-16 12:39:23 +01:00
_showMarkers = true;
2016-12-06 01:48:26 +01:00
_trackWidth = 3;
_routeWidth = 3;
_trackStyle = Qt::SolidLine;
_routeStyle = Qt::DashLine;
_waypointSize = 8;
_waypointColor = Qt::black;
_poiSize = 8;
_poiColor = Qt::black;
2016-08-09 01:16:19 +02:00
#ifdef ENABLE_HIDPI
_deviceRatio = 1.0;
_mapRatio = 1.0;
#endif // ENABLE_HIDPI
2018-08-23 20:26:10 +02:00
_opengl = false;
2016-08-09 01:16:19 +02:00
_plot = false;
2017-04-05 22:53:25 +02:00
_digitalZoom = 0;
2017-01-20 01:17:22 +01:00
_res = _map->resolution(_map->bounds());
_scene->setSceneRect(_map->bounds());
centerOn(_scene->sceneRect().center());
}
void MapView::centerOn(const QPointF &pos)
{
QGraphicsView::centerOn(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
_res = _map->resolution(vr);
_mapScale->setResolution(_res);
}
PathItem *MapView::addTrack(const Track &track)
{
2019-01-31 01:46:53 +01:00
if (!track.isValid()) {
skipColor();
2016-09-19 00:56:10 +02:00
return 0;
2016-03-23 20:49:40 +01:00
}
TrackItem *ti = new TrackItem(track, _map);
2016-08-09 01:16:19 +02:00
_tracks.append(ti);
2016-11-11 17:58:18 +01:00
_tr |= ti->path().boundingRect();
2016-12-06 01:48:26 +01:00
ti->setColor(_palette.nextColor());
ti->setWidth(_trackWidth);
2016-12-06 01:48:26 +01:00
ti->setStyle(_trackStyle);
ti->setUnits(_units);
2016-08-09 01:16:19 +02:00
ti->setVisible(_showTracks);
ti->setDigitalZoom(_digitalZoom);
2017-12-03 00:36:52 +01:00
ti->setMarkerColor(_markerColor);
2019-02-16 12:39:23 +01:00
ti->showMarker(_showMarkers);
2016-08-09 01:16:19 +02:00
_scene->addItem(ti);
2016-09-19 00:56:10 +02:00
2017-11-26 18:54:03 +01:00
if (_showTracks)
addPOI(_poi->points(ti->path()));
2016-10-08 14:53:10 +02:00
2016-09-19 00:56:10 +02:00
return ti;
2016-03-03 09:15:56 +01:00
}
PathItem *MapView::addRoute(const Route &route)
2016-08-09 01:16:19 +02:00
{
2019-01-31 01:46:53 +01:00
if (!route.isValid()) {
skipColor();
2016-09-19 00:56:10 +02:00
return 0;
2016-08-09 01:16:19 +02:00
}
RouteItem *ri = new RouteItem(route, _map);
2016-08-09 01:16:19 +02:00
_routes.append(ri);
2016-11-11 17:58:18 +01:00
_rr |= ri->path().boundingRect();
2016-12-06 01:48:26 +01:00
ri->setColor(_palette.nextColor());
ri->setWidth(_routeWidth);
2016-12-06 01:48:26 +01:00
ri->setStyle(_routeStyle);
ri->setUnits(_units);
ri->setCoordinatesFormat(_coordinatesFormat);
2016-08-09 01:16:19 +02:00
ri->setVisible(_showRoutes);
2016-08-09 10:47:49 +02:00
ri->showWaypoints(_showRouteWaypoints);
ri->showWaypointLabels(_showWaypointLabels);
ri->setDigitalZoom(_digitalZoom);
2017-12-03 00:36:52 +01:00
ri->setMarkerColor(_markerColor);
2019-02-16 12:39:23 +01:00
ri->showMarker(_showMarkers);
2016-08-09 01:16:19 +02:00
_scene->addItem(ri);
2016-09-19 00:56:10 +02:00
2017-11-26 18:54:03 +01:00
if (_showRoutes)
addPOI(_poi->points(ri->path()));
2016-10-08 14:53:10 +02:00
2016-09-19 00:56:10 +02:00
return ri;
2016-08-09 01:16:19 +02:00
}
2019-01-31 01:46:53 +01:00
void MapView::addArea(const Area &area)
{
if (!area.isValid()) {
skipColor();
return;
}
AreaItem *ai = new AreaItem(area, _map);
_areas.append(ai);
_ar |= ai->area().boundingRect();
ai->setColor(_palette.nextColor());
ai->setWidth(_areaWidth);
ai->setStyle(_areaStyle);
ai->setOpacity(_areaOpacity);
ai->setDigitalZoom(_digitalZoom);
ai->setVisible(_showAreas);
_scene->addItem(ai);
if (_showAreas)
addPOI(_poi->points(ai->area()));
}
2019-01-18 00:17:28 +01:00
void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
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
WaypointItem *wi = new WaypointItem(w, _map);
_waypoints.append(wi);
_wr = _wr.united(wi->waypoint().coordinates());
2016-03-15 01:20:24 +01:00
wi->setZValue(1);
wi->setSize(_waypointSize);
wi->setColor(_waypointColor);
2016-08-09 01:16:19 +02:00
wi->showLabel(_showWaypointLabels);
wi->setToolTipFormat(_units, _coordinatesFormat);
2016-08-09 01:16:19 +02:00
wi->setVisible(_showWaypoints);
wi->setDigitalZoom(_digitalZoom);
2016-03-15 01:20:24 +01:00
_scene->addItem(wi);
2017-11-26 18:54:03 +01:00
if (_showWaypoints)
addPOI(_poi->points(w));
}
2016-03-15 01:20:24 +01:00
}
QList<PathItem *> MapView::loadData(const Data &data)
2016-03-03 09:15:56 +01:00
{
2016-09-19 00:56:10 +02:00
QList<PathItem *> paths;
2018-03-10 08:40:55 +01:00
int zoom = _map->zoom();
2016-10-23 11:09:20 +02:00
for (int i = 0; i < data.tracks().count(); i++)
2019-01-31 01:46:53 +01:00
paths.append(addTrack(data.tracks().at(i)));
2016-10-23 11:09:20 +02:00
for (int i = 0; i < data.routes().count(); i++)
2019-01-31 01:46:53 +01:00
paths.append(addRoute(data.routes().at(i)));
for (int i = 0; i < data.areas().count(); i++)
addArea(data.areas().at(i));
2016-10-23 11:09:20 +02:00
addWaypoints(data.waypoints());
2016-03-15 01:20:24 +01:00
2019-01-31 01:46:53 +01:00
if (_tracks.empty() && _routes.empty() && _waypoints.empty()
&& _areas.empty())
2016-09-19 00:56:10 +02:00
return paths;
2016-03-15 01:20:24 +01:00
if (fitMapZoom() != zoom)
rescale();
2017-01-20 01:17:22 +01:00
else
2016-10-08 14:53:10 +02:00
updatePOIVisibility();
centerOn(contentCenter());
2016-09-19 00:56:10 +02:00
return paths;
}
int MapView::fitMapZoom() const
{
2019-01-31 01:46:53 +01:00
RectC br = _tr | _rr | _wr | _ar;
2016-03-15 01:20:24 +01:00
2017-12-01 20:52:34 +01:00
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
2018-04-03 22:36:08 +02:00
br.isNull() ? RectC(_map->xy2ll(_map->bounds().topLeft()),
_map->xy2ll(_map->bounds().bottomRight())) : br);
2016-03-15 01:20:24 +01:00
}
QPointF MapView::contentCenter() const
{
2019-01-31 01:46:53 +01:00
RectC br = _tr | _rr | _wr | _ar;
2017-12-01 20:52:34 +01:00
return br.isNull() ? sceneRect().center() : _map->ll2xy(br.center());
}
void MapView::updatePOIVisibility()
{
QHash<SearchPointer<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();
}
}
}
}
void MapView::rescale()
{
_scene->setSceneRect(_map->bounds());
2018-08-18 21:06:36 +02:00
reloadMap();
2017-01-16 09:54:12 +01:00
2016-08-09 01:16:19 +02:00
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setMap(_map);
2016-08-09 01:16:19 +02:00
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(_map);
2019-01-31 01:46:53 +01:00
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(_map);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);
2016-03-15 01:20:24 +01:00
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2016-10-08 14:53:10 +02:00
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setMap(_map);
2016-10-08 14:53:10 +02:00
updatePOIVisibility();
}
void MapView::setPalette(const Palette &palette)
2016-12-06 01:48:26 +01:00
{
_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());
2019-01-31 01:46:53 +01:00
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setColor(_palette.nextColor());
2016-12-06 01:48:26 +01:00
}
void MapView::setMap(Map *map)
{
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
2017-06-26 00:20:42 +02:00
_map->unload();
2017-10-04 23:15:39 +02:00
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
_map = map;
2018-08-23 20:26:10 +02:00
_map->load();
2018-08-18 21:06:36 +02:00
#ifdef ENABLE_HIDPI
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
2018-08-18 21:06:36 +02:00
#endif // ENABLE_HIDPI
2017-10-04 23:15:39 +02:00
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
2017-12-01 21:27:12 +01:00
digitalZoom(0);
2017-04-05 22:53:25 +02:00
_map->zoomFit(viewport()->rect().size(), cr);
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setMap(map);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(map);
2019-01-31 01:46:53 +01:00
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(map);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(map);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2017-04-05 22:53:25 +02:00
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setMap(_map);
updatePOIVisibility();
QPointF nc = QRectF(_map->ll2xy(cr.topLeft()),
_map->ll2xy(cr.bottomRight())).center();
centerOn(nc);
2018-08-18 21:06:36 +02:00
reloadMap();
2017-05-22 14:54:22 +02:00
QPixmapCache::clear();
}
void MapView::setPOI(POI *poi)
2016-10-08 14:53:10 +02:00
{
disconnect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
connect(poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
2016-10-09 23:46:30 +02:00
2016-10-08 14:53:10 +02:00
_poi = poi;
updatePOI();
2016-10-08 14:53:10 +02:00
}
void MapView::updatePOI()
2016-10-08 14:53:10 +02:00
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2016-10-09 23:46:30 +02:00
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
_scene->removeItem(it.value());
delete it.value();
}
_pois.clear();
2017-11-26 18:54:03 +01:00
if (_showTracks)
for (int i = 0; i < _tracks.size(); i++)
addPOI(_poi->points(_tracks.at(i)->path()));
if (_showRoutes)
for (int i = 0; i < _routes.size(); i++)
addPOI(_poi->points(_routes.at(i)->path()));
2019-01-31 01:46:53 +01:00
if (_showAreas)
for (int i = 0; i < _areas.size(); i++)
addPOI(_poi->points(_areas.at(i)->area()));
2017-11-26 18:54:03 +01:00
if (_showWaypoints)
for (int i = 0; i< _waypoints.size(); i++)
addPOI(_poi->points(_waypoints.at(i)->waypoint()));
2016-10-08 14:53:10 +02:00
updatePOIVisibility();
}
void MapView::addPOI(const QList<Waypoint> &waypoints)
{
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(SearchPointer<Waypoint>(&w)))
continue;
WaypointItem *pi = new WaypointItem(w, _map);
pi->setZValue(1);
pi->setSize(_poiSize);
pi->setColor(_poiColor);
2016-08-09 01:16:19 +02:00
pi->showLabel(_showPOILabels);
2016-10-08 14:53:10 +02:00
pi->setVisible(_showPOI);
pi->setDigitalZoom(_digitalZoom);
pi->setToolTipFormat(_units, _coordinatesFormat);
_scene->addItem(pi);
_pois.insert(SearchPointer<Waypoint>(&(pi->waypoint())), pi);
}
}
void MapView::setUnits(Units units)
{
if (_units == units)
return;
2016-07-25 19:32:36 +02:00
_units = units;
_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);
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)->setToolTipFormat(_units, _coordinatesFormat);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
void MapView::setCoordinatesFormat(CoordinatesFormat format)
{
if (_coordinatesFormat == format)
return;
_coordinatesFormat = format;
for (int i = 0; i < _waypoints.count(); i++)
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
for (int i = 0; i < _routes.count(); i++)
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
2016-08-02 00:28:56 +02:00
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2016-08-02 00:28:56 +02:00
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
void MapView::clearMapCache()
{
2017-10-04 23:15:39 +02:00
_map->clearCache();
fitMapZoom();
rescale();
centerOn(contentCenter());
}
void MapView::digitalZoom(int zoom)
2017-04-05 22:53:25 +02:00
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2017-12-01 21:27:12 +01:00
if (zoom) {
_digitalZoom += zoom;
scale(pow(2, zoom), pow(2, zoom));
} else {
_digitalZoom = 0;
resetTransform();
}
2017-04-05 22:53:25 +02:00
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setDigitalZoom(_digitalZoom);
2019-01-31 01:46:53 +01:00
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setDigitalZoom(_digitalZoom);
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setDigitalZoom(_digitalZoom);
2017-04-05 22:53:25 +02:00
_mapScale->setDigitalZoom(_digitalZoom);
2017-04-05 22:53:25 +02:00
}
2018-05-03 19:11:55 +02:00
void MapView::zoom(int zoom, const QPoint &pos)
2017-04-05 22:53:25 +02:00
{
bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
if (_digitalZoom) {
if (((_digitalZoom > 0 && zoom > 0) && (!shift || _digitalZoom
2017-06-26 00:20:42 +02:00
>= MAX_DIGITAL_ZOOM)) || ((_digitalZoom < 0 && zoom < 0) && (!shift
|| _digitalZoom <= MIN_DIGITAL_ZOOM)))
2017-04-05 22:53:25 +02:00
return;
digitalZoom(zoom);
} else {
2018-05-03 19:11:55 +02:00
Coordinates c = _map->xy2ll(mapToScene(pos));
2018-10-15 01:15:00 +02:00
int oz = _map->zoom();
int nz = (zoom > 0) ? _map->zoomIn() : _map->zoomOut();
2017-04-05 22:53:25 +02:00
2018-10-15 01:15:00 +02:00
if (nz != oz) {
2017-04-05 22:53:25 +02:00
rescale();
centerOn(_map->ll2xy(c) - (pos - viewport()->rect().center()));
2017-04-05 22:53:25 +02:00
} else {
if (shift)
digitalZoom(zoom);
}
}
}
void MapView::wheelEvent(QWheelEvent *event)
{
2017-04-01 06:56:50 +02:00
static int deg = 0;
deg += event->delta() / 8;
if (qAbs(deg) < 15)
return;
deg = 0;
2018-05-03 19:11:55 +02:00
zoom((event->delta() > 0) ? 1 : -1, event->pos());
}
void MapView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton && event->button() != Qt::RightButton)
return;
2018-05-03 19:11:55 +02:00
zoom((event->button() == Qt::LeftButton) ? 1 : -1, event->pos());
}
void MapView::keyPressEvent(QKeyEvent *event)
{
2017-04-05 22:53:25 +02:00
int z;
2017-06-27 22:42:59 +02:00
QPoint pos = viewport()->rect().center();
if (event->key() == ZOOM_IN)
2017-04-05 22:53:25 +02:00
z = 1;
else if (event->key() == ZOOM_OUT)
2017-04-05 22:53:25 +02:00
z = -1;
else if (_digitalZoom && event->key() == Qt::Key_Escape) {
2017-12-01 21:27:12 +01:00
digitalZoom(0);
return;
} else {
2017-04-05 22:53:25 +02:00
QGraphicsView::keyPressEvent(event);
return;
}
2018-05-03 19:11:55 +02:00
zoom(z, pos);
}
void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
bool hires)
{
QRect orig, adj;
qreal ratio, diff, q;
2017-08-31 16:28:37 +02:00
QPointF origScene, origPos;
2018-04-28 22:18:11 +02:00
int zoom;
2016-05-20 22:44:03 +02:00
// Enter plot mode
setUpdatesEnabled(false);
2017-08-31 16:28:37 +02:00
_plot = true;
2018-08-18 21:06:36 +02:00
#ifdef ENABLE_HIDPI
_map->setDevicePixelRatio(_deviceRatio, 1.0);
2018-08-18 21:06:36 +02:00
#endif // ENABLE_HIDPI
// Compute sizes & ratios
2016-05-15 13:19:07 +02:00
orig = viewport()->rect();
2017-08-31 16:28:37 +02:00
origPos = _mapScale->pos();
2016-05-27 22:45:58 +02:00
if (orig.height() * (target.width() / target.height()) - orig.width() < 0) {
ratio = target.height() / target.width();
2016-05-27 22:45:58 +02:00
diff = (orig.width() * ratio) - orig.height();
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);
}
q = (target.width() / scale) / adj.width();
2017-08-31 16:28:37 +02:00
// Adjust the view for printing
if (hires) {
2018-04-28 22:18:11 +02:00
zoom = _map->zoom();
QRectF vr(mapToScene(orig).boundingRect());
origScene = vr.center();
2017-08-31 16:28:37 +02:00
QPointF s(painter->device()->logicalDpiX()
/ (qreal)metric(QPaintDevice::PdmDpiX),
painter->device()->logicalDpiY()
/ (qreal)metric(QPaintDevice::PdmDpiY));
2017-08-31 16:28:37 +02:00
adj = QRect(0, 0, adj.width() * s.x(), adj.height() * s.y());
2019-01-31 01:46:53 +01:00
_map->zoomFit(adj.size(), _tr | _rr | _wr | _ar);
rescale();
QPointF center = contentCenter();
centerOn(center);
adj.moveCenter(mapFromScene(center));
_mapScale->setDigitalZoom(_digitalZoom - log2(s.x() / q));
2017-08-31 16:28:37 +02:00
_mapScale->setPos(mapToScene(QPoint(adj.bottomRight() + QPoint(
-(SCALE_OFFSET + _mapScale->boundingRect().width()) * (s.x() / q),
-(SCALE_OFFSET + _mapScale->boundingRect().height()) * (s.x() / q)))));
2017-08-31 16:28:37 +02:00
} else {
_mapScale->setDigitalZoom(_digitalZoom - log2(1.0 / q));
2017-08-31 16:28:37 +02:00
_mapScale->setPos(mapToScene(QPoint(adj.bottomRight() + QPoint(
-(SCALE_OFFSET + _mapScale->boundingRect().width()) / q ,
-(SCALE_OFFSET + _mapScale->boundingRect().height()) / q))));
2017-08-31 16:28:37 +02:00
}
2016-05-20 22:44:03 +02:00
2017-08-31 16:28:37 +02:00
// Print the view
render(painter, target, adj);
2016-05-20 22:44:03 +02:00
2017-08-31 16:28:37 +02:00
// Revert view changes to display mode
if (hires) {
2018-04-28 22:18:11 +02:00
_map->setZoom(zoom);
rescale();
centerOn(origScene);
}
2018-04-28 22:18:11 +02:00
_mapScale->setDigitalZoom(_digitalZoom);
2017-08-31 16:28:37 +02:00
_mapScale->setPos(origPos);
// Exit plot mode
2018-08-18 21:06:36 +02:00
#ifdef ENABLE_HIDPI
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
2018-08-18 21:06:36 +02:00
#endif // ENABLE_HIDPI
2017-08-31 16:28:37 +02:00
_plot = false;
2016-05-20 22:44:03 +02:00
setUpdatesEnabled(true);
}
void MapView::clear()
{
_pois.clear();
2016-08-09 01:16:19 +02:00
_tracks.clear();
_routes.clear();
2019-01-31 01:46:53 +01:00
_areas.clear();
_waypoints.clear();
_scene->removeItem(_mapScale);
_scene->clear();
_scene->addItem(_mapScale);
2016-03-02 09:34:39 +01:00
_palette.reset();
2017-06-30 18:15:22 +02:00
_tr = RectC();
_rr = RectC();
_wr = RectC();
2019-01-31 01:46:53 +01:00
_ar = RectC();
2017-04-05 22:53:25 +02:00
2017-12-01 21:27:12 +01:00
digitalZoom(0);
// If not reset, causes huge redraw areas (and system memory exhaustion)
resetCachedContent();
}
void MapView::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);
2017-11-26 18:54:03 +01:00
updatePOI();
2016-08-09 01:16:19 +02:00
}
void MapView::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);
2017-11-26 18:54:03 +01:00
updatePOI();
2016-08-09 01:16:19 +02:00
}
void MapView::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);
2017-11-26 18:54:03 +01:00
updatePOI();
2016-08-09 01:16:19 +02:00
}
2019-01-31 01:46:53 +01:00
void MapView::showAreas(bool show)
{
_showAreas = show;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setVisible(show);
updatePOI();
}
void MapView::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);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->showWaypointLabels(show);
2016-08-09 01:16:19 +02:00
}
void MapView::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);
}
2019-02-16 12:39:23 +01:00
void MapView::showMarkers(bool show)
{
_showMarkers = show;
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->showMarker(show);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->showMarker(show);
}
void MapView::showMap(bool show)
{
_showMap = show;
2018-08-18 21:06:36 +02:00
reloadMap();
}
void MapView::showPOI(bool show)
2016-10-08 14:53:10 +02:00
{
_showPOI = show;
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2016-10-08 14:53:10 +02:00
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setVisible(show);
updatePOIVisibility();
}
void MapView::showPOILabels(bool show)
2016-08-09 01:16:19 +02:00
{
_showPOILabels = show;
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
2016-08-09 01:16:19 +02:00
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
}
void MapView::setPOIOverlap(bool overlap)
{
2016-08-09 01:16:19 +02:00
_overlapPOIs = overlap;
2016-10-08 14:53:10 +02:00
updatePOIVisibility();
}
void MapView::setTrackWidth(int width)
2016-12-06 01:48:26 +01:00
{
_trackWidth = width;
for (int i = 0; i < _tracks.count(); i++)
_tracks.at(i)->setWidth(width);
2016-12-06 01:48:26 +01:00
}
void MapView::setRouteWidth(int width)
2016-12-06 01:48:26 +01:00
{
_routeWidth = width;
for (int i = 0; i < _routes.count(); i++)
_routes.at(i)->setWidth(width);
2016-12-06 01:48:26 +01:00
}
2019-01-31 01:46:53 +01:00
void MapView::setAreaWidth(int width)
{
_areaWidth = width;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setWidth(width);
}
void MapView::setTrackStyle(Qt::PenStyle style)
2016-12-06 01:48:26 +01:00
{
_trackStyle = style;
for (int i = 0; i < _tracks.count(); i++)
_tracks.at(i)->setStyle(style);
}
void MapView::setRouteStyle(Qt::PenStyle style)
2016-12-06 01:48:26 +01:00
{
_routeStyle = style;
for (int i = 0; i < _routes.count(); i++)
_routes.at(i)->setStyle(style);
}
2019-01-31 01:46:53 +01:00
void MapView::setAreaStyle(Qt::PenStyle style)
{
_areaStyle = style;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setStyle(style);
}
void MapView::setAreaOpacity(int opacity)
{
_areaOpacity = opacity / 100.0;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setOpacity(_areaOpacity);
}
void MapView::setWaypointSize(int size)
{
_waypointSize = size;
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setSize(size);
}
void MapView::setWaypointColor(const QColor &color)
{
_waypointColor = color;
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setColor(color);
}
void MapView::setPOISize(int size)
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
_poiSize = size;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setSize(size);
}
void MapView::setPOIColor(const QColor &color)
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
_poiColor = color;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setColor(color);
}
void MapView::setMapOpacity(int opacity)
{
2019-01-31 01:46:53 +01:00
_mapOpacity = opacity / 100.0;
2018-08-18 21:06:36 +02:00
reloadMap();
}
void MapView::setBackgroundColor(const QColor &color)
{
2017-09-15 00:07:09 +02:00
_backgroundColor = color;
2018-08-18 21:06:36 +02:00
reloadMap();
}
void MapView::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->fillRect(rect, _backgroundColor);
if (_showMap) {
QRectF ir = rect.intersected(_map->bounds());
2018-08-23 20:26:10 +02:00
Map::Flags flags = Map::NoFlags;
2019-01-31 01:46:53 +01:00
if (_mapOpacity < 1.0)
painter->setOpacity(_mapOpacity);
2018-08-23 20:26:10 +02:00
if (_plot)
flags = Map::Block;
else if (_opengl)
flags = Map::OpenGL;
_map->draw(painter, ir, flags);
}
}
void MapView::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
2018-03-10 08:40:55 +01:00
int zoom = _map->zoom();
if (fitMapZoom() != zoom)
rescale();
centerOn(contentCenter());
}
void MapView::paintEvent(QPaintEvent *event)
{
2016-05-20 22:44:03 +02:00
QPointF scenePos = mapToScene(rect().bottomRight() + QPoint(
-(SCALE_OFFSET + _mapScale->boundingRect().width()),
-(SCALE_OFFSET + _mapScale->boundingRect().height())));
if (_mapScale->pos() != scenePos && !_plot)
_mapScale->setPos(scenePos);
QGraphicsView::paintEvent(event);
}
2016-12-06 01:48:26 +01:00
void MapView::scrollContentsBy(int dx, int dy)
2017-01-16 09:54:12 +01:00
{
QGraphicsView::scrollContentsBy(dx, dy);
QRectF sr(mapToScene(viewport()->rect()).boundingRect());
qreal res = _map->resolution(sr);
2017-01-16 09:54:12 +01:00
if (qMax(res, _res) / qMin(res, _res) > 1.1) {
_mapScale->setResolution(res);
_res = res;
}
}
void MapView::useOpenGL(bool use)
2016-12-06 01:48:26 +01:00
{
_opengl = use;
2017-02-12 17:38:20 +01:00
if (use)
2017-01-02 23:01:50 +01:00
setViewport(new OPENGL_WIDGET);
2017-02-12 17:38:20 +01:00
else
2016-12-06 01:48:26 +01:00
setViewport(new QWidget);
}
2017-09-15 00:07:09 +02:00
void MapView::useAntiAliasing(bool use)
2017-09-15 00:07:09 +02:00
{
setRenderHint(QPainter::Antialiasing, use);
}
2017-10-04 23:15:39 +02:00
2017-12-03 00:36:52 +01:00
void MapView::setMarkerColor(const QColor &color)
{
_markerColor = color;
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setMarkerColor(color);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMarkerColor(color);
}
void MapView::reloadMap()
2017-10-04 23:15:39 +02:00
{
2018-08-18 21:06:36 +02:00
_scene->invalidate();
}
void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
2018-08-18 21:06:36 +02:00
{
#ifdef ENABLE_HIDPI
if (_deviceRatio == deviceRatio && _mapRatio == mapRatio)
2018-08-18 21:06:36 +02:00
return;
_deviceRatio = deviceRatio;
_mapRatio = mapRatio;
QPixmapCache::clear();
2018-08-18 21:06:36 +02:00
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
2018-08-18 21:06:36 +02:00
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setMap(_map);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(_map);
2019-01-31 01:46:53 +01:00
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(_map);
2018-08-18 21:06:36 +02:00
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
it.value()->setMap(_map);
updatePOIVisibility();
QPointF nc = QRectF(_map->ll2xy(cr.topLeft()),
_map->ll2xy(cr.bottomRight())).center();
centerOn(nc);
reloadMap();
#else // ENABLE_HIDPI
2018-11-17 21:01:08 +01:00
Q_UNUSED(deviceRatio);
Q_UNUSED(mapRatio);
2018-08-18 21:06:36 +02:00
#endif // ENABLE_HIDPI
2017-10-04 23:15:39 +02:00
}