9b58ba74abc880e18f1eb6b2988d239b3a2f53a1
[gpssportsniffer] / utils.cpp
1 /****************************************************************************
2 **
3 **  Copyright (C) 2011  Tito Eritja Real <jtitoo@gmail.com>
4 **
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.
9 **
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.
14 **
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/>.
17 **
18 ****************************************************************************/
19
20 #include "utils.h"
21 #include "constants.h"
22 #include "track.h"
23 #include <QFile>
24 #include <QDebug>
25 #include <QXmlStreamReader>
26
27 uint qHash(const QPoint& p)
28 {
29     return p.x() * 17 ^ p.y();
30 }
31
32
33 qreal max(qreal a, qreal b){
34
35     if(a>=b){
36         return a;
37     }else
38         return b;
39 }
40
41 qreal min(qreal a, qreal b){
42
43     if(a<b){
44         return a;
45     }else
46         return b;
47 }
48
49 QString stringDateFromSeconds(qreal amount){
50
51
52
53     int hours = static_cast<int>(amount/3600);
54     int minutes = static_cast<int>((static_cast<int>(amount)%3600)/60);
55     int seconds = (static_cast<int>(amount)%3600)%60;
56
57     QString dateString=QString("%1h %2m %3s").arg(hours).arg(minutes).arg(seconds);
58
59     //qDebug()<<"amount " << amount << " seconds has been transformated to:" << dateString;
60     return dateString;
61 }
62
63 qreal toRad(qreal degrees){
64     qreal radians = degrees*PI/180;
65     return radians;
66 }
67
68 Track* readFromXML(QString fileName){
69
70     // I need this function to work by now, When I've time I've to make it proper
71     // It doesn't work with no valid XML files!!!
72
73     QFile* file= new QFile(fileName);
74     bool nameFound=false;
75
76     qDebug() << "going to read file:" << fileName;
77
78     Track* myTrack = new Track(fileName);
79     myTrack->addActivity("doesn'tmatter");
80
81     if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
82         qDebug() << "Error: Cannot read file "
83                  << qPrintable(fileName) << ": "
84                  << qPrintable(file->errorString());
85         return myTrack;
86     }
87
88     XMLFileType fileType;
89
90     if(fileName.endsWith(".tcx",Qt::CaseInsensitive)){
91         fileType=XMLFile_TCX;
92     }else if(fileName.endsWith(".gpx",Qt::CaseInsensitive)){
93         fileType=XMLFile_GPX;
94     }else{
95         qDebug()<<"Error: XML not recognized. " << "nameFile:" << fileName;
96     }
97
98     QXmlStreamReader xml(file);
99
100     while (!xml.atEnd() && !xml.hasError()) {
101
102         /* Read next element.*/
103         QXmlStreamReader::TokenType token = xml.readNext();
104         /* If token is just StartDocument, we'll go to next.*/
105         if(token == QXmlStreamReader::StartDocument) {
106             continue;
107         }
108         /* If token is StartElement, we'll see if we can read it.*/
109         if(token == QXmlStreamReader::StartElement) {
110             // just read Positions, dont care about nothing more...
111             // this means, all activities, laps or  track sequences are
112             // processed as a single one!
113
114             if(fileType==XMLFile_GPX){
115                 if(xml.name() == "trkpt") {
116                     GpsPoint* point = parseGPXGpsPoint(xml);
117                     //qDebug()<<"adding point: " << point->toString();
118                     myTrack->addPoint(point);
119                 }else{
120                     continue;
121                 }
122             }else if(fileType==XMLFile_TCX){
123                 if(xml.name() == "Trackpoint") {
124                     GpsPoint* point = parseTCXGpsPoint(xml);
125                     //qDebug()<<"adding point: " << point->toString();
126                     myTrack->addPoint(point);
127
128                 }else{
129                     continue;
130                 }
131             }
132             if(xml.name()=="name"){
133                 myTrack->setName(parseStringElement(xml,"name"));
134                 nameFound=true;
135             }
136             if(xml.name()=="Activity" && !nameFound){
137
138                 myTrack->setName(parseAttribute(xml,"Activity","Sport"));
139                 nameFound=true;
140             }
141         }
142     }
143     /* Error handling. */
144     if(xml.hasError()) {
145         qDebug() << "Error: in readFromXML "
146                  << qPrintable(fileName) << ": "
147                  << qPrintable(file->errorString());
148     }
149     /* Removes any device() or data from the reader
150         * and resets its internal state to the initial state. */
151     qDebug()<<"clearing xml!";
152     xml.clear();
153     qDebug() << "going to return myTrack";
154     return myTrack;
155 }
156
157 qreal parseDoubleAttribute(QXmlStreamReader& xml, const char* stringElement, const char* stringAttribute){
158     QString sValue = parseAttribute(xml,stringElement,stringAttribute);
159     return sValue.toDouble();
160 }
161
162 QString parseAttribute(QXmlStreamReader& xml, const char* stringElement, const char* stringAttribute){
163
164     QString value = QString();
165     if(xml.tokenType() == QXmlStreamReader::StartElement && (xml.name() == stringElement)) {
166         // Let's get the attributes
167         QXmlStreamAttributes attributes = xml.attributes();
168         // Let's check that element has the attribute
169         if(attributes.hasAttribute(stringAttribute)) {
170             value.append(attributes.value(stringAttribute).toString());
171         }
172     }
173     return value;
174 }
175
176 QString parseStringElement(QXmlStreamReader& xml,const char* stringElement){
177
178     // It is suposed the XML is valid!
179     QString value = QString();
180     if(xml.tokenType() == QXmlStreamReader::StartElement && (xml.name() == stringElement)) {
181         /* We've found the element */
182
183         xml.readNext();
184         if(xml.tokenType() == QXmlStreamReader::Characters) {
185
186             value.append(xml.text().toString());
187         }
188     }
189     return value;
190 }
191
192 qreal parseDoubleElement(QXmlStreamReader& xml,const char* stringElement){
193     // It is suposed the XML is valid!
194     qreal value=0;
195     if(xml.tokenType() == QXmlStreamReader::StartElement && (xml.name() == stringElement)) {
196         /* We've found the element */
197
198         xml.readNext();
199         if(xml.tokenType() == QXmlStreamReader::Characters) {
200             /* Now we can add it to the point.*/
201             QString valueString = xml.text().toString();
202             value=valueString.toDouble();
203         }
204     }
205     return value;
206 }
207
208 QDateTime parseDateElement(QXmlStreamReader& xml,const char* stringElement){
209     // It is suposed the XML is valid!
210     QDateTime value;
211     if(xml.tokenType() == QXmlStreamReader::StartElement && (xml.name() == stringElement)) {
212         /* We've found the element */
213
214         xml.readNext();
215         if(xml.tokenType() == QXmlStreamReader::Characters) {
216             /* Now we can add it to the point.*/
217             QString valueString = xml.text().toString();
218             value = QDateTime::fromString(valueString,XML_DATE_FORMAT);
219         }
220     }
221     return value;
222 }
223
224
225 GpsPoint* parseGPXGpsPoint(QXmlStreamReader& xml){
226     GpsPoint* point = new GpsPoint(0,0,0);
227     /* Let's check that we're really getting a Trackpoint. */
228     if(xml.tokenType() != QXmlStreamReader::StartElement &&
229             xml.name() == "trkpt") {
230         return point;
231     }
232     // Let's take latitude and longitude attributes.
233
234     point->setLatitude(parseDoubleAttribute(xml,"trkpt","lat"));
235     point->setLongitude(parseDoubleAttribute(xml,"trkpt","lon"));
236
237     xml.readNext();
238
239     while(!(xml.tokenType() == QXmlStreamReader::EndElement &&
240             xml.name() == "trkpt")){
241
242         if(xml.tokenType() == QXmlStreamReader::StartElement) {
243
244             if(xml.name() == "ele"){
245                 //qDebug()<<"found ele element";
246                 point->setElevation(parseDoubleElement(xml,"ele"));
247             }
248             if(xml.name() == "time"){
249                 point->setTime(parseDateElement(xml,"time"));
250                 //qDebug()<<"found Trackpoint element";
251             }
252         }
253         xml.readNext();
254     }
255     return point;
256 }
257
258 GpsPoint* parseTCXGpsPoint(QXmlStreamReader& xml){
259
260     GpsPoint* point = new GpsPoint(0,0,0);
261     /* Let's check that we're really getting a Trackpoint. */
262     if(xml.tokenType() != QXmlStreamReader::StartElement &&
263             xml.name() == "Trackpoint") {
264         return point;
265     }
266     xml.readNext();
267
268
269     while(!(xml.tokenType() == QXmlStreamReader::EndElement &&
270             xml.name() == "Trackpoint")){
271
272         if(xml.tokenType() == QXmlStreamReader::StartElement) {
273
274             if(xml.name() == "Time"){
275                 //qDebug()<<"found Time element";
276                 point->setTime(parseDateElement(xml,"Time"));
277             }
278             if(xml.name() == "Position"){
279                 //qDebug()<<"found Position element";
280                 xml.readNext();
281                 while(!(xml.tokenType() == QXmlStreamReader::EndElement &&
282                         xml.name() == "Position")){
283                     if(xml.tokenType()==QXmlStreamReader::StartElement && xml.name() == "LongitudeDegrees"){
284                         //qDebug()<<"found LongitudeDegrees element";
285                         point->setLongitude(parseDoubleElement(xml,"LongitudeDegrees"));
286                     }if(xml.tokenType()==QXmlStreamReader::StartElement && xml.name() == "LatitudeDegrees"){
287                         //qDebug()<<"found LatitudeDegrees element";
288                         point->setLatitude(parseDoubleElement(xml,"LatitudeDegrees"));
289                     }
290                     xml.readNext();
291                     //qDebug()<<"element readed: " << xml.name();
292                 }
293             }
294             if(xml.tokenType()==QXmlStreamReader::StartElement && xml.name() == "AltitudeMeters"){
295                 point->setElevation(parseDoubleElement(xml,"AltitudeMeters"));
296                 //qDebug()<<"found Trackpoint element";
297             }
298             if(xml.tokenType()==QXmlStreamReader::StartElement && xml.name() == "DistanceMeters"){
299                 point->setDistancePrev(parseDoubleElement(xml,"DistanceMeters"));
300                 //qDebug()<<"found Trackpoint element";
301             }
302         }
303         xml.readNext();
304     }
305     return point;
306 }
307