3a5694c7c23a1f5b1aadfafa768c92e21b8db153
[situare] / src / map / mapscene.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5        Sami Rämö - sami.ramo@ixonos.com
6
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.
10
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.
15
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,
19    USA.
20 */
21
22 #include <QDebug>
23
24 #include "mapscene.h"
25 #include "mapengine.h"
26
27 MapScene::MapScene(QObject *parent)
28     : QGraphicsScene(parent)
29     , m_isRemoveStackedTilesRunning(false)
30     , m_viewRect(QRect(0, 0, 0, 0))
31 {
32     qDebug() << __PRETTY_FUNCTION__;
33
34     const int maxTilesPerSide = (1 << MAX_MAP_ZOOM_LEVEL);
35     const int maxPixelsX = maxTilesPerSide * TILE_SIZE_X;
36     const int maxPixelsY = maxTilesPerSide * TILE_SIZE_Y;
37     setSceneRect(0, 0, maxPixelsX, maxPixelsY);
38 }
39
40 void MapScene::addTile(MapTile *mapTile, QString hashKey)
41 {
42     qDebug() << __PRETTY_FUNCTION__;
43
44     m_mapTilesInScene.insert(hashKey, mapTile);
45     addItem(mapTile);
46 }
47
48 void MapScene::enqueueRemoveStackedTiles(MapTile *newTile)
49 {
50     qDebug() << __PRETTY_FUNCTION__;
51
52     m_removeStackedTilesList << newTile;
53     if (!m_isRemoveStackedTilesRunning) {
54         m_isRemoveStackedTilesRunning = true;
55         QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
56     }
57 }
58
59 bool MapScene::isTileInScene(QString hashKey)
60 {
61     qDebug() << __PRETTY_FUNCTION__;
62
63     return m_mapTilesInScene.contains(hashKey);
64 }
65
66 void MapScene::runNextStackedTilesRemoval()
67 {
68     qDebug() << __PRETTY_FUNCTION__;
69
70     if (!m_removeStackedTilesList.isEmpty()) {
71         MapTile *tile = m_removeStackedTilesList.takeFirst();
72         removeStackedTiles(tile);
73     }
74
75     // schedule removal of the next tile if the list is not empty
76     if (!m_removeStackedTilesList.isEmpty()) {
77         QTimer::singleShot(0, this, SLOT(runNextStackedTilesRemoval()));
78     }
79     else {
80         m_isRemoveStackedTilesRunning = false;
81         qDebug() << __PRETTY_FUNCTION__ << "Stacked tiles removal queue processing finished,"
82                                         << "items count:" << items().count();
83     }
84 }
85
86 void MapScene::removeOutOfViewTiles()
87 {
88     qDebug() << __PRETTY_FUNCTION__;
89
90     QList<QGraphicsItem *> viewTiles = items(m_viewRect, Qt::IntersectsItemBoundingRect);
91     QList<QGraphicsItem *> allTiles = items();
92
93     qDebug() << __PRETTY_FUNCTION__ << "All tiles:" << allTiles.count();
94     qDebug() << __PRETTY_FUNCTION__ << "Tiles in view area:" << viewTiles.count();
95
96     //Remove tiles which are in view from allTiles
97     foreach (QGraphicsItem *tile, viewTiles)
98         allTiles.removeOne(tile);
99
100
101     //Remove tiles out of view
102     foreach (QGraphicsItem *tile, allTiles) {
103         MapTile *tileToRemove = dynamic_cast<MapTile *>(tile);
104         if (tileToRemove)
105             removeTile(tileToRemove);
106     }
107
108     qDebug() << __PRETTY_FUNCTION__ << "finished, items count:" << items().count();
109 }
110
111 void MapScene::removeStackedTiles(MapTile *newTile)
112 {
113     qDebug() << __PRETTY_FUNCTION__;
114
115     QRectF newTileSceneRect = newTile->sceneBoundingRect();
116
117     //Loop all items under new tile
118     QList<QGraphicsItem *> collidingItems = newTile->collidingItems(Qt::IntersectsItemBoundingRect);
119     foreach (QGraphicsItem *collidingItem, collidingItems) {
120         MapTile *collidingTile = dynamic_cast<MapTile *>(collidingItem);
121         if (collidingTile) {
122             if (newTile->zValue() > collidingTile->zValue()) {
123                 // remove tile if it is fully obscured by new tile
124                 QRectF collidingTileSceneRect = collidingTile->sceneBoundingRect();
125                 if (newTileSceneRect.contains(collidingTileSceneRect))
126                     removeTile(collidingTile);
127             }
128
129         }
130     }
131 }
132
133 void MapScene::removeTile(MapTile *tile)
134 {
135     qDebug() << __PRETTY_FUNCTION__;
136
137     if (tile) {
138         m_mapTilesInScene.remove(MapEngine::tilePath(tile->zoomLevel(),
139                                                      tile->tileNumber().x(),
140                                                      tile->tileNumber().y()));
141         removeItem(tile);
142         m_removeStackedTilesList.removeAll(tile);
143         delete tile;
144     }
145 }
146
147 void MapScene::setTilesDrawingLevels(int zoomLevel)
148 {
149     qDebug() << __PRETTY_FUNCTION__ << "zoomLevel:" << zoomLevel;
150
151     QList<QGraphicsItem *> allItems = items();
152
153     for (int i = 0; i < allItems.size(); ++i) {
154         MapTile *item = dynamic_cast<MapTile *>(allItems.at(i));
155         if (item)
156             item->setSceneLevel(zoomLevel);
157     }
158 }
159
160 void MapScene::viewRectUpdated(QRect viewRect)
161 {
162     qDebug() << __PRETTY_FUNCTION__;
163
164     m_viewRect = viewRect;
165 }