const int MIN_MAP_ZOOM_LEVEL = 0; ///< Minimum zoom level
const int MAX_MAP_ZOOM_LEVEL = 18; ///< Maximum zoom level
+const int MIN_VIEW_ZOOM_LEVEL = 2; ///< Minimum zoom level for MapView
const int MIN_MAP_SCENE_NORMAL_LEVEL = MAX_MAP_ZOOM_LEVEL + 1;
const int ZOOM_FPS = 30; ///< FPS for the zoom effect
: QObject(parent)
, m_centerTile(QPoint(UNDEFINED, UNDEFINED))
, m_viewSize(QSize(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT))
+ , m_zoomDirection(OUT)
, m_zoomLevel(DEFAULT_ZOOM_LEVEL)
{
m_mapScene = new MapScene(this);
if (!m_mapScene->isTileInScene(hashKey)) {
MapTile *mapTile = new MapTile();
+ /// @todo SET SCENE LEVEL AUTOMATICALLY WHEN CHANGING ZOOM LEVEL
mapTile->setZoomLevel(zoom);
+ mapTile->setSceneLevel(m_zoomLevel);
mapTile->setTileNumber(QPoint(x, y));
mapTile->setPixmap(pixmap);
m_mapScene->debugItemsCount();
- m_mapScene->removeStackedTiles(mapTile, viewRect());
+ m_mapScene->enqueueRemoveStackedTiles(mapTile);
+ //m_mapScene->removeStackedTiles(mapTile, viewRect());
}
}
if (isCenterTileChanged(sceneCoordinate)) {
getTiles(sceneCoordinate);
- m_mapScene->removeOutOfViewTiles(viewRect());
+ m_mapScene->removeOutOfViewTiles();
}
}
{
// qDebug() << __PRETTY_FUNCTION__;
- m_viewGrid = calculateTileGrid(sceneCoordinate);
+ m_viewTilesGrid = calculateTileGrid(sceneCoordinate);
+ updateViewTilesSceneRect();
- 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 topLeftX = m_viewTilesGrid.topLeft().x();
+ int topLeftY = m_viewTilesGrid.topLeft().y();
+ int bottomRightX = m_viewTilesGrid.bottomRight().x();
+ int bottomRightY = m_viewTilesGrid.bottomRight().y();
int tileMaxVal = tileMaxValue(m_zoomLevel);
}
}
-QRect MapEngine::viewRect()
+void MapEngine::updateViewTilesSceneRect()
{
- QPoint topLeft = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewGrid.topLeft());
- QPoint bottomRight = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewGrid.bottomRight()
+ QPoint topLeft = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewTilesGrid.topLeft());
+ QPoint bottomRight = convertTileNumberToSceneCoordinate(m_zoomLevel, m_viewTilesGrid.bottomRight()
+ QPoint(1, 1));
- return QRect(topLeft, bottomRight);
+
+ m_mapScene->viewRectUpdated(QRect(topLeft, bottomRight));
}
void MapEngine::viewResized(const QSize &size)
{
m_viewSize = size;
getTiles(m_sceneCoordinate);
- m_mapScene->removeOutOfViewTiles(viewRect());
+ m_mapScene->removeOutOfViewTiles();
}
-void MapEngine::viewZoomInFinished()
+void MapEngine::viewZoomFinished()
{
- qDebug() << __PRETTY_FUNCTION__;
- m_mapScene->removeOutOfViewTiles(viewRect());
+// qDebug() << __PRETTY_FUNCTION__;
+
+ if (m_zoomDirection == IN)
+ m_mapScene->removeOutOfViewTiles();
}
void MapEngine::zoomIn()
if (m_zoomLevel < MAX_MAP_ZOOM_LEVEL) {
m_zoomLevel++;
+ m_zoomDirection = IN;
emit zoomLevelChanged(m_zoomLevel);
m_mapScene->setTilesDrawingLevels(m_zoomLevel);
{
// qDebug() << __PRETTY_FUNCTION__;
- if (m_zoomLevel > MIN_MAP_ZOOM_LEVEL) {
+ if (m_zoomLevel > MIN_VIEW_ZOOM_LEVEL) {
m_zoomLevel--;
+ m_zoomDirection = OUT;
emit zoomLevelChanged(m_zoomLevel);
m_mapScene->setTilesDrawingLevels(m_zoomLevel);
int tileMaxValue(int zoomLevel);
/**
- * @brief Returns the current view rect including margins
+ * @brief Updates the current view rect including margins
*
- * @return Current view rect
+ * Calculates tiles rect in scene based on m_viewTilesGrid and
+ * calls MapScene::viewRectUpdated()
*/
- QRect viewRect();
+ void updateViewTilesSceneRect();
private slots:
/**
*
* Does run removeOutOfViewTiles
*/
- void viewZoomInFinished();
+ void viewZoomFinished();
/**
* @brief Slot for zooming in
* DATA MEMBERS
******************************************************************************/
private:
+ enum ZoomDirection { IN, OUT };
+
MapFetcher *m_mapFetcher; ///< Fetcher for map tiles
MapScene *m_mapScene; ///< Scene for map tiles
MapZoomPanel *m_mapZoomPanel; ///< Toolbar for zoom buttons
QPoint m_centerTile; ///< Current center tile
QPoint m_sceneCoordinate; ///< Current center coordinate
- QRect m_viewGrid; ///< Current grid of tiles in view (includes margin)
+ QRect m_viewTilesGrid; ///< Current grid of tiles in view (includes margin)
QSize m_viewSize; ///< Current view size
+ ZoomDirection m_zoomDirection;
int m_zoomLevel; ///< Current zoom level
};
MapScene::MapScene(QObject *parent)
: QGraphicsScene(parent)
+ , m_isRemoveStackedTilesRunning(false)
+ , m_viewRect(QRect(0, 0, 0, 0))
{
const int maxTilesPerSide = (1 << MAX_MAP_ZOOM_LEVEL);
const int maxPixelsX = maxTilesPerSide * TILE_SIZE_X;
void MapScene::debugItemsCount()
{
-// qDebug() << __PRETTY_FUNCTION__ << "items:" << items().count();
+#ifndef Q_WS_MAEMO_5
+ qDebug() << __PRETTY_FUNCTION__ << "ITEM ADDED:" << items().count();
+#endif // Q_WS_MAEMO_5
+}
+
+void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
+{
+// qDebug() << __PRETTY_FUNCTION__;
+
+ m_removeStackedTilesList << newTile;
+ if (!m_isRemoveStackedTilesRunning) {
+ m_isRemoveStackedTilesRunning = true;
+ QTimer::singleShot(0, this, SLOT(removeStackedTile()));
+ }
}
bool MapScene::isTileInScene(QString hashKey)
return m_mapTilesInScene.contains(hashKey);
}
-void MapScene::removeOutOfViewTiles(QRect viewRect)
+void MapScene::removeStackedTile()
{
// qDebug() << __PRETTY_FUNCTION__;
- QList<QGraphicsItem *> viewTiles = items(viewRect, Qt::ContainsItemBoundingRect);
+ if (!m_removeStackedTilesList.isEmpty()) {
+ MapTile *tile = m_removeStackedTilesList.takeFirst();
+ removeStackedTiles(tile);
+ }
+
+ // schedule removal of the next tile if the list is not empty
+ if (!m_removeStackedTilesList.isEmpty()) {
+ QTimer::singleShot(0, this, SLOT(removeStackedTile()));
+ }
+ else {
+ m_isRemoveStackedTilesRunning = false;
+#ifndef Q_WS_MAEMO_5
+ qDebug() << __PRETTY_FUNCTION__ << "STACKED END:" << items().count();
+#endif // Q_WS_MAEMO_5
+ }
+}
+
+void MapScene::removeOutOfViewTiles()
+{
+// qDebug() << __PRETTY_FUNCTION__;
+
+ QList<QGraphicsItem *> viewTiles = items(m_viewRect, Qt::ContainsItemBoundingRect);
QList<QGraphicsItem *> allTiles = items();
+#ifndef Q_WS_MAEMO_5
+ qDebug() << __PRETTY_FUNCTION__ << "OUT OF VIEW START:" << items().count();
+#endif // Q_WS_MAEMO_5
+
+
// qDebug() << __PRETTY_FUNCTION__ << "All tiles:" << allTiles.count();
// qDebug() << __PRETTY_FUNCTION__ << "Tiles in view area:" << viewTiles.count();
removeTile(tileToRemove);
}
- debugItemsCount();
+#ifndef Q_WS_MAEMO_5
+ qDebug() << __PRETTY_FUNCTION__ << "OUT OF VIEW END:" << items().count();
+#endif // Q_WS_MAEMO_5
+
}
-void MapScene::removeStackedTiles(MapTile *newTile, QRect viewRect)
+void MapScene::removeStackedTiles(MapTile *newTile)
{
// qDebug() << __PRETTY_FUNCTION__;
else {
// remove tile if it is obscured in the view area
QRect collidingTileViewableArea =
- collidingTileSceneRect.intersected(viewRect).toRect();
+ collidingTileSceneRect.intersected(m_viewRect).toRect();
if (collidingTile->isObscured(collidingTileViewableArea)) {
qDebug() << __PRETTY_FUNCTION__ << "Deleting obscured item";
MapTile *tile = dynamic_cast<MapTile *>(collidingTile);
}
// qDebug() << __PRETTY_FUNCTION__ << "All tiles after:"
// << newTile->collidingItems(Qt::IntersectsItemBoundingRect).count();
- debugItemsCount();
}
tile->tileNumber().x(),
tile->tileNumber().y()));
removeItem(tile);
+ m_removeStackedTilesList.removeAll(tile);
delete tile;
}
}
item->setSceneLevel(zoomLevel);
}
}
+
+void MapScene::viewRectUpdated(QRect viewRect)
+{
+ m_viewRect = viewRect;
+}
*/
class MapScene : public QGraphicsScene
{
+ Q_OBJECT
public:
/**
* @brief Constructor
void debugItemsCount();
+ void enqueueRemoveStackedTiles(MapTile *newTile);
+
/**
* @brief Returns if tile mathcing hash key is already in the scene
*
*
* @param viewRect Current view rect
*/
- void removeOutOfViewTiles(QRect viewRect);
+ void removeOutOfViewTiles();
/**
* @brief Remove tiles which are stacked.
* tiles.
*
* @param newTile new tile covering old tiles
- * @param viewRect Current view rect
*/
- void removeStackedTiles(MapTile *newTile, QRect viewRect);
+ void removeStackedTiles(MapTile *newTile);
/**
* @brief Remove tile.
*/
void setTilesDrawingLevels(int zoomLevel);
+ void viewRectUpdated(QRect viewRect);
+
+public slots:
+ void removeStackedTile();
+
/*******************************************************************************
* DATA MEMBERS
******************************************************************************/
private:
+ bool m_isRemoveStackedTilesRunning;
QHash<QString, MapTile *> m_mapTilesInScene; ///< List of map tiles in map scene
+ QList<MapTile *> m_removeStackedTilesList;
+ QRect m_viewRect;
};
#endif // MAPSCENE_H
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ m_zoomAnimation = new QPropertyAnimation(this, "viewScale");
+ connect(m_zoomAnimation, SIGNAL(finished()), this, SIGNAL(viewZoomFinished()));
}
void MapView::setZoomLevel(int zoomLevel)
{
- 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);
+// 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);
+
+ m_zoomAnimation->stop();
+ m_zoomAnimation->setDuration(ZOOM_TIME);
+ m_zoomAnimation->setStartValue(viewScale());
+ m_zoomAnimation->setEndValue(pow(2, zoomLevel - MAX_MAP_ZOOM_LEVEL));
+
+ m_zoomAnimation->start();
}
void MapView::timerEvent(QTimerEvent *event)
emit viewContentChanged(mapToScene(viewport()->x(), viewport()->y()).toPoint());
if (finished && m_zoomScaleDelta > 0)
- emit viewZoomInFinished();
+ emit viewZoomFinished();
}
}
return currentTransform.m11();
}
+qreal MapView::viewScale()
+{
+ QTransform currentTransform = transform();
+ return currentTransform.m11();
+}
+
+void MapView::setViewScale(qreal viewScale)
+{
+ QTransform transform;
+ transform.scale(viewScale, viewScale);
+ setTransform(transform);
+ emit viewContentChanged(mapToScene(viewport()->x(), viewport()->y()).toPoint());
+}
+
void MapView::mouseMoveEvent(QMouseEvent *event)
{
m_scenePosition += m_mousePosition - mapToScene(event->pos()).toPoint();
#define MAPVIEW_H
#include <QGraphicsView>
+#include <QPropertyAnimation>
/**
* @brief Map view widget
{
Q_OBJECT
+ Q_PROPERTY(qreal viewScale READ viewScale WRITE setViewScale)
+
public:
/**
* @brief Constructor
*/
qreal currentScale();
+ void setViewScale(qreal viewScale);
+
+ qreal viewScale();
+
/*******************************************************************************
* SIGNALS
******************************************************************************/
void viewScrolled(QPoint sceneCoordinate);
/**
- * @brief Signal for informing that zooming in is finished
+ * @brief Signal for informing that zooming animation is finished
*
*/
- void viewZoomInFinished();
+ void viewZoomFinished();
/**
* @brief Signal for updating view content
/*******************************************************************************
* DATA MEMBERS
******************************************************************************/
-private:
+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
+ QPropertyAnimation *m_zoomAnimation;
qreal m_zoomScaleDelta; ///< Scaling factor delta for smooth zoom transition effect
qreal m_zoomTargetScale; ///< Scaling factor of the target zoom level
};
connect(mapView, SIGNAL(viewResized(QSize)), mapEngine, SLOT(viewResized(QSize)));
connect(mapView, SIGNAL(viewContentChanged(QPoint)),
mapEngine, SLOT(alignImmovableItems(QPoint)));
- connect(mapView, SIGNAL(viewZoomInFinished()), mapEngine, SLOT(viewZoomInFinished()));
+ connect(mapView, SIGNAL(viewZoomFinished()), mapEngine, SLOT(viewZoomFinished()));
QHBoxLayout *mapViewLayout = new QHBoxLayout;
//DEBUG