1 /****************************************************************************
3 ** Copyright (C) 2011 Tito Eritja Real <jtitoo@gmail.com>
5 ** This program is free software: you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation, either version 3 of the License, or
8 ** (at your option) any later version.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
18 ****************************************************************************/
22 #include <QXmlStreamWriter>
25 #include <QtCore/qmath.h>
29 Summarized::Summarized(){
31 startTime=QDateTime::currentDateTime();
46 lastElevationAccuracy=ACCURACY_V_GAIN+1;
50 QString Summarized::toSumString(){
51 return QString("Summarized={numPoints: %1, startTime: %2, duration: %3, distance: %4, avgSpeed: %5, maxSpeed: %6, elevationGain: %7, elevationLoss: %8, minElevation: %9, maxElevation: %10, avgPace: %11, minPace: %12}")
52 .arg(numPoints).arg(startTime.toString(CLEAN_DATE_FORMAT)).arg(duration).arg(distance)
53 .arg(avgSpeed).arg(maxSpeed).arg(elevationGain).arg(elevationLoss).arg(minElevation).arg(maxElevation).arg(avgPace).arg(bestPace);
55 void Summarized::addSummary(Summarized summary){
57 duration+=summary.getDuration();
58 distance+=summary.getDistance();
60 // avgSpeed of summary is not Avg, is speed of last point!
61 if(summary.getAvgPace()!=-1)
62 avgSpeed=((avgSpeed*numPoints)+summary.getAvgSpeed())/(numPoints+1);
64 if(summary.lastElevationAccuracy<=ACCURACY_V_GAIN){
66 elevationGain+=summary.getElevationGain();
67 elevationLoss+=summary.getElevationLoss();
69 if(minElevation!=0 && summary.minElevation!=0){
70 minElevation=min(minElevation,summary.minElevation);
71 }else if(minElevation==0 && summary.minElevation!=0){
72 minElevation=summary.minElevation;
75 maxElevation=max(maxElevation,summary.maxElevation);
76 lastElevation=summary.lastElevation;
77 lastElevationAccuracy=summary.lastElevationAccuracy;
80 maxSpeed=max(maxSpeed,summary.maxSpeed);
82 if(bestPace!=0 && summary.avgPace!=0){
83 bestPace=min(bestPace,summary.avgPace);
84 }else if(bestPace==0 && summary.avgPace!=0){
85 bestPace=summary.avgPace;
89 avgPace=(1000*duration)/(60*distance);
94 Summarized& Summarized::account(GpsPoint point){
96 // this just is usefull for accounting the diference
97 // between two points. The summary MUST be new!!!
98 // data in here is not secure and not controlled.
101 startTime=point.getTime();
102 endTime=point.getTime();
103 maxSpeed=point.getSpeed();
104 avgSpeed=point.getSpeed();
106 lastElevationAccuracy = point.getVerticalAccuracy();
109 if(lastElevationAccuracy<=ACCURACY_V_GAIN){
110 minElevation=point.getElevation();
111 maxElevation=point.getElevation();
112 lastElevation=point.getElevation();
118 Summarized& Summarized::account(GpsPoint first, GpsPoint last){
120 // this just is usefull for accounting the diference
121 // between two points. The summary MUST be new!!!
122 // data in here is not secure and not controlled.
126 qDebug() << "first:" << first.toString();
127 qDebug() << "last:" << last.toString();
129 distance=first.distance(last);
130 duration=first.getTime().secsTo(last.getTime());
131 startTime=first.getTime();
132 endTime=last.getTime();
133 double lastEle=last.getElevation();
134 double firstEle=first.getElevation();
136 lastElevationAccuracy = last.getVerticalAccuracy();
138 qDebug() <<"firstElevation:" << firstEle;
139 qDebug() <<"lastElevation:" << lastEle;
140 qDebug() << "vertical accuracy:" << lastElevationAccuracy;
143 if(lastElevationAccuracy<=ACCURACY_V_GAIN){
144 if(lastEle>=firstEle){
145 elevationGain=lastEle-firstEle;
147 elevationLoss=firstEle-lastEle;
150 minElevation=min(first.getElevation(),last.getElevation());
151 maxElevation=max(first.getElevation(),last.getElevation());
152 lastElevation = last.getElevation();
155 maxSpeed=max(first.getSpeed(),last.getSpeed());
156 // keep speed of last point, will be usefull
158 avgSpeed=last.getSpeed();
162 avgPace=(1000*duration)/(60*distance);
168 GpsPoint::GpsPoint(double latitude, double longitude, double elevation)
170 longitude(longitude),
171 elevation(elevation),speed(0),direction(0),magneticVariation(0),horizontalAccuracy(0),verticalAccuracy(0){
174 GpsPoint::GpsPoint(double latitude, double longitude, double elevation,QDateTime time,
175 double speed, double direction, double magneticVariation, double horizontalAccuracy, double verticalAccuracy)
176 :latitude(latitude),longitude(longitude),elevation(elevation), time(time),
177 speed(speed), direction(direction), magneticVariation(magneticVariation),
178 horizontalAccuracy(horizontalAccuracy),verticalAccuracy(verticalAccuracy){
180 //qDebug() << "elevation:" << elevation;
183 GpsPoint::GpsPoint(double latitude, double longitude, double elevation,QDateTime time,
184 double speed, double direction, double magneticVariation, double horizontalAccuracy, double verticalAccuracy,
185 double distancePrev, QTime timeToPrev)
186 :latitude(latitude),longitude(longitude),elevation(elevation),time(time),
187 speed(speed), direction(direction), magneticVariation(magneticVariation),
188 horizontalAccuracy(horizontalAccuracy),verticalAccuracy(verticalAccuracy),distancePrev(distancePrev), timeToPrev(timeToPrev){
192 QString GpsPoint::toString(){
193 QString point = QString("GpsPoint{latitude: %1, longitude: %2, elevation: %3, time: %4, speed: %5, direction: %6, magneticVariation: %7, horizontalAccuracy: %8, verticalAccuracy: %9:, distancePrev: %10}")
194 .arg(latitude).arg(longitude).arg(elevation).arg(time.toString("dd-MM-yyyy hh:mm:ss")).arg(speed).arg(direction).arg(magneticVariation)
195 .arg(horizontalAccuracy).arg(verticalAccuracy).arg(QString::number(distancePrev,'f',10));
199 GpsPoint& GpsPoint::operator= (const GpsPoint &p){
203 longitude=p.longitude;
204 elevation=p.elevation;
206 direction=p.direction;
207 magneticVariation=p.magneticVariation;
209 distancePrev=p.distancePrev;
210 timeToPrev=p.timeToPrev;
211 horizontalAccuracy=p.horizontalAccuracy;
212 verticalAccuracy=p.verticalAccuracy;
219 double GpsPoint::distance(GpsPoint p){
223 double latitude1 = toRad(latitude);
224 double longitude1 = toRad(longitude);
226 double latitude2 = toRad(p.latitude);
227 double longitude2 = toRad(p.longitude);
229 if(latitude1==latitude2 && longitude1==longitude2){
233 double temp = sin(latitude1)*sin(latitude2)+cos(latitude1)*cos(latitude2)*cos(longitude2-longitude1);
234 dist= acos(temp)*EARTH_RADIUS*1000;
236 qDebug() << "distance between points: " << QString::number(dist,'f',10);
240 int operator== (const GpsPoint& a, const GpsPoint& b)
242 if (a.latitude==b.latitude&&a.longitude==b.longitude&&a.elevation==b.elevation&&a.speed==b.speed
243 &&a.direction==b.direction &&a.magneticVariation==b.magneticVariation&&a.time==b.time
244 &&a.horizontalAccuracy==b.horizontalAccuracy&&a.verticalAccuracy==b.verticalAccuracy
245 &&a.distancePrev==b.distancePrev&&a.timeToPrev==b.timeToPrev)
251 int operator!= (const GpsPoint& a, const GpsPoint& b)
253 if (a.latitude!=b.latitude||a.longitude!=b.longitude||a.elevation!=b.elevation||a.speed!=b.speed
254 ||a.direction!=b.direction || a.magneticVariation!=b.magneticVariation||a.time!=b.time
255 ||a.horizontalAccuracy!=b.horizontalAccuracy||a.verticalAccuracy!=b.verticalAccuracy
256 ||a.distancePrev!=b.distancePrev||a.timeToPrev!=b.timeToPrev)
271 for (int i = 0; i < points.size(); ++i) {
277 Summarized* Lap::addPoint(GpsPoint *point){
278 //qDebug() <<"--- Lap::addPoint ---";
279 Summarized *summary = new Summarized();
281 GpsPoint* last = points.last();
282 point->setDistancePrev(point->distance(*last));
283 //qDebug() << "DistancePrev:" << QString::number(point->getDistancePrev(),'f',10);
284 summary->account(*last,*point);
286 //qDebug() << "First lap point!";
287 summary->account(*point);
289 addSummary(*summary);
290 //qDebug() << "Track summary:" << toSumString();
292 points.append(point);
296 QString Lap::toString(){
297 QString lap = QString("Lap={number:").append(QString::number(number)).append(", numPoints:").append(QString::number(numPoints));
299 QListIterator<GpsPoint*> i(points);
300 while (i.hasNext()) {
301 GpsPoint* p = i.next();
302 lap.append(QString(", %1").arg(p->toString()));
304 lap.append(QString("}"));
308 Activity::Activity(QString sport)
310 id=QDateTime::currentDateTime();
315 Activity::~Activity(){
316 for (int i = 0; i < laps.size(); ++i) {
321 QString Activity::toString(){
322 QString activity = QString("Activity={sport:%1, id:%2, numLaps:%3").arg(sport).arg(id.toString(CLEAN_DATE_FORMAT)).arg(numLaps);
324 QListIterator<Lap*> i(laps);
327 activity.append(QString(", %1").arg(l->toString()));
329 activity.append(QString("}"));
333 void Activity::addLap(){
335 Lap* newLap = new Lap(numLaps);
339 Summarized* Activity::addPoint(GpsPoint* point){
341 //qDebug() <<"--- Activity::addPoint ---";
342 Lap* lastLap = laps.last();
343 Summarized* summary = lastLap->addPoint(point);
344 addSummary(*summary);
345 //qDebug() << "Track summary:" << toSumString();
352 Track::Track(QString file,QString nameTrack)
353 :fileName(file),name(nameTrack){
355 addActivity(nameTrack);
358 Track::Track(QString fname)
359 :fileName(fname),name(fname){
365 :fileName("noname"),name("noname"){
372 for (int i = 0; i < activities.size(); ++i) {
373 delete activities.at(i);
377 void Track::addLap(){
379 if(activities.size()>0){
380 Activity* activity = activities.last();
386 void Track::addActivity(QString sport){
389 Activity* activity = new Activity(sport);
390 activities.append(activity);
394 Summarized* Track::addPoint(GpsPoint* point){
396 //qDebug() <<"--- Track::addPoint ---";
397 //qDebug() << "Adding point: " << point->toString();
399 Activity* actualActivity = activities.last();
400 Summarized* summary = actualActivity->addPoint(point);
401 addSummary(*summary);
402 //qDebug() << "Track summary:" << toSumString();
407 QString Track::toString(){
409 QString track = QString("Track={fileName:%2, numActivities:%3").arg(fileName).arg(numActivities);
411 QListIterator<Activity*> i(activities);
413 Activity* a = i.next();
414 track.append(QString(", %1").arg(a->toString()));
416 track.append(QString("}"));
420 QList<GpsPoint*> Track::getGpsPoints(){
422 QList<GpsPoint*> points=QList<GpsPoint*>();
427 QListIterator<Activity*> iAct(activities);
428 while (iAct.hasNext()) {
429 Activity* act = iAct.next();
431 QListIterator<Lap*> iLap(act->getLaps());
432 while (iLap.hasNext()) {
433 Lap* lap = iLap.next();
435 QListIterator<GpsPoint*> iPts(lap->getPoints());
436 while (iPts.hasNext()) {
437 GpsPoint* point = iPts.next();
438 points.append(point);
445 bool Track::saveToXML(){
447 XMLFileType fileType;
448 QFile file(fileName);
453 if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) {
454 qDebug() << "Error: Cannot write file "
455 << qPrintable(fileName) << ": "
456 << qPrintable(file.errorString());
460 if(fileName.endsWith(".tcx",Qt::CaseInsensitive)){
461 fileType=XMLFile_TCX;
462 }else if(fileName.endsWith(".gpx",Qt::CaseInsensitive)){
463 fileType=XMLFile_GPX;
465 qDebug()<<"Error: XML not recognized. " << "nameFile:" << fileName;
468 QXmlStreamWriter xmlWriter(&file);
470 xmlWriter.setAutoFormatting(true);
472 xmlWriter.writeStartDocument();
474 if(fileType==XMLFile_TCX){
475 xmlWriter.writeStartElement("TrainingCenterDatabase");
476 xmlWriter.writeAttribute("xmlns", TCX_XMLNS);
477 xmlWriter.writeAttribute("xmlns:xsi", TCX_XMLNS_XSI);
478 xmlWriter.writeAttribute("xsi:schemaLocation", TCX_XSI_SCHEMALOCATION);
480 writeTCXCourses(&xmlWriter);
483 xmlWriter.writeStartElement("gpx");
484 xmlWriter.writeAttribute("version",GPX_VERSION);
485 xmlWriter.writeAttribute("creator",GPX_CREATOR);
486 xmlWriter.writeAttribute("xmlns",GPX_XMLNS);
488 writeGPXTracks(&xmlWriter);
494 //xmlWriter->writeEndElement();
495 xmlWriter.writeEndDocument();
497 qDebug() << "file closed";
499 qDebug() << "Error on close: Cannot write file "
500 << qPrintable(fileName) << ": "
501 << qPrintable(file.errorString());
507 void Track::writeGPXTracks(QXmlStreamWriter* xmlWriter){
509 QListIterator<Activity*> i(activities);
511 while (i.hasNext()) {
512 Activity* act = i.next();
513 //xmlWriter->writeStartElement("NextSport");
514 writeGPXTrack(xmlWriter, act);
515 xmlWriter->writeEndElement();
517 xmlWriter->writeEndElement();
518 xmlWriter->writeEndElement();
522 void Track::writeTCXCourses(QXmlStreamWriter* xmlWriter){
524 xmlWriter->writeStartElement("Courses");
525 //xmlWriter->writeStartElement("MultiSportSession");
527 //xmlWriter->writeTextElement("Id",startTime.toString(XML_DATE_FORMAT));
529 QListIterator<Activity*> i(activities);
531 while (i.hasNext()) {
532 Activity* act = i.next();
533 //xmlWriter->writeStartElement("NextSport");
534 writeTCXCourse(xmlWriter, act);
535 xmlWriter->writeEndElement();
537 xmlWriter->writeEndElement();
538 xmlWriter->writeEndElement();
541 void Track::writeGPXTrack(QXmlStreamWriter* xmlWriter, Activity* act){
543 xmlWriter->writeStartElement("trk");
545 xmlWriter->writeTextElement("Name",act->getSport());
547 QListIterator<Lap*> i(act->getLaps());
548 while (i.hasNext()) {
550 writeGPXTrkseg(xmlWriter, lap);
552 xmlWriter->writeEndElement();
557 void Track::writeTCXCourse(QXmlStreamWriter* xmlWriter, Activity* act){
560 xmlWriter->writeStartElement("Course");
561 //xmlWriter->writeAttribute("Sport", act->getSport());
562 xmlWriter->writeTextElement("Name",act->getSport());
564 QListIterator<Lap*> i(act->getLaps());
565 while (i.hasNext()) {
567 writeTCXLap(xmlWriter, lap);
569 xmlWriter->writeEndElement();
572 void Track::writeGPXTrkseg(QXmlStreamWriter* xmlWriter, Lap* lap){
574 xmlWriter->writeStartElement("trkseg");
576 QListIterator<GpsPoint*> i(lap->getPoints());
577 while (i.hasNext()) {
578 GpsPoint* point = i.next();
579 writeGPXPoint(xmlWriter,point);
581 xmlWriter->writeEndElement();
584 void Track::writeTCXLap(QXmlStreamWriter* xmlWriter, Lap* lap){
586 xmlWriter->writeStartElement("Lap");
587 xmlWriter->writeAttribute("StartTime", lap->getStartTime().toString(XML_DATE_FORMAT));
588 xmlWriter->writeTextElement("TotalTimeSeconds",QString::number(lap->getDuration()));
589 xmlWriter->writeTextElement("DistanceMeters",QString::number(lap->getDistance(),'f',10));
590 xmlWriter->writeTextElement("MaximumSpeed",QString::number(lap->getMaxSpeed()));
592 QListIterator<GpsPoint*> i(lap->getPoints());
593 xmlWriter->writeStartElement("Track");
594 while (i.hasNext()) {
595 GpsPoint* point = i.next();
596 writeTCXPoint(xmlWriter,point);
598 xmlWriter->writeEndElement();
599 xmlWriter->writeEndElement();
602 void Track::writeGPXPoint(QXmlStreamWriter* xmlWriter, GpsPoint* point){
604 xmlWriter->writeStartElement("trkpt");
605 xmlWriter->writeAttribute("lat",QString::number(point->getLatitude(),'f',20));
606 xmlWriter->writeAttribute("lon",QString::number(point->getLatitude(),'f',20));
609 xmlWriter->writeTextElement("ele",QString::number(point->getElevation(),'f',20));
610 xmlWriter->writeTextElement("time",point->getTime().toString(XML_DATE_FORMAT));
612 xmlWriter->writeEndElement();
615 void Track::writeTCXPoint(QXmlStreamWriter* xmlWriter, GpsPoint* point){
617 xmlWriter->writeStartElement("Trackpoint");
618 xmlWriter->writeTextElement("Time",point->getTime().toString(XML_DATE_FORMAT));
619 xmlWriter->writeStartElement("Position");
620 xmlWriter->writeTextElement("LatitudeDegrees",QString::number(point->getLatitude(),'f',20));
621 xmlWriter->writeTextElement("LongitudeDegrees",QString::number(point->getLongitude(),'f',20));
622 xmlWriter->writeEndElement();
623 xmlWriter->writeTextElement("AltitudeMeters",QString::number(point->getElevation(),'f',20));
624 xmlWriter->writeTextElement("DistanceMeters",QString::number(point->getDistancePrev(),'f',20));
625 xmlWriter->writeEndElement();