Merge branch 'wallika-own' v0.2
authorKaj Wallin <kaj.wallin@ixonos.com>
Mon, 19 Apr 2010 13:08:22 +0000 (16:08 +0300)
committerKaj Wallin <kaj.wallin@ixonos.com>
Mon, 19 Apr 2010 13:08:22 +0000 (16:08 +0300)
Conflicts:
src/ui/mapviewscreen.cpp

36 files changed:
Doxyfile
doc/map/map_class_diagram.dia [deleted file]
src/common.h [deleted file]
src/map/OSM/README.txt [deleted file]
src/map/mapcommon.h [new file with mode: 0644]
src/map/mapengine.cpp
src/map/mapengine.h
src/map/mapfetcher.cpp
src/map/mapfetcher.h
src/map/mapscene.cpp
src/map/mapscene.h
src/map/maptile.cpp
src/map/maptile.h
src/map/mapview.cpp
src/map/mapview.h
src/src.pro
src/ui/mapviewscreen.cpp
src/ui/mapviewscreen.h
tests/map/mapengine/testmapengine.cpp [new file with mode: 0644]
tests/map/mapengine/testmapengine.pro [new file with mode: 0644]
tests/map/mapscene/maptile.png [new file with mode: 0644]
tests/map/mapscene/testmapscene.cpp [new file with mode: 0644]
tests/map/mapscene/testmapscene.pro [new file with mode: 0644]
tests/map/maptile/testmaptile.cpp [new file with mode: 0644]
tests/map/maptile/testmaptile.pro [new file with mode: 0644]
tests/map/mapview/testmapview.cpp [new file with mode: 0644]
tests/map/mapview/testmapview.pro [new file with mode: 0644]
tests/testmap/testmapengine/testmapengine.cpp [deleted file]
tests/testmap/testmapengine/testmapengine.pro [deleted file]
tests/testmap/testmapscene/maptile.png [deleted file]
tests/testmap/testmapscene/testmapscene.cpp [deleted file]
tests/testmap/testmapscene/testmapscene.pro [deleted file]
tests/testmap/testmaptile/testmaptile.cpp [deleted file]
tests/testmap/testmaptile/testmaptile.pro [deleted file]
tests/testmap/testmapview/testmapview.cpp [deleted file]
tests/testmap/testmapview/testmapview.pro [deleted file]

index 1f2fd1f..1ba01a2 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -302,7 +302,7 @@ EXTRACT_ALL            = NO
 # If the EXTRACT_PRIVATE tag is set to YES all private members of a class
 # will be included in the documentation.
 
-EXTRACT_PRIVATE        = NO
+EXTRACT_PRIVATE        = YES
 
 # If the EXTRACT_STATIC tag is set to YES all static members of a file
 # will be included in the documentation.
diff --git a/doc/map/map_class_diagram.dia b/doc/map/map_class_diagram.dia
deleted file mode 100644 (file)
index 45f962b..0000000
Binary files a/doc/map/map_class_diagram.dia and /dev/null differ
diff --git a/src/common.h b/src/common.h
deleted file mode 100644 (file)
index e3d90ca..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#include <QtCore>
-
-static const int TILE_SIZE_X = 256; ///< Tile image size in x direction
-static const int TILE_SIZE_Y = 256; ///< Tile image size in y direction
-static const int MIN_ZOOM_LEVEL = 0; ///< Minimum zoom level
-static const int MAX_ZOOM_LEVEL = 18; ///< Maximum zoom level
-static const qreal MIN_LATITUDE = -85.0511; ///< Minimum latitude value
-static const qreal MAX_LATITUDE = 85.0511;  ///< Maximum latitude value
-static const qreal MIN_LONGITUDE = -180.0;  ///< Minimum longitude value
-static const qreal MAX_LONGITUDE = 180.0;  ///< Maximum longitude value
-/**
-* \var UNDEFINED
-* \brief Value to be used when zoom level, tile numbers or position are not defined
-*/
-static const int UNDEFINED = -1;
-
-#endif // COMMON_H
diff --git a/src/map/OSM/README.txt b/src/map/OSM/README.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/map/mapcommon.h b/src/map/mapcommon.h
new file mode 100644 (file)
index 0000000..2ebb115
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+   Situare - A location system for Facebook
+   Copyright (C) 2010  Ixonos Plc. Authors:
+
+       Sami Rämö - sami.ramo@ixonos.com
+       Jussi Laitinen - jussi.laitinen@ixonos.com
+
+   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.
+
+   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.
+*/
+
+#ifndef MAPCOMMON_H
+#define MAPCOMMON_H
+
+#include <QtCore>
+
+const int TILE_SIZE_X = 256; ///< Tile image size in x direction
+const int TILE_SIZE_Y = 256; ///< Tile image size in y direction
+
+const int MIN_MAP_ZOOM_LEVEL = 0; ///< Minimum zoom level
+const int MAX_MAP_ZOOM_LEVEL = 18; ///< Maximum zoom level
+const int MIN_MAP_SCENE_NORMAL_LEVEL = MAX_MAP_ZOOM_LEVEL + 1;
+
+const int ZOOM_FPS = 30; ///< FPS for the zoom effect
+const qreal ZOOM_TIME = 250; ///< Length of the zoom effect (ms)
+
+const qreal MAX_LATITUDE = 85.05112877980659237802;  ///< Maximum latitude value
+const qreal MIN_LATITUDE = -MAX_LATITUDE; ///< Minimum latitude value
+const qreal MIN_LONGITUDE = -180.0;  ///< Minimum longitude value
+const qreal MAX_LONGITUDE = 180.0;  ///< Maximum longitude value
+
+const int DEFAULT_SCREEN_WIDTH = 973;    ///< Default screen width
+const int DEFAULT_SCREEN_HEIGHT = 614;   ///< Default screen height
+const int DEFAULT_ZOOM_LEVEL = 14;       ///< Default zoom level
+const qreal DEFAULT_LONGITUDE = 25.5000; ///< Default longitude value
+const qreal DEFAULT_LATITUDE = 65.0000;  ///< Default latitude value
+
+const int GRID_PADDING = 1;  ///< Grid padding used in tile grid calculation
+
+/**
+* \var UNDEFINED
+* \brief Value to be used when zoom level, tile numbers or position are not defined
+*/
+const int UNDEFINED = -1;
+
+#endif // MAPCOMMON_H
index 0cb6a85..f05a470 100644 (file)
 #include <QString>
 #include <QStringList>
 #include <QUrl>
+#include <QHash>
+#include <QHashIterator>
+#include <QRect>
 
 #include "mapengine.h"
 #include "maptile.h"
 
-#include <QtCore>
-#include <QtGlobal>
-
 MapEngine::MapEngine(QObject *parent)
     : QObject(parent)
+    , m_centerTile(QPoint(UNDEFINED, UNDEFINED))
+    , m_viewSize(QSize(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT))
+    , m_zoomLevel(DEFAULT_ZOOM_LEVEL)
 {
     m_mapScene = new MapScene(this);
-    m_zoomLevel = 14;
 
     m_mapFetcher = new MapFetcher(new QNetworkAccessManager(this), this);
+    connect(this, SIGNAL(fetchImage(QUrl)), m_mapFetcher, SLOT(fetchMapImage(QUrl)));
     connect(m_mapFetcher, SIGNAL(mapImageReceived(QUrl,QPixmap)), this,
             SLOT(mapImageReceived(QUrl, QPixmap)));
 }
 
-void MapEngine::setViewLocation(QPointF latLonCoordinate)
+void MapEngine::init()
 {
     emit zoomLevelChanged(m_zoomLevel);
+    setViewLocation(QPointF(DEFAULT_LONGITUDE, DEFAULT_LATITUDE));
+}
 
-    /// Fetch some map tiles for demo purposes
-    for (int x=9351; x<=9354; x++) {
-        for (int y=4261; y<=4264; y++) {
-            QUrl url = buildURL(m_zoomLevel, QPoint(x, y));
-            m_mapFetcher->fetchMapImage(url);
-        }
-    }
+void MapEngine::setViewLocation(QPointF latLonCoordinate)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    setLocation(convertLatLonToSceneCoordinate(latLonCoordinate));
 }
 
 QUrl MapEngine::buildURL(int zoomLevel, QPoint tileNumbers)
@@ -70,32 +72,311 @@ void MapEngine::parseURL(const QUrl &url, int &zoom, int &x, int &y)
 
     int size = pathParts.size();
 
