, m_zoomedIn(false)
, m_zoomLevel(DEFAULT_ZOOM_LEVEL)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_mapScene = new MapScene(this);
m_mapFetcher = new MapFetcher(new QNetworkAccessManager(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(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)));
m_mapZoomPanel = new MapZoomPanel(NULL, MAP_ZOOM_PANEL_POSITION_X, MAP_ZOOM_PANEL_POSITION_Y);
m_mapScene->addItem(m_mapZoomPanel);
void MapEngine::init()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
emit zoomLevelChanged(m_zoomLevel);
setViewLocation(QPointF(DEFAULT_LONGITUDE, DEFAULT_LATITUDE));
}
void MapEngine::setViewLocation(QPointF latLonCoordinate)
{
qDebug() << __PRETTY_FUNCTION__;
+
setLocation(convertLatLonToSceneCoordinate(latLonCoordinate));
}
QGraphicsScene* MapEngine::scene()
{
- return dynamic_cast<QGraphicsScene *>(m_mapScene);
+ qDebug() << __PRETTY_FUNCTION__;
+
+ return m_mapScene;
}
int MapEngine::tileMaxValue(int zoomLevel)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
return (1 << zoomLevel) - 1;
}
QRect MapEngine::calculateTileGrid(QPoint sceneCoordinate)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QPoint tileCoordinate = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
int gridWidth = (m_viewSize.width()/TILE_SIZE_X + 1) + (GRID_PADDING*2);
int gridHeight = (m_viewSize.height()/TILE_SIZE_Y + 1) + (GRID_PADDING*2);
bool MapEngine::isCenterTileChanged(QPoint sceneCoordinate)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QPoint centerTile = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
QPoint temp = m_centerTile;
m_centerTile = centerTile;
void MapEngine::updateViewTilesSceneRect()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ const QPoint ONE_TILE = QPoint(1, 1);
+ const QPoint ONE_PIXEL = QPoint(1, 1);
+
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()
- + QPoint(1, 1)) - QPoint(1, 1);
+ + ONE_TILE) - ONE_PIXEL;
m_mapScene->viewRectUpdated(QRect(topLeft, bottomRight));
}
void MapEngine::viewResized(const QSize &size)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_viewSize = size;
getTiles(m_sceneCoordinate);
m_mapScene->removeOutOfViewTiles();
QString MapEngine::tilePath(int zoomLevel, int x, int y)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QString tilePathString(QString::number(zoomLevel) + "/");
tilePathString.append(QString::number(x) + "/");
tilePathString.append(QString::number(y));
QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate)
{
+ 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));
QPoint MapEngine::convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
{
+ 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;
* DATA MEMBERS
******************************************************************************/
private:
+ QPoint m_centerTile; ///< Current center tile
MapFetcher *m_mapFetcher; ///< Fetcher for map tiles
MapScene *m_mapScene; ///< Scene for map tiles
MapZoomPanel *m_mapZoomPanel; ///< Toolbar for zoom buttons
- QPoint m_centerTile; ///< Current center tile
OwnLocationItem *m_ownLocation; ///< Item to show own location
QPoint m_sceneCoordinate; ///< Current center coordinate
QRect m_viewTilesGrid; ///< Current grid of tiles in view (includes margin)
#include "mapfetcher.h"
#include "mapcommon.h"
+const int MAX_PARALLEL_DOWNLOADS = 2; ///< Max simultaneous parallel downloads
+const int NOT_FOUND = -1; ///< Return value if matching request is not found from the list
+
MapFetcher::MapFetcher(QNetworkAccessManager *manager, QObject *parent)
: QObject(parent)
, m_pendingRequestsSize(0)
, m_fetchMapImagesTimerRunning(false)
, m_manager(manager)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
diskCache->setCacheDirectory(QDesktopServices::storageLocation(
QDesktopServices::CacheLocation));
QUrl MapFetcher::buildURL(int zoomLevel, QPoint tileNumbers)
{
- QString url = QString("http://tile.openstreetmap.org/mapnik/%1/%2/%3.png")
- .arg(zoomLevel).arg(tileNumbers.x()).arg(tileNumbers.y());
+ qDebug() << __PRETTY_FUNCTION__;
- return QUrl(url);
+ /**
+ * @brief Map server string for building actual URL
+ *
+ * %1 zoom level
+ * %2 x index
+ * %3 y index
+ *
+ * NOTE: If the URL is changed, then the parseURL method must be changed to match
+ * the new URL structure
+ *
+ * @var MAP_SERVER_URL
+ */
+ const QString MAP_SERVER_URL = QString("http://tile.openstreetmap.org/mapnik/%1/%2/%3.png");
+
+ return QString(MAP_SERVER_URL)
+ .arg(zoomLevel).arg(tileNumbers.x()).arg(tileNumbers.y());
}
void MapFetcher::checkNextRequestFromCache()
int i = newestRequestIndex(false);
- if (i != -1) {
- if (!m_pendingRequests[i].url.isEmpty() && m_pendingRequests[i].url.isValid()) {
- if (loadImageFromCache(m_pendingRequests[i].url)) {
+ if (i != NOT_FOUND) {
+ QUrl url = m_pendingRequests[i].url;
+ if (!url.isEmpty() && url.isValid()) {
+ if (loadImageFromCache(url)) {
// was found, remove from the list
m_pendingRequests.removeAt(i);
}
}
// schedule checking of the next request if the list is not empty
- if (newestRequestIndex(false) != -1)
+ if (newestRequestIndex(false) != NOT_FOUND)
QTimer::singleShot(0, this, SLOT(checkNextRequestFromCache()));
else
m_fetchMapImagesTimerRunning = false;
int zoomLevel;
int x;
int y;
- parseURL(url, zoomLevel, x, y);
+ parseURL(url, &zoomLevel, &x, &y);
emit mapImageReceived(zoomLevel, x, y, QPixmap::fromImage(image));
}
if (m_pendingRequests[i].url == url) {
m_pendingRequests.move(i, 0);
found = true;
- qDebug() << __PRETTY_FUNCTION__ << "URL was already found, moved to begin";
break;
}
}
// ...or add new request to the begining of the list
if (!found) {
- qDebug() << __PRETTY_FUNCTION__ << "URL was added";
- Request request;
- request.cacheChecked = false;
- request.url = url;
+ MapTileRequest request(url);
m_pendingRequests.prepend(request);
}
int zoomLevel;
int x;
int y;
- parseURL(url, zoomLevel, x, y);
+ parseURL(url, &zoomLevel, &x, &y);
int originalZoomLevel = zoomLevel;
// try to fetch requested and upper level images until found or all levels tried
do {
QIODevice *cacheImage = cache->data(buildURL(zoomLevel, QPoint(x, y)));
if (cacheImage) {
- QImage image;
-
- if (image.load(cacheImage, 0)) {
+ QPixmap pixmap;
+ if (pixmap.loadFromData(cacheImage->readAll())) {
imageFound = true;
-
- emit mapImageReceived(zoomLevel, x, y, QPixmap::fromImage(image));
+ emit mapImageReceived(zoomLevel, x, y, pixmap);
}
delete cacheImage;
bool MapFetcher::translateIndexesToUpperLevel(int &zoomLevel, int &x, int &y)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
if (zoomLevel > MIN_MAP_ZOOM_LEVEL) {
zoomLevel--;
x /= 2;
{
qDebug() << __PRETTY_FUNCTION__;
- if (!m_pendingRequests.isEmpty()) {
- for (int i = 0; i < m_pendingRequests.size(); i++) {
- if (m_pendingRequests[i].cacheChecked == cacheChecked) {
- return i;
- }
+ for (int i = 0; i < m_pendingRequests.size(); i++) {
+ if (m_pendingRequests[i].cacheChecked == cacheChecked) {
+ return i;
}
}
- return -1;
+ return NOT_FOUND;
}
-void MapFetcher::parseURL(const QUrl &url, int &zoom, int &x, int &y)
+void MapFetcher::parseURL(const QUrl &url, int *zoom, int *x, int *y)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QString path = url.path();
QStringList pathParts = path.split("/", QString::SkipEmptyParts);
int size = pathParts.size();
- if (size >= 3) {
- zoom = (pathParts.at(size-3)).toInt();
- x = (pathParts.at(size-2)).toInt();
- QString yString = pathParts.at(size-1);
- yString.chop(4);
- y = yString.toInt();
+ // Example URL: "http://tile.openstreetmap.org/mapnik/14/9354/4263.png"
+ const int MIN_PATH_SPLITTED_PARTS = 4;
+ const int ZOOM_INDEX = size - 3;
+ const int X_INDEX = size - 2;
+ const int Y_INDEX = size - 1;
+ const int FILE_EXTENSION_LENGTH = 4;
+
+ if (size >= MIN_PATH_SPLITTED_PARTS) {
+ *zoom = (pathParts.at(ZOOM_INDEX)).toInt();
+ *x = (pathParts.at(X_INDEX)).toInt();
+ QString yString = pathParts.at(Y_INDEX);
+ yString.chop(FILE_EXTENSION_LENGTH);
+ *y = yString.toInt();
}
}
int i = newestRequestIndex(true);
- if (i != -1) {
+ if (i != NOT_FOUND) {
QUrl url = m_pendingRequests.takeAt(i).url;
QNetworkRequest request(url);
#include <QtCore>
#include <QNetworkAccessManager>
+#include "maptilerequest.h"
+
class QNetworkReply;
class QUrl;
{
Q_OBJECT
- /**
- * @brief Type for download requests
- *
- * @typedef Request
- */
- /**
- * @brief Struct for download requests
- *
- * @struct _Request
- */
- typedef struct _Request {
- bool cacheChecked; ///< Is this request already checked from the cache
- QUrl url; ///< URL
- } Request;
-
public:
/**
* @brief Constructor for MapFetcher.
* @param [out] x x variable
* @param [out] y y variable
*/
- void parseURL(const QUrl &url, int &zoom, int &x, int &y);
+ void parseURL(const QUrl &url, int *zoom, int *x, int *y);
/**
* @brief Translate indexes to matching upper level map tile indexes
* DATA MEMBERS
******************************************************************************/
private:
- static const int MAX_PARALLEL_DOWNLOADS = 2; ///< Max simultaneous parallel downloads
-
QList<QNetworkReply*> m_currentDownloads; ///< List of current downloads
int m_pendingRequestsSize; ///< Max number of pending requests
bool m_fetchMapImagesTimerRunning; ///< is the singleshot timer already running
QNetworkAccessManager *m_manager; ///< Network access manager
- QList<Request> m_pendingRequests; ///< List of map image fetching requests
+ QList<MapTileRequest> m_pendingRequests; ///< List of map image fetching requests
};
#endif
, m_isRemoveStackedTilesRunning(false)
, m_viewRect(QRect(0, 0, 0, 0))
{
+ qDebug() << __PRETTY_FUNCTION__;
+
const int maxTilesPerSide = (1 << MAX_MAP_ZOOM_LEVEL);
const int maxPixelsX = maxTilesPerSide * TILE_SIZE_X;
const int maxPixelsY = maxTilesPerSide * TILE_SIZE_Y;
void MapScene::addTile(MapTile *mapTile, QString hashKey)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_mapTilesInScene.insert(hashKey, mapTile);
addItem(mapTile);
}
bool MapScene::isTileInScene(QString hashKey)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
return m_mapTilesInScene.contains(hashKey);
}
void MapScene::viewRectUpdated(QRect viewRect)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_viewRect = viewRect;
}
MapTile::MapTile()
: m_tileNumber(QPoint(UNDEFINED, UNDEFINED))
, m_zoomLevel(UNDEFINED)
-{
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
setPos(UNDEFINED, UNDEFINED);
setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
}
int MapTile::zoomLevel()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
return m_zoomLevel;
}
void MapTile::setZoomLevel(int tileZoomLevel, int currentViewZoomLevel)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_zoomLevel = tileZoomLevel;
setPosition();
void MapTile::setSceneLevel(int currentZoomLevel)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
if (currentZoomLevel < m_zoomLevel) {
qreal z = static_cast<qreal>(MIN_MAP_SCENE_NORMAL_LEVEL + currentZoomLevel
- (m_zoomLevel - currentZoomLevel)) + 0.5;
}
else
setZValue(static_cast<qreal>(MIN_MAP_SCENE_NORMAL_LEVEL + m_zoomLevel));
-
- qDebug() << __PRETTY_FUNCTION__ << "Tile:" << m_tileNumber
- << "m_zoomLevel" << m_zoomLevel
- << "zValue:" << zValue();
}
QPoint MapTile::tileNumber()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
return m_tileNumber;
}
void MapTile::setTileNumber(QPoint tileNumber)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_tileNumber = tileNumber;
setPosition();
}
void MapTile::setPosition()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
const int maxTileNumber = (1 << m_zoomLevel) - 1;
if ((m_zoomLevel >= MIN_MAP_ZOOM_LEVEL) && (m_zoomLevel <= MAX_MAP_ZOOM_LEVEL) &&
MapView::MapView(QWidget *parent)
: QGraphicsView(parent)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
void MapView::setZoomLevel(int zoomLevel)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
m_zoomAnimation->stop();
m_zoomAnimation->setDuration(ZOOM_TIME);
m_zoomAnimation->setStartValue(viewScale());
qreal MapView::currentScale()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QTransform currentTransform = transform();
return currentTransform.m11();
}
qreal MapView::viewScale()
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QTransform currentTransform = transform();
return currentTransform.m11();
}
void MapView::setViewScale(qreal viewScale)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QTransform transform;
transform.scale(viewScale, viewScale);
setTransform(transform);
{
m_scenePosition += m_mousePosition - mapToScene(event->pos()).toPoint();
- emit viewScrolled(m_scenePosition);
qDebug() << __PRETTY_FUNCTION__ << "m_scenePosition:" << m_scenePosition;
+ emit viewScrolled(m_scenePosition);
+
m_mousePosition = mapToScene(event->pos()).toPoint();
emit viewContentChanged(mapToScene(viewport()->x(), viewport()->y()).toPoint());
}
void MapView::mousePressEvent(QMouseEvent *event)
{
+ qDebug() << __PRETTY_FUNCTION__;
+
QGraphicsView::mousePressEvent(event);
m_mousePosition = mapToScene(event->pos()).toPoint();
ui/buttonitem.cpp \
ui/situareuser.cpp \
engine/engine.cpp \
- ui/settingsdialog.cpp
+ ui/settingsdialog.cpp \
+ map/maptilerequest.cpp
HEADERS += ui/mainwindow.h \
ui/mapviewscreen.h \
ui/listviewscreen.h \
ui/situareuser.h \
engine/engine.h \
user/user.h \
- ui/settingsdialog.h
+ ui/settingsdialog.h \
+ map/maptilerequest.h
QT += network \
webkit
-
DEFINES += QT_NO_DEBUG_OUTPUT
-
!maemo5 {
message(QJson built in)
message(Make sure you have QJson development headers installed)
message(install headers with: sudo apt-get install libqjson-dev)
}
-
maemo5 {
message(QJson built in)
message(Make sure you have QJson development headers installed)