Re-factored the source to use the new coordinate classes
[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        Pekka Nissinen - pekka.nissinen@ixonos.com
8        Ville Tiensuu - ville.tiensuu@ixonos.com
9        Henri Lampela - henri.lampela@ixonos.com
10
11    Situare is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License
13    version 2 as published by the Free Software Foundation.
14
15    Situare is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with Situare; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
23    USA.
24 */
25
26 #ifndef MAPENGINE_H
27 #define MAPENGINE_H
28
29 #include <QtCore>
30
31 #include "coordinates/geocoordinate.h"
32 #include "coordinates/scenecoordinate.h"
33
34 class QGraphicsScene;
35
36 class FriendItemsHandler;
37 class GPSLocationItem;
38 class MapFetcher;
39 class MapScene;
40 class MapScroller;
41 class MapTile;
42 class OwnLocationItem;
43 class User;
44
45 /**
46  * @brief Map engine
47  *
48  * Logic for controlling map functionality. Does also include static methods for
49  * converting coordinates.
50  *
51  * @author Sami Rämö - sami.ramo (at) ixonos.com
52  * @author Jussi Laitinen - jussi.laitinen (at) ixonos.com
53  * @author Pekka Nissinen - pekka.nissinen (at) ixonos.com
54  * @author Ville Tiensuu - ville.tiensuu (at) ixonos.com
55  */
56 class MapEngine : public QObject
57 {
58     Q_OBJECT
59
60 public:
61     /**
62      * @brief Constructor
63      *
64      * @param parent Parent
65      */
66     MapEngine(QObject *parent = 0);
67
68     /**
69      * @brief Destructor
70      * Saves view of the map to settings file
71      */
72     ~MapEngine();
73
74 /*******************************************************************************
75  * MEMBER FUNCTIONS AND SLOTS
76  ******************************************************************************/
77 public:
78     /**
79      * @brief Coordinates of the current center point
80      *
81      * @return Current coordinates
82      */
83     GeoCoordinate centerGeoCoordinate();
84
85     /// @todo remove
86 //    /**
87 //     * @brief Convert latitude and longitude to scene coordinates.
88 //     *
89 //     * @param latLonCoordinate latitude and longitude values
90 //     * @return scene coordinate
91 //     */
92 //    static QPoint convertLatLonToSceneCoordinate(GeoCoordinate latLonCoordinate);
93
94 //    /**
95 //     * @brief converts scene coordinates to latitude and longitude
96 //     *
97 //     * @param zoomLevel current zoom level
98 //     * @param sceneCoordinate that will be converted
99 //     */
100 //    GeoCoordinate convertSceneCoordinateToLatLon(int zoomLevel, QPoint sceneCoordinate);
101
102     /**
103      * @brief Convert MapScene coordinate to tile x & y numbers.
104      *
105      * @param zoomLevel ZoomLevel
106      * @param sceneCoordinate MapScene coordinate
107      * @return tile x & y numbers
108      */
109     static QPoint convertSceneCoordinateToTileNumber(int zoomLevel, SceneCoordinate sceneCoordinate);
110
111     /**
112      * @brief Convert tile x & y numbers to MapScene coordinates
113      *
114      * @param zoomLevel Zoom level
115      * @param tileNumber x & y numbers of the tile
116      * @return Scene coordinate
117      */
118     static SceneCoordinate convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber);
119
120     /**
121      * @brief Calculate great-circle distance between two geographic coordinates
122      *
123      * Calculate great-circle distance between two given geographic locations using
124      * haversine formula
125      *
126      * @param firstLocation Coordinates of the first location
127      * @param secondLocation Coordinates of the second location
128      * @return qreal Distance in kilometers
129      */
130     qreal greatCircleDistance(GeoCoordinate firstLocation, GeoCoordinate secondLocation);
131
132     /**
133      * @brief Set initial values for the map
134      *
135      * Set initial location and zoom level from the settings, if available, or use the default
136      * values set in the constructor. Signals locationChanged() and zoomLevelChanged() are emitted,
137      * so init should be called after those signals are connected.
138      */
139     void init();
140
141     /**
142      * @brief Return given value translated between min and max
143      *
144      * If given value is not inside the given range (min <= value <= max), then the allowed range
145      * is adder or subtracted until the value does fit in the range.
146      *
147      * @param value Value to be normalized
148      * @param min Minimum allowed value
149      * @param max Maximum allowed value
150      * @return value which is moved to be inside the given limits
151      */
152     static int normalize(int value, int min, int max);
153
154     /**
155      * @brief Getter for scene
156      *
157      * @return QGraphicsScene
158      */
159     QGraphicsScene* scene();
160
161     /**
162      * @brief Sets new zoom level
163      *
164      * @return newZoomLevel value that is set to new zoom level
165      */
166     void setZoomLevel(const int newZoomLevel);
167
168     /**
169      * @brief Return tile path created from tile values.
170      *
171      * @param zoomLevel tile's zoom level
172      * @param x tile's x value
173      * @param y tile's y value
174      * @return QString tile path
175      */
176     static QString tilePath(int zoomLevel, int x, int y);
177
178     /**
179      * @brief Maximum number of individual tiles per side at given zoom level
180      *
181      * @param zoomLevel Zoom level
182      * @return amount of tiles per side at given zoom level
183      */
184     static int tilesPerSide(int zoomLevel);
185
186 public slots:
187     /**
188      * @brief Center smoothly to given latitude and longitude coordinates.
189      *
190      * @param latLonCoordinate Latitude & longitude coordinates for location
191      */
192     void centerToCoordinates(GeoCoordinate latLonCoordinate);
193
194     /**
195      * @brief Slot to catch user own location data
196      *
197      * @param user User info
198      */
199     void receiveOwnLocation(User *user);
200
201     /**
202      * @brief Set auto centering.
203      *
204      * @param enabled true if enabled, false otherwise
205      */
206     void setAutoCentering(bool enabled);
207
208     /**
209      * @brief Slot for enabling / disabling GPS
210      *
211      * GPS location item is disabled or enabled based on GPS state
212      *
213      * @param enabled True is GPS is enabled, otherwise false
214      */
215     void setGPSEnabled(bool enabled);
216
217     /**
218      * @brief Calculate maximum value for tile in this zoom level.
219      *
220      * @param zoomLevel zoom level
221      * @return int tile's maximum value
222      */
223     static int tileMaxIndex(int zoomLevel);
224
225     /**
226      * @brief Slot for view resizing.
227      *
228      * @param size view size
229      */
230     void viewResized(const QSize &size);
231
232 private:
233     /**
234      * @brief Calculate grid of tile coordinates from current scene coordinate.
235      *
236      * Grid size is calculated from view size and scene's current center coordinate.
237      *
238      * @param sceneCoordinate scene's current center coordinate
239      * @return QRect grid of tile coordinates
240      */
241     QRect calculateTileGrid(SceneCoordinate sceneCoordinate);
242
243     /**
244      * @brief Request disabling of auto centering if centered too far from the real location.
245      *
246      * @param sceneCoordinate scene's center coordinate
247      */
248     void disableAutoCenteringIfRequired(SceneCoordinate sceneCoordinate);
249
250     /**
251      * @brief Get new tiles.
252      *
253      * Calculates which tiles has to be fetched. Does emit fetchImage for tiles which
254      * aren't already in the scene.
255      * @param sceneCoordinate scene's center coordinate
256      */
257     void getTiles(SceneCoordinate sceneCoordinate);
258
259     /**
260      * @brief Check if auto centering is enabled
261      *
262      * @return true if enabled, false otherwise
263      */
264     bool isAutoCenteringEnabled();
265
266     /**
267      * @brief Check if center tile has changed.
268      *
269      * @param sceneCoordinate scene's center coordinate
270      * @return bool true if center tile changed, false otherwise
271      */
272     bool isCenterTileChanged(SceneCoordinate sceneCoordinate);
273
274     /**
275      * @brief Calculate scale at the map center of the map in meters/pixel
276      *
277      * @return qreal Scale of the map in meters/pixel
278      */
279     qreal sceneResolution();
280
281     /**
282      * @brief Set size of tiles grid based on view size
283      *
284      * @param viewSize Current view size
285      */
286     void setTilesGridSize(const QSize &viewSize);
287
288     /**
289      * @brief Updates the current view rect including margins
290      *
291      * Calculates tiles rect in scene based on m_viewTilesGrid and
292      * calls MapScene::viewRectUpdated()
293      */
294     void updateViewTilesSceneRect();
295
296     /**
297      * @brief This method is ran always when the map is zoomed
298      *
299      * This method is the right place for all actions which must be done when ever map is zoomed.
300      */
301     void zoomed();
302
303 private slots:
304     /**
305      * @brief This slot is called after friend items position have been updated
306      *
307      * Does run MapScene::spanItems()
308      */
309     void friendsPositionsUpdated();
310
311     /**
312      * @brief Slot for GPS position updates
313      *
314      * GPS location item is updated and map centered to new location (if automatic
315      * centering is enabled).
316      *
317      * @param position New coordinates from GPS
318      * @param accuracy Accuracy of the GPS fix
319      */
320     void gpsPositionUpdate(GeoCoordinate position, qreal accuracy);
321
322     /**
323      * @brief Slot for received map tile images
324      *
325      * Does receive map tile images from MapFetcher. Calls MapScene::addTile() for creating and adding
326      * the actual MapTile object to the MapScene.
327      *
328      * Tile is added also to outside the world horizontal limits, if required, for spanning the map.
329      *
330      * @param zoomLevel Zoom level
331      * @param x Tile x index
332      * @param y Tile y index
333      * @param image Received pixmap
334      */
335     void mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image);
336
337     /**
338     * @brief Called when MapScroller state is changed
339     *
340     * Does check if the smooth scroll effect was interrupted and should the auto centering
341     * feature to be disabled.
342     *
343     * @param newState New state
344     */
345     void scrollerStateChanged(QAbstractAnimation::State newState);
346
347     /**
348     * @brief Scroll smoothly to given scene position
349     *
350     * @param scenePosition Target position in the scene
351     */
352     void scrollToPosition(SceneCoordinate scenePosition);
353
354     /**
355      * @brief Set center point in the scene
356      *
357      * Does emit locationChanged signal.
358      * @param scenePosition Scene coordinates for new position
359      */
360     void setCenterPosition(SceneCoordinate scenePosition);
361
362     /**
363      * @brief Slot for actions after view zoom is finished
364      *
365      * Does run removeOutOfViewTiles
366      */
367     void viewZoomFinished();
368
369     /**
370      * @brief Slot for zooming in
371      */
372     void zoomIn();
373
374     /**
375      * @brief Slot for zooming out
376      */
377     void zoomOut();
378
379 /*******************************************************************************
380  * SIGNALS
381  ******************************************************************************/
382 signals:
383     /**
384     * @brief Signals error
385     *
386     * @param context error context
387     * @param error error code
388     */
389     void error(const int context, const int error);
390
391     /**
392      * @brief Signal for image fetching.
393      *
394      * @param zoomLevel Zoom level
395      * @param x Tile x index
396      * @param y Tile y index
397      */
398     void fetchImage(int zoomLevel, int x, int y);
399
400     /**
401     * @brief Signal when friend image is ready
402     *
403     * @param user Friend
404     */
405     void friendImageReady(User *user);
406
407     /**
408      * @brief Signal when friend list locations are fetched
409      *
410      * @param friendsList Friends list data
411      */
412     void friendsLocationsReady(QList<User *> &friendsList);
413
414     /**
415      * @brief Request view centering to new locaiton
416      *
417      * @param sceneCoordinate New scene coordinates
418      */
419     void locationChanged(SceneCoordinate sceneCoordinate);
420
421     /**
422      * @brief Signal is emitted when location item is clicked.
423      *
424      * @param userIDs list of friends user IDs in the group
425      */
426     void locationItemClicked(const QList<QString> &userIDs);
427
428     /**
429      * @brief Signal to notify map scrolling.
430      */
431     void mapScrolledManually();
432
433     /**
434      * @brief Signal to notify when map is zoomed in to the maxmimum.
435      */
436     void maxZoomLevelReached();
437
438     /**
439      * @brief Signal to notify when map is zoomed out to the minimum.
440      */
441     void minZoomLevelReached();
442
443     /**
444      * @brief Signal to pass the scale of the map to map scale
445      */
446     void newMapResolution(qreal scale);
447
448     /**
449      * @brief Request view changing zoom level
450      *
451      * @param newZoomLevel New zoom level
452      */
453     void zoomLevelChanged(int newZoomLevel);
454
455 /*******************************************************************************
456  * DATA MEMBERS
457  ******************************************************************************/
458 private:
459     bool m_autoCenteringEnabled;    ///< Auto centering enabled
460     bool m_scrollStartedByGps;      ///< Smooth scroll is started by GPS?
461     bool m_smoothScrollRunning;     ///< Smooth scroll is running?
462     bool m_zoomedIn;                ///< Flag for checking if zoomed in when zoom is finished
463
464     int m_zoomLevel;                ///< Current zoom level
465
466     QPoint m_centerTile;            ///< Current center tile
467     SceneCoordinate m_lastAutomaticPosition; ///< Last automatically set position in scene coordinate
468     SceneCoordinate m_sceneCoordinate;       ///< Current center coordinate
469
470     QRect m_viewTilesGrid;          ///< Current grid of tiles in view (includes margin)
471
472     QSize m_tilesGridSize;          ///< Current size of the tiles grid
473     QSize m_viewSize;               ///< Current view size
474
475     FriendItemsHandler *m_friendItemsHandler;   ///< Handler for friend and group items
476     GPSLocationItem *m_gpsLocationItem;         ///< Item pointing current location from GPS
477     MapFetcher *m_mapFetcher;                   ///< Fetcher for map tiles
478     MapScene *m_mapScene;                       ///< Scene for map tiles
479     MapScroller *m_scroller;                    ///< Kinetic scroller
480     OwnLocationItem *m_ownLocation;             ///< Item to show own location
481 };
482
483 #endif // MAPENGINE_H