-    if (size < 3)
-        return;
-
-    zoom = (pathParts.at(size-3)).toInt();
-    x = (pathParts.at(size-2)).toInt();
-    QString yString = pathParts.at(size-1);
-    yString.chop(4);
-    y = yString.toInt();
+    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();
+    }
 }
 
 void MapEngine::mapImageReceived(const QUrl &url, const QPixmap &pixmap)
 {
-    int zoom = -1;
-    int x = -1;
-    int y = -1;
+    //qDebug() << __PRETTY_FUNCTION__;
+
+    int zoom = UNDEFINED;
+    int x = UNDEFINED;
+    int y = UNDEFINED;
 
     parseURL(url, zoom, x, y);
+    QString hashKey = tilePath(zoom, x, y);
+    if (!m_mapTilesInScene.contains(hashKey)) {
+
+        MapTile *mapTile = new MapTile();
+        mapTile->setZoomLevel(zoom);
+        mapTile->setTileNumber(QPoint(x, y));
+        mapTile->setPixmap(pixmap);
+
+        m_mapTilesInScene.insert(hashKey, mapTile);
+        m_mapScene->addMapTile(mapTile);
 
-    MapTile *mapTile = new MapTile();
-    mapTile->setZoomLevel(zoom);
-    mapTile->setTileNumber(QPoint(x, y));
-    mapTile->setPixmap(pixmap);
-    m_mapScene->addMapTile(mapTile);
+        removeStackedTiles(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);
+
+    return QRect(topLeftX, topLeftY, gridWidth, gridHeight);
+}
+
+void MapEngine::setLocation(QPoint sceneCoordinate)
+{
+    //qDebug() << __PRETTY_FUNCTION__;
+
+    m_sceneCoordinate = sceneCoordinate;
+    emit locationChanged(m_sceneCoordinate);
+
+    if (isCenterTileChanged(sceneCoordinate)) {
+        getTiles(sceneCoordinate);
+        removeTilesOutOfView();
+    }
+}
+
+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_viewGrid = calculateTileGrid(sceneCoordinate);
+
+    int topLeftX = m_viewGrid.topLeft().x();
+    int topLeftY = m_viewGrid.topLeft().y();
+    int bottomRightX = m_viewGrid.bottomRight().x();
+    int bottomRightY = m_viewGrid.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;
+
+            QUrl url = buildURL(m_zoomLevel, QPoint(tileX, tileY));
+
+            if (!m_mapTilesInScene.contains(tilePath(m_zoomLevel, tileX, tileY)))
+                emit fetchImage(url);
+        }
+    }
+}
+
+void MapEngine::removeTile(MapTile *tile)
+{
+    //qDebug() << __PRETTY_FUNCTION__;
+
+    if (tile) {
+       m_mapTilesInScene.remove(tilePath(tile->zoomLevel(), tile->tileNumber().x(),
+                                         tile->tileNumber().y()));
+       m_mapScene->removeItem(tile);
+       delete tile;
+    }
+}
+
+void MapEngine::removeTilesOutOfView()
+{
+    //qDebug() << __PRETTY_FUNCTION__;
+
+    QPoint topLeft = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewGrid.topLeft());
+    QPoint bottomRight = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewGrid.bottomRight()
+                                                             + QPoint(1, 1));
+    qreal width = bottomRight.x() - topLeft.x();
+    qreal height = bottomRight.y() - topLeft.y();
+
+    QList<QGraphicsItem *> viewTiles = m_mapScene->items(topLeft.x(), topLeft.y(), width, height,
+                                                         Qt::ContainsItemBoundingRect);
+    QList<QGraphicsItem *> allTiles = m_mapScene->items();
+
+    //Remove tiles which are in view from allTiles
+    foreach (QGraphicsItem *tile, viewTiles)
+        allTiles.removeOne(tile);
+
+    //Remove tiles out of view
+    foreach (QGraphicsItem *tile, allTiles) {
+        MapTile *tileToRemove = dynamic_cast<MapTile *>(tile);
+        removeTile(tileToRemove);
+    }
+}
+
+void MapEngine::removeStackedTiles(MapTile *newTile)
+{
+    //qDebug() << __PRETTY_FUNCTION__;
+
+    QRectF newTileSceneRect = newTile->sceneBoundingRect();
+    QList<QGraphicsItem *> collidingTiles = newTile->collidingItems(Qt::IntersectsItemBoundingRect);
+
+    //Loop all items under new tile
+    foreach (QGraphicsItem *collidingTile, collidingTiles) {
+
+        QRectF collidingTileSceneRect = collidingTile->sceneBoundingRect();
+
+        //If new tile covers the tile under, remove the tile
+        if (newTileSceneRect.contains(collidingTileSceneRect)) {
+            MapTile *tile = dynamic_cast<MapTile *>(collidingTile);
+            removeTile(tile);
+        }
+
+        else {
+            //Get tiles below removal candidate
+            QList<QGraphicsItem *> stackedTiles = m_mapScene->items(collidingTileSceneRect,
+                                                                    Qt::ContainsItemBoundingRect);
+            QRectF combined = combineTiles(collidingTile, stackedTiles);
+
+            //If combined tiles below removal candidate covers removal candidate, remove it
+            if (combined.contains(collidingTileSceneRect)) {
+                MapTile *tile = dynamic_cast<MapTile *>(collidingTile);
+                removeTile(tile);
+            }
+        }
+    }
+}
+
+QRectF MapEngine::combineTiles(QGraphicsItem *parentTile,
+                               const QList<QGraphicsItem*> &stackedTiles)
+{
+    QRectF combined;
+    int count = 0;
+
+    foreach (QGraphicsItem *stackedTile, stackedTiles) {
+        if (stackedTile != parentTile) {
+            count++;
+            QRectF stackedTileSceneRect = stackedTile->sceneBoundingRect();
+            combined = combined.united(stackedTileSceneRect);
+        }
+    }
+
+    if (count < 4)
+        combined = QRectF();
+
+    return combined;
+}
+
+void MapEngine::viewResized(const QSize &size)
+{
+    m_viewSize = size;
+    getTiles(m_sceneCoordinate);
+    removeTilesOutOfView();
+}
+
+void MapEngine::zoomIn()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if (m_zoomLevel < MAX_MAP_ZOOM_LEVEL) {
+        m_zoomLevel++;
+        emit zoomLevelChanged(m_zoomLevel);
+
+        setTilesDrawingLevels();
+
+        getTiles(m_sceneCoordinate);
+
+        // remove unused tiles after zooming is done
+        QTimer::singleShot(ZOOM_TIME*2, this, SLOT(removeTilesOutOfView()));
+    }
+}
+
+void MapEngine::zoomOut()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if (m_zoomLevel > MIN_MAP_ZOOM_LEVEL) {
+        m_zoomLevel--;
+        emit zoomLevelChanged(m_zoomLevel);
+
+        setTilesDrawingLevels();
+
+        getTiles(m_sceneCoordinate);
+    }
+}
+
+void MapEngine::setTilesDrawingLevels()
+{
+    //qDebug() << __PRETTY_FUNCTION__ << "m_zoomLevel:" << m_zoomLevel;
+
+    QList<QGraphicsItem *> items = m_mapScene->items();
+
+    for (int i = 0; i < items.size(); ++i) {
+        MapTile *item = dynamic_cast<MapTile *>(items.at(i));
+        if (item)
+            item->setSceneLevel(m_zoomLevel);
+    }
+
+}
+
+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;
+}
+
+void MapEngine::scalingFactorChanged(qreal scaleFactor)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    Q_UNUSED(scaleFactor);
+}
+
+QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate)
+{
+    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 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();
+}
index b833981..9e202f5 100644 (file)
 
 #include <QtCore>
 
-#include "common.h"
+#include "mapcommon.h"
 #include "mapfetcher.h"
 #include "mapscene.h"
+#include "maptile.h"
 
 /**
 * @brief Map engine
@@ -35,6 +36,7 @@
 * Logic for controlling map functionality. Does also include static methods for
 * converting coordinates.
 * @author Sami Rämö - sami.ramo (at) ixonos.com
+* @author Jussi Laitinen - jussi.laitinen (at) ixonos.com
 */
 class MapEngine : public QObject
 {
@@ -46,7 +48,27 @@ public:
     * @param parent Parent
     */
     MapEngine(QObject *parent = 0);
-    
+
+/*******************************************************************************
+ * CLASS SPECIFIC MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
+    /**
+    * @brief Convert latitude and longitude to scene coordinates.
+    *
+    * @param latLonCoordinate latitude and longitude values
+    * @return scene coordinate
+    */
+    static QPoint convertLatLonToSceneCoordinate(QPointF latLonCoordinate);
+
+    /**
+    * @brief Convert MapScene coordinate to tile x & y numbers.
+    *
+    * @param zoomLevel ZoomLevel
+    * @param sceneCoordinate MapScene coordinate
+    * @return QPoint tile x & y numbers
+    */
+    static QPoint convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate);
+
     /**
     * @brief Convert tile x & y numbers to MapScene coordinates
     *
@@ -54,15 +76,24 @@ public:
     * @param tileNumber x & y numbers of the tile
     * @return QPoint MapScene coordinate
     */
+    static QPoint convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber);
 
-    static QPoint convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
-    {
-        int pow = 1 << (MAX_ZOOM_LEVEL - zoomLevel);
-        int x = tileNumber.x() * TILE_SIZE_X * pow;
-        int y = tileNumber.y() * TILE_SIZE_Y * pow;
+    /**
+    * @brief MapEngine initializer
+    *
+    * Set initial location and zoom level for the engine. locationChanged and
+    * zoomLevelChanged signals are emitted, so init should be called after
+    * those signals are connected to MapView.
+    */
+    void init();
 
-        return QPoint(x, y);
-    }
+    /**
+    * @brief Helper for setting view location based on latitude and longitude
+    * coordinates
+    *
+    * @param latLonCoordinate Latitude & longitude coordinates for location
+    */
+    void setViewLocation(QPointF latLonCoordinate);
 
     /**
     * @brief Getter for scene
@@ -71,42 +102,21 @@ public:
     */
     QGraphicsScene* scene();
 
+public slots:
     /**
-    * @brief Set view location
+    * @brief Slot for setting current view location
     *
-    * @param latLonCoordinate Latitude & longitude coordinates for location
+    * Emits locationChanged signal.
+    * @param sceneCoordinate Scene coordinates for new position
     */
-    void setViewLocation(QPointF latLonCoordinate);
+    void setLocation(QPoint sceneCoordinate);
 
     /**
-    * @brief Converts latitude, longitude and zoom to tile x, y values.
+    * @brief Slot for view resizing.
     *
-    * @param zoomLevel zoom level
-    * @param latLonCoordinate latitude and longitude values
-    * @return QPoint tile x,y value
+    * @param size view size
     */
-    static QPoint convertLatLonToTile(int zoomLevel, QPointF latLonCoordinate)
-    {
-        qDebug() << __PRETTY_FUNCTION__;
-
-        qreal longitude = latLonCoordinate.x();
-        qreal latitude = latLonCoordinate.y();
-
-        if ((zoomLevel > MAX_ZOOM_LEVEL) || (zoomLevel < MIN_ZOOM_LEVEL))
-            return QPoint(UNDEFINED, UNDEFINED);
-        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 << zoomLevel);
-
-        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 QPoint(qFloor(x*z), qFloor(y*z));
-    }
+    void viewResized(const QSize &size);
 
 private:
     /**
@@ -119,7 +129,42 @@ private:
     QUrl buildURL(int zoomLevel, QPoint tileNumbers);
 
     /**
-    * @brief Parses given URL to zoom, x and y values. Parsed values are
+    * @brief Calculate grid of tile coordinates from current scene coordinate.
+    *
+    * Grid size is calculated from view size and scene's current center coordinate.
+    *
+    * @param sceneCoordinate scene's current center coordinate
+    * @return QRect grid of tile coordinates
+    */
+    QRect calculateTileGrid(QPoint sceneCoordinate);
+
+    /**
+    * @brief Get new tiles.
+    *
+    * Calculates which tiles has to be fetched.
+    * @param sceneCoordinate scene's center coordinate
+    */
+    void getTiles(QPoint sceneCoordinate);
+
+    /**
+    * @brief Check if center tile has changed.
+    *
+    * @param sceneCoordinate scene's center coordinate
+    * @return bool true if center tile changed, false otherwise
+    */
+    bool isCenterTileChanged(QPoint sceneCoordinate);
+
+    /**
+    * @brief Combine tiles' rectangles to one rectangle.
+    *
+    * @param parentTile parent tile not to combine
+    * @param stackedTiles tiles to combine
+    * @return QRectF resulting rectangle
+    */
+    QRectF combineTiles(QGraphicsItem *parentTile, const QList<QGraphicsItem*> &stackedTiles);
+
+    /**
+    * @brief Parse given URL to zoom, x and y values. Parsed values are
     * placed in variables given as parameters.
     *
     * @param url url to parse
@@ -129,6 +174,49 @@ private:
     */
     void parseURL(const QUrl &url, int &zoom, int &x, int &y);
 
+    /**
+    * @brief Remove tiles which are stacked.
+    *
+    * Iterate through tiles which are under this map tile and remove obscured
+    * tiles.
+    *
+    * @param newTile new tile covering old tiles
+    */
+    void removeStackedTiles(MapTile *newTile);
+
+    /**
+    * @brief Remove tile.
+    *
+    * Removes tile from scene and list of current tiles in scene.
+    * @param tile MapTile to remove
+    */
+    void removeTile(MapTile *tile);
+
+    /**
+    * @brief Set drawing order of all tiles in the scene
+    *
+    * Check MapTile::setSceneLevel for more information.
+    */
+    void setTilesDrawingLevels();
+
+    /**
+    * @brief Calculate maximum value for tile in this zoom level.
+    *
+    * @param zoomLevel zoom level
+    * @return int tile's maximum value
+    */
+    int tileMaxValue(int zoomLevel);
+
+    /**
+    * @brief Return tile path created from tile values.
+    *
+    * @param zoomLevel tile's zoom level
+    * @param x tile's x value
+    * @param y tile's y value
+    * @return QString tile path
+    */
+    QString tilePath(int zoomLevel, int x, int y);
+
 private slots:
     /**
     * @brief Slot for received map tile images
@@ -139,7 +227,50 @@ private slots:
     */
     void mapImageReceived(const QUrl &url, const QPixmap &pixmap);
 
-signals:
+    /**
+    * @brief Remove tiles which are out of view bounds.
+    */
+    void removeTilesOutOfView();
+
+    /**
+    * @brief Slot for view scaling factor change events
+    *
+    * Can be used to trigger scaling of zoom buttons, friend indicators and other
+    * MapScene elements which should retain their visual size
+    * @param scaleFactor view's scale factor
+    */
+    void scalingFactorChanged(qreal scaleFactor);
+
+    /**
+    * @brief Slot for zooming in
+    *
+    */
+    void zoomIn();
+
+    /**
+    * @brief Slot for zooming out
+    *
+    */
+    void zoomOut();
+
+/*******************************************************************************
+ * SIGNALS
+ ******************************************************************************/
+signals:   
+    /**
+    * @brief Signal for image fetching.
+    *
+    * @param url image url
+    */
+    void fetchImage(const QUrl &url);
+
+    /**
+    * @brief Signal for view location change
+    *
+    * @param sceneCoordinate New scene coordinates
+    */
+    void locationChanged(QPoint sceneCoordinate);
+
     /**
     * @brief Signal for zoom level change
     *
@@ -147,9 +278,17 @@ signals:
     */
     void zoomLevelChanged(int newZoomLevel);
 
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
 private:
-    MapScene *m_mapScene; ///< Scene for map tiles
+    QPoint m_centerTile;    ///< Current center tile
     MapFetcher *m_mapFetcher; ///< Fetcher for map tiles
+    MapScene *m_mapScene; ///< Scene for map tiles
+    QHash<QString, MapTile *> m_mapTilesInScene;  ///< List of map tiles in map scene
+    QPoint m_sceneCoordinate;  ///< Current center coordinate
+    QRect m_viewGrid; ///< Current grid of tiles in view
+    QSize m_viewSize;   ///< Current view size
     int m_zoomLevel; ///< Current zoom level
 };
 
index 49cf855..7ee67eb 100644 (file)
 #include <QDesktopServices>
 
 #include "mapfetcher.h"
-
-static int MAX_PARALLEL_DOWNLOADS = 2;
+#include "mapcommon.h"
 
 MapFetcher::MapFetcher(QNetworkAccessManager *manager, QObject *parent)
-    : QObject(parent), m_manager(manager)
+    : QObject(parent)
+    , m_manager(manager)
 {
     QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
     diskCache->setCacheDirectory(QDesktopServices::storageLocation(
             QDesktopServices::CacheLocation));
     m_manager->setCache(diskCache);
 
-    connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
+    connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(
+            downloadFinished(QNetworkReply*)));
 }
 
 void MapFetcher::fetchMapImage(const QUrl &url)
 {
-    qDebug() << __PRETTY_FUNCTION__;
+    //qDebug() << __PRETTY_FUNCTION__;
 
     if (url.isEmpty() || !url.isValid())
         return;
@@ -53,29 +54,34 @@ void MapFetcher::fetchMapImage(const QUrl &url)
     if (loadImageFromCache(url))
         return;
 
-    downloadQueue.enqueue(url);
+    if (m_downloadQueue.size() >= DOWNLOAD_QUEUE_SIZE)
+        m_downloadQueue.dequeue();
+
+    m_downloadQueue.enqueue(url);
 
-    if (currentDownloads.size() < MAX_PARALLEL_DOWNLOADS)
+    if (m_currentDownloads.size() < MAX_PARALLEL_DOWNLOADS)
         startNextDownload();
 }
 
 bool MapFetcher::loadImageFromCache(const QUrl &url)
 {
-    qDebug() << __PRETTY_FUNCTION__;
+    //qDebug() << __PRETTY_FUNCTION__;
 
     bool imageFound = false;
 
-    QIODevice *cacheImage = m_manager->cache()->data(url);
+    if (m_manager->cache()) {
+        QIODevice *cacheImage = m_manager->cache()->data(url);
 
-    if (cacheImage) {
-        QImage image;
+        if (cacheImage) {
+            QImage image;
 
-        if (image.load(cacheImage, 0)) {
-            imageFound = true;
-            emit mapImageReceived(url, QPixmap::fromImage(image));
-        }
+            if (image.load(cacheImage, 0)) {
+                imageFound = true;
+                emit mapImageReceived(url, QPixmap::fromImage(image));
+            }
 
-        delete cacheImage;
+            delete cacheImage;
+        }
     }
 
     return imageFound;
@@ -83,22 +89,23 @@ bool MapFetcher::loadImageFromCache(const QUrl &url)
 
 void MapFetcher::startNextDownload()
 {
-    qDebug() << __PRETTY_FUNCTION__;
+    //qDebug() << __PRETTY_FUNCTION__;
 
-    if (downloadQueue.isEmpty())
+    if (m_downloadQueue.isEmpty())
         return;
 
-    QUrl url = downloadQueue.dequeue();
+    QUrl url = m_downloadQueue.dequeue();
+
     QNetworkRequest request(url);
-    request.setRawHeader("User-Agent", "Map Test");
+    request.setRawHeader("User-Agent", "Situare");
     QNetworkReply *reply = m_manager->get(request);
 
-    currentDownloads.append(reply);
+    m_currentDownloads.append(reply);
 }
 
 void MapFetcher::downloadFinished(QNetworkReply *reply)
 {
-    qDebug() << __PRETTY_FUNCTION__;
+    //qDebug() << __PRETTY_FUNCTION__;
 
     if (reply->error() == QNetworkReply::NoError) {
         QImage image;
@@ -113,12 +120,7 @@ void MapFetcher::downloadFinished(QNetworkReply *reply)
         emit error(reply->errorString());
     }
 
-    currentDownloads.removeAll(reply);
+    m_currentDownloads.removeAll(reply);
     reply->deleteLater();
     startNextDownload();
 }
-
-MapFetcher::~MapFetcher()
-{
-
-}
index 787c3ba..dbfef0d 100644 (file)
@@ -48,8 +48,10 @@ public:
     */
     MapFetcher(QNetworkAccessManager *manager, QObject *parent = 0);
 
-    ~MapFetcher();
-
+/*******************************************************************************
+ * CLASS SPECIFIC MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
+public slots:
     /**
     * @brief Fetch image from given URL.
     *
@@ -57,23 +59,16 @@ public:
     */
     void fetchMapImage(const QUrl &url);
 
-signals:    
-    /**
-    * @brief Signal which is emitted when a map tile
-    * is received from the server and loaded to pixmap.
-    *
-    * @param url URL to image
-    * @param image image pixmap
-    */
-    void mapImageReceived(const QUrl &url, const QPixmap &image);
-
+private:
     /**
-    * @brief Signal which is emitted when there is error
-    * in network reply.
+    * @brief Loads image from cache if it's available and emits imageReveived
+    * signal with url and image. If image is in cache returns true, false
+    * otherwise.
     *
-    * @param message error message
+    * @param url
+    * @return bool true if image was loaded from cache, false otherwise
     */
-    void error(const QString &message);
+    bool loadImageFromCache(const QUrl &url);
 
 private slots:
 
@@ -92,21 +87,37 @@ private slots:
     */
     void startNextDownload();
 
-private:
+/*******************************************************************************
+ * SIGNALS
+ ******************************************************************************/
+signals:    
+    /**
+    * @brief Signal which is emitted when a map tile
+    * is received from the server and loaded to pixmap.
+    *
+    * @param url URL to image
+    * @param image image pixmap
+    */
+    void mapImageReceived(const QUrl &url, const QPixmap &image);
 
     /**
-    * @brief Loads image from cache if it's available and emits imageReveived
-    * signal with url and image. If image is in cache returns true, false
-    * otherwise.
+    * @brief Signal which is emitted when there is error
+    * in network reply.
     *
-    * @param url
-    * @return bool true if image was loaded from cache, false otherwise
+    * @param message error message
     */
-    bool loadImageFromCache(const QUrl &url);
+    void error(const QString &message);
+
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
+private:
+    static const int MAX_PARALLEL_DOWNLOADS = 2; ///< Max simultaneous parallel downloads
+    static const int DOWNLOAD_QUEUE_SIZE = 50; ///< Max downloads waiting in queue
 
+    QList<QNetworkReply*> m_currentDownloads; ///< List of current downloads
+    QQueue<QUrl> m_downloadQueue;             ///< Queue of pending requests
     QNetworkAccessManager *m_manager;       ///< Network access manager
-    QList<QNetworkReply*> currentDownloads; ///< List of current downloads
-    QQueue<QUrl> downloadQueue;             ///< Queue of pending requests
 };
 
 #endif
index f39e808..f7b55ba 100644 (file)
 MapScene::MapScene(QObject *parent)
     : QGraphicsScene(parent)
 {
+    const int maxTilesPerSide = (1 << MAX_MAP_ZOOM_LEVEL);
+    const int maxPixelsX = maxTilesPerSide * TILE_SIZE_X;
+    const int maxPixelsY = maxTilesPerSide * TILE_SIZE_Y;
+    setSceneRect(0, 0, maxPixelsX, maxPixelsY);
 }
 
 void MapScene::addMapTile(MapTile *mapTile)
index 2425d62..4ba5896 100644 (file)
@@ -29,7 +29,7 @@
 /**
 * @brief Map scene for storing MapTile items
 *
-* \author Sami Rämö - sami.ramo (at) ixonos.com
+* @author Sami Rämö - sami.ramo (at) ixonos.com
 */
 class MapScene : public QGraphicsScene
 {
@@ -37,10 +37,14 @@ public:
     /**
     * @brief Constructor
     *
+    * Scene size is set to the amount of pixels on closest zoom level
     * @param parent Parent
     */
     MapScene(QObject *parent = 0);
 
+/*******************************************************************************
+ * CLASS SPECIFIC MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
     /**
     * @brief Add MapTile item to scene
     *
index 704d85f..0bae905 100644 (file)
 #include <QDebug>
 #include <QTransform>
 
-#include "common.h"
+#include "mapcommon.h"
 #include "mapengine.h"
 #include "maptile.h"
 
 MapTile::MapTile()
-{
-    m_tileNumber = QPoint(UNDEFINED, UNDEFINED);
-    m_zoomLevel = UNDEFINED;
+    : m_tileNumber(QPoint(UNDEFINED, UNDEFINED))
+    , m_zoomLevel(UNDEFINED)
+{    
     setPos(UNDEFINED, UNDEFINED);
 }
 
@@ -43,10 +43,27 @@ void MapTile::setZoomLevel(int zoomLevel)
     m_zoomLevel = zoomLevel;
     setPosition();
 
-    qreal zoomFactor = (qreal)(1 << (MAX_ZOOM_LEVEL - m_zoomLevel));
+    setZValue(static_cast<qreal>(MIN_MAP_SCENE_NORMAL_LEVEL + zoomLevel));
+
+    qreal zoomFactor = static_cast<qreal>(1 << (MAX_MAP_ZOOM_LEVEL - m_zoomLevel));
     setScale(zoomFactor);
 }
 
+void MapTile::setSceneLevel(int currentZoomLevel)
+{
+    if (currentZoomLevel < m_zoomLevel) {
+        qreal z = static_cast<qreal>(MIN_MAP_SCENE_NORMAL_LEVEL + currentZoomLevel
+                                     - (m_zoomLevel - currentZoomLevel)) + 0.5;
+        setZValue(z);
+    }
+    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()
 {
     return m_tileNumber;
@@ -62,14 +79,15 @@ void MapTile::setPosition()
 {
     const int maxTileNumber = (1 << m_zoomLevel) - 1;
 
-    if ((m_zoomLevel >= MIN_ZOOM_LEVEL) && (m_zoomLevel <= MAX_ZOOM_LEVEL) &&
-            (m_tileNumber.x() >= 0) && (m_tileNumber.x() <= maxTileNumber) &&
-            (m_tileNumber.y() >= 0) && (m_tileNumber.y() <= maxTileNumber)) {
+    if ((m_zoomLevel >= MIN_MAP_ZOOM_LEVEL) && (m_zoomLevel <= MAX_MAP_ZOOM_LEVEL) &&
+        (m_tileNumber.x() >= 0) && (m_tileNumber.x() <= maxTileNumber) &&
+        (m_tileNumber.y() >= 0) && (m_tileNumber.y() <= maxTileNumber)) {
+
         setPos(MapEngine::convertTileNumberToSceneCoordinate(m_zoomLevel, m_tileNumber));
-        return; // done
+        //qDebug() << __PRETTY_FUNCTION__ << "tile position:" << pos();
+    }
+    else {
+        setPos(UNDEFINED, UNDEFINED);
     }
-    // else
-    setPos(UNDEFINED, UNDEFINED);
-    //Q_ASSERT_X(false, __PRETTY_FUNCTION__, "m_zoomLevel and/or m_tileNumber is undefined");
 }
 
index a85e78e..7e40cce 100644 (file)
@@ -38,12 +38,27 @@ public:
     */
     MapTile();
 
+/*******************************************************************************
+ * MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
     /**
-    * @brief Getter for zoom level
+    * @brief Set drawing level of the tile based on current zoom level
     *
-    * @return Zoom level
+    * Drawing order of MapTiles, which has the zoom level higher than the current
+    * zoom level, is reversed and those MapTiles are mapped between lower level MapTiles.
+    * Example: If maximum zoom level is 18 and current view zoomlevel is 15, then
+    * the drawing order from top to bottom is 15, 16, 14, 17, 13, 18, 12, 11, 10, ...
+    * @param currentZoomLevel current zoom level
     */
-    int zoomLevel();
+    void setSceneLevel(int currentZoomLevel);
+
+    /**
+    * @brief Setter for tile number
+    *
+    * Does also set the position for the item in the MapScene coordinate system
+    * @param tileNumber Tile number
+    */
+    void setTileNumber(QPoint tileNumber);
 
     /**
     * @brief Setter for zoom level
@@ -60,12 +75,11 @@ public:
     QPoint tileNumber();
 
     /**
-    * @brief Setter for tile number
+    * @brief Getter for zoom level
     *
-    * Does also set the position for the item in the MapScene coordinate system
-    * @param tileNumber Tile number
+    * @return Zoom level
     */
-    void setTileNumber(QPoint tileNumber);
+    int zoomLevel();
 
 private:
     /**
@@ -76,9 +90,12 @@ private:
     */
     void setPosition();
 
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
 private:
-    int m_zoomLevel; ///< Zoom level
     QPoint m_tileNumber; ///< Tile number
+    int m_zoomLevel; ///< Zoom level
 };
 
 #endif // MAPTILE_H
index 6dc8d69..cf8c27c 100644 (file)
    USA.
 */
 
-#include <math.h>
+#include <cmath>
 
 #include <QDebug>
 #include <QMouseEvent>
 
-#include "common.h"
+#ifndef Q_WS_MAEMO_5
+    #include <QGLWidget>
+#endif // Q_WS_MAEMO_5
+
+#include "mapcommon.h"
 #include "mapview.h"
 
-MapView::MapView(QWidget *parent) : QGraphicsView(parent)
+MapView::MapView(QWidget *parent)
+    : QGraphicsView(parent)
+    , m_timerID(NULL)
 {
+/**
+  * Use OpenGL for desktop to gain some performance in map view.
+  * OpenGL can't be used in scratchbox.
+  */
+#ifndef Q_WS_MAEMO_5
+    setViewport(new QGLWidget(QGLFormat(QGL::DoubleBuffer)));
+#endif // !Q_WS_MAEMO_5
+
     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 }
 
 void MapView::setZoomLevel(int zoomLevel)
 {
-    double scaleFactor = pow(2, zoomLevel - MAX_ZOOM_LEVEL);
-    QTransform transform;
-    transform.scale(scaleFactor, scaleFactor);
-    setTransform(transform);
+    m_zoomTargetScale = pow(2, zoomLevel - MAX_MAP_ZOOM_LEVEL);
+    m_zoomScaleDelta = (m_zoomTargetScale - currentScale()) / (ZOOM_FPS * (ZOOM_TIME / 1000));
+
+    if (m_timerID)
+        killTimer(m_timerID);
+
+    m_timerID = startTimer(1000/ZOOM_FPS);
+}
+
+void MapView::timerEvent(QTimerEvent *event)
+{
+    if (event->timerId() == m_timerID) {
+        qreal scaleFactor = currentScale();
+
+//        qDebug() << __PRETTY_FUNCTION__
+//                 << "abs(m_zoomTargetScale - scaleFactor)" << fabs(m_zoomTargetScale - scaleFactor)
+//                 << "abs(m_zoomScaleDelta)" << fabs(m_zoomScaleDelta);
+
+        if (fabs(m_zoomTargetScale - scaleFactor) <= fabs(m_zoomScaleDelta)) {
+            scaleFactor = m_zoomTargetScale;
+            killTimer(event->timerId());
+        }
+        else {
+            scaleFactor += m_zoomScaleDelta;
+        }
+
+//        qDebug() << __PRETTY_FUNCTION__ << "currentScale:" << currentScale()
+//                                        << "m_zoomScaleDelta" << m_zoomScaleDelta
+//                                        << "scaleFactor:" << scaleFactor;
+
+        QTransform transform;
+        transform.scale(scaleFactor, scaleFactor);
+        emit scalingFactorChanged(scaleFactor);
+        setTransform(transform);
+    }
+}
+
+qreal MapView::currentScale()
+{
+    QTransform currentTransform = transform();
+    return currentTransform.m11();
+}
+
+void MapView::mouseMoveEvent(QMouseEvent *event)
+{
+    m_scenePosition += m_mousePosition - mapToScene(event->pos()).toPoint();
+
+    emit viewScrolled(m_scenePosition);
+    //qDebug() << __PRETTY_FUNCTION__ << "m_scenePosition" << m_scenePosition;
+
+    m_mousePosition = mapToScene(event->pos()).toPoint();
 }
 
 void MapView::mousePressEvent(QMouseEvent *event)
 {
-    qDebug() << __PRETTY_FUNCTION__ << "scene coordinate:" << mapToScene(event->pos());
+    m_mousePosition = mapToScene(event->pos()).toPoint();
+    m_scenePosition = mapToScene(width() / 2 - 1, height() / 2 - 1).toPoint();
+}
+
+
+void MapView::centerToSceneCoordinates(QPoint sceneCoordinate)
+{
+//    qDebug() << __PRETTY_FUNCTION__ << "sceneCoordinate" << sceneCoordinate;
+    centerOn(sceneCoordinate);
+}
+
+void MapView::resizeEvent(QResizeEvent *event)
+{
+    //qDebug() << "Resize event: " << event->size();
+    emit viewResized(event->size());
 }
index 8cbde50..7ad9005 100644 (file)
@@ -40,20 +40,107 @@ public:
     */
     MapView(QWidget *parent = 0);
 
-private slots:
+/*******************************************************************************
+ * BASE CLASS INHERITED AND REIMPLEMENTED MEMBER FUNCTIONS
+ ******************************************************************************/
+protected:
     /**
-    * @brief Slot for mouse events
+    * @brief Called when view is resized.
     *
+    * @param event resize event
+    */
+    void resizeEvent(QResizeEvent *event);
+
+private:
+    /**
+    * @brief Event handler for mouse move events
+    *
+    * Does calculate mouse movement delta from last event position and new view center
+    * based on that delta. Saves current event position for next round. Emits viewScrolled
+    * signal and doesn't actually scroll the view.
+    * @param event Mouse event
+    */
+    void mouseMoveEvent(QMouseEvent *event);
+
+    /**
+    * @brief Event handler for mouse press events
+    *
+    * Saves inial values for mouse and scene location for dragging view.
     * @param event Mouse event
     */
     void mousePressEvent(QMouseEvent *event);
 
     /**
+    * @brief Event handler for timer events, used for smooth zoom effect
+    *
+    * @param event
+    */
+    void timerEvent(QTimerEvent *event);
+
+/*******************************************************************************
+ * MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
+public slots:
+    /**
+    * @brief Slot for centering view to new location
+    *
+    * @param sceneCoordinate Scene coordinates of the new center point
+    */
+    void centerToSceneCoordinates(QPoint sceneCoordinate);
+
+    /**
     * @brief Set zoom level of the view
     *
     * @param zoomLevel Zoom level
     */
     void setZoomLevel(int zoomLevel);
+
+private:
+    /**
+    * @brief get current horizontal scale (vertical should be same)
+    *
+    * @return qreal Current horizontal scale value
+    */
+    qreal currentScale();
+
+/*******************************************************************************
+ * SIGNALS
+ ******************************************************************************/
+signals:
+    /**
+    * @brief Signal for view scale factor change events
+    *
+    * Can be used to trigger scaling of zoom buttons, friend indicators and other
+    * MapScene elements which should retain their visual size
+    * @param scaleFactor view's scale factor
+    */
+    void scalingFactorChanged(qreal scaleFactor);
+
+    /**
+    * @brief Signal for view resize events.
+    *
+    * Signal is emitted when view has been resized.
+    * @param size view size
+    */
+    void viewResized(const QSize &size);
+
+    /**
+    * @brief Signal for view scroll events
+    *
+    * Signal is emitted when view is scrolled.
+    * @param sceneCoordinate Scene coordinates of the new center point of the view
+    */
+    void viewScrolled(QPoint sceneCoordinate);
+
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
+private:
+    QPoint m_mousePosition; ///< Previous mouse event position
+    QPoint m_scenePosition; ///< New center position
+    int m_timerID; ///< ID number of the timer used for smooth zoom effect
+    qreal m_zoomScaleDelta; ///< Scaling factor delta for smooth zoom transition effect
+    qreal m_zoomTargetScale; ///< Scaling factor of the target zoom level
 };
 
 #endif // MAPVIEW_H
index 25445a3..692831f 100644 (file)
@@ -29,7 +29,7 @@ HEADERS += ui/mainwindow.h \
     map/mapscene.h \
     map/maptile.h \
     map/mapfetcher.h \
-    common.h \
+    map/mapcommon.h \
     ui/pixmap.h \
     ui/infotab.h \
     ui/updatelocation/updatelocationdialog.h \
@@ -43,6 +43,14 @@ HEADERS += ui/mainwindow.h \
 QT += network \
     webkit
 
+# use don't use OpenGL when building in scratchbox
+!maemo5 { 
+    QT += opengl
+    message(OpenGL built in)
+    message(Make sure you have OpenGL development headers installed)
+    message(install headers with: sudo apt-get install libgl-dev libglu-dev)
+}
+
 # -----------------------------------------------------------------
 # Debian packetizing additions
 # -----------------------------------------------------------------
@@ -70,3 +78,4 @@ unix {
     target.path = $$BINDIR
     INSTALLS += target
 }
+RESOURCES += 
index d5bfd08..cc7b7da 100644 (file)
 MapViewScreen::MapViewScreen(QWidget *parent)
    : QWidget(parent)
 {
-   QHBoxLayout *mapViewLayout = new QHBoxLayout;
-   MapView *mapView = new MapView(this);
-   mapViewLayout->addWidget(mapView);
-   setLayout(mapViewLayout);
-   MapEngine *mapEngine = new MapEngine(this);
-   mapView->setScene(mapEngine->scene());
-   connect(mapEngine, SIGNAL(zoomLevelChanged(int)), mapView, SLOT(setZoomLevel(int)));
-   mapEngine->setViewLocation(QPointF(25.5000, 65.0000));
-   setObjectName(tr("Map view"));
+    MapView *mapView = new MapView(this);
+    mapEngine = new MapEngine(this);
+    mapView->setScene(mapEngine->scene());
+
+    connect(mapView, SIGNAL(viewScrolled(QPoint)), mapEngine, SLOT(setLocation(QPoint)));
+    connect(mapEngine, SIGNAL(locationChanged(QPoint)),
+            mapView, SLOT(centerToSceneCoordinates(QPoint)));
+    connect(mapEngine, SIGNAL(zoomLevelChanged(int)), mapView, SLOT(setZoomLevel(int)));
+    connect(mapView, SIGNAL(viewResized(QSize)), mapEngine, SLOT(viewResized(QSize)));
+    connect(mapView, SIGNAL(scalingFactorChanged(qreal)),
+            mapEngine, SLOT(scalingFactorChanged(qreal)));
+
+    QHBoxLayout *mapViewLayout = new QHBoxLayout;
+    //DEBUG
+    QVBoxLayout *mapControlLayout = new QVBoxLayout;
+    QWidget *mapControl = new QWidget(this);
+    mapControl->setLayout(mapControlLayout);
+    search = new QPushButton("Search", this);
+    zoomOut = new QPushButton("-", this);
+    zoomIn = new QPushButton("+", this);
+    mapControlLayout->addWidget(&latLine);
+    mapControlLayout->addWidget(&lonLine);
+    mapControlLayout->addWidget(search);
+    mapControlLayout->addWidget(zoomIn);
+    mapControlLayout->addWidget(zoomOut);
+    mapViewLayout->addWidget(mapControl);
+    connect(search, SIGNAL(clicked()), this, SLOT(searchMap()));
+    connect(zoomIn, SIGNAL(clicked()), mapEngine, SLOT(zoomIn()));
+    connect(zoomOut, SIGNAL(clicked()), mapEngine, SLOT(zoomOut()));
+    //DEBUG
+    mapViewLayout->addWidget(mapView);
+    setLayout(mapViewLayout);
+
+    mapViewLayout->setMargin(0);
+
+    mapEngine->init();
+}
+
+void MapViewScreen::searchMap()
+{
+    qreal lat = latLine.text().toFloat();
+    qreal lon = lonLine.text().toFloat();
+
+    qDebug() << lat << "," << lon;
+
+    mapEngine->setViewLocation(QPointF(lon, lat));
 }
index 394dd4f..8e1eb3f 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <QtGui>
 
+#include "map/mapengine.h"
+
 /**
 * @brief Map View class. Used to display Map
 *
 */
 class MapViewScreen : public QWidget
 {
+    Q_OBJECT
+
 public:
     MapViewScreen(QWidget *parent = 0);
+
+private slots:
+    /**
+    * @brief Debug method for centering to given coordinates
+    */
+    void searchMap();
+
+private:
+    MapEngine *mapEngine; ///< MapEngine
+    //DEBUG
+    QPushButton *zoomIn; ///< Debug button for zooming in
+    QPushButton *zoomOut; ///< Debug button for zooming out
+    QLineEdit latLine; ///< Debug input field for latitude
+    QLineEdit lonLine; ///< Debug input field for longitude
+    QPushButton *search; ///< Debug button for centering to given coordinates
 };
 
 #endif // MAPVIEWTAB_H
diff --git a/tests/map/mapengine/testmapengine.cpp b/tests/map/mapengine/testmapengine.cpp
new file mode 100644 (file)
index 0000000..9685efa
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+    Situare - A location system for Facebook
+    Copyright (C) 2010  Ixonos Plc. Authors:
+
+        Sami Rämö - sami.ramo@ixonos.com
+
+    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.
+
+    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 <QtTest/QtTest>
+
+#include "map/mapengine.h"
+
+class TestMapEngine: public QObject
+{
+    Q_OBJECT
+private slots:
+    void convertTileNumberToSceneCoordinate();
+    void convertLatLonToSceneCoordinate_data();
+    void convertLatLonToSceneCoordinate();
+    void setLocationNewTilesCount();
+    void setLocationRemovedTilesCount();
+    void zoomOutRemovedTilesCount();
+    void zoomInRemovedTilesCount();
+};
+
+/**
+* @brief Test converting tile numbers to scene coordinates
+*
+* Different zoom levels are also tested
+*/
+void TestMapEngine::convertTileNumberToSceneCoordinate()
+{
+    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(18, QPoint(0,0)), QPoint(0,0));
+    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(18, QPoint(1,2)), QPoint(256,512));
+    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(16, QPoint(3,4)), QPoint(3072,4096));
+}
+
+/**
+  * @brief Test data for converting latitude and longitude coordinates to scene coordinates
+  */
+void TestMapEngine::convertLatLonToSceneCoordinate_data()
+{
+    QTest::addColumn<QPointF>("coordinate");
+    QTest::addColumn<QPoint>("result");
+
+    QTest::newRow("top left") << QPointF(MIN_LONGITUDE, MAX_LATITUDE) << QPoint(0, 0);
+
+    int x = (1 << MAX_MAP_ZOOM_LEVEL) * TILE_SIZE_X;
+    int y = (1 << MAX_MAP_ZOOM_LEVEL) * TILE_SIZE_Y;
+    QTest::newRow("bottom right") << QPointF(MAX_LONGITUDE, MIN_LATITUDE) << QPoint(x, y);
+}
+
+/**
+* @brief Test converting real world cordinates to scene coordinates
+* @todo Implement
+*/
+void TestMapEngine::convertLatLonToSceneCoordinate()
+{
+    QFETCH(QPointF, coordinate);
+    QFETCH(QPoint, result);
+
+    QCOMPARE(MapEngine::convertLatLonToSceneCoordinate(coordinate), result);
+}
+
+void TestMapEngine::setLocationNewTilesCount()
+{
+    MapEngine engine;
+    engine.viewResized(QSize(800, 480));
+
+    QSignalSpy fetchImageSpy(&engine, SIGNAL(fetchImage(QUrl)));
+    QTest::qWait(1000);
+    fetchImageSpy.clear();
+
+    engine.setLocation(QPoint(1220*16, 1220*16));
+    QTest::qWait(1000);
+    QCOMPARE(fetchImageSpy.count(), 6*4);
+    fetchImageSpy.clear();
+
+    engine.setLocation(QPoint((1220+TILE_SIZE_X)*16, (1220+TILE_SIZE_Y)*16));
+    QTest::qWait(1000);
+    QCOMPARE(fetchImageSpy.count(), 9);
+    fetchImageSpy.clear();
+}
+
+void TestMapEngine::setLocationRemovedTilesCount()
+{
+    MapEngine engine;
+    engine.viewResized(QSize(800, 480));
+
+    const int maxItemsCount = 40;
+
+    engine.setLocation(QPoint(1220*16, 1220*16));
+    QTest::qWait(1000);
+    engine.setLocation(QPoint(2220*16, 2220*16));
+    QTest::qWait(1000);
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+
+    engine.setLocation(QPoint(520*16, 2220*16));
+    QTest::qWait(1000);
+    engine.setLocation(QPoint(2220*16, 520*16));
+    QTest::qWait(1000);
+
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+}
+
+void TestMapEngine::zoomInRemovedTilesCount()
+{
+    MapEngine engine;
+    engine.viewResized(QSize(800, 480));
+
+    const int maxItemsCount = 40;
+
+    engine.setLocation(QPoint(1220*16, 1220*16));
+    QTest::qWait(1000);
+    QTest::qWait(1000);
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+
+    engine.setLocation(QPoint(520*16, 2220*16));
+    QTest::qWait(1000);
+    engine.setLocation(QPoint(2220*16, 520*16));
+    QTest::qWait(1000);
+
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+}
+
+void TestMapEngine::zoomOutRemovedTilesCount()
+{
+    MapEngine engine;
+    engine.viewResized(QSize(800, 480));
+
+    const int maxItemsCount = 40;
+
+    engine.setLocation(QPoint(1220*16, 1220.23*16));
+    QTest::qWait(1000);
+    engine.setLocation(QPoint(2220*16, 2220.23*16));
+    QTest::qWait(1000);
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+
+    engine.setLocation(QPoint(520*16, 2220*16));
+    QTest::qWait(1000);
+    engine.setLocation(QPoint(2220*16, 520*16));
+    QTest::qWait(1000);
+
+    QVERIFY(engine.scene()->items().count() <= maxItemsCount);
+}
+
+QTEST_MAIN(TestMapEngine)
+#include "testmapengine.moc"
diff --git a/tests/map/mapengine/testmapengine.pro b/tests/map/mapengine/testmapengine.pro
new file mode 100644 (file)
index 0000000..8ec760c
--- /dev/null
@@ -0,0 +1,34 @@
+# #####################################################################
+# Automatically generated by qmake (2.01a) Fri Mar 26 15:09:16 2010
+# #####################################################################
+CONFIG += qtestlib
+QT += network
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . \
+    ../../../src/
+#DEFINES += QT_NO_DEBUG_OUTPUT
+
+# Input
+SOURCES += testmapengine.cpp \
+    ../../../src/map/mapengine.cpp \
+    ../../../src/map/mapscene.cpp \
+    ../../../src/map/maptile.cpp \
+    ../../../src/map/mapview.cpp \
+    ../../../src/map/mapfetcher.cpp
+HEADERS += ../../../src/map/mapengine.h \
+    ../../../src/map/mapscene.h \
+    ../../../src/map/maptile.h \
+    ../../../src/map/mapview.h \
+    ../../../src/map/mapfetcher.h \
+    ../../../src/common.h
+RESOURCES += 
+
+# use don't use OpenGL when building in scratchbox
+!maemo5 {
+    QT += opengl
+    message(OpenGL built in)
+    message(Make sure you have OpenGL development headers installed)
+    message(install headers with: sudo apt-get install libgl-dev libglu-dev)
+}
diff --git a/tests/map/mapscene/maptile.png b/tests/map/mapscene/maptile.png
new file mode 100644 (file)
index 0000000..71914e5
Binary files /dev/null and b/tests/map/mapscene/maptile.png differ
diff --git a/tests/map/mapscene/testmapscene.cpp b/tests/map/mapscene/testmapscene.cpp
new file mode 100644 (file)
index 0000000..3159d9f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    Situare - A location system for Facebook
+    Copyright (C) 2010  Ixonos Plc. Authors:
+
+        Sami Rämö - sami.ramo@ixonos.com
+
+    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.
+
+    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 <QtTest/QtTest>
+#include <QDebug>
+
+#include "map/mapscene.h"
+#include "map/maptile.h"
+#include "map/mapengine.h"
+
+class TestMapScene : public QObject
+{
+    Q_OBJECT
+private slots:
+    void addMapTile();
+};
+
+/**
+* @brief Test adding map tiles
+*
+* Does check that the map tile is found in right coordinates
+*/
+void TestMapScene::addMapTile()
+{
+    MapScene mapScene;
+
+    // First test:
+    // Zoom level is 18, so no stretching should occure
+    // Top-left corner x = 256, y = 512
+    // Bottom-right corner x + 255, y + 255
+    MapTile *mapTile = new MapTile();
+    mapTile->setZoomLevel(18);
+    mapTile->setTileNumber(QPoint(1, 2));
+    mapTile->setPixmap(QPixmap("maptile.png"));
+
+    mapScene.addMapTile(mapTile);
+
+    // Check around top-left and bottom-right corners
+    int x = 256;
+    int y = 512;
+    int s = 255; //side length -1
+    QCOMPARE(mapScene.itemAt(x-1, y), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x, y-1), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x, y), dynamic_cast<QGraphicsItem *>(mapTile));
+    QCOMPARE(mapScene.itemAt(x+s, y+s), dynamic_cast<QGraphicsItem *>(mapTile));
+    QCOMPARE(mapScene.itemAt(x+s+1, y+s), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x+s, y+s+1), (QGraphicsItem *)0);
+
+    // Second test:
+    // Zoom level is 16, so stretching is also tested
+    // Top-left corner x = 2048, y = 3072
+    // Bottom-right corner x + 1023, y + 1023
+    mapTile->setZoomLevel(16);
+    mapTile->setTileNumber(QPoint(2, 3));
+
+    // Check around top-left and bottom-right corners
+    x = 2048;
+    y = 3072;
+    s = 1023; //side length -1
+    QCOMPARE(mapScene.itemAt(x-1, y), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x, y-1), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x, y), dynamic_cast<QGraphicsItem *>(mapTile));
+    QCOMPARE(mapScene.itemAt(x+s, y+s), dynamic_cast<QGraphicsItem *>(mapTile));
+    QCOMPARE(mapScene.itemAt(x+s+1, y+s), (QGraphicsItem *)0);
+    QCOMPARE(mapScene.itemAt(x+s, y+s+1), (QGraphicsItem *)0);
+}
+
+QTEST_MAIN(TestMapScene)
+#include "testmapscene.moc"
diff --git a/tests/map/mapscene/testmapscene.pro b/tests/map/mapscene/testmapscene.pro
new file mode 100644 (file)
index 0000000..0058538
--- /dev/null
@@ -0,0 +1,21 @@
+# #####################################################################
+# Automatically generated by qmake (2.01a) Mon Mar 29 10:06:28 2010
+# #####################################################################
+CONFIG += qtestlib
+QT += network
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . \
+    ../../../src/
+
+# Input
+SOURCES += testmapscene.cpp \
+    ../../../src/map/mapscene.cpp \
+    ../../../src/map/maptile.cpp \
+    ../../../src/map/mapengine.cpp \
+    ../../../src/map/mapfetcher.cpp
+HEADERS += ../../../src/map/mapscene.h \
+    ../../../src/map/maptile.h \
+    ../../../src/map/mapengine.h \
+    ../../../src/map/mapfetcher.h
diff --git a/tests/map/maptile/testmaptile.cpp b/tests/map/maptile/testmaptile.cpp
new file mode 100644 (file)
index 0000000..c6676f4
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+    Situare - A location system for Facebook
+    Copyright (C) 2010  Ixonos Plc. Authors:
+
+        Sami Rämö - sami.ramo@ixonos.com
+
+    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.
+
+    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 <QtTest/QtTest>
+
+#include "map/maptile.h"
+
+class TestMapTile : public QObject
+{
+    Q_OBJECT
+private slots:
+    void zoomLevel();
+    void tileNumber();
+    void position_data();
+    void position();    
+    void positionUnsetValues();
+    void sceneLevel_data();
+    void sceneLevel();
+};
+
+/**
+* @brief Test setting zoomlevel
+*/
+void TestMapTile::zoomLevel()
+{
+    MapTile mapTile;
+    mapTile.setZoomLevel(13);
+    QVERIFY(mapTile.zoomLevel() == 13);
+
+}
+
+/**
+* @brief Test setting tile numbers
+*/
+void TestMapTile::tileNumber()
+{
+    MapTile mapTile;
+    mapTile.setTileNumber(QPoint(24, 17));
+    QVERIFY(mapTile.tileNumber() == QPoint(24, 17));
+}
+
+/**
+* @brief Data for position test
+*/
+void TestMapTile::position_data()
+{
+    QTest::addColumn<int>("zoomLevel");
+    QTest::addColumn<QPoint>("tileNumber");
+    QTest::addColumn<QPointF>("result");
+
+    QTest::newRow("allowed values") << 16 << QPoint(24, 17) << QPointF(24576, 17408); //ok
+    QTest::newRow("x position negative") << 16 << QPoint(-1, 0) << QPointF(-1, -1); //fail
+    QTest::newRow("y position negative") << 16 << QPoint(0, -1) << QPointF(-1, -1); //fail
+
+    QTest::newRow("min zoom") << 0 << QPoint(0, 0) << QPointF(0, 0); //ok
+    QTest::newRow("min zoom - 1") << -1 << QPoint(0, 0) << QPointF(-1, -1); //fail
+    QTest::newRow("min zoom & x out of range (upper limit)") << 0 << QPoint(1, 0) << QPointF(-1, -1); //fail
+    QTest::newRow("min zoom & y out of range (upper limit)") << 0 << QPoint(0, 1) << QPointF(-1, -1); //fail
+    QTest::newRow("min zoom, x & y out of range (upper limit)") << 0 << QPoint(1, 1) << QPointF(-1, -1); //fail
+
+    QTest::newRow("max zoom") << 18 << QPoint(2, 3) << QPointF(512, 768); //ok
+    QTest::newRow("max zoom + 1") << 19 << QPoint(2, 3) << QPointF(-1, -1); //fail
+    QTest::newRow("max zoom & x out of range (upper limit)") << 18 << QPoint(262144, 0) << QPointF(-1, -1); //fail
+    QTest::newRow("max zoom & y out of range (upper limit)") << 18 << QPoint(0, 262144) << QPointF(-1, -1); //fail
+    QTest::newRow("max zoom, x & y out of range(upper limit) ") << 18 << QPoint(262144, 262144) << QPointF(-1, -1); //fail
+}
+
+/**
+* @brief Test position correctness
+*/
+void TestMapTile::position()
+{
+    QFETCH(int, zoomLevel);
+    QFETCH(QPoint, tileNumber);
+    QFETCH(QPointF, result);
+
+    MapTile mapTile;
+    mapTile.setZoomLevel(zoomLevel);
+    mapTile.setTileNumber(tileNumber);
+    QCOMPARE(mapTile.pos(), result);
+}
+
+/**
+* @brief Test position correctness when some values are not set
+*/
+void TestMapTile::positionUnsetValues()
+{
+    MapTile mapTile;
+
+    // zoom level and tile numbers unset
+    QCOMPARE(mapTile.pos(), QPointF(-1, -1));
+
+    // only tile numbers set
+    mapTile.setTileNumber(QPoint(24, 17));
+    QCOMPARE(mapTile.pos(), QPointF(-1, -1));
+
+    // both set
+    mapTile.setZoomLevel(16);
+    QCOMPARE(mapTile.pos(), QPointF(24576, 17408));
+
+    // only zoom level set
+    MapTile anotherMapTile;
+    anotherMapTile.setZoomLevel(14);
+    QCOMPARE(anotherMapTile.pos(), QPointF(-1, -1));
+}
+
+/**
+  * @brief Data for test of setting zValues
+  */
+void TestMapTile::sceneLevel_data()
+{
+    QTest::addColumn<int>("tileZoomLevel");
+    QTest::addColumn<int>("viewZoomLevel");
+    QTest::addColumn<qreal>("result");
+
+    QTest::newRow("tile zoom 15, view zoom 17") << 15 << 17 << 15.0 + 19;
+    QTest::newRow("tile zoom 15, view zoom 16") << 15 << 16 << 15.0 + 19;
+    QTest::newRow("tile zoom 15, view zoom 15") << 15 << 15 << 15.0 + 19;
+    QTest::newRow("tile zoom 15, view zoom 14") << 15 << 14 << 13.5 + 19;
+    QTest::newRow("tile zoom 15, view zoom 13") << 15 << 13 << 11.5 + 19;
+    QTest::newRow("tile zoom 15, view zoom 12") << 15 << 12 << 9.5 + 19;
+    QTest::newRow("tile zoom 18, view zoom 1") << 18 << 1 << -15.5 + 19;
+    QTest::newRow("tile zoom 18, view zoom 0") << 18 << 0 << -17.5 + 19;
+}
+
+/**
+  * @brief Test setting zValues (drawing order)
+  */
+void TestMapTile::sceneLevel()
+{
+    QFETCH(int, tileZoomLevel);
+    QFETCH(int, viewZoomLevel);
+    QFETCH(qreal, result);
+
+    MapTile tile;
+    tile.setZoomLevel(tileZoomLevel);
+    tile.setSceneLevel(viewZoomLevel);
+    QCOMPARE(tile.zValue(), result);
+}
+
+QTEST_MAIN(TestMapTile)
+#include "testmaptile.moc"
diff --git a/tests/map/maptile/testmaptile.pro b/tests/map/maptile/testmaptile.pro
new file mode 100644 (file)
index 0000000..5b54264
--- /dev/null
@@ -0,0 +1,21 @@
+# #####################################################################
+# Automatically generated by qmake (2.01a) Mon Mar 29 10:06:28 2010
+# #####################################################################
+CONFIG += qtestlib
+QT += network
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . \
+    ../../../src/
+
+# Input
+SOURCES += testmaptile.cpp \
+    ../../../src/map/maptile.cpp \
+    ../../../src/map/mapfetcher.cpp \
+    ../../../src/map/mapengine.cpp \
+    ../../../src/map/mapscene.cpp
+HEADERS += ../../../src/map/maptile.h \
+    ../../../src/map/mapfetcher.h \
+    ../../../src/map/mapengine.h \
+    ../../../src/map/mapscene.h
diff --git a/tests/map/mapview/testmapview.cpp b/tests/map/mapview/testmapview.cpp
new file mode 100644 (file)
index 0000000..7179447
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+    Situare - A location system for Facebook
+    Copyright (C) 2010  Ixonos Plc. Authors:
+
+        Sami Rämö - sami.ramo@ixonos.com
+
+    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.
+
+    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 <QtTest/QtTest>
+
+#include "map/mapview.h"
+
+class TestMapView: public QObject
+{
+    Q_OBJECT
+public:
+    TestMapView();
+
+private slots:
+    void init();
+    void cleanup();
+    void zoomLevelChange_data();
+    void zoomLevelChange();
+
+private:
+    MapView *m_mapView;
+};
+
+/**
+  * @brief Constructor for setting pointer to MapView to NULL
+  */
+TestMapView::TestMapView() : m_mapView(NULL)
+{
+
+}
+
+/**
+  * @brief Test case initialization
+  */
+void TestMapView::init()
+{
+    m_mapView = new MapView();
+    QVERIFY(m_mapView);
+}
+
+/**
+  * @brief Test case cleanup
+  */
+void TestMapView::cleanup()
+{
+    delete m_mapView;
+    m_mapView = 0;
+}
+
+/**
+  * @brief Test data for zoom level change test
+  */
+void TestMapView::zoomLevelChange_data()
+{
+    QTest::addColumn<int>("zoomLevel");
+    QTest::addColumn<qreal>("result");
+
+    QTest::newRow("zoom 18") << 18 << 1.0;
+    QTest::newRow("zoom 17") << 17 << 0.5;
+    QTest::newRow("zoom 16") << 16 << 0.25;
+    QTest::newRow("zoom 15") << 15 << 0.125;
+}
+
+/**
+  * @brief Test view zoom level scaling
+  */
+void TestMapView::zoomLevelChange()
+{
+    QFETCH(int, zoomLevel);
+    QFETCH(qreal, result);
+
+    m_mapView->setZoomLevel(zoomLevel);
+    QTest::qWait(300);
+    QCOMPARE(m_mapView->transform().m11(), result);
+    QCOMPARE(m_mapView->transform().m22(), result);
+}
+
+QTEST_MAIN(TestMapView)
+#include "testmapview.moc"
diff --git a/tests/map/mapview/testmapview.pro b/tests/map/mapview/testmapview.pro
new file mode 100644 (file)
index 0000000..86c3ec2
--- /dev/null
@@ -0,0 +1,15 @@
+# #####################################################################
+# Automatically generated by qmake (2.01a) Fri Mar 26 15:22:56 2010
+# #####################################################################
+CONFIG += qtestlib
+QT += opengl
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . \
+    ../../../src/
+
+# Input
+SOURCES += testmapview.cpp \
+    ../../../src/map/mapview.cpp
+HEADERS += ../../../src/map/mapview.h
diff --git a/tests/testmap/testmapengine/testmapengine.cpp b/tests/testmap/testmapengine/testmapengine.cpp
deleted file mode 100644 (file)
index 948638d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-    Situare - A location system for Facebook
-    Copyright (C) 2010  Ixonos Plc. Authors:
-
-        Sami Rämö - sami.ramo@ixonos.com
-
-    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.
-
-    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 <QtTest/QtTest>
-
-#include "map/mapengine.h"
-
-class TestMapEngine: public QObject
-{
-    Q_OBJECT
-private slots:
-    void convertTileNumberToSceneCoordinate();
-//    void setViewLocation();
-    void convertLatLonToTile();
-};
-
-/**
-* @brief Test converting tile numbers to scene coordinates
-*
-* Different zoom levels are also tested
-*/
-void TestMapEngine::convertTileNumberToSceneCoordinate()
-{
-    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(18, QPoint(0,0)), QPoint(0,0));
-    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(18, QPoint(1,2)), QPoint(256,512));
-    QCOMPARE(MapEngine::convertTileNumberToSceneCoordinate(16, QPoint(3,4)), QPoint(3072,4096));
-}
-
-/**
-* @brief DUMMY TESTCASE!
-*
-* @todo Actual test should be added when there is something to be tested
-*/
-//void TestMapEngine::setViewLocation()
-//{
-//    MapEngine mapEngine;
-//    mapEngine.setViewLocation(QPointF(25.0000, 65.0000));
-//}
-
-/**
-* @brief Test converting real world cordinates to tile numbers
-* @todo Implement
-*/
-void TestMapEngine::convertLatLonToTile()
-{
-    QCOMPARE(MapEngine::convertLatLonToTile(7, QPointF(25.5, 65.0)), QPoint(73, 33));
-    QCOMPARE(MapEngine::convertLatLonToTile(1, QPointF(25.5, 65.0)), QPoint(1, 0));
-    QCOMPARE(MapEngine::convertLatLonToTile(1, QPointF(-190.0, 65.0)), QPoint(UNDEFINED, UNDEFINED));
-    QCOMPARE(MapEngine::convertLatLonToTile(100, QPointF(20.0, 65.0)), QPoint(UNDEFINED, UNDEFINED));
-}
-
-QTEST_MAIN(TestMapEngine)
-#include "testmapengine.moc"
diff --git a/tests/testmap/testmapengine/testmapengine.pro b/tests/testmap/testmapengine/testmapengine.pro
deleted file mode 100644 (file)
index 6a67097..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# #####################################################################
-# Automatically generated by qmake (2.01a) Fri Mar 26 15:09:16 2010
-# #####################################################################
-CONFIG += qtestlib
-QT += network
-TEMPLATE = app
-TARGET = 
-DEPENDPATH += .
-INCLUDEPATH += . \
-    ../../../src/
-DEFINES += QT_NO_DEBUG_OUTPUT
-
-# Input
-SOURCES += testmapengine.cpp \
-    ../../../src/map/mapengine.cpp \
-    ../../../src/map/mapscene.cpp \
-    ../../../src/map/maptile.cpp \
-    ../../../src/map/mapview.cpp \
-    ../../../src/map/mapfetcher.cpp
-HEADERS += ../../../src/map/mapengine.h \
-    ../../../src/map/mapscene.h \
-    ../../../src/map/maptile.h \
-    ../../../src/map/mapview.h \
-    ../../../src/map/mapfetcher.h
-RESOURCES += 
diff --git a/tests/testmap/testmapscene/maptile.png b/tests/testmap/testmapscene/maptile.png
deleted file mode 100644 (file)
index 71914e5..0000000
Binary files a/tests/testmap/testmapscene/maptile.png and /dev/null differ
diff --git a/tests/testmap/testmapscene/testmapscene.cpp b/tests/testmap/testmapscene/testmapscene.cpp
deleted file mode 100644 (file)
index 3159d9f..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-    Situare - A location system for Facebook
-    Copyright (C) 2010  Ixonos Plc. Authors:
-
-        Sami Rämö - sami.ramo@ixonos.com
-
-    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.
-
-    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 <QtTest/QtTest>
-#include <QDebug>
-
-#include "map/mapscene.h"
-#include "map/maptile.h"
-#include "map/mapengine.h"
-
-class TestMapScene : public QObject
-{
-    Q_OBJECT
-private slots:
-    void addMapTile();
-};
-
-/**
-* @brief Test adding map tiles
-*
-* Does check that the map tile is found in right coordinates
-*/
-void TestMapScene::addMapTile()
-{
-    MapScene mapScene;
-
-    // First test:
-    // Zoom level is 18, so no stretching should occure
-    // Top-left corner x = 256, y = 512
-    // Bottom-right corner x + 255, y + 255
-    MapTile *mapTile = new MapTile();
-    mapTile->setZoomLevel(18);
-    mapTile->setTileNumber(QPoint(1, 2));
-    mapTile->setPixmap(QPixmap("maptile.png"));
-
-    mapScene.addMapTile(mapTile);
-
-    // Check around top-left and bottom-right corners
-    int x = 256;
-    int y = 512;
-    int s = 255; //side length -1
-    QCOMPARE(mapScene.itemAt(x-1, y), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x, y-1), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x, y), dynamic_cast<QGraphicsItem *>(mapTile));
-    QCOMPARE(mapScene.itemAt(x+s, y+s), dynamic_cast<QGraphicsItem *>(mapTile));
-    QCOMPARE(mapScene.itemAt(x+s+1, y+s), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x+s, y+s+1), (QGraphicsItem *)0);
-
-    // Second test:
-    // Zoom level is 16, so stretching is also tested
-    // Top-left corner x = 2048, y = 3072
-    // Bottom-right corner x + 1023, y + 1023
-    mapTile->setZoomLevel(16);
-    mapTile->setTileNumber(QPoint(2, 3));
-
-    // Check around top-left and bottom-right corners
-    x = 2048;
-    y = 3072;
-    s = 1023; //side length -1
-    QCOMPARE(mapScene.itemAt(x-1, y), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x, y-1), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x, y), dynamic_cast<QGraphicsItem *>(mapTile));
-    QCOMPARE(mapScene.itemAt(x+s, y+s), dynamic_cast<QGraphicsItem *>(mapTile));
-    QCOMPARE(mapScene.itemAt(x+s+1, y+s), (QGraphicsItem *)0);
-    QCOMPARE(mapScene.itemAt(x+s, y+s+1), (QGraphicsItem *)0);
-}
-
-QTEST_MAIN(TestMapScene)
-#include "testmapscene.moc"
diff --git a/tests/testmap/testmapscene/testmapscene.pro b/tests/testmap/testmapscene/testmapscene.pro
deleted file mode 100644 (file)
index 4c5bd24..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# #####################################################################
-# Automatically generated by qmake (2.01a) Mon Mar 29 10:06:28 2010
-# #####################################################################
-CONFIG += qtestlib
-QT += network
-TEMPLATE = app
-TARGET = 
-DEPENDPATH += .
-INCLUDEPATH += . \
-    ../../../src/
-
-# Input
-SOURCES += testmapscene.cpp \
-    ../../../src/map/mapscene.cpp \
-    ../../../src/map/maptile.cpp
-HEADERS += ../../../src/map/mapscene.h \
-    ../../../src/map/maptile.h
diff --git a/tests/testmap/testmaptile/testmaptile.cpp b/tests/testmap/testmaptile/testmaptile.cpp
deleted file mode 100644 (file)
index b7e8159..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-    Situare - A location system for Facebook
-    Copyright (C) 2010  Ixonos Plc. Authors:
-
-        Sami Rämö - sami.ramo@ixonos.com
-
-    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.
-
-    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 <QtTest/QtTest>
-
-#include "map/maptile.h"
-
-class TestMapTile : public QObject
-{
-    Q_OBJECT
-private slots:
-    void zoomLevel();
-    void tileNumber();
-    void position_data();
-    void position();    
-    void positionUnsetValues();
-};
-
-/**
-* @brief Test setting zoomlevel
-*/
-void TestMapTile::zoomLevel()
-{
-    MapTile mapTile;
-    mapTile.setZoomLevel(13);
-    QVERIFY(mapTile.zoomLevel() == 13);
-
-}
-
-/**
-* @brief Test setting tile numbers
-*/
-void TestMapTile::tileNumber()
-{
-    MapTile mapTile;
-    mapTile.setTileNumber(QPoint(24, 17));
-    QVERIFY(mapTile.tileNumber() == QPoint(24, 17));
-}
-
-/**
-* @brief Data for position test
-*/
-void TestMapTile::position_data()
-{
-    QTest::addColumn<int>("zoomLevel");
-    QTest::addColumn<QPoint>("tileNumber");
-    QTest::addColumn<QPointF>("result");
-
-    QTest::newRow("allowed values") << 16 << QPoint(24, 17) << QPointF(24576, 17408); //ok
-    QTest::newRow("x position negative") << 16 << QPoint(-1, 0) << QPointF(-1, -1); //fail
-    QTest::newRow("y position negative") << 16 << QPoint(0, -1) << QPointF(-1, -1); //fail
-
-    QTest::newRow("min zoom") << 0 << QPoint(0, 0) << QPointF(0, 0); //ok
-    QTest::newRow("min zoom - 1") << -1 << QPoint(0, 0) << QPointF(-1, -1); //fail
-    QTest::newRow("min zoom & x out of range (upper limit)") << 0 << QPoint(1, 0) << QPointF(-1, -1); //fail
-    QTest::newRow("min zoom & y out of range (upper limit)") << 0 << QPoint(0, 1) << QPointF(-1, -1); //fail
-    QTest::newRow("min zoom, x & y out of range (upper limit)") << 0 << QPoint(1, 1) << QPointF(-1, -1); //fail
-
-    QTest::newRow("max zoom") << 18 << QPoint(2, 3) << QPointF(512, 768); //ok
-    QTest::newRow("max zoom + 1") << 19 << QPoint(2, 3) << QPointF(-1, -1); //fail
-    QTest::newRow("max zoom & x out of range (upper limit)") << 18 << QPoint(262144, 0) << QPointF(-1, -1); //fail
-    QTest::newRow("max zoom & y out of range (upper limit)") << 18 << QPoint(0, 262144) << QPointF(-1, -1); //fail
-    QTest::newRow("max zoom, x & y out of range(upper limit) ") << 18 << QPoint(262144, 262144) << QPointF(-1, -1); //fail
-}
-
-/**
-* @brief Test position correctness
-*/
-void TestMapTile::position()
-{
-    QFETCH(int, zoomLevel);
-    QFETCH(QPoint, tileNumber);
-    QFETCH(QPointF, result);
-
-    MapTile mapTile;
-    mapTile.setZoomLevel(zoomLevel);
-    mapTile.setTileNumber(tileNumber);
-    QCOMPARE(mapTile.pos(), result);
-}
-
-/**
-* @brief Test position correctness when some values are not set
-*/
-void TestMapTile::positionUnsetValues()
-{
-    MapTile mapTile;
-
-    // zoom level and tile numbers unset
-    QCOMPARE(mapTile.pos(), QPointF(-1, -1));
-
-    // only tile numbers set
-    mapTile.setTileNumber(QPoint(24, 17));
-    QCOMPARE(mapTile.pos(), QPointF(-1, -1));
-
-    // both set
-    mapTile.setZoomLevel(16);
-    QCOMPARE(mapTile.pos(), QPointF(24576, 17408));
-
-    // only zoom level set
-    MapTile anotherMapTile;
-    anotherMapTile.setZoomLevel(14);
-    QCOMPARE(anotherMapTile.pos(), QPointF(-1, -1));
-}
-
-QTEST_MAIN(TestMapTile)
-#include "testmaptile.moc"
diff --git a/tests/testmap/testmaptile/testmaptile.pro b/tests/testmap/testmaptile/testmaptile.pro
deleted file mode 100644 (file)
index 8526f70..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# #####################################################################
-# Automatically generated by qmake (2.01a) Mon Mar 29 10:06:28 2010
-# #####################################################################
-CONFIG += qtestlib
-QT += network
-TEMPLATE = app
-TARGET = 
-DEPENDPATH += .
-INCLUDEPATH += . \
-    ../../../src/
-
-# Input
-SOURCES += testmaptile.cpp \
-    ../../../src/map/maptile.cpp
-HEADERS += ../../../src/map/maptile.h
diff --git a/tests/testmap/testmapview/testmapview.cpp b/tests/testmap/testmapview/testmapview.cpp
deleted file mode 100644 (file)
index e6e08cf..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-    Situare - A location system for Facebook
-    Copyright (C) 2010  Ixonos Plc. Authors:
-
-        Sami Rämö - sami.ramo@ixonos.com
-
-    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.
-
-    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 <QtTest/QtTest>
-
-#include "map/mapview.h"
-
-class TestMapView: public QObject
-{
-    Q_OBJECT
-private slots:
-//    void dummyTestCase();
-};
-
-/**
-* @brief DUMMY TESTCASE!
-* @todo Implement test(s) when there is something to be tested
-*/
-//void TestMapView::dummyTestCase()
-//{
-//    QVERIFY(true);
-//}
-
-QTEST_MAIN(TestMapView)
-#include "testmapview.moc"
diff --git a/tests/testmap/testmapview/testmapview.pro b/tests/testmap/testmapview/testmapview.pro
deleted file mode 100644 (file)
index fbd09d9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# #####################################################################
-# Automatically generated by qmake (2.01a) Fri Mar 26 15:22:56 2010
-# #####################################################################
-CONFIG += qtestlib
-TEMPLATE = app
-TARGET = 
-DEPENDPATH += .
-INCLUDEPATH += . \
-    ../../../src/
-
-# Input
-SOURCES += testmapview.cpp \
-    ../../../src/map/mapview.cpp
-HEADERS += ../../../src/map/mapview.h