Modified MapView viewportUpdateMode.
[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 "common.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
68     static QPoint convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber)
69     {
70         int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
71         int x = tileNumber.x() * TILE_SIZE_X * pow;
72         int y = tileNumber.y() * TILE_SIZE_Y * pow;
73
74         return QPoint(x, y);
75     }
76
77     static QPoint convertSceneCoordinateToTileNumber(int zoomLevel, QPointF sceneCoordinate)
78     {
79         int pow = 1 << (MAX_MAP_ZOOM_LEVEL - zoomLevel);
80         int x = static_cast<int>(sceneCoordinate.x() / (TILE_SIZE_X*pow));
81         int y = static_cast<int>(sceneCoordinate.y() / (TILE_SIZE_Y*pow));
82
83         return QPoint(x, y);
84     }
85
86     /**
87     * @brief Getter for scene
88     *
89     * @return QGraphicsScene
90     */
91     QGraphicsScene* scene();
92
93     /**
94     * @brief Helper for setting view location based on latitude and longitude
95     * coordinates
96     *
97     * @param latLonCoordinate Latitude & longitude coordinates for location
98     */
99     void setViewLocation(QPointF latLonCoordinate);
100
101     /**
102     * @brief Converts latitude, longitude and zoom to tile x, y values.
103     *
104     * @param latLonCoordinate latitude and longitude values
105     * @return QPoint tile x,y value
106     */
107     static QPointF convertLatLonToSceneCoordinate(QPointF latLonCoordinate)
108     {
109         /// @todo CREATE TEST CASE & CHECK CALCULATION
110         qDebug() << __PRETTY_FUNCTION__;
111
112         qreal longitude = latLonCoordinate.x();
113         qreal latitude = latLonCoordinate.y();
114
115         if ((longitude > MAX_LONGITUDE) || (longitude < MIN_LONGITUDE))
116             return QPoint(UNDEFINED, UNDEFINED);
117         if ((latitude > MAX_LATITUDE) || (latitude < MIN_LATITUDE))
118             return QPoint(UNDEFINED, UNDEFINED);
119
120         qreal z = static_cast<qreal>(1 << MAX_MAP_ZOOM_LEVEL);
121
122         qreal x = static_cast<qreal>((longitude + 180.0) / 360.0);
123         qreal y = static_cast<qreal>((1.0 - log(tan(latitude * M_PI / 180.0) + 1.0
124                                     / cos(latitude * M_PI / 180.0)) / M_PI) / 2.0);
125
126         return QPointF(x*z*TILE_SIZE_X, y*z*TILE_SIZE_Y);
127     }
128
129 public slots:
130     /**
131     * @brief Slot for setting current view location
132     *
133     * Emits locationChanged signal.
134     * @param sceneCoordinate Scene coordinates for new position
135     */
136     void setLocation(QPointF sceneCoordinate);
137
138     void viewResized(const QSize &size);
139
140 private:
141     /**
142     * @brief Build URL for donwloading single map tile from OpenStreetMap tile server
143     *
144     * @param zoomLevel Zoom level
145     * @param tileNumbers Tile x & y numbers
146     * @return URL for the required tile
147     */
148     QUrl buildURL(int zoomLevel, QPoint tileNumbers);
149
150     /**
151     * @brief Parses given URL to zoom, x and y values. Parsed values are
152     * placed in variables given as parameters.
153     *
154     * @param url url to parse
155     * @param [out] zoom zoom variable
156     * @param [out] x x variable
157     * @param [out] y y variable
158     */
159     void parseURL(const QUrl &url, int &zoom, int &x, int &y);
160
161     /**
162     * @brief Set zValues for all tiles in the scene
163     *
164     * Drawing order of MapTiles, which has the zoom level higher than the current
165     * zoom level, is reversed and those MapTiles are mapped between lower level MapTiles.
166     * Example: If maximum zoom level is 18 and current view zoomlevel is 15, then
167     * the drawing order from top to bottom is 15, 16, 14, 17, 13, 18, 12, 11, 10, ...
168     */
169     void setZValues();
170
171     int tileMaxValue(int zoomLevel);
172
173     /**
174     * @brief Calculates grid of tile coordinates from current scene coordinate.
175     *
176     * Grid size is calculated from view size and scene's current center coordinate.
177     *
178     * @param sceneCoordinate scene's current center coordinate
179     * @return QRect grid of tile coordinates
180     */
181     QRect calculateGrid(QPointF sceneCoordinate);
182
183     /**
184     * @brief Calculate new tiles to fetch.
185     *
186     * @param sceneCoordinate scene's center coordinate
187     */
188     void calculateNewTiles(QPointF sceneCoordinate);
189
190     /**
191     * @brief Removes tiles which are out of view bounds.
192     */
193     void removeOldTiles();
194
195     /**
196     * @brief Checks if center tile has changed.
197     *
198     * @param sceneCoordinate scene's center coordinate
199     * @return bool true if center tile changed, false otherwise
200     */
201     bool centerTileChanged(QPointF sceneCoordinate);
202
203 private slots:
204     /**
205     * @brief Slot for received map tile images
206     *
207     * Does add MapTile objects to MapScene. Zoom level and location is parsed from URL.
208     * @param url URL of the received image
209     * @param pixmap Received pixmap
210     */
211     void mapImageReceived(const QUrl &url, const QPixmap &pixmap);
212
213     /**
214     * @brief Slot for zooming in
215     *
216     */
217     void zoomIn();
218
219     /**
220     * @brief Slot for zooming out
221     *
222     */
223     void zoomOut();
224
225 signals:
226     /**
227     * @brief Signal for view location change
228     *
229     * @param sceneCoordinate New scene coordinates
230     */
231     void locationChanged(QPointF sceneCoordinate);
232
233     /**
234     * @brief Signal for zoom level change
235     *
236     * @param newZoomLevel New zoom level
237     */
238     void zoomLevelChanged(int newZoomLevel);
239
240     void fetchImage(const QUrl &url);
241
242     void centerToSceneCoordinates(QPointF sceneCoordinate);
243
244 private:
245
246     MapScene *m_mapScene; ///< Scene for map tiles
247     MapFetcher *m_mapFetcher; ///< Fetcher for map tiles
248     int m_zoomLevel; ///< Current zoom level
249     QHash<QString, MapTile *> mapTilesInScene;  ///< List of map tiles in map scene
250     QSize m_viewSize;
251     QPointF m_sceneCoordinate;
252     QQueue<QString> mapTilesInView;
253     QPoint m_centerTile;
254     QRect viewGrid;
255 };
256
257 #endif // MAPENGINE_H