- /*
- Situare - A location system for Facebook
- Copyright (C) 2010 Ixonos Plc. Authors:
+/*
+ Situare - A location system for Facebook
+ Copyright (C) 2010 Ixonos Plc. Authors:
- Sami Rämö - sami.ramo@ixonos.com
+ Sami Rämö - sami.ramo@ixonos.com
+ Jussi Laitinen - jussi.laitinen@ixonos.com
+ Pekka Nissinen - pekka.nissinen@ixonos.com
- Situare is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
+ Situare is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
- Situare is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ Situare is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Situare; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA.
- */
+ You should have received a copy of the GNU General Public License
+ along with Situare; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA.
+*/
-#include <math.h>
+#include <QDebug>
+#include <QString>
+#include <QStringList>
+#include <QUrl>
+#include <QHash>
+#include <QHashIterator>
+#include <QRect>
#include "mapengine.h"
#include "maptile.h"
-MapEngine::MapEngine()
+MapEngine::MapEngine(QObject *parent)
+ : QObject(parent)
+ , m_centerTile(QPoint(UNDEFINED, UNDEFINED))
+ , m_viewSize(QSize(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT))
+ , m_zoomedIn(false)
+ , m_zoomLevel(DEFAULT_ZOOM_LEVEL)
{
+ 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)));
+
+ m_mapZoomPanel = new MapZoomPanel(NULL, MAP_ZOOM_PANEL_POSITION_X, MAP_ZOOM_PANEL_POSITION_Y);
+ m_mapScene->addItem(m_mapZoomPanel);
+ connect(m_mapZoomPanel, SIGNAL(zoomInPressed()), this, SLOT(zoomIn()));
+ connect(m_mapZoomPanel, SIGNAL(zoomOutPressed()), this, SLOT(zoomOut()));
+
+ m_ownLocation = new OwnLocationItem();
+ m_mapScene->addItem(m_ownLocation);
+}
+
+void MapEngine::init()
+{
+ emit zoomLevelChanged(m_zoomLevel);
+ setViewLocation(QPointF(DEFAULT_LONGITUDE, DEFAULT_LATITUDE));
+}
+
+void MapEngine::setViewLocation(QPointF latLonCoordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+ setLocation(convertLatLonToSceneCoordinate(latLonCoordinate));
+}
+
+void MapEngine::mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ QString hashKey = tilePath(zoomLevel, x, y);
+ if (!m_mapScene->isTileInScene(hashKey)) {
+
+ MapTile *mapTile = new MapTile();
+ mapTile->setZoomLevel(zoomLevel, m_zoomLevel);
+ mapTile->setTileNumber(QPoint(x, y));
+ mapTile->setPixmap(image);
+
+ m_mapScene->addTile(mapTile, hashKey);
+
+ m_mapScene->enqueueRemoveStackedTiles(mapTile);
+ }
+}
+
+QGraphicsScene* MapEngine::scene()
+{
+ return dynamic_cast<QGraphicsScene *>(m_mapScene);
+}
+
+int MapEngine::tileMaxValue(int zoomLevel)
+{
+ return (1 << zoomLevel) - 1;
+}
+
+QRect MapEngine::calculateTileGrid(QPoint sceneCoordinate)
+{
+ 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);
+ int topLeftX = tileCoordinate.x() - (gridWidth/2);
+ int topLeftY = tileCoordinate.y() - (gridHeight/2);
+
+ m_mapFetcher->setDownloadQueueSize(gridWidth * gridHeight);
+
+ return QRect(topLeftX, topLeftY, gridWidth, gridHeight);
+}
+
+void MapEngine::alignImmovableItems(QPoint viewTopLeft)
+{
+ m_mapZoomPanel->setPos(viewTopLeft);
+
+ qDebug() << __PRETTY_FUNCTION__ << "viewTopLeft:" << viewTopLeft;
+}
+
+void MapEngine::setLocation(QPoint sceneCoordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ m_sceneCoordinate = sceneCoordinate;
+ emit locationChanged(m_sceneCoordinate);
+
+ if (isCenterTileChanged(sceneCoordinate)) {
+ getTiles(sceneCoordinate);
+ m_mapScene->removeOutOfViewTiles();
+ }
+}
+
+bool MapEngine::isCenterTileChanged(QPoint sceneCoordinate)
+{
+ QPoint centerTile = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
+ QPoint temp = m_centerTile;
+ m_centerTile = centerTile;
+
+ return (centerTile != temp);
+}
+
+void MapEngine::getTiles(QPoint sceneCoordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ m_viewTilesGrid = calculateTileGrid(sceneCoordinate);
+ updateViewTilesSceneRect();
+
+ 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);
+
+ for (int x = topLeftX; x <= bottomRightX; ++x) {
+ for (int y = topLeftY; y <= bottomRightY; ++y) {
+
+ int tileX = x;
+ int tileY = y;
+
+ if (tileX < 0)
+ tileX += tileMaxVal;
+ else if (tileX > tileMaxVal)
+ tileX -= tileMaxVal;
+
+ if (tileY < 0)
+ tileY += tileMaxVal;
+ else if (tileY > tileMaxVal)
+ tileY -= tileMaxVal;
+
+ if (!m_mapScene->isTileInScene(tilePath(m_zoomLevel, tileX, tileY)))
+ emit fetchImage(m_zoomLevel, tileX, tileY);
+ }
+ }
+}
+
+void MapEngine::updateViewTilesSceneRect()
+{
+ QPoint topLeft = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewTilesGrid.topLeft());
+ QPoint bottomRight = convertTileNumberToSceneCoordinate(m_zoomLevel,
+ m_viewTilesGrid.bottomRight()
+ + QPoint(1, 1)) - QPoint(1, 1);
+
+ m_mapScene->viewRectUpdated(QRect(topLeft, bottomRight));
+}
+
+void MapEngine::viewResized(const QSize &size)
+{
+ m_viewSize = size;
+ getTiles(m_sceneCoordinate);
+ m_mapScene->removeOutOfViewTiles();
+}
+
+void MapEngine::viewZoomFinished()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ if (m_zoomedIn) {
+ m_zoomedIn = false;
+ m_mapScene->removeOutOfViewTiles();
+ }
+}
+
+void MapEngine::zoomIn()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ if (m_zoomLevel < MAX_MAP_ZOOM_LEVEL) {
+ m_zoomLevel++;
+ m_zoomedIn = true;
+ emit zoomLevelChanged(m_zoomLevel);
+
+ m_mapScene->setTilesDrawingLevels(m_zoomLevel);
+
+ getTiles(m_sceneCoordinate);
+ }
+}
+
+void MapEngine::zoomOut()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ if (m_zoomLevel > MIN_VIEW_ZOOM_LEVEL) {
+ m_zoomLevel--;
+ emit zoomLevelChanged(m_zoomLevel);
+
+ m_mapScene->setTilesDrawingLevels(m_zoomLevel);
+
+ getTiles(m_sceneCoordinate);
+ }
+}
+
+QString MapEngine::tilePath(int zoomLevel, int x, int y)
+{
+ QString tilePathString(QString::number(zoomLevel) + "/");
+ tilePathString.append(QString::number(x) + "/");
+ tilePathString.append(QString::number(y));
+
+ return tilePathString;
}
-MapEngine::MapEngine(MapView *mapView)
+QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate)
{
-// m_mapView = mapView;
-// m_mapScene = new MapScene();
-// mapView->setScene(m_mapScene);
-//
-// /// \todo remove debug data
-// for (int x=4261; x<=4264; x++) {
-// for (int y=9352; y<=9353; y++) {
-// MapTile *mapTile = new MapTile();
-// mapTile->setZoomLevel(14);
-// mapTile->setTileXY(x, y);
-// mapTile->setPixmap(QPixmap("/home/ramosam-local/situare/src/map/static_test_tiles/14_9352_4261.png"));
-// mapTile->setOffset((x-4261)*256, (y-9352)*256);
-// m_mapScene->addMapTile(mapTile);
-// }
-// }
+ 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));
+
+ return QPoint(x, y);
}
QPoint MapEngine::convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
{
- int x = tileNumber.x() * TILE_SIZE_X * pow(2, MAX_ZOOM_LEVEL - zoomLevel);
- int y = tileNumber.y() * TILE_SIZE_Y * pow(2, MAX_ZOOM_LEVEL - zoomLevel);
+ int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
+ int x = tileNumber.x() * TILE_SIZE_X * pow;
+ int y = tileNumber.y() * TILE_SIZE_Y * pow;
return QPoint(x, y);
}
+
+QPoint MapEngine::convertLatLonToSceneCoordinate(QPointF latLonCoordinate)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ qreal longitude = latLonCoordinate.x();
+ qreal latitude = latLonCoordinate.y();
+
+ if ((longitude > MAX_LONGITUDE) || (longitude < MIN_LONGITUDE))
+ return QPoint(UNDEFINED, UNDEFINED);
+ if ((latitude > MAX_LATITUDE) || (latitude < MIN_LATITUDE))
+ return QPoint(UNDEFINED, UNDEFINED);
+
+ 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);
+
+ return QPointF(x*z*TILE_SIZE_X, y*z*TILE_SIZE_Y).toPoint();
+}