2 * This file is part of jSpeed.
4 * jSpeed is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * jSpeed is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with jSpeed. If not, see <http://www.gnu.org/licenses/>.
19 #include <QtCore/QString>
20 #include <QtCore/QDir>
21 #include <QtCore/QTimer>
22 #include <QtCore/QFile>
23 #include <QtCore/QDebug>
25 #include "poialerts.h"
29 #include "mediaplayer.h"
33 static double const EARTH_MEAN_RADIUS = 6371.0072;
34 static double const PI = 3.14159265;
37 inline static double degToRad(double deg)
39 return deg * PI / 180;
42 inline static double radToDeg(double rad)
44 return rad * 180 / PI;
47 PoiAlerts::PoiAlerts(): QObject(0), enabled_(false), currentPoi_(0), loaded_(false)
51 PoiAlerts::~PoiAlerts()
56 PoiAlerts& PoiAlerts::instance()
58 static PoiAlerts instance;
62 bool PoiAlerts::start()
74 connect(&(Odometer::instance()), SIGNAL(dataUpdated()), this, SLOT(onDataUpdated()));
84 disconnect(&(Odometer::instance()), SIGNAL(dataUpdated()), this, SLOT(onDataUpdated()));
88 playedSounds_.clear();
94 bool PoiAlerts::loadConfig()
98 bool enabled = Settings::instance().value("alert_enabled", false).toBool();
107 distance_ = Settings::instance().value("alert_distance", 300).toBool();
108 onlyOnRoute_ = Settings::instance().value("alert_only_on_route", true).toBool();
115 QString filename = Settings::instance().value("alert_sound", "").toString();
117 if(filename.isEmpty())
119 filename = "alert.wav";
122 QString soundDir = MediaPlayer::getSoundDir();
123 QString localDir = MediaPlayer::getLocalSoundDir();
125 if(!filename.isEmpty() && QFile::exists(soundDir + filename))
127 file_ = soundDir + filename;
129 else if(!filename.isEmpty() && QFile::exists(localDir + filename))
131 file_ = localDir + filename;
154 bool PoiAlerts::loadPois()
156 QString filename = Settings::instance().value("alert_poi_file", "").toString();
158 QString poiFile = getPoiDir() + filename;
160 if(filename.isEmpty() || !QFile::exists(poiFile))
162 error_ = "Poi file doesn't exist";
166 PoiReader* reader = PoiReader::getReader(poiFile);
170 error_ = "Unknown file format: " + poiFile;
174 if(!reader->read(pois_))
176 error_ = reader->error();
183 double PoiAlerts::getCurrentDistance() const
190 return currentDistance_;
193 QString PoiAlerts::getCurrentPoi() const
197 return currentPoi_->name;
203 bool PoiAlerts::poiInView() const
205 return currentPoi_ != 0;
208 QString const& PoiAlerts::error() const
213 void PoiAlerts::onDataUpdated()
215 qDebug() << "Data update";
220 double travelled = Odometer::instance().getTotal();
221 const Location::Fix* fix = &(Odometer::instance().getLatestFix());
223 if(fix->latitude < 0.01 || fix->longitude < 0.01 || fix->kmSpeed < 0.01)
231 pois_[0].latitude = fix->latitude;
232 pois_[0].longitude = fix->longitude;
237 double inRouteMargin = IN_ROUTE_MARGIN + (fix->eph / 1000.0);
239 qDebug() << "Eph: " << fix->eph;
240 qDebug() << "In route margin: " << inRouteMargin;
242 if(1 == 1 || abs(travelled - travelled_) > 0.03)
244 travelled_ = travelled;
246 for(int i = 0; i < pois_.size(); i++)
248 if((distance = calculateDistance(pois_.at(i).latitude, pois_.at(i).longitude,
249 fix->latitude, fix->longitude)) <= distance_)
251 qDebug() << "Distance: " << distance;
255 double track = abs(calculateTrack(fix->latitude, fix->longitude,
256 pois_.at(i).latitude, pois_.at(i).longitude) - fix->track);
260 track = 360.0 - track;
263 qDebug() << "Real track: " << track;
264 qDebug() << "Epd: " << fix->epd;
268 if(distance < (inRouteMargin * 2.0))
274 trackLimit = 90.0 - radToDeg(acos((inRouteMargin + (distance * 0.15)) / distance));
277 qDebug() << "Tracklimit: " << trackLimit;
279 if(track < trackLimit)
281 currentPoi_ = &pois_[i];
282 currentDistance_ = distance;
293 currentPoi_ = &pois_[i];
294 currentDistance_ = distance;
303 qDebug() << "Distance: " << distance;
311 void PoiAlerts::startTest()
313 Odometer::instance().start();
320 pois_.push_back(poi);
325 double PoiAlerts::calculateDistance(double latitude1, double longitude1,
326 double latitude2, double longitude2)
328 double dlat = degToRad(latitude1 - latitude2);
329 double dlon = degToRad(longitude1 - longitude2);
330 double y = sin(dlat / 2.0) * sin(dlat / 2.0)
331 + cos(degToRad(latitude2))
332 * cos(degToRad(latitude1))
333 * sin(dlon / 2.0) * sin(dlon / 2.0);
334 double x = 2 * atan2(sqrt(y), sqrt(1 - y));
335 return x * EARTH_MEAN_RADIUS * 1000;
338 double PoiAlerts::calculateTrack(double latitude1, double longitude1,
339 double latitude2, double longitude2)
341 double dlon = degToRad(longitude2 - longitude1);
342 double lat1Rad = degToRad(latitude1);
343 double lat2Rad = degToRad(latitude2);
344 double y = sin(dlon) * cos(lat2Rad);
345 double x = cos(lat1Rad) * sin(lat2Rad) - sin(lat1Rad) * cos(lat2Rad) * cos(dlon);
347 double fraction = modf(radToDeg(atan2(y, x)), &whole);
348 return (int(whole + 360) % 360) + fraction;
351 void PoiAlerts::playSound(int poiIndex)
353 qDebug() << "Almost play sound";
355 if(playedSounds_.indexOf(poiIndex) == -1)
357 playedSounds_.enqueue(poiIndex);
359 qDebug() << "Play sound";
360 MediaPlayer::play(file_);
362 QTimer::singleShot(POI_ALERT_INTERVAL * 1000, this, SLOT(removePlayed()));
367 void PoiAlerts::removePlayed()
369 if(!playedSounds_.isEmpty())
371 int removed = playedSounds_.dequeue();
372 qDebug() << "Removed: " << removed;
376 QString PoiAlerts::getPoiDir()
378 return Settings::getDir() + "pois" + QDir::separator();