Implemented smooth centering feature
authorSami Rämö <sami.ramo@ixonos.com>
Mon, 21 Jun 2010 11:34:36 +0000 (14:34 +0300)
committerSami Rämö <sami.ramo@ixonos.com>
Mon, 21 Jun 2010 11:34:36 +0000 (14:34 +0300)
src/engine/engine.cpp
src/map/mapengine.cpp
src/map/mapengine.h
src/map/mapscroller.cpp
src/map/mapscroller.h
src/map/mapview.cpp
tests/map/mapengine/testmapengine.cpp

index f087fa9..78be25f 100644 (file)
@@ -49,7 +49,7 @@ SituareEngine::SituareEngine(QMainWindow *parent)
       m_userMoved(false),
       m_automaticUpdateIntervalTimer(0),
       m_lastUpdatedGPSPosition(QPointF())
-{    
+{
     qDebug() << __PRETTY_FUNCTION__;
     m_ui = new MainWindow;
     m_ui->updateItemVisibility();
@@ -209,7 +209,7 @@ void SituareEngine::enableAutomaticLocationUpdate(bool enabled, int updateInterv
 
 void SituareEngine::error(const int error)
 {
-    qDebug() << __PRETTY_FUNCTION__;    
+    qDebug() << __PRETTY_FUNCTION__;
 
     switch(error)
     {
@@ -428,7 +428,7 @@ void SituareEngine::setFirstStartZoomLevel(QPointF latLonCoordinate, qreal accur
     Q_UNUSED(latLonCoordinate);
     Q_UNUSED(accuracy);
 
-    if (m_autoCenteringEnabled) // autocentering is disabled when map is scrolled        
+    if (m_autoCenteringEnabled) // autocentering is disabled when map is scrolled
         m_mapEngine->setZoomLevel(DEFAULT_ZOOM_LEVEL_WHEN_GPS_IS_AVAILABLE);
 
     disconnect(m_gps, SIGNAL(position(QPointF,qreal)),
@@ -477,7 +477,7 @@ void SituareEngine::signalsFromGPS()
 
 void SituareEngine::signalsFromMainWindow()
 {
-    qDebug() << __PRETTY_FUNCTION__;    
+    qDebug() << __PRETTY_FUNCTION__;
 
     connect(m_ui, SIGNAL(error(int)),
             this, SLOT(error(int)));
@@ -496,7 +496,7 @@ void SituareEngine::signalsFromMainWindow()
 
     // signals from map view
     connect(m_ui, SIGNAL(mapViewScrolled(QPoint)),
-            m_mapEngine, SLOT(setLocation(QPoint)));
+            m_mapEngine, SLOT(setCenterPosition(QPoint)));
 
     connect(m_ui, SIGNAL(mapViewResized(QSize)),
             m_mapEngine, SLOT(viewResized(QSize)));
@@ -529,18 +529,18 @@ void SituareEngine::signalsFromMainWindow()
             this, SLOT(requestUpdateLocation(QString,bool)));
 
     connect(m_ui, SIGNAL(enableAutomaticLocationUpdate(bool, int)),
-            this, SLOT(enableAutomaticLocationUpdate(bool, int)));    
+            this, SLOT(enableAutomaticLocationUpdate(bool, int)));
 
     // signals from user info tab
     connect(m_ui, SIGNAL(refreshUserData()),
             this, SLOT(refreshUserData()));
 
     connect(m_ui, SIGNAL(findUser(QPointF)),
-            m_mapEngine, SLOT(setViewLocation(QPointF)));
+            m_mapEngine, SLOT(centerToCoordinates(QPointF)));
 
     // signals from friend list tab
     connect(m_ui, SIGNAL(findFriend(QPointF)),
-            m_mapEngine, SLOT(setViewLocation(QPointF)));
+            m_mapEngine, SLOT(centerToCoordinates(QPointF)));
 }
 
 void SituareEngine::signalsFromMapEngine()
index ca6d33e..6df3d06 100644 (file)
@@ -45,6 +45,8 @@
 
 #include "mapengine.h"
 
+const int SMOOTH_CENTERING_TIME_MS = 1000;
+
 MapEngine::MapEngine(QObject *parent)
     : QObject(parent),
       m_autoCenteringEnabled(false),
@@ -90,7 +92,7 @@ MapEngine::MapEngine(QObject *parent)
     m_scroller = &MapScroller::getInstance();
 
     connect(m_scroller, SIGNAL(coordinateUpdated(QPoint)),
-            this, SLOT(setLocation(QPoint)));
+            this, SLOT(setCenterPosition(QPoint)));
 }
 
 MapEngine::~MapEngine()
@@ -123,6 +125,17 @@ QPointF MapEngine::centerGeoCoordinate()
     return convertSceneCoordinateToLatLon(m_zoomLevel, m_sceneCoordinate);
 }
 
+void MapEngine::centerToCoordinates(QPointF latLonCoordinate)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    QPoint scenePosition = convertLatLonToSceneCoordinate(latLonCoordinate);
+
+    m_lastManualPosition = scenePosition;
+
+    scrollToPosition(scenePosition);
+}
+
 QPoint MapEngine::convertLatLonToSceneCoordinate(QPointF latLonCoordinate)
 {
     qDebug() << __PRETTY_FUNCTION__;
@@ -244,7 +257,7 @@ void MapEngine::gpsPositionUpdate(QPointF position, qreal accuracy)
     m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
 
     if (m_autoCenteringEnabled)
-        setViewLocation(position);
+        centerToCoordinates(position);
 }
 
 qreal MapEngine::greatCircleDistance(QPointF firstLocation, QPointF secondLocation)
@@ -282,7 +295,7 @@ void MapEngine::init()
     }
 
     emit zoomLevelChanged(m_zoomLevel);
-    setViewLocation(QPointF(startLocation.x(), startLocation.y()));
+    centerToCoordinates(QPointF(startLocation.x(), startLocation.y()));
 }
 
 bool MapEngine::isAutoCenteringEnabled()
@@ -380,6 +393,16 @@ QGraphicsScene* MapEngine::scene()
     return m_mapScene;
 }
 
+void MapEngine::scrollToPosition(QPoint scenePosition)
+{
+    m_scroller->stop();
+    m_scroller->setEasingCurve(QEasingCurve::InOutQuart);
+    m_scroller->setDuration(SMOOTH_CENTERING_TIME_MS);
+    m_scroller->setStartValue(m_sceneCoordinate);
+    m_scroller->setEndValue(scenePosition);
+    m_scroller->start();
+}
+
 void MapEngine::setAutoCentering(bool enabled)
 {
     m_autoCenteringEnabled = enabled;
@@ -390,24 +413,24 @@ void MapEngine::setGPSEnabled(bool enabled)
     m_gpsLocationItem->setEnabled(enabled);
 }
 
-void MapEngine::setLocation(QPoint sceneCoordinate)
+void MapEngine::setCenterPosition(QPoint scenePosition)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
     // jump to opposite side of the world if world horizontal limit is exceeded
-    sceneCoordinate.setX(normalize(sceneCoordinate.x(), MAP_MIN_PIXEL_X, MAP_MAX_PIXEL_X));
+    scenePosition.setX(normalize(scenePosition.x(), MAP_MIN_PIXEL_X, MAP_MAX_PIXEL_X));
 
     // don't allow vertical scene coordinates go out of the map
-    sceneCoordinate.setY(qBound(MAP_MIN_PIXEL_Y, sceneCoordinate.y(), MAP_MAX_PIXEL_Y));
+    scenePosition.setY(qBound(MAP_MIN_PIXEL_Y, scenePosition.y(), MAP_MAX_PIXEL_Y));
 
-    if (disableAutoCentering(sceneCoordinate))
+    if (disableAutoCentering(scenePosition))
         emit mapScrolledManually();
 
-    m_sceneCoordinate = sceneCoordinate;
+    m_sceneCoordinate = scenePosition;
     emit locationChanged(m_sceneCoordinate);
 
-    if (isCenterTileChanged(sceneCoordinate)) {
-        getTiles(sceneCoordinate);
+    if (isCenterTileChanged(scenePosition)) {
+        getTiles(scenePosition);
         m_mapScene->removeOutOfViewTiles(m_viewTilesGrid, m_zoomLevel);
     }
 
@@ -445,17 +468,6 @@ void MapEngine::setTilesGridSize(const QSize &viewSize)
     m_tilesGridSize.setWidth(gridWidth);
 }
 
-void MapEngine::setViewLocation(QPointF latLonCoordinate)
-{
-    qDebug() << __PRETTY_FUNCTION__;
-
-    QPoint sceneCoordinate = convertLatLonToSceneCoordinate(latLonCoordinate);
-
-    m_lastManualPosition = sceneCoordinate;
-
-    setLocation(sceneCoordinate);
-}
-
 int MapEngine::tileMaxIndex(int zoomLevel)
 {
     qDebug() << __PRETTY_FUNCTION__;
index 810f25f..ba505f0 100644 (file)
@@ -180,6 +180,13 @@ public:
 
 public slots:
     /**
+     * @brief Center smoothly to given latitude and longitude coordinates.
+     *
+     * @param latLonCoordinate Latitude & longitude coordinates for location
+     */
+    void centerToCoordinates(QPointF latLonCoordinate);
+
+    /**
      * @brief Slot to catch user own location data
      *
      * @param user User info
@@ -203,22 +210,6 @@ public slots:
     void setGPSEnabled(bool enabled);
 
     /**
-     * @brief Slot for setting current view location
-     *
-     * Emits locationChanged signal.
-     * @param sceneCoordinate Scene coordinates for new position
-     */
-    void setLocation(QPoint sceneCoordinate);
-
-    /**
-     * @brief Helper for setting view location based on latitude and longitude
-     * coordinates
-     *
-     * @param latLonCoordinate Latitude & longitude coordinates for location
-     */
-    void setViewLocation(QPointF latLonCoordinate);
-
-    /**
      * @brief Calculate maximum value for tile in this zoom level.
      *
      * @param zoomLevel zoom level
@@ -340,6 +331,21 @@ private slots:
     void mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image);
 
     /**
+    * @brief Scroll smoothly to given scene position
+    *
+    * @param scenePosition Target position in the scene
+    */
+    void scrollToPosition(QPoint scenePosition);
+
+    /**
+     * @brief Set center point in the scene
+     *
+     * Does emit locationChanged signal.
+     * @param scenePosition Scene coordinates for new position
+     */
+    void setCenterPosition(QPoint scenePosition);
+
+    /**
      * @brief Slot for actions after view zoom is finished
      *
      * Does run removeOutOfViewTiles
index d7ad402..d458c91 100644 (file)
 
 #include "mapscroller.h"
 
-MapScroller::MapScroller()
-{
-    qDebug() << __PRETTY_FUNCTION__;
-
-    setEasingCurve(QEasingCurve::OutCirc);
-}
-
 MapScroller& MapScroller::getInstance()
 {
     qDebug() << __PRETTY_FUNCTION__;
index acd6644..6f44401 100644 (file)
@@ -42,7 +42,7 @@ private:
     /**
     * @brief Constructor in not accessible because class is using singleton design pattern.
     */
-    MapScroller();
+    MapScroller() {}
 
     /**
     * @brief Destructor in not accessible because class is using singleton design pattern.
index 6b38ff4..471e28b 100644 (file)
@@ -130,6 +130,7 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
             QPointF effectSceneDistance = effectViewDistance
                                           * (1 << (MAX_MAP_ZOOM_LEVEL - m_zoomLevel));
 
+            m_scroller->setEasingCurve(QEasingCurve::OutCirc);
             m_scroller->setDuration(KINETIC_SCROLL_TIME_MS);
             m_scroller->setStartValue(m_scenePosition);
             m_scroller->setEndValue(m_scenePosition + effectSceneDistance.toPoint());
index 269e845..3cdb973 100644 (file)
@@ -43,6 +43,9 @@ private slots:
     void zoomOutRemovedTilesCount();
     void zoomInRemovedTilesCount();
     void usingLastLocation();
+
+signals:
+    void setCenterPosition(QPoint); // a way to call a private slot
 };
 
 /**
@@ -88,20 +91,21 @@ void TestMapEngine::setLocationNewTilesCount()
 {
     MapEngine engine;
     engine.viewResized(QSize(800, 480));
+    connect(this, SIGNAL(setCenterPosition(QPoint)), &engine, SLOT(setCenterPosition(QPoint)));
 
     QSignalSpy fetchImageSpy(&engine, SIGNAL(fetchImage(int,int,int)));
     QTest::qWait(1000);
     fetchImageSpy.clear();
 
     // first test, scene is empty so all tiles should be downloaded
-    engine.setLocation(QPoint(1220*16, 1220*16));
+    emit setCenterPosition(QPoint(1220*16, 1220*16));
     QTest::qWait(1000);
     QCOMPARE(fetchImageSpy.count(), 5*4);
     fetchImageSpy.clear();
 
     // move one tile to east and south, only most right one column and most bottom one row tiles
     // should be downloaded
-    engine.setLocation(QPoint((1220+TILE_SIZE_X)*16, (1220+TILE_SIZE_Y)*16));
+    emit setCenterPosition(QPoint((1220+TILE_SIZE_X)*16, (1220+TILE_SIZE_Y)*16));
     QTest::qWait(1000);
     QCOMPARE(fetchImageSpy.count(), 4 + 4);
     fetchImageSpy.clear();
@@ -111,18 +115,19 @@ void TestMapEngine::setLocationRemovedTilesCount()
 {
     MapEngine engine;
     engine.viewResized(QSize(800, 480));
+    connect(this, SIGNAL(setCenterPosition(QPoint)), &engine, SLOT(setCenterPosition(QPoint)));
 
     const int maxItemsCount = 40;
 
-    engine.setLocation(QPoint(1220*16, 1220*16));
+    emit setCenterPosition(QPoint(1220*16, 1220*16));
     QTest::qWait(1000);
-    engine.setLocation(QPoint(2220*16, 2220*16));
+    emit setCenterPosition(QPoint(2220*16, 2220*16));
     QTest::qWait(1000);
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
 
-    engine.setLocation(QPoint(520*16, 2220*16));
+    emit setCenterPosition(QPoint(520*16, 2220*16));
     QTest::qWait(1000);
-    engine.setLocation(QPoint(2220*16, 520*16));
+    emit setCenterPosition(QPoint(2220*16, 520*16));
     QTest::qWait(1000);
 
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
@@ -132,17 +137,18 @@ void TestMapEngine::zoomInRemovedTilesCount()
 {
     MapEngine engine;
     engine.viewResized(QSize(800, 480));
+    connect(this, SIGNAL(setCenterPosition(QPoint)), &engine, SLOT(setCenterPosition(QPoint)));
 
     const int maxItemsCount = 40;
 
-    engine.setLocation(QPoint(1220*16, 1220*16));
+    emit setCenterPosition(QPoint(1220*16, 1220*16));
     QTest::qWait(1000);
     QTest::qWait(1000);
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
 
-    engine.setLocation(QPoint(520*16, 2220*16));
+    emit setCenterPosition(QPoint(520*16, 2220*16));
     QTest::qWait(1000);
-    engine.setLocation(QPoint(2220*16, 520*16));
+    emit setCenterPosition(QPoint(2220*16, 520*16));
     QTest::qWait(1000);
 
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
@@ -152,18 +158,19 @@ void TestMapEngine::zoomOutRemovedTilesCount()
 {
     MapEngine engine;
     engine.viewResized(QSize(800, 480));
+    connect(this, SIGNAL(setCenterPosition(QPoint)), &engine, SLOT(setCenterPosition(QPoint)));
 
     const int maxItemsCount = 40;
 
-    engine.setLocation(QPoint(1220*16, 1220.23*16));
+    emit setCenterPosition(QPoint(1220*16, 1220.23*16));
     QTest::qWait(1000);
-    engine.setLocation(QPoint(2220*16, 2220.23*16));
+    emit setCenterPosition(QPoint(2220*16, 2220.23*16));
     QTest::qWait(1000);
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
 
-    engine.setLocation(QPoint(520*16, 2220*16));
+    emit setCenterPosition(QPoint(520*16, 2220*16));
     QTest::qWait(1000);
-    engine.setLocation(QPoint(2220*16, 520*16));
+    emit setCenterPosition(QPoint(2220*16, 520*16));
     QTest::qWait(1000);
 
     QVERIFY(engine.scene()->items().count() <= maxItemsCount);
@@ -174,6 +181,7 @@ void TestMapEngine::usingLastLocation()
     // Create mapengine and start monitoring zoomLevelChanged-signal
     MapEngine *mapengine = new MapEngine;
     QSignalSpy mapEngineSpy(mapengine, SIGNAL(zoomLevelChanged(int)));
+    connect(this, SIGNAL(setCenterPosition(QPoint)), mapengine, SLOT(setCenterPosition(QPoint)));
     QVERIFY (mapEngineSpy.isValid());
     QCOMPARE (mapEngineSpy.count(), 0);
 
@@ -204,7 +212,7 @@ void TestMapEngine::usingLastLocation()
 
     // Call set location with know parameter to get location changed
     // Store new location and zoomlevel to settings
-    mapengine->setLocation(NEW_TEST_SCENECOORDINATE);
+    emit setCenterPosition(NEW_TEST_SCENECOORDINATE);
     delete mapengine;
 
     // Read settings and verify that zoomlevel is correct