1 /* 2 * Copyright 2013 Thomas Schöps 3 * Copyright 2016, 2018 Kai Pastor 4 * 5 * This file is part of OpenOrienteering. 6 * 7 * OpenOrienteering is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * OpenOrienteering 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 OpenOrienteering. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 22 #ifndef OPENORIENTEERING_GPS_DISPLAY_H 23 #define OPENORIENTEERING_GPS_DISPLAY_H 24 25 #include <QtGlobal> 26 #include <QObject> 27 #include <QString> 28 29 #include "core/map_coord.h" 30 31 class QGeoPositionInfo; 32 class QGeoPositionInfoSource; 33 class QPainter; 34 class QTimerEvent; 35 36 namespace OpenOrienteering { 37 38 class Georeferencing; 39 class MapWidget; 40 41 42 /** 43 * Retrieves the GPS position and displays a marker at this position on a MapWidget. 44 * 45 * \todo Use qreal instead of float (in all sensor code) for consistency with Qt. 46 */ 47 class GPSDisplay : public QObject 48 { 49 Q_OBJECT 50 public: 51 /// Creates a GPS display for the given map widget and georeferencing. 52 GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing, QObject* parent = nullptr); 53 /// Destructor, removes the GPS display from the map widget. 54 ~GPSDisplay() override; 55 56 /** 57 * Checks if GPS is enabled, and may guide the user to the device settings. 58 * 59 * If GPS is not enabled in the device settings, it asks the user whether he 60 * wishes to open the device's location settings dialog. 61 * (At the moment, this is implemented for Android only.) 62 * 63 * Returns true if GPS is enabled, but also when the settings dialog remains 64 * open when returning from this function and the final setting is unknown. 65 */ 66 bool checkGPSEnabled(); 67 68 /// Starts regular position updates. This will issue redraws of the map widget. 69 void startUpdates(); 70 /// Stops regular position updates. 71 void stopUpdates(); 72 73 /// Sets GPS marker visibility (true by default) 74 void setVisible(bool visible); 75 /// Returns GPS marker visibility isVisible()76 bool isVisible() const { return visible; } 77 78 /// Sets whether distance rings are drawn 79 void enableDistanceRings(bool enable); 80 /// Sets whether the current heading from the Compass is used to draw a heading indicator. 81 void enableHeadingIndicator(bool enable); 82 83 /// This is called from the MapWidget drawing code to draw the GPS position marker. 84 void paint(QPainter* painter); 85 86 /// Returns if a valid position was received since the last call to startUpdates(). hasValidPosition()87 bool hasValidPosition() const { return has_valid_position; } 88 /// Returns the latest received GPS coord. Check hasValidPosition() beforehand! getLatestGPSCoord()89 const MapCoordF& getLatestGPSCoord() const { return latest_gps_coord; } 90 /// Returns the accuracy of the latest received GPS coord, or -1 if unknown. Check hasValidPosition() beforehand! getLatestGPSCoordAccuracy()91 float getLatestGPSCoordAccuracy() const { return latest_gps_coord_accuracy; } 92 93 /// Starts quick blinking for one or more seconds. 94 void startBlinking(int seconds); 95 96 /// Stops blinking. 97 void stopBlinking(); 98 99 /// Returns true while blinking is active. isBlinking()100 bool isBlinking() const { return blink_count > 0; } 101 102 protected: 103 /// Handles blinking. 104 void timerEvent(QTimerEvent* e) override; 105 106 signals: 107 /// Is emitted whenever a new position update happens. 108 /// If the accuracy is unknown, -1 will be given. 109 void mapPositionUpdated(const OpenOrienteering::MapCoordF& coord, float accuracy); 110 111 /// Like mapPositionUpdated(), but gives the values as 112 /// latitude / longitude in degrees and also gives altitude 113 /// (meters above sea level; -9999 is unknown) 114 void latLonUpdated(double latitude, double longitude, double altitude, float accuracy); 115 116 /// Is emitted when updates are interrupted after previously being active, 117 /// due to loss of satellite reception or another error such as the user 118 /// turning off the GPS receiver. 119 void positionUpdatesInterrupted(); 120 121 private slots: 122 void positionUpdated(const QGeoPositionInfo& info); 123 void error(); 124 void updateTimeout(); 125 void debugPositionUpdate(); 126 127 private: 128 MapCoordF calcLatestGPSCoord(bool& ok); 129 void updateMapWidget(); 130 131 /** 132 * A lightweight utility for sinusoidal pulsating opacity. 133 * 134 * This class depends on another object's QObject::timerEvent() override 135 * to advance the pulsation state and eventually stop the activity. 136 * 137 * \see QBasicTimer 138 */ 139 class PulsatingOpacity 140 { 141 public: 142 /// Returns true when the pulsation is active. isActive()143 bool isActive() const { return bool(timer_id); } 144 /// Starts a timer on the given object. 145 void start(QObject& object); 146 /// Stops the timer on the given object. 147 void stop(QObject& object); 148 /// Returns the ID of the active timer. timerId()149 int timerId() const { return timer_id; } 150 151 /// Advances the pulsation state. 152 bool advance(); 153 /// Returns the current opacity. 154 qreal current() const; 155 156 private: 157 int timer_id = 0; 158 quint8 index = 0; 159 }; 160 161 MapWidget* widget; 162 const Georeferencing& georeferencing; 163 QGeoPositionInfoSource* source = nullptr; 164 MapCoordF latest_gps_coord; 165 float latest_gps_coord_accuracy = 0; 166 PulsatingOpacity pulsating_opacity; 167 int blink_count = 0; 168 bool tracking_lost = false; 169 bool has_valid_position = false; 170 bool gps_updated = false; 171 bool visible = false; 172 bool distance_rings_enabled = false; 173 bool heading_indicator_enabled = false; 174 }; 175 176 177 } // namespace OpenOrienteering 178 179 #endif 180