Jussi Laitinen - jussi.laitinen@ixonos.com
Pekka Nissinen - pekka.nissinen@ixonos.com
Ville Tiensuu - ville.tiensuu@ixonos.com
+ Henri Lampela - henri.lampela@ixonos.com
Situare is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
#include <QtAlgorithms>
#include <QDebug>
+#include <QGraphicsView>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QRect>
#include "common.h"
+#include "coordinates/geocoordinate.h"
#include "frienditemshandler.h"
#include "gpslocationitem.h"
#include "mapcommon.h"
#include "mapfetcher.h"
+#include "maprouteitem.h"
#include "mapscene.h"
+#include "mapscroller.h"
#include "maptile.h"
#include "network/networkaccessmanager.h"
#include "ownlocationitem.h"
#include "mapengine.h"
+const int SMOOTH_CENTERING_TIME_MS = 1000;
+
MapEngine::MapEngine(QObject *parent)
: QObject(parent),
m_autoCenteringEnabled(false),
+ m_scrollStartedByGps(false),
+ m_smoothScrollRunning(false),
m_zoomedIn(false),
- m_zoomLevel(DEFAULT_ZOOM_LEVEL),
+ m_zoomLevel(MAP_DEFAULT_ZOOM_LEVEL),
m_centerTile(QPoint(UNDEFINED, UNDEFINED)),
- m_lastManualPosition(QPoint(0, 0)),
+ m_sceneCoordinate(SceneCoordinate(GeoCoordinate(MAP_DEFAULT_LATITUDE, MAP_DEFAULT_LONGITUDE))),
m_tilesGridSize(QSize(0, 0)),
- m_viewSize(QSize(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT))
+ m_viewSize(QSize(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT)),
+ m_mapRouteItem(0)
{
qDebug() << __PRETTY_FUNCTION__;
m_mapScene = new MapScene(this);
- m_mapFetcher = new MapFetcher(NetworkAccessManager::instance(), this);
+ m_mapFetcher = new MapFetcher(new NetworkAccessManager(this), this);
connect(this, SIGNAL(fetchImage(int, int, int)),
m_mapFetcher, SLOT(enqueueFetchMapImage(int, int, int)));
connect(m_mapFetcher, SIGNAL(mapImageReceived(int, int, int, QPixmap)),
this, SLOT(mapImageReceived(int, int, int, QPixmap)));
+ connect(m_mapFetcher, SIGNAL(error(int, int)),
+ this, SIGNAL(error(int, int)));
m_ownLocation = new OwnLocationItem();
m_ownLocation->hide(); // hide until first location info is received
connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)),
m_friendItemsHandler, SLOT(friendListUpdated(QList<User*>&)));
+ connect(this, SIGNAL(friendImageReady(User*)),
+ m_friendItemsHandler, SLOT(friendImageReady(User*)));
+
+ connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)),
+ this, SLOT(friendsPositionsUpdated()));
+
connect(m_friendItemsHandler, SIGNAL(locationItemClicked(QList<QString>)),
this, SIGNAL(locationItemClicked(QList<QString>)));
+
+ m_scroller = &MapScroller::getInstance();
+
+ connect(m_scroller, SIGNAL(coordinateUpdated(SceneCoordinate)),
+ this, SLOT(setCenterPosition(SceneCoordinate)));
+
+ connect(m_scroller, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)),
+ this, SLOT(scrollerStateChanged(QAbstractAnimation::State)));
}
MapEngine::~MapEngine()
qDebug() << __PRETTY_FUNCTION__;
QSettings settings(DIRECTORY_NAME, FILE_NAME);
- settings.setValue(MAP_LAST_POSITION,
- convertSceneCoordinateToLatLon(m_zoomLevel, m_sceneCoordinate));
+
+ settings.setValue(MAP_LAST_POSITION, QVariant::fromValue(centerGeoCoordinate()));
settings.setValue(MAP_LAST_ZOOMLEVEL, m_zoomLevel);
}
-QRect MapEngine::calculateTileGrid(QPoint sceneCoordinate)
+QRect MapEngine::calculateTileGrid(SceneCoordinate coordinate)
{
qDebug() << __PRETTY_FUNCTION__;
- QPoint tileCoordinate = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
+ QPoint tileCoordinate = convertSceneCoordinateToTileNumber(m_zoomLevel, coordinate);
QPoint topLeft;
topLeft.setX(tileCoordinate.x() - (m_tilesGridSize.width() / 2));
return QRect(topLeft, m_tilesGridSize);
}
-QPointF MapEngine::centerGeoCoordinate()
+void MapEngine::centerAndZoomTo(QRect rect, bool useMargins)
{
qDebug() << __PRETTY_FUNCTION__;
- return convertSceneCoordinateToLatLon(m_zoomLevel, m_sceneCoordinate);
-}
+ int marginHorizontal = 0;
+ int marginVertical = 0;
-QPoint MapEngine::convertLatLonToSceneCoordinate(QPointF latLonCoordinate)
-{
- qDebug() << __PRETTY_FUNCTION__;
+ if (useMargins) {
+ marginHorizontal = 50;
+ marginVertical = 5;
+ }
+
+ // calculate the usable size of the view
+ int viewUsableHeight = m_viewSize.height() - 2 * marginHorizontal;
+ int viewUsableWidth = m_viewSize.width() - 2 * marginVertical;
- qreal longitude = latLonCoordinate.x();
- qreal latitude = latLonCoordinate.y();
+ // calculate how many levels must be zoomed out from the closest zoom level to get the rect
+ // fit inside the usable view area
+ int shift = 0;
+ while ((rect.height() > (viewUsableHeight * (1 << shift)))
+ || (rect.width() > (viewUsableWidth * (1 << shift)))) {
- if ((longitude > MAX_LONGITUDE) || (longitude < MIN_LONGITUDE))
- return QPoint(UNDEFINED, UNDEFINED);
- if ((latitude > MAX_LATITUDE) || (latitude < MIN_LATITUDE))
- return QPoint(UNDEFINED, UNDEFINED);
+ shift++;
+ }
- qreal z = static_cast<qreal>(1 << MAX_MAP_ZOOM_LEVEL);
- qreal x = static_cast<qreal>((longitude + 180.0) / 360.0);
- qreal y = static_cast<qreal>((1.0 - log(tan(latitude * M_PI / 180.0) + 1.0
- / cos(latitude * M_PI / 180.0)) / M_PI) / 2.0);
+ scrollToPosition(SceneCoordinate(double(rect.center().x()), double(rect.center().y())));
- return QPointF(x * z * TILE_SIZE_X, y * z * TILE_SIZE_Y).toPoint();
+ int zoomLevel = qBound(OSM_MIN_ZOOM_LEVEL, OSM_MAX_ZOOM_LEVEL - shift, OSM_MAX_ZOOM_LEVEL);
+ setZoomLevel(zoomLevel);
}
-QPointF MapEngine::convertSceneCoordinateToLatLon(int zoomLevel, QPoint sceneCoordinate)
+GeoCoordinate MapEngine::centerGeoCoordinate()
{
qDebug() << __PRETTY_FUNCTION__;
- double tileFactor = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
- double xFactor = (sceneCoordinate.x() / (TILE_SIZE_X*tileFactor));
- double yFactor = (sceneCoordinate.y() / (TILE_SIZE_Y*tileFactor));
+ return GeoCoordinate(m_sceneCoordinate);
+}
- tileFactor = 1 << zoomLevel;
- double longitude = xFactor / tileFactor * 360.0 - 180;
+void MapEngine::centerToCoordinates(GeoCoordinate coordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
- double n = M_PI - 2.0 * M_PI * yFactor / tileFactor;
- double latitude = 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
+ scrollToPosition(SceneCoordinate(coordinate));
+}
+
+void MapEngine::clearRoute()
+{
+ qDebug() << __PRETTY_FUNCTION__;
- return QPointF(longitude, latitude);
+ if (m_mapRouteItem) {
+ m_mapScene->removeItem(m_mapRouteItem);
+ delete m_mapRouteItem;
+ m_mapRouteItem = 0;
+ }
}
-QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate)
+QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, SceneCoordinate coordinate)
{
qDebug() << __PRETTY_FUNCTION__;
- int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
- int x = static_cast<int>(sceneCoordinate.x() / (TILE_SIZE_X * pow));
- int y = static_cast<int>(sceneCoordinate.y() / (TILE_SIZE_Y * pow));
+ int pow = 1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel);
+ int x = static_cast<int>(coordinate.x() / (OSM_TILE_SIZE_X * pow));
+ int y = static_cast<int>(coordinate.y() / (OSM_TILE_SIZE_Y * pow));
return QPoint(x, y);
}
-QPoint MapEngine::convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
+QRectF MapEngine::currentViewSceneRect() const
{
qDebug() << __PRETTY_FUNCTION__;
- int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
- int x = tileNumber.x() * TILE_SIZE_X * pow;
- int y = tileNumber.y() * TILE_SIZE_Y * pow;
+ const QPoint ONE_PIXEL = QPoint(1, 1);
- return QPoint(x, y);
+ QGraphicsView *view = m_mapScene->views().first();
+ QPointF sceneTopLeft = view->mapToScene(0, 0);
+ QPoint viewBottomRight = QPoint(view->size().width(), view->size().height()) - ONE_PIXEL;
+ QPointF sceneBottomRight = view->mapToScene(viewBottomRight);
+
+ return QRectF(sceneTopLeft, sceneBottomRight);
}
-bool MapEngine::disableAutoCentering(QPoint sceneCoordinate)
+void MapEngine::disableAutoCenteringIfRequired(SceneCoordinate coordinate)
{
if (isAutoCenteringEnabled()) {
- int zoomFactor = (1 << (MAX_MAP_ZOOM_LEVEL - m_zoomLevel));
+ int zoomFactor = (1 << (OSM_MAX_ZOOM_LEVEL - m_zoomLevel));
+
+ SceneCoordinate oldPixelValue(m_lastAutomaticPosition.x() / zoomFactor,
+ m_lastAutomaticPosition.y() / zoomFactor);
- QPoint oldPixelValue = QPoint(m_lastManualPosition.x() / zoomFactor,
- m_lastManualPosition.y() / zoomFactor);
+ SceneCoordinate newPixelValue(coordinate.x() / zoomFactor,
+ coordinate.y() / zoomFactor);
- QPoint newPixelValue = QPoint(sceneCoordinate.x() / zoomFactor,
- sceneCoordinate.y() / zoomFactor);
+ if ((abs(oldPixelValue.x() - newPixelValue.x()) > AUTO_CENTERING_DISABLE_DISTANCE)
+ || (abs(oldPixelValue.y() - newPixelValue.y()) > AUTO_CENTERING_DISABLE_DISTANCE)) {
- if ((abs(oldPixelValue.x() - newPixelValue.x()) > AUTO_CENTERING_DISABLE_DISTANCE) ||
- (abs(oldPixelValue.y() - newPixelValue.y()) > AUTO_CENTERING_DISABLE_DISTANCE))
- return true;
+ emit mapScrolledManually();
+ }
}
+}
+
+void MapEngine::friendsPositionsUpdated()
+{
+ qDebug() << __PRETTY_FUNCTION__;
- return false;
+ m_mapScene->spanItems(currentViewSceneRect());
}
-void MapEngine::getTiles(QPoint sceneCoordinate)
+void MapEngine::getTiles(SceneCoordinate coordinate)
{
qDebug() << __PRETTY_FUNCTION__;
- m_viewTilesGrid = calculateTileGrid(sceneCoordinate);
+ m_viewTilesGrid = calculateTileGrid(coordinate);
updateViewTilesSceneRect();
+ m_mapScene->setTilesGrid(m_viewTilesGrid);
int topLeftX = m_viewTilesGrid.topLeft().x();
int topLeftY = m_viewTilesGrid.topLeft().y();
int bottomRightX = m_viewTilesGrid.bottomRight().x();
int bottomRightY = m_viewTilesGrid.bottomRight().y();
- int tileMaxVal = tileMaxValue(m_zoomLevel);
+ int tileMaxVal = MapTile::lastTileIndex(m_zoomLevel);
for (int x = topLeftX; x <= bottomRightX; ++x) {
for (int y = topLeftY; y <= bottomRightY; ++y) {
- int tileX = x;
- int tileY = y;
-
- // span in horizontal direction if world limits has been reached
-// if (tileX < 0)
-// tileX += tileMaxVal + 1;
-// else if (tileX > tileMaxVal)
-// tileX -= tileMaxVal + 1;
-
- // map doesn't span in vertical direction
- if (tileY < 0 || tileY > tileMaxVal) /// @todo replace variable with method
- continue;
-
- if (!m_mapScene->tileInScene(tilePath(m_zoomLevel, tileX, tileY)))
- emit fetchImage(m_zoomLevel, normalizeTileNumberX(tileX), tileY);
+ // map doesn't span in vertical direction, so y index must be inside the limits
+ if (y >= MAP_TILE_MIN_INDEX && y <= tileMaxVal) {
+ if (!m_mapScene->tileInScene(MapTile::tilePath(m_zoomLevel, x, y)))
+ emit fetchImage(m_zoomLevel, normalize(x, MAP_TILE_MIN_INDEX, tileMaxVal), y);
+ }
}
}
-
- QRect spanRect = m_mapScene->spanItems(m_scrollDirection, m_zoomLevel);
- m_friendItemsHandler->spanHiddenFriendLocationItems(m_scrollDirection, spanRect);
- m_friendItemsHandler->refactorFriendItems(m_zoomLevel);
}
-void MapEngine::gpsPositionUpdate(QPointF position, qreal accuracy)
+void MapEngine::gpsPositionUpdate(GeoCoordinate position, qreal accuracy)
{
qDebug() << __PRETTY_FUNCTION__;
- m_gpsLocationItem->updatePosition(convertLatLonToSceneCoordinate(position), accuracy);
+ m_gpsPosition = position;
+
+ // update GPS location item (but only if accuracy is a valid number)
+ if (!isnan(accuracy)) {
+ qreal resolution = MapScene::horizontalResolutionAtLatitude(position.latitude());
+ m_gpsLocationItem->updateItem(SceneCoordinate(position).toPointF(), accuracy, resolution);
+ }
+
+ m_mapScene->spanItems(currentViewSceneRect());
- if (m_autoCenteringEnabled)
- setViewLocation(position);
+ // do automatic centering (if enabled)
+ if (m_autoCenteringEnabled) {
+ m_lastAutomaticPosition = SceneCoordinate(position);
+ m_scrollStartedByGps = true;
+ scrollToPosition(m_lastAutomaticPosition);
+ }
+
+ updateDirectionIndicator();
}
void MapEngine::init()
{
qDebug() << __PRETTY_FUNCTION__;
- QPointF startLocation;
QSettings settings(DIRECTORY_NAME, FILE_NAME);
- if (settings.value(MAP_LAST_POSITION, ERROR_VALUE_NOT_FOUND_ON_SETTINGS).toString()
- == ERROR_VALUE_NOT_FOUND_ON_SETTINGS || settings.value(MAP_LAST_ZOOMLEVEL,
- ERROR_VALUE_NOT_FOUND_ON_SETTINGS).toString() == ERROR_VALUE_NOT_FOUND_ON_SETTINGS) {
+ // init can be only done if both values exists in the settings
+ if (settings.contains(MAP_LAST_POSITION) && settings.contains(MAP_LAST_ZOOMLEVEL)) {
+ QVariant zoomLevel = settings.value(MAP_LAST_ZOOMLEVEL);
+ QVariant location = settings.value(MAP_LAST_POSITION);
- startLocation = QPointF(DEFAULT_LONGITUDE, DEFAULT_LATITUDE);
- m_zoomLevel = qBound(MIN_VIEW_ZOOM_LEVEL, DEFAULT_START_ZOOM_LEVEL, MAX_MAP_ZOOM_LEVEL);
- } else {
- m_zoomLevel = settings.value(MAP_LAST_ZOOMLEVEL, ERROR_VALUE_NOT_FOUND_ON_SETTINGS).toInt();
- startLocation = settings.value(MAP_LAST_POSITION,
- ERROR_VALUE_NOT_FOUND_ON_SETTINGS).toPointF();
+ // also the init can be only done if we are able to convert variants into target data types
+ if (zoomLevel.canConvert<int>() && location.canConvert<GeoCoordinate>()) {
+ m_zoomLevel = zoomLevel.toInt();
+ m_sceneCoordinate = SceneCoordinate(location.value<GeoCoordinate>());
+ }
}
+ // emit zoom level and center coordinate so that all parts of the map system gets initialized
+ // NOTE: emit is also done even if we weren't able to read initial valuef from the settings
+ // so that the default values set in the constructor are used
emit zoomLevelChanged(m_zoomLevel);
- setViewLocation(QPointF(startLocation.x(), startLocation.y()));
+ scrollToPosition(m_sceneCoordinate);
}
bool MapEngine::isAutoCenteringEnabled()
return m_autoCenteringEnabled;
}
-bool MapEngine::isCenterTileChanged(QPoint sceneCoordinate)
+bool MapEngine::isCenterTileChanged(SceneCoordinate coordinate)
{
qDebug() << __PRETTY_FUNCTION__;
- QPoint centerTile = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
+ QPoint centerTile = convertSceneCoordinateToTileNumber(m_zoomLevel, coordinate);
QPoint temp = m_centerTile;
m_centerTile = centerTile;
void MapEngine::mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image)
{
-// if (y != 3)
-// return;
-
- qWarning() << __PRETTY_FUNCTION__ << "x:" << x << "y:" << y;
+ qDebug() << __PRETTY_FUNCTION__;
- // add normal tile
+ // add normal tile inside the world
QPoint tileNumber(x, y);
m_mapScene->addTile(zoomLevel, tileNumber, image, m_zoomLevel);
- // expand to east side?
- if (tileNumber.x() < 3) {
- QPoint adjustedTileNumber(tileNumber.x() + tileMaxValue(zoomLevel) + 1, tileNumber.y());
+ // note: add 1 so odd width is rounded up and even is rounded down
+ int tilesGridWidthHalf = (m_viewTilesGrid.width() + 1) / 2;
+
+ // duplicate to east side? (don't need to duplicate over padding)
+ if (tileNumber.x() < (tilesGridWidthHalf - MAP_GRID_PADDING)) {
+ QPoint adjustedTileNumber(tileNumber.x() + MapTile::lastTileIndex(zoomLevel) + 1,
+ tileNumber.y());
m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
- qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to east, x:" << x << "->" << adjustedTileNumber.x() << "y:" << adjustedTileNumber.y();
}
- // expand to west side?
- if (tileNumber.x() > (tileMaxValue(zoomLevel) - 3)) {
- QPoint adjustedTileNumber(tileNumber.x() - tileMaxValue(zoomLevel) - 1, tileNumber.y());
+ // duplicate to west side? (don't need to duplicate over padding)
+ if (tileNumber.x() > (MapTile::lastTileIndex(zoomLevel)
+ - tilesGridWidthHalf
+ + MAP_GRID_PADDING)) {
+ QPoint adjustedTileNumber(tileNumber.x() - MapTile::lastTileIndex(zoomLevel) - 1,
+ tileNumber.y());
m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
- qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to west, x:" << x << "->" << adjustedTileNumber.x() << "y:" << adjustedTileNumber.y();
}
-
-// // expanding is only done if received tile zoom level is same as current zoom level
-// if (zoomLevel == m_zoomLevel) {
-// // expand to east side?
-// if (m_viewTilesGrid.right() > tileMaxValue(zoomLevel)) {
-// int crossing = m_viewTilesGrid.right() - tileMaxValue(zoomLevel);
-// if (tileNumber.x() < crossing) {
-// QPoint adjustedTileNumber(tileNumber.x() + tileMaxValue(zoomLevel) + 1, tileNumber.y());
-// m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
-// qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to east, x:" << x << "->" << adjustedTileNumber.x() << "y:" << adjustedTileNumber.y();
-// }
-// }
-
-// // expand to west side?
-// if (m_viewTilesGrid.left() < 0) {
-// int crossing = -m_viewTilesGrid.left();
-// if (tileNumber.x() > (tileMaxValue(zoomLevel) - crossing)) {
-// QPoint adjustedTileNumber(tileNumber.x() - tileMaxValue(zoomLevel) - 1, tileNumber.y());
-// m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
-// qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to west, x:" << x << "->" << adjustedTileNumber.x() << "y:" << adjustedTileNumber.y();
-// }
-// }
-// }
-
-
-// int crossing = m_tilesGridSize.width() - tileMaxValue(zoomLevel) - 1;
-//// qWarning() << __PRETTY_FUNCTION__ << "crossing:" << crossing;
-// if (crossing > 0) {
-// qWarning() << __PRETTY_FUNCTION__ << "grid was bigger than amount of tiles at this tile level";
-
-// if (x < crossing) {
-// // expand to east side
-// QPoint adjustedTileNumber(tileNumber.x() + tileMaxValue(zoomLevel) + 1, tileNumber.y());
-// m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
-// qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to east, x:" << x << "->" << adjustedTileNumber.x();
-// }
-
-// if (x > (tileMaxValue(zoomLevel) - crossing)) {
-// // expand to west side
-// QPoint adjustedTileNumber(tileNumber.x() - tileMaxValue(zoomLevel) - 1, tileNumber.y());
-// m_mapScene->addTile(zoomLevel, adjustedTileNumber, image, m_zoomLevel);
-// qWarning() << __PRETTY_FUNCTION__ << "duplicate tile to west, x:" << x << "->" << adjustedTileNumber.x();
-// }
-// }
-
- m_mapScene->spanItems(m_scrollDirection, m_zoomLevel);
}
-int MapEngine::normalizeTileNumberX(int tileX)
+int MapEngine::normalize(int value, int min, int max)
{
- int tileMaxVal = tileMaxValue(m_zoomLevel);
+ qDebug() << __PRETTY_FUNCTION__;
+ Q_ASSERT_X(max >= min, "parameters", "max can't be smaller than min");
- while (tileX < 0)
- tileX += tileMaxVal + 1;
+ while (value < min)
+ value += max - min + 1;
- while (tileX > tileMaxVal)
- tileX -= tileMaxVal + 1;
+ while (value > max)
+ value -= max - min + 1;
- return tileX;
+ return value;
}
void MapEngine::receiveOwnLocation(User *user)
qDebug() << __PRETTY_FUNCTION__;
if(user) {
- QPoint newPosition = convertLatLonToSceneCoordinate(user->coordinates());
- if (m_ownLocation->pos().toPoint() != newPosition) {
- m_ownLocation->setPos(newPosition);
- }
-
+ m_ownLocation->setPos(SceneCoordinate(user->coordinates()).toPointF());
if (!m_ownLocation->isVisible())
m_ownLocation->show();
- }
- else {
+ } else {
m_ownLocation->hide();
}
+
+ m_mapScene->spanItems(currentViewSceneRect());
}
QGraphicsScene* MapEngine::scene()
return m_mapScene;
}
-void MapEngine::setAutoCentering(bool enabled)
+void MapEngine::scrollerStateChanged(QAbstractAnimation::State newState)
{
- m_autoCenteringEnabled = enabled;
+ qDebug() << __PRETTY_FUNCTION__;
+
+ if (m_smoothScrollRunning
+ && newState != QAbstractAnimation::Running) {
+ m_smoothScrollRunning = false;
+
+ // don't disable auto centering if current animation was stopped by new update from GPS
+ if (!m_scrollStartedByGps)
+ disableAutoCenteringIfRequired(m_sceneCoordinate);
+ }
+
+ m_scrollStartedByGps = false;
}
-void MapEngine::setGPSEnabled(bool enabled)
+void MapEngine::scrollToPosition(SceneCoordinate coordinate)
{
- m_gpsLocationItem->setEnabled(enabled);
+ qDebug() << __PRETTY_FUNCTION__;
+
+ m_scroller->stop();
+ m_scroller->setEasingCurve(QEasingCurve::InOutQuart);
+ m_scroller->setDuration(SMOOTH_CENTERING_TIME_MS);
+ m_scroller->setStartValue(m_sceneCoordinate);
+ m_scroller->setEndValue(coordinate);
+ m_smoothScrollRunning = true;
+ m_scroller->start();
}
-void MapEngine::setLocation(QPoint sceneCoordinate)
+void MapEngine::setAutoCentering(bool enabled)
{
qDebug() << __PRETTY_FUNCTION__;
- // jump to opposite side of the world if world limit is exceeded
- if (sceneCoordinate.x() < 0)
- sceneCoordinate.setX(sceneCoordinate.x() + WORLD_PIXELS_X);
- else if (sceneCoordinate.x() > WORLD_PIXELS_X - 1)
- sceneCoordinate.setX(sceneCoordinate.x() - WORLD_PIXELS_X);
+ m_autoCenteringEnabled = enabled;
- if (sceneCoordinate.x() > m_sceneCoordinate.x())
- m_scrollDirection = SCROLL_EAST;
- else
- m_scrollDirection = SCROLL_WEST;
+ if (!m_autoCenteringEnabled && m_gpsLocationItem->isVisible())
+ updateDirectionIndicator();
+}
+
+void MapEngine::setCenterPosition(SceneCoordinate coordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
- if (disableAutoCentering(sceneCoordinate))
- emit mapScrolledManually();
+ // jump to opposite side of the world if world horizontal limit is exceeded
+ coordinate.setX(normalize(coordinate.x(), OSM_MAP_MIN_PIXEL_X, OSM_MAP_MAX_PIXEL_X));
- m_sceneCoordinate = sceneCoordinate;
+ // don't allow vertical scene coordinates go out of the map
+ coordinate.setY(qBound(double(OSM_MAP_MIN_PIXEL_Y),
+ coordinate.y(),
+ double(OSM_MAP_MAX_PIXEL_Y)));
+
+ if (!m_smoothScrollRunning)
+ disableAutoCenteringIfRequired(coordinate);
+
+ m_sceneCoordinate = coordinate;
emit locationChanged(m_sceneCoordinate);
- if (isCenterTileChanged(sceneCoordinate)) {
- getTiles(sceneCoordinate);
+ if (isCenterTileChanged(coordinate)) {
+ getTiles(coordinate);
m_mapScene->removeOutOfViewTiles(m_viewTilesGrid, m_zoomLevel);
}
+
+ m_mapScene->spanItems(currentViewSceneRect());
+ emit newMapResolution(viewResolution());
+
+ updateDirectionIndicator();
+}
+
+void MapEngine::setGPSEnabled(bool enabled)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ m_gpsLocationItem->setEnabled(enabled);
+}
+
+void MapEngine::setRoute(Route &route)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ clearRoute();
+
+ m_mapRouteItem = new MapRouteItem(&route);
+ m_mapScene->addItem(m_mapRouteItem);
+
+ centerAndZoomTo(m_mapRouteItem->boundingRect().toRect());
}
void MapEngine::setZoomLevel(int newZoomLevel)
// converting scene tile to tile number does cause grid centering inaccuracy of one tile
const int CENTER_TILE_INACCURACY = 1;
- int gridWidth = ceil(qreal(viewSize.width()) / TILE_SIZE_X + SCROLLING_RESERVE)
- + CENTER_TILE_INACCURACY + (GRID_PADDING * 2);
- int gridHeight = ceil(qreal(viewSize.height()) / TILE_SIZE_Y + SCROLLING_RESERVE)
- + CENTER_TILE_INACCURACY + (GRID_PADDING * 2);
+ int gridWidth = ceil(qreal(viewSize.width()) / OSM_TILE_SIZE_X + SCROLLING_RESERVE)
+ + CENTER_TILE_INACCURACY + (MAP_GRID_PADDING * 2);
+ int gridHeight = ceil(qreal(viewSize.height()) / OSM_TILE_SIZE_Y + SCROLLING_RESERVE)
+ + CENTER_TILE_INACCURACY + (MAP_GRID_PADDING * 2);
m_mapFetcher->setDownloadQueueSize(gridWidth * gridHeight);
m_tilesGridSize.setHeight(gridHeight);
m_tilesGridSize.setWidth(gridWidth);
-
- qWarning() << __PRETTY_FUNCTION__ << "tiles grid:" << m_tilesGridSize.width()
- << "*" << m_tilesGridSize.height();
}
-void MapEngine::setViewLocation(QPointF latLonCoordinate)
+void MapEngine::showMapArea(const GeoCoordinate &swBound, const GeoCoordinate &neBound)
{
qDebug() << __PRETTY_FUNCTION__;
- QPoint sceneCoordinate = convertLatLonToSceneCoordinate(latLonCoordinate);
+ QRect area;
+ area.setTopRight(SceneCoordinate(neBound).toPointF().toPoint());
+ area.setBottomLeft(SceneCoordinate(swBound).toPointF().toPoint());
- m_lastManualPosition = sceneCoordinate;
-
- setLocation(sceneCoordinate);
+ centerAndZoomTo(area, false);
}
-int MapEngine::tileMaxValue(int zoomLevel)
+void MapEngine::updateDirectionIndicator()
{
qDebug() << __PRETTY_FUNCTION__;
- return (1 << zoomLevel) - 1;
-}
+ qreal distance = m_gpsPosition.distanceTo(m_sceneCoordinate);
-QString MapEngine::tilePath(int zoomLevel, int x, int y)
-{
- qDebug() << __PRETTY_FUNCTION__;
+ qreal direction = m_sceneCoordinate.azimuthTo(SceneCoordinate(m_gpsPosition));
- QString tilePathString(QString::number(zoomLevel) + "/");
- tilePathString.append(QString::number(x) + "/");
- tilePathString.append(QString::number(y));
+ // direction indicator triangle should be drawn only if the gps location item is not currently
+ // visible on the view
+ bool drawDirectionIndicatorTriangle = true;
+ if (currentViewSceneRect().contains(m_gpsLocationItem->pos()))
+ drawDirectionIndicatorTriangle = false;
- return tilePathString;
+ emit directionIndicatorValuesUpdate(direction, distance, drawDirectionIndicatorTriangle);
}
void MapEngine::updateViewTilesSceneRect()
qDebug() << __PRETTY_FUNCTION__;
const QPoint ONE_TILE = QPoint(1, 1);
- const QPoint ONE_PIXEL = QPoint(1, 1);
+ const double ONE_PIXEL = 1;
+
+ SceneCoordinate topLeft = MapTile::convertTileNumberToSceneCoordinate(m_zoomLevel,
+ m_viewTilesGrid.topLeft());
- QPoint topLeft = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewTilesGrid.topLeft());
// one tile - one pixel is added because returned coordinates are pointing to upper left corner
// of the last tile.
- QPoint bottomRight = convertTileNumberToSceneCoordinate(m_zoomLevel,
- m_viewTilesGrid.bottomRight()
- + ONE_TILE) - ONE_PIXEL;
+ SceneCoordinate bottomRight
+ = MapTile::convertTileNumberToSceneCoordinate(m_zoomLevel,
+ m_viewTilesGrid.bottomRight() + ONE_TILE);
+ bottomRight.setX(bottomRight.x() - ONE_PIXEL);
+ bottomRight.setY(bottomRight.y() - ONE_PIXEL);
- m_mapScene->tilesSceneRectUpdated(QRect(topLeft, bottomRight));
+ m_mapScene->tilesSceneRectUpdated(QRect(topLeft.toPointF().toPoint(),
+ bottomRight.toPointF().toPoint()));
}
void MapEngine::viewResized(const QSize &size)
m_mapScene->setSceneVerticalOverlap(m_viewSize.height(), m_zoomLevel);
}
+qreal MapEngine::viewResolution()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ qreal scale = (1 << (OSM_MAX_ZOOM_LEVEL - m_zoomLevel));
+
+ return MapScene::horizontalResolutionAtLatitude(centerGeoCoordinate().latitude()) * scale;
+}
+
void MapEngine::viewZoomFinished()
{
qDebug() << __PRETTY_FUNCTION__;
+ updateDirectionIndicator();
+
if (m_zoomedIn) {
m_zoomedIn = false;
m_mapScene->removeOutOfViewTiles(m_viewTilesGrid, m_zoomLevel);
}
- if (m_zoomLevel == MAX_MAP_ZOOM_LEVEL)
+ if (m_zoomLevel == OSM_MAX_ZOOM_LEVEL)
emit maxZoomLevelReached();
- else if (m_zoomLevel == MIN_VIEW_ZOOM_LEVEL)
+ else if (m_zoomLevel == MAP_VIEW_MIN_ZOOM_LEVEL)
emit minZoomLevelReached();
}
{
emit zoomLevelChanged(m_zoomLevel);
m_mapScene->setTilesDrawingLevels(m_zoomLevel);
+ m_mapScene->setZoomLevel(m_zoomLevel);
getTiles(m_sceneCoordinate);
m_mapScene->setSceneVerticalOverlap(m_viewSize.height(), m_zoomLevel);
+ m_mapScene->spanItems(currentViewSceneRect());
+ emit newMapResolution(viewResolution());
}
void MapEngine::zoomIn()
{
qDebug() << __PRETTY_FUNCTION__;
- if (m_zoomLevel < MAX_MAP_ZOOM_LEVEL) {
+ if (m_zoomLevel < OSM_MAX_ZOOM_LEVEL) {
m_zoomLevel++;
m_zoomedIn = true;
zoomed();
{
qDebug() << __PRETTY_FUNCTION__;
- if (m_zoomLevel > MIN_VIEW_ZOOM_LEVEL) {
+ if (m_zoomLevel > MAP_VIEW_MIN_ZOOM_LEVEL) {
m_zoomLevel--;
zoomed();
}