2 Situare - A location system for Facebook
3 Copyright (C) 2010 Ixonos Plc. Authors:
5 Sami Rämö - sami.ramo@ixonos.com
7 Situare is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 version 2 as published by the Free Software Foundation.
11 Situare is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Situare; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24 #include "coordinates/scenecoordinate.h"
25 #include "coordinates/geocoordinate.h"
26 #include "mapcommon.h"
31 MapScene::MapScene(QObject *parent)
32 : QGraphicsScene(parent)
33 , m_isRemoveStackedTilesRunning(false)
35 , m_tilesSceneRect(QRect(0, 0, 0, 0))
36 , m_viewTilesGrid(QRect(0, 0, 0, 0))
38 qDebug() << __PRETTY_FUNCTION__;
40 setBackgroundBrush(Qt::lightGray);
41 setSceneRect(QRect(QPoint(MAP_SCENE_MIN_PIXEL_X, OSM_MAP_MIN_PIXEL_Y),
42 QPoint(MAP_SCENE_MAX_PIXEL_X, OSM_MAP_MAX_PIXEL_Y)));
45 void MapScene::addTile(int tileZoomLevel, QPoint tileNumber, const QPixmap &image, int viewZoomLevel)
47 qDebug() << __PRETTY_FUNCTION__;
49 // tile might already be in the scene if expired tile was returned from the cache to be
50 // temporarily shown while downloading the fresh one.
51 QString hashKey = MapTile::tilePath(tileZoomLevel, tileNumber.x(), tileNumber.y());
52 MapTile *oldTile = tileInScene(hashKey);
56 MapTile *tile = new MapTile();
57 tile->setZoomLevel(tileZoomLevel, viewZoomLevel);
58 tile->setTileNumber(tileNumber);
59 tile->setPixmap(image);
61 m_mapTilesInScene.insert(hashKey, tile);
64 qDebug() << __PRETTY_FUNCTION__ << "tiles count:" << m_mapTilesInScene.count();
66 enqueueRemoveStackedTiles(tile);
67 removeOtherLevelTiles();
70 void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
72 qDebug() << __PRETTY_FUNCTION__;
74 m_removeStackedTilesList << newTile;
75 if (!m_isRemoveStackedTilesRunning) {
76 m_isRemoveStackedTilesRunning = true;
77 QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
81 qreal MapScene::horizontalResolutionAtLatitude(double latitude)
83 qDebug() << __PRETTY_FUNCTION__;
85 const int SHIFT = 200;
87 GeoCoordinate from = GeoCoordinate(latitude, 0);
89 SceneCoordinate fromScene = SceneCoordinate(from);
90 SceneCoordinate toScene(fromScene.x() + SHIFT, fromScene.y());
91 GeoCoordinate to(toScene);
93 qreal distance = from.distanceTo(to);
95 return (distance / SHIFT);
98 void MapScene::moveIntersectingItemsHorizontally(QRect from, int distance)
100 qDebug() << __PRETTY_FUNCTION__;
102 QList<QGraphicsItem *> spanItems = items(from, Qt::IntersectsItemBoundingRect);
103 foreach (QGraphicsItem *item, spanItems) {
104 if (!dynamic_cast<MapTile *>(item))
105 item->moveBy(distance, 0);
109 MapTile* MapScene::tileInScene(QString hashKey)
111 qDebug() << __PRETTY_FUNCTION__;
113 return m_mapTilesInScene.value(hashKey, 0);
116 void MapScene::runNextStackedTilesRemoval()
118 qDebug() << __PRETTY_FUNCTION__;
120 if (!m_removeStackedTilesList.isEmpty()) {
121 MapTile *tile = m_removeStackedTilesList.takeFirst();
122 removeStackedTiles(tile);
125 // schedule removal of the next tile if the list is not empty
126 if (!m_removeStackedTilesList.isEmpty())
127 QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
129 m_isRemoveStackedTilesRunning = false;
132 void MapScene::removeOtherLevelTiles()
134 qDebug() << __PRETTY_FUNCTION__;
136 for (int x = m_viewTilesGrid.left(); x <= m_viewTilesGrid.right(); x++) {
137 for (int y = m_viewTilesGrid.top(); y <= m_viewTilesGrid.bottom(); y++) {
138 if (!m_mapTilesInScene.contains(MapTile::tilePath(m_zoomLevel, x, y)))
143 foreach(MapTile *tile, m_mapTilesInScene) {
144 if (tile->zoomLevel() != m_zoomLevel) {
146 qDebug() << __PRETTY_FUNCTION__ << "removed other level tile";
151 void MapScene::removeOutOfViewTiles(QRect tilesGrid, int zoomLevel)
153 qDebug() << __PRETTY_FUNCTION__;
155 QList<QGraphicsItem *> viewItems = items(m_tilesSceneRect, Qt::IntersectsItemBoundingRect);
156 QList<QGraphicsItem *> allItems = items();
158 //Remove tiles which are in view from allTiles
159 foreach (QGraphicsItem *item, viewItems)
160 allItems.removeOne(item);
162 // note: add 1 so odd values are rounded up
163 int tilesGridWidthHalf = (tilesGrid.width() + 1) / 2;
165 // if view is near east limit of the map, then there is duplicate tiles also on the opposite
166 // side of the world which are removed from allTiles
167 if (tilesGrid.right() > ((MapTile::lastTileIndex(zoomLevel)
169 + MAP_GRID_PADDING))) {
170 QRect oppositeRect = m_tilesSceneRect;
171 oppositeRect.translate(-OSM_MAP_PIXELS_X, 0);
172 QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
173 foreach (QGraphicsItem *item, oppositeItems)
174 allItems.removeOne(item);
177 // if view is near west limit of the map, then there is duplicate tiles also on the opposite
178 // side of the world which are removed from allTiles
179 if (tilesGrid.left() < (tilesGridWidthHalf - MAP_GRID_PADDING)) {
180 QRect oppositeRect = m_tilesSceneRect;
181 oppositeRect.translate(OSM_MAP_PIXELS_X, 0);
182 QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
183 foreach (QGraphicsItem *item, oppositeItems)
184 allItems.removeOne(item);
187 //Remove tiles out of view
188 foreach (QGraphicsItem *item, allItems) {
189 MapTile *tile = dynamic_cast<MapTile *>(item);
195 void MapScene::removeStackedTiles(MapTile *newTile)
197 qDebug() << __PRETTY_FUNCTION__;
199 QRectF newTileSceneRect = newTile->sceneBoundingRect();
201 //Loop all items under new tile
202 QList<QGraphicsItem *> collidingItems = newTile->collidingItems(Qt::IntersectsItemBoundingRect);
203 foreach (QGraphicsItem *collidingItem, collidingItems) {
204 MapTile *collidingTile = dynamic_cast<MapTile *>(collidingItem);
206 if (newTile->zValue() > collidingTile->zValue()) {
207 // remove tile if it is fully obscured by new tile
208 QRectF collidingTileSceneRect = collidingTile->sceneBoundingRect();
209 if (newTileSceneRect.contains(collidingTileSceneRect))
210 removeTile(collidingTile);
216 void MapScene::removeTile(MapTile *tile)
218 qDebug() << __PRETTY_FUNCTION__;
220 m_mapTilesInScene.remove(MapTile::tilePath(tile->zoomLevel(),
221 tile->tileNumber().x(),
222 tile->tileNumber().y()));
224 m_removeStackedTilesList.removeAll(tile);
227 qDebug() << __PRETTY_FUNCTION__ << "tiles count:" << m_mapTilesInScene.count();
230 void MapScene::setSceneVerticalOverlap(int viewHeight, int zoomLevel)
232 qDebug() << __PRETTY_FUNCTION__;
234 int overlap = viewHeight / 2 * (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel));
236 QRect rect = sceneRect().toRect();
237 rect.setTop(OSM_MAP_MIN_PIXEL_Y - overlap);
238 rect.setBottom(OSM_MAP_MAX_PIXEL_Y + overlap);
242 void MapScene::setTilesDrawingLevels(int zoomLevel)
244 qDebug() << __PRETTY_FUNCTION__ << "zoomLevel:" << zoomLevel;
246 QList<QGraphicsItem *> allItems = items();
248 for (int i = 0; i < allItems.size(); ++i) {
249 MapTile *item = dynamic_cast<MapTile *>(allItems.at(i));
251 item->setSceneLevel(zoomLevel);
255 void MapScene::setTilesGrid(QRect grid)
257 qDebug() << __PRETTY_FUNCTION__ ;
259 m_viewTilesGrid = grid;
262 void MapScene::setZoomLevel(int zoomLevel)
264 qDebug() << __PRETTY_FUNCTION__ ;
266 m_zoomLevel = zoomLevel;
269 void MapScene::spanItems(QRectF viewSceneRect)
271 qDebug() << __PRETTY_FUNCTION__;
273 // create rects for left and right side
274 QRect leftRect = sceneRect().toRect(); // this way we get the horizontal limits of the scene
275 leftRect.setTop(OSM_MAP_MIN_PIXEL_Y);
276 leftRect.setBottom(OSM_MAP_MAX_PIXEL_Y);
277 QRect rightRect = leftRect;
279 // limit rects to include only area which really must be moved
280 leftRect.setRight(-1 - (OSM_MAP_PIXELS_X - 1 - viewSceneRect.right()));
281 rightRect.setLeft(OSM_MAP_PIXELS_X + viewSceneRect.left());
283 Q_ASSERT_X(leftRect.right() < viewSceneRect.left(), "spanning rect right value", "move rect is in the view area");
284 Q_ASSERT_X(rightRect.left() > viewSceneRect.right(), "spanning rect left value", "move rect is in the view area");
286 // move all items which intersects the rects
287 if (leftRect.left() < leftRect.right())
288 moveIntersectingItemsHorizontally(leftRect, OSM_MAP_PIXELS_X);
289 if (rightRect.left() < rightRect.right())
290 moveIntersectingItemsHorizontally(rightRect, -OSM_MAP_PIXELS_X);
293 void MapScene::tilesSceneRectUpdated(QRect tilesSceneRect)
295 qDebug() << __PRETTY_FUNCTION__;
297 m_tilesSceneRect = tilesSceneRect;