Created osm.h, re-factoring, unit test script bug fix
[situare] / src / map / mapscene.cpp
index 25ed041..556ac85 100644 (file)
 
 #include <QDebug>
 
-#include "mapscene.h"
+#include "mapcommon.h"
 #include "mapengine.h"
+#include "maptile.h"
+
+#include "mapscene.h"
 
 MapScene::MapScene(QObject *parent)
     : QGraphicsScene(parent)
     , m_isRemoveStackedTilesRunning(false)
-    , m_viewRect(QRect(0, 0, 0, 0))
+    , m_tilesSceneRect(QRect(0, 0, 0, 0))
 {
-    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);
-}
+    qDebug() << __PRETTY_FUNCTION__;
 
-void MapScene::addTile(MapTile *mapTile, QString hashKey)
-{
-    m_mapTilesInScene.insert(hashKey, mapTile);
-    addItem(mapTile);
+    setBackgroundBrush(Qt::lightGray);
+    setSceneRect(QRect(QPoint(MAP_SCENE_MIN_PIXEL_X, OSM_MAP_MIN_PIXEL_Y),
+                       QPoint(MAP_SCENE_MAX_PIXEL_X, OSM_MAP_MAX_PIXEL_Y)));
 }
 
-void MapScene::debugItemsCount()
+void MapScene::addTile(int tileZoomLevel, QPoint tileNumber, const QPixmap &image, int viewZoomLevel)
 {
-#ifndef Q_WS_MAEMO_5
-    qDebug() << __PRETTY_FUNCTION__ << "ITEM ADDED:" << items().count();
-#endif // Q_WS_MAEMO_5
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // tile might already be in the scene if expired tile was returned from the cache to be
+    // temporarily shown while downloading the fresh one.
+    QString hashKey = MapEngine::tilePath(tileZoomLevel, tileNumber.x(), tileNumber.y());
+    MapTile *oldTile = tileInScene(hashKey);
+    if (oldTile)
+        removeTile(oldTile);
+
+    MapTile *tile = new MapTile();
+    tile->setZoomLevel(tileZoomLevel, viewZoomLevel);
+    tile->setTileNumber(tileNumber);
+    tile->setPixmap(image);
+
+    m_mapTilesInScene.insert(hashKey, tile);
+    addItem(tile);
+
+    qDebug() << __PRETTY_FUNCTION__ << "tiles count:" << m_mapTilesInScene.count();
+
+    enqueueRemoveStackedTiles(tile);
+    removeOtherLevelTiles();
 }
 
 void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
 {
-//    qDebug() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
     m_removeStackedTilesList << newTile;
     if (!m_isRemoveStackedTilesRunning) {
@@ -59,14 +75,27 @@ void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
     }
 }
 
-bool MapScene::isTileInScene(QString hashKey)
+void MapScene::moveIntersectingItemsHorizontally(QRect from, int distance)
 {
-    return m_mapTilesInScene.contains(hashKey);
+    qDebug() << __PRETTY_FUNCTION__;
+
+    QList<QGraphicsItem *> spanItems = items(from, Qt::IntersectsItemBoundingRect);
+    foreach (QGraphicsItem *item, spanItems) {
+        if (!dynamic_cast<MapTile *>(item))
+            item->moveBy(distance, 0);
+    }
+}
+
+MapTile* MapScene::tileInScene(QString hashKey)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    return m_mapTilesInScene.value(hashKey, 0);
 }
 
 void MapScene::runNextStackedTilesRemoval()
 {
-//    qDebug() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
     if (!m_removeStackedTilesList.isEmpty()) {
         MapTile *tile = m_removeStackedTilesList.takeFirst();
@@ -74,53 +103,76 @@ void MapScene::runNextStackedTilesRemoval()
     }
 
     // schedule removal of the next tile if the list is not empty
-    if (!m_removeStackedTilesList.isEmpty()) {
+    if (!m_removeStackedTilesList.isEmpty())
         QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
-    }
-    else {
+    else
         m_isRemoveStackedTilesRunning = false;
-#ifndef Q_WS_MAEMO_5
-    qDebug() << __PRETTY_FUNCTION__ << "STACKED END:" << items().count();
-#endif // Q_WS_MAEMO_5
-    }
 }
 
-void MapScene::removeOutOfViewTiles()
+void MapScene::removeOtherLevelTiles()
 {
-//    qDebug() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
-    QList<QGraphicsItem *> viewTiles = items(m_viewRect, Qt::IntersectsItemBoundingRect);
-    QList<QGraphicsItem *> allTiles = items();
+    for (int x = m_viewTilesGrid.left(); x <= m_viewTilesGrid.right(); x++) {
+        for (int y = m_viewTilesGrid.top(); y <= m_viewTilesGrid.bottom(); y++) {
+            if (!m_mapTilesInScene.contains(MapEngine::tilePath(m_zoomLevel, x, y)))
+                return;
+        }
+    }
 
-#ifndef Q_WS_MAEMO_5
-    qDebug() << __PRETTY_FUNCTION__ << "OUT OF VIEW START:" << items().count();
-#endif // Q_WS_MAEMO_5
+    foreach(MapTile *tile, m_mapTilesInScene) {
+        if (tile->zoomLevel() != m_zoomLevel) {
+            removeTile(tile);
+            qDebug() << __PRETTY_FUNCTION__ << "removed other level tile";
+        }
+    }
+}
 
+void MapScene::removeOutOfViewTiles(QRect tilesGrid, int zoomLevel)
+{
+    qDebug() << __PRETTY_FUNCTION__;
 
-//    qDebug() << __PRETTY_FUNCTION__ << "All tiles:" << allTiles.count();
-//    qDebug() << __PRETTY_FUNCTION__ << "Tiles in view area:" << viewTiles.count();
+    QList<QGraphicsItem *> viewItems = items(m_tilesSceneRect, Qt::IntersectsItemBoundingRect);
+    QList<QGraphicsItem *> allItems = items();
 
     //Remove tiles which are in view from allTiles
-    foreach (QGraphicsItem *tile, viewTiles)
-        allTiles.removeOne(tile);
+    foreach (QGraphicsItem *item, viewItems)
+        allItems.removeOne(item);
+
+    // note: add 1 so odd values are rounded up
+    int tilesGridWidthHalf = (tilesGrid.width() + 1) / 2;
+
+    // if view is near east limit of the map, then there is duplicate tiles also on the opposite
+    // side of the world which are removed from allTiles
+    if (tilesGrid.right() > (MapEngine::tileMaxIndex(zoomLevel) - tilesGridWidthHalf + MAP_GRID_PADDING)) {
+        QRect oppositeRect = m_tilesSceneRect;
+        oppositeRect.translate(-OMS_MAP_PIXELS_X, 0);
+        QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
+        foreach (QGraphicsItem *item, oppositeItems)
+            allItems.removeOne(item);
+    }
 
+    // if view is near west limit of the map, then there is duplicate tiles also on the opposite
+    // side of the world which are removed from allTiles
+    if (tilesGrid.left() < (tilesGridWidthHalf - MAP_GRID_PADDING)) {
+        QRect oppositeRect = m_tilesSceneRect;
+        oppositeRect.translate(OMS_MAP_PIXELS_X, 0);
+        QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
+        foreach (QGraphicsItem *item, oppositeItems)
+            allItems.removeOne(item);
+    }
 
     //Remove tiles out of view
-    foreach (QGraphicsItem *tile, allTiles) {
-        MapTile *tileToRemove = dynamic_cast<MapTile *>(tile);
-        if (tileToRemove)
-            removeTile(tileToRemove);
+    foreach (QGraphicsItem *item, allItems) {
+        MapTile *tile = dynamic_cast<MapTile *>(item);
+        if (tile)
+            removeTile(tile);
     }
-
-#ifndef Q_WS_MAEMO_5
-    qDebug() << __PRETTY_FUNCTION__ << "OUT OF VIEW END:" << items().count();
-#endif // Q_WS_MAEMO_5
-
 }
 
 void MapScene::removeStackedTiles(MapTile *newTile)
 {
-//    qDebug() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
     QRectF newTileSceneRect = newTile->sceneBoundingRect();
 
@@ -129,31 +181,45 @@ void MapScene::removeStackedTiles(MapTile *newTile)
     foreach (QGraphicsItem *collidingItem, collidingItems) {
         MapTile *collidingTile = dynamic_cast<MapTile *>(collidingItem);
         if (collidingTile) {
-             // remove tile if it is fully obscured by new tile
-            QRectF collidingTileSceneRect = collidingTile->sceneBoundingRect();
-            if (newTileSceneRect.contains(collidingTileSceneRect))
-                removeTile(collidingTile);
+            if (newTile->zValue() > collidingTile->zValue()) {
+                // remove tile if it is fully obscured by new tile
+                QRectF collidingTileSceneRect = collidingTile->sceneBoundingRect();
+                if (newTileSceneRect.contains(collidingTileSceneRect))
+                    removeTile(collidingTile);
+            }
         }
     }
 }
 
 void MapScene::removeTile(MapTile *tile)
 {
-//    qDebug() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
-    if (tile) {
-        m_mapTilesInScene.remove(MapEngine::tilePath(tile->zoomLevel(),
-                                                     tile->tileNumber().x(),
-                                                     tile->tileNumber().y()));
-        removeItem(tile);
-        m_removeStackedTilesList.removeAll(tile);
-        delete tile;
-    }
+    m_mapTilesInScene.remove(MapEngine::tilePath(tile->zoomLevel(),
+                                                 tile->tileNumber().x(),
+                                                 tile->tileNumber().y()));
+    removeItem(tile);
+    m_removeStackedTilesList.removeAll(tile);
+    delete tile;
+
+    qDebug() << __PRETTY_FUNCTION__ << "tiles count:" << m_mapTilesInScene.count();
+}
+
+void MapScene::setSceneVerticalOverlap(int viewHeight, int zoomLevel)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    int overlap = viewHeight / 2 * (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel));
+
+    QRect rect = sceneRect().toRect();
+    rect.setTop(OSM_MAP_MIN_PIXEL_Y - overlap);
+    rect.setBottom(OSM_MAP_MAX_PIXEL_Y + overlap);
+    setSceneRect(rect);
 }
 
 void MapScene::setTilesDrawingLevels(int zoomLevel)
 {
-//    qDebug() << __PRETTY_FUNCTION__ << "m_zoomLevel:" << m_zoomLevel;
+    qDebug() << __PRETTY_FUNCTION__ << "zoomLevel:" << zoomLevel;
 
     QList<QGraphicsItem *> allItems = items();
 
@@ -164,7 +230,52 @@ void MapScene::setTilesDrawingLevels(int zoomLevel)
     }
 }
 
-void MapScene::viewRectUpdated(QRect viewRect)
+void MapScene::setTilesGrid(QRect grid)
 {
-    m_viewRect = viewRect;
+    qDebug() << __PRETTY_FUNCTION__ ;
+
+    m_viewTilesGrid = grid;
+}
+
+void MapScene::setZoomLevel(int zoomLevel)
+{
+    qDebug() << __PRETTY_FUNCTION__ ;
+
+    m_zoomLevel = zoomLevel;
+}
+
+void MapScene::spanItems(int zoomLevel, QPoint sceneCoordinate, QSize viewSize)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // create rects for left and right side
+    QRect leftRect = sceneRect().toRect(); // this way we get the horizontal limits of the scene
+    leftRect.setTop(OSM_MAP_MIN_PIXEL_Y);
+    leftRect.setBottom(OSM_MAP_MAX_PIXEL_Y);
+    QRect rightRect = leftRect;
+
+    // calculate current horizontal area shown on the view
+    int viewSceneWidth = (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel)) * viewSize.width();
+    int viewSceneLeft = sceneCoordinate.x() - viewSceneWidth / 2;
+    int viewSceneRight = sceneCoordinate.x() + viewSceneWidth / 2;
+
+    // limit rects to include only area which really must be moved
+    leftRect.setRight(-1 - (OMS_MAP_PIXELS_X - 1 - viewSceneRight));
+    rightRect.setLeft(OMS_MAP_PIXELS_X + viewSceneLeft);
+
+    Q_ASSERT_X(leftRect.right() < viewSceneLeft, "spanning rect right value", "move rect is in the view area");
+    Q_ASSERT_X(rightRect.left() > viewSceneRight, "spanning rect left value", "move rect is in the view area");
+
+    // move all items which intersects the rects
+    if (leftRect.left() < leftRect.right())
+        moveIntersectingItemsHorizontally(leftRect, OMS_MAP_PIXELS_X);
+    if (rightRect.left() < rightRect.right())
+        moveIntersectingItemsHorizontally(rightRect, -OMS_MAP_PIXELS_X);
+}
+
+void MapScene::tilesSceneRectUpdated(QRect tilesSceneRect)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_tilesSceneRect = tilesSceneRect;
 }