#include <QDebug>
+#include "coordinates/scenecoordinate.h"
+#include "mapcommon.h"
+#include "maptile.h"
+
#include "mapscene.h"
-#include "mapengine.h"
MapScene::MapScene(QObject *parent)
: QGraphicsScene(parent)
, m_isRemoveStackedTilesRunning(false)
- , m_viewRect(QRect(0, 0, 0, 0))
+ , m_zoomLevel(0)
+ , m_tilesSceneRect(QRect(0, 0, 0, 0))
+ , m_viewTilesGrid(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 = MapTile::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) {
m_isRemoveStackedTilesRunning = true;
- QTimer::singleShot(0, this, SLOT(removeStackedTile()));
+ QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
+ }
+}
+
+qreal MapScene::horizontalResolutionAtLatitude(double latitude)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ const int SHIFT = 200;
+
+ GeoCoordinate from = GeoCoordinate(latitude, 0);
+
+ SceneCoordinate fromScene = SceneCoordinate(from);
+ SceneCoordinate toScene(fromScene.x() + SHIFT, fromScene.y());
+ GeoCoordinate to(toScene);
+
+ qreal distance = from.distanceTo(to);
+
+ return (distance / SHIFT);
+}
+
+void MapScene::moveIntersectingItemsHorizontally(QRect from, int distance)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ QList<QGraphicsItem *> spanItems = items(from, Qt::IntersectsItemBoundingRect);
+ foreach (QGraphicsItem *item, spanItems) {
+ if (!dynamic_cast<MapTile *>(item))
+ item->moveBy(distance, 0);
}
}
-bool MapScene::isTileInScene(QString hashKey)
+MapTile* MapScene::tileInScene(QString hashKey)
{
- return m_mapTilesInScene.contains(hashKey);
+ qDebug() << __PRETTY_FUNCTION__;
+
+ return m_mapTilesInScene.value(hashKey, 0);
}
-void MapScene::removeStackedTile()
+void MapScene::runNextStackedTilesRemoval()
{
-// qDebug() << __PRETTY_FUNCTION__;
+ qDebug() << __PRETTY_FUNCTION__;
if (!m_removeStackedTilesList.isEmpty()) {
MapTile *tile = m_removeStackedTilesList.takeFirst();
}
// schedule removal of the next tile if the list is not empty
- if (!m_removeStackedTilesList.isEmpty()) {
- QTimer::singleShot(0, this, SLOT(removeStackedTile()));
- }
- else {
+ if (!m_removeStackedTilesList.isEmpty())
+ QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
+ 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(MapTile::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() > ((MapTile::lastTileIndex(zoomLevel)
+ - tilesGridWidthHalf
+ + MAP_GRID_PADDING))) {
+ QRect oppositeRect = m_tilesSceneRect;
+ oppositeRect.translate(-OSM_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(OSM_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();
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(MapTile::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();
}
}
-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(QRectF viewSceneRect)
+{
+ 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;
+
+ // limit rects to include only area which really must be moved
+ leftRect.setRight(-1 - (OSM_MAP_PIXELS_X - 1 - viewSceneRect.right()));
+ rightRect.setLeft(OSM_MAP_PIXELS_X + viewSceneRect.left());
+
+ Q_ASSERT_X(leftRect.right() < viewSceneRect.left(), "spanning rect right value", "move rect is in the view area");
+ Q_ASSERT_X(rightRect.left() > viewSceneRect.right(), "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, OSM_MAP_PIXELS_X);
+ if (rightRect.left() < rightRect.right())
+ moveIntersectingItemsHorizontally(rightRect, -OSM_MAP_PIXELS_X);
+}
+
+void MapScene::tilesSceneRectUpdated(QRect tilesSceneRect)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ m_tilesSceneRect = tilesSceneRect;
}