Created osm.h, re-factoring, unit test script bug fix
[situare] / src / map / mapscene.cpp
index 2e16267..556ac85 100644 (file)
@@ -19,8 +19,6 @@
    USA.
 */
 
-#include <cmath>
-
 #include <QDebug>
 
 #include "mapcommon.h"
@@ -29,8 +27,6 @@
 
 #include "mapscene.h"
 
-const int WORLD_PIXELS_Y = MAX_TILES_PER_SIDE * TILE_SIZE_Y;
-
 MapScene::MapScene(QObject *parent)
     : QGraphicsScene(parent)
     , m_isRemoveStackedTilesRunning(false)
@@ -39,7 +35,8 @@ MapScene::MapScene(QObject *parent)
     qDebug() << __PRETTY_FUNCTION__;
 
     setBackgroundBrush(Qt::lightGray);
-    setSceneRect(-WORLD_PIXELS_X * 2, 0, WORLD_PIXELS_X * 5 - 1, WORLD_PIXELS_Y - 1);
+    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::addTile(int tileZoomLevel, QPoint tileNumber, const QPixmap &image, int viewZoomLevel)
@@ -47,9 +44,7 @@ void MapScene::addTile(int tileZoomLevel, QPoint tileNumber, const QPixmap &imag
     qDebug() << __PRETTY_FUNCTION__;
 
     // tile might already be in the scene if expired tile was returned from the cache to be
-    // temporarily displayed while downloading the fresh one. Tile can also be in the scene if the
-    // zoom level is low and world is spanning around, in which case the old tile removal is
-    // unnecessary, but this situation can't be recognised with information currently available
+    // temporarily shown while downloading the fresh one.
     QString hashKey = MapEngine::tilePath(tileZoomLevel, tileNumber.x(), tileNumber.y());
     MapTile *oldTile = tileInScene(hashKey);
     if (oldTile)
@@ -60,10 +55,13 @@ void MapScene::addTile(int tileZoomLevel, QPoint tileNumber, const QPixmap &imag
     tile->setTileNumber(tileNumber);
     tile->setPixmap(image);
 
-    m_mapTilesInScene.insertMulti(hashKey, tile);
+    m_mapTilesInScene.insert(hashKey, tile);
     addItem(tile);
 
+    qDebug() << __PRETTY_FUNCTION__ << "tiles count:" << m_mapTilesInScene.count();
+
     enqueueRemoveStackedTiles(tile);
+    removeOtherLevelTiles();
 }
 
 void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
@@ -81,14 +79,10 @@ void MapScene::moveIntersectingItemsHorizontally(QRect from, int distance)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-//    qWarning() << __PRETTY_FUNCTION__ << "left:" << from.left() << "right:" << from.right() << "distance:" << distance;
-
     QList<QGraphicsItem *> spanItems = items(from, Qt::IntersectsItemBoundingRect);
     foreach (QGraphicsItem *item, spanItems) {
-        if (dynamic_cast<MapTile *>(item))
-            continue;
-//        qWarning() << __PRETTY_FUNCTION__ << "moving item...";
-        item->moveBy(distance, 0);
+        if (!dynamic_cast<MapTile *>(item))
+            item->moveBy(distance, 0);
     }
 }
 
@@ -115,46 +109,64 @@ void MapScene::runNextStackedTilesRemoval()
         m_isRemoveStackedTilesRunning = false;
 }
 
-void MapScene::removeOutOfViewTiles(QRect tilesGrid, int zoomLevel)
+void MapScene::removeOtherLevelTiles()
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-//    qWarning() << __PRETTY_FUNCTION__ << "m_tilesSceneRect:" << m_tilesSceneRect.left() << m_tilesSceneRect.top() << "/" << m_tilesSceneRect.right() << m_tilesSceneRect.bottom();
+    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;
+        }
+    }
 
-    QList<QGraphicsItem *> viewTiles = items(m_tilesSceneRect, Qt::IntersectsItemBoundingRect);
-    QList<QGraphicsItem *> allTiles = items();
+    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__;
+
+    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;
-//    qWarning() << __PRETTY_FUNCTION__ << "half:" << tilesGridWidthHalf;
 
-    if (tilesGrid.right() > (MapEngine::tileMaxValue(zoomLevel) - tilesGridWidthHalf + GRID_PADDING)) { /// @todo must be mirrored also when near the world limit
+    // 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(-WORLD_PIXELS_X, 0);
-//        qWarning() << __PRETTY_FUNCTION__ << "oppositeRect:" << oppositeRect.left() << oppositeRect.top() << "/" << oppositeRect.right() << oppositeRect.bottom();
-        QList<QGraphicsItem *> oppositeTiles = items(oppositeRect, Qt::IntersectsItemBoundingRect);
-        foreach (QGraphicsItem *tile, oppositeTiles)
-            allTiles.removeOne(tile);
+        oppositeRect.translate(-OMS_MAP_PIXELS_X, 0);
+        QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
+        foreach (QGraphicsItem *item, oppositeItems)
+            allItems.removeOne(item);
     }
 
-    if (tilesGrid.left() < (tilesGridWidthHalf - GRID_PADDING)) { /// @todo must be mirrored also when near the world limit
+    // 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(WORLD_PIXELS_X, 0);
-        QList<QGraphicsItem *> oppositeTiles = items(oppositeRect, Qt::IntersectsItemBoundingRect);
-        foreach (QGraphicsItem *tile, oppositeTiles)
-            allTiles.removeOne(tile);
+        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) {
-//            qWarning() << __PRETTY_FUNCTION__ << "removing tile, x:" << tileToRemove->tileNumber().x() << "y:" << tileToRemove->tileNumber().y() << "pos:" << tileToRemove->pos().x() << tileToRemove->pos().y();
-            removeTile(tileToRemove);
-        }
+    foreach (QGraphicsItem *item, allItems) {
+        MapTile *tile = dynamic_cast<MapTile *>(item);
+        if (tile)
+            removeTile(tile);
     }
 }
 
@@ -189,20 +201,20 @@ void MapScene::removeTile(MapTile *tile)
     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 << (MAX_MAP_ZOOM_LEVEL - zoomLevel));
+    int overlap = viewHeight / 2 * (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel));
 
     QRect rect = sceneRect().toRect();
-    rect.setTop(-overlap);
-    rect.setBottom(WORLD_PIXELS_Y + overlap - 1);
+    rect.setTop(OSM_MAP_MIN_PIXEL_Y - overlap);
+    rect.setBottom(OSM_MAP_MAX_PIXEL_Y + overlap);
     setSceneRect(rect);
-
-//    qWarning() << __PRETTY_FUNCTION__ << "scene rect:" << rect.left() << rect.top() << rect.right() << rect.bottom();
 }
 
 void MapScene::setTilesDrawingLevels(int zoomLevel)
@@ -218,80 +230,47 @@ void MapScene::setTilesDrawingLevels(int zoomLevel)
     }
 }
 
-void MapScene::spanItems(ScrollDirection direction, int zoomLevel, QPoint sceneCoordinate, QSize viewSize)
+void MapScene::setTilesGrid(QRect grid)
+{
+    qDebug() << __PRETTY_FUNCTION__ ;
+
+    m_viewTilesGrid = grid;
+}
+
+void MapScene::setZoomLevel(int zoomLevel)
 {
-//    qWarning() << __PRETTY_FUNCTION__;
+    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(0);
-    leftRect.setBottom(WORLD_PIXELS_Y);
+    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 << (MAX_MAP_ZOOM_LEVEL - zoomLevel)) * viewSize.width();
+    int viewSceneWidth = (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel)) * viewSize.width();
     int viewSceneLeft = sceneCoordinate.x() - viewSceneWidth / 2;
     int viewSceneRight = sceneCoordinate.x() + viewSceneWidth / 2;
 
-//    qWarning() << __PRETTY_FUNCTION__ << "width:" << viewSceneWidth << "left:" << viewSceneLeft << "right:" << viewSceneRight;
-
     // limit rects to include only area which really must be moved
-    leftRect.setRight(-1 - (WORLD_PIXELS_X - 1 - viewSceneRight));
-    rightRect.setLeft(WORLD_PIXELS_X + viewSceneLeft);
+    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");
+    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, WORLD_PIXELS_X);
+        moveIntersectingItemsHorizontally(leftRect, OMS_MAP_PIXELS_X);
     if (rightRect.left() < rightRect.right())
-        moveIntersectingItemsHorizontally(rightRect, -WORLD_PIXELS_X);
-
-    /// @todo get small rects from boths sides of the view
-
-    /// @todo get all intersecting items, check which end of the view is nearer and move there
-
-
-//    QRect spanRect; // = m_viewRect;
-//    spanRect.setTop(0);
-//    spanRect.setBottom(WORLD_PIXELS_Y);
-//    int delta;
-
-//    int viewSceneWidth = (1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel)) * viewSize.width();
-//    int gap = WORLD_PIXELS_X - viewSceneWidth;
-//    if (gap < 0)
-//        qCritical() << __PRETTY_FUNCTION__ << "viewSceneWidth > WORLD_PIXELS_X";
-
-//    int limiterUnNormalized = sceneCoordinate.x() + ((viewSceneWidth + gap) / 2);
-//    int limiter = MapEngine::normalize(limiterUnNormalized, 0, WORLD_PIXELS_X -1);
-
-//    if (sceneCoordinate.x() > limiter) {
-//        spanRect.setRight(limiter);
-//        spanRect.setLeft(sceneRect().left());
-//        delta = WORLD_PIXELS_X;
-//        qWarning() << __PRETTY_FUNCTION__ << "-->";
-//    }
-//    else {
-//        spanRect.setLeft(limiter);
-//        spanRect.setRight(sceneRect().right());
-//        delta = -WORLD_PIXELS_X;
-//        qWarning() << __PRETTY_FUNCTION__ << "<--";
-//    }
-
-//    QTransform transform;
-//    qreal scale = pow(2, zoomLevel - MAX_MAP_ZOOM_LEVEL);
-//    transform.scale(scale, scale);
-//    QList<QGraphicsItem *> spanItems = items(spanRect, Qt::IntersectsItemBoundingRect,
-//                                             Qt::DescendingOrder, transform);
-
-//    foreach (QGraphicsItem *item, spanItems) {
-//        if (dynamic_cast<MapTile *>(item))
-//            continue;
-//        item->moveBy(delta, 0);
-//    }
-
-//    return spanRect;
+        moveIntersectingItemsHorizontally(rightRect, -OMS_MAP_PIXELS_X);
 }
 
 void MapScene::tilesSceneRectUpdated(QRect tilesSceneRect)