Modified MapEngine::removeStackedTiles.
[situare] / src / map / mapengine.h
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        Jussi Laitinen - jussi.laitinen@ixonos.com
7
8    Situare is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License
10    version 2 as published by the Free Software Foundation.
11
12    Situare is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Situare; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
20    USA.
21 */
22
23 #ifndef MAPENGINE_H
24 #define MAPENGINE_H
25
26 #include <QtCore>
27
28 #include "mapcommon.h"
29 #include "mapfetcher.h"
30 #include "mapscene.h"
31 #include "maptile.h"
32
33 /**
34 * @brief Map engine
35 *
36 * Logic for controlling map functionality. Does also include static methods for
37 * converting coordinates.
38 * @author Sami Rämö - sami.ramo (at) ixonos.com
39 */
40 class MapEngine : public QObject
41 {
42     Q_OBJECT
43 public:
44     /**
45     * @brief Constructor
46     *
47     * @param parent Parent
48     */
49     MapEngine(QObject *parent = 0);
50
51     /**
52     * @brief MapEngine initializer
53     *
54     * Set initial location and zoom level for the engine. locationChanged and
55     * zoomLevelChanged signals are emitted, so init should be called after
56     * those signals are connected to MapView.
57     */
58     void init();
59     
60     /**
61     * @brief Convert tile x & y numbers to MapScene coordinates
62     *
63     * @param zoomLevel Zoom level
64     * @param tileNumber x & y numbers of the tile
65     * @return QPoint MapScene coordinate
66     */
67     static QPoint convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
68     {
69         int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
70         int x = tileNumber.x() * TILE_SIZE_X * pow;
71         int y = tileNumber.y() * TILE_SIZE_Y * pow;
72
73         return QPoint(x, y);
74     }
75
76     /**
77     * @brief Convert MapScene coordinate to tile x & y numbers.
78     *
79     * @param zoomLevel ZoomLevel
80     * @param sceneCoordinate MapScene coordinate
81     * @return QPoint tile x & y numbers
82     */
83     static QPoint convertSceneCoordinateToTileNumber(int zoomLevel, QPoint sceneCoordinate)
84     {
85         int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
86         int x = static_cast<int>(sceneCoordinate.x() / (TILE_SIZE_X*pow));
87         int y = static_cast<int>(sceneCoordinate.y() / (TILE_SIZE_Y*pow));
88
89         return QPoint(x, y);
90     }
91
92     /**
93     * @brief Getter for scene
94     *
95     * @return QGraphicsScene
96     */
97     QGraphicsScene* scene();
98
99     /**
100     * @brief Helper for setting view location based on latitude and longitude
101     * coordinates
102     *
103     * @param latLonCoordinate Latitude & longitude coordinates for location
104     */
105     void setViewLocation(QPointF latLonCoordinate);
106
107     /**
108     * @brief Convert latitude and longitude to scene coordinates.
109     *
110     * @param latLonCoordinate latitude and longitude values
111     * @return scene coordinate
112     */
113     static QPoint convertLatLonToSceneCoordinate(QPointF latLonCoordinate)
114     {
115         /// @todo CREATE TEST CASE & CHECK CALCULATION
116         qDebug() << __PRETTY_FUNCTION__;
117
118         qreal longitude = latLonCoordinate.x();
119         qreal latitude = latLonCoordinate.y();
120
121         if ((longitude > MAX_LONGITUDE) || (longitude < MIN_LONGITUDE))
122             return QPoint(UNDEFINED, UNDEFINED);
123         if ((latitude > MAX_LATITUDE) || (latitude < MIN_LATITUDE))
124             return QPoint(UNDEFINED, UNDEFINED);
125
126         qreal z = static_cast<qreal>(1 << MAX_MAP_ZOOM_LEVEL);
127
128         qreal x = static_cast<qreal>((longitude + 180.0) / 360.0);
129         qreal y = static_cast<qreal>((1.0 - log(tan(latitude * M_PI / 180.0) + 1.0
130                                     / cos(latitude * M_PI / 180.0)) / M_PI) / 2.0);
131
132         return QPointF(x*z*TILE_SIZE_X, y*z*TILE_SIZE_Y).toPoint();
133     }
134
135 public slots:
136     /**
137     * @brief Slot for setting current view location
138     *
139     * Emits locationChanged signal.
140     * @param sceneCoordinate Scene coordinates for new position
141     */
142     void setLocation(QPoint sceneCoordinate);
143
144     void viewResized(const QSize &size);
145
146 private:
147     /**
148     * @brief Build URL for donwloading single map tile from OpenStreetMap tile server
149     *
150     * @param zoomLevel Zoom level
151     * @param tileNumbers Tile x & y numbers
152     * @return URL for the required tile
153     */
154     QUrl buildURL(int zoomLevel, QPoint tileNumbers);
155
156     /**
157     * @brief Parse given URL to zoom, x and y values. Parsed values are
158     * placed in variables given as parameters.
159     *
160     * @param url url to parse
161     * @param [out] zoom zoom variable
162     * @param [out] x x variable
163     * @param [out] y y variable
164     */
165     void parseURL(const QUrl &url, int &zoom, int &x, int &y);
166
167     /**
168     * @brief Set zValues for all tiles in the scene
169     *
170     * Drawing order of MapTiles, which has the zoom level higher than the current
171     * zoom level, is reversed and those MapTiles are mapped between lower level MapTiles.
172     * Example: If maximum zoom level is 18 and current view zoomlevel is 15, then
173     * the drawing order from top to bottom is 15, 16, 14, 17, 13, 18, 12, 11, 10, ...
174     */
175     void setZValues();
176
177     /**
178     * @brief Calculate maximum value for tile in this zoom level.
179     *
180     * @param zoomLevel zoom level
181     * @return int tile's maximum value
182     */
183     int tileMaxValue(int zoomLevel);
184
185     /**
186     * @brief Calculate grid of tile coordinates from current scene coordinate.
187     *
188     * Grid size is calculated from view size and scene's current center coordinate.
189     *
190     * @param sceneCoordinate scene's current center coordinate
191     * @return QRect grid of tile coordinates
192     */
193     QRect calculateGrid(QPoint sceneCoordinate);
194
195     /**
196     * @brief Calculate new tiles to fetch.
197     *
198     * @param sceneCoordinate scene's center coordinate
199     */
200     void calculateNewTiles(QPoint sceneCoordinate);
201
202     /**
203     * @brief Remove tiles which are out of view bounds.
204     */
205     void removeOldTiles();
206
207     /**
208     * @brief Remove tiles which are stacked.
209     *
210     * Iterate through tiles which are under this map tile and remove obscured
211     * tiles.
212     *
213     * @param newTile new tile covering old tiles
214     */
215     void removeStackedTiles(MapTile *newTile);
216
217     /**
218     * @brief Check if center tile has changed.
219     *
220     * @param sceneCoordinate scene's center coordinate
221     * @return bool true if center tile changed, false otherwise
222     */
223     bool centerTileChanged(QPoint sceneCoordinate);
224
225     /**
226     * @brief Return tile path created from tile values.
227     *
228     * @param zoomLevel tile's zoom level
229     * @param x tile's x value
230     * @param y tile's y value
231     * @return QString tile path
232     */
233     inline QString tilePath(int zoomLevel, int x, int y);
234
235 private slots:
236     /**
237     * @brief Slot for received map tile images
238     *
239     * Does add MapTile objects to MapScene. Zoom level and location is parsed from URL.
240     * @param url URL of the received image
241     * @param pixmap Received pixmap
242     */
243     void mapImageReceived(const QUrl &url, const QPixmap &pixmap);
244
245     /**
246     * @brief Slot for zooming in
247     *
248     */
249     void zoomIn();
250
251     /**
252     * @brief Slot for zooming out
253     *
254     */
255     void zoomOut();
256
257 signals:
258     /**
259     * @brief Signal for view location change
260     *
261     * @param sceneCoordinate New scene coordinates
262     */
263     void locationChanged(QPoint sceneCoordinate);
264
265     /**
266     * @brief Signal for zoom level change
267     *
268     * @param newZoomLevel New zoom level
269     */
270     void zoomLevelChanged(int newZoomLevel);
271
272     /**
273     * @brief Signal for image fetching.
274     *
275     * @param url image url
276     */
277     void fetchImage(const QUrl &url);
278
279 private:
280
281     MapScene *m_mapScene; ///< Scene for map tiles
282     MapFetcher *m_mapFetcher; ///< Fetcher for map tiles
283     int m_zoomLevel; ///< Current zoom level
284     QHash<QString, MapTile *> mapTilesInScene;  ///< List of map tiles in map scene
285     QSize m_viewSize;   ///< Current view size
286     QPoint m_sceneCoordinate;  ///< Current center coordinate
287     QPoint m_centerTile;    ///< Current center tile
288     QRect viewGrid; ///< Current grid of tiles in view
289 };
290
291 #endif // MAPENGINE_H