diff options
Diffstat (limited to 'kipi-plugins/gpssync/gpsdataparser.cpp')
-rw-r--r-- | kipi-plugins/gpssync/gpsdataparser.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/kipi-plugins/gpssync/gpsdataparser.cpp b/kipi-plugins/gpssync/gpsdataparser.cpp new file mode 100644 index 0000000..2124f1d --- /dev/null +++ b/kipi-plugins/gpssync/gpsdataparser.cpp @@ -0,0 +1,275 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2006-09-19 + * Description : GPS data file parser. + * (GPX format http://www.topografix.com/gpx.asp). + * + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// Qt includes. + +#include <qstring.h> +#include <qstringlist.h> +#include <qfile.h> +#include <qdom.h> +#include <qtextstream.h> + +// KDE includes. + +#include <kdebug.h> + +// Local includes. + +#include "gpsdataparser.h" + +namespace KIPIGPSSyncPlugin +{ + +GPSDataParser::GPSDataParser() +{ + clear(); +} + +void GPSDataParser::clear() +{ + m_GPSDataMap.clear(); +} + +int GPSDataParser::numPoints() +{ + return m_GPSDataMap.count(); +} + +bool GPSDataParser::matchDate(const QDateTime& photoDateTime, int maxGapTime, int timeZone, + bool interpolate, int interpolationDstTime, + GPSDataContainer& gpsData) +{ + // GPS device are sync in time by satelite using GMT time. + // If the camera time is different than GMT time, we need to convert it to GMT time + // Using the time zone. + QDateTime cameraGMTDateTime = photoDateTime.addSecs(timeZone*(-1)); + + kdDebug() << "cameraGMTDateTime: " << cameraGMTDateTime << endl; + + // We trying to find the right date in the GPS points list. + bool findItem = false; + int nbSecItem = maxGapTime; + int nbSecs; + + for (GPSDataMap::Iterator it = m_GPSDataMap.begin(); + it != m_GPSDataMap.end(); ++it ) + { + // Here we check a possible accuracy in seconds between the + // Camera GMT time and the GPS device GMT time. + + nbSecs = abs(cameraGMTDateTime.secsTo( it.key() )); + + // We tring to find the minimal accuracy. + if( nbSecs < maxGapTime && nbSecs < nbSecItem) + { + gpsData = m_GPSDataMap[it.key()]; + findItem = true; + nbSecItem = nbSecs; + } + } + + if (findItem) return true; + + // If we can't find it, we will trying to interpolate the GPS point. + + if (interpolate) + { + // The interpolate GPS point will be separate by at the maximum of 'interpolationDstTime' + // seconds before and after the next and previous real GPS point found. + + QDateTime prevDateTime = findPrevDate(cameraGMTDateTime, interpolationDstTime); + QDateTime nextDateTime = findNextDate(cameraGMTDateTime, interpolationDstTime); + + if (!nextDateTime.isNull() && !prevDateTime.isNull()) + { + GPSDataContainer prevGPSPoint = m_GPSDataMap[prevDateTime]; + GPSDataContainer nextGPSPoint = m_GPSDataMap[nextDateTime]; + + double alt1 = prevGPSPoint.altitude(); + double lon1 = prevGPSPoint.longitude(); + double lat1 = prevGPSPoint.latitude(); + uint t1 = prevDateTime.toTime_t(); + double alt2 = nextGPSPoint.altitude(); + double lon2 = nextGPSPoint.longitude(); + double lat2 = nextGPSPoint.latitude(); + uint t2 = nextDateTime.toTime_t(); + uint tCor = cameraGMTDateTime.toTime_t(); + + if (tCor-t1 != 0) + { + gpsData.setAltitude(alt1 + (alt2-alt1) * (tCor-t1)/(t2-t1)); + gpsData.setLatitude(lat1 + (lat2-lat1) * (tCor-t1)/(t2-t1)); + gpsData.setLongitude(lon1 + (lon2-lon1) * (tCor-t1)/(t2-t1)); + gpsData.setInterpolated(true); + return true; + } + } + } + + return false; +} + +QDateTime GPSDataParser::findNextDate(const QDateTime& dateTime, int secs) +{ + // We will find the item in GPS data list where the time is + // at the maximum bigger than 'secs' mn of the value to match. + QDateTime itemFound = dateTime.addSecs(secs); + bool found = false; + + for (GPSDataMap::Iterator it = m_GPSDataMap.begin(); + it != m_GPSDataMap.end(); ++it ) + { + if (it.key() > dateTime) + { + if (it.key() < itemFound) + { + itemFound = it.key(); + found = true; + } + } + } + + if (found) + return itemFound; + + return QDateTime(); +} + +QDateTime GPSDataParser::findPrevDate(const QDateTime& dateTime, int secs) +{ + // We will find the item in GPS data list where the time is + // at the maximum smaller than 'secs' mn of the value to match. + QDateTime itemFound = dateTime.addSecs((-1)*secs); + bool found = false; + + for (GPSDataMap::Iterator it = m_GPSDataMap.begin(); + it != m_GPSDataMap.end(); ++it ) + { + if (it.key() < dateTime) + { + if (it.key() > itemFound) + { + itemFound = it.key(); + found = true; + } + } + } + + if (found) + return itemFound; + + return QDateTime(); +} + +bool GPSDataParser::loadGPXFile(const KURL& url) +{ + QFile gpxfile(url.path()); + + if (!gpxfile.open(IO_ReadOnly)) + return false; + + QDomDocument gpxDoc("gpx"); + if (!gpxDoc.setContent(&gpxfile)) + return false; + + QDomElement gpxDocElem = gpxDoc.documentElement(); + if (gpxDocElem.tagName()!="gpx") + return false; + + for (QDomNode nTrk = gpxDocElem.firstChild(); + !nTrk.isNull(); nTrk = nTrk.nextSibling()) + { + QDomElement trkElem = nTrk.toElement(); + if (trkElem.isNull()) continue; + if (trkElem.tagName() != "trk") continue; + + for (QDomNode nTrkseg = trkElem.firstChild(); + !nTrkseg.isNull(); nTrkseg = nTrkseg.nextSibling()) + { + QDomElement trksegElem = nTrkseg.toElement(); + if (trksegElem.isNull()) continue; + if (trksegElem.tagName() != "trkseg") continue; + + for (QDomNode nTrkpt = trksegElem.firstChild(); + !nTrkpt.isNull(); nTrkpt = nTrkpt.nextSibling()) + { + QDomElement trkptElem = nTrkpt.toElement(); + if (trkptElem.isNull()) continue; + if (trkptElem.tagName() != "trkpt") continue; + + QDateTime ptDateTime; + double ptAltitude = 0.0; + double ptLatitude = 0.0; + double ptLongitude = 0.0; + + // Get GPS position. If not available continue to next point. + QString lat = trkptElem.attribute("lat"); + QString lon = trkptElem.attribute("lon"); + if (lat.isEmpty() || lon.isEmpty()) continue; + + ptLatitude = lat.toDouble(); + ptLongitude = lon.toDouble(); + + // Get metadata of track point (altitude and time stamp) + for (QDomNode nTrkptMeta = trkptElem.firstChild(); + !nTrkptMeta.isNull(); nTrkptMeta = nTrkptMeta.nextSibling()) + { + QDomElement trkptMetaElem = nTrkptMeta.toElement(); + if (trkptMetaElem.isNull()) continue; + if (trkptMetaElem.tagName() == QString("time")) + { + // Get GPS point time stamp. If not available continue to next point. + QString time = trkptMetaElem.text(); + if (time.isEmpty()) continue; + ptDateTime = QDateTime::fromString(time, Qt::ISODate); + } + if (trkptMetaElem.tagName() == QString("ele")) + { + // Get GPS point altitude. If not available continue to next point. + QString ele = trkptMetaElem.text(); + if (!ele.isEmpty()) + ptAltitude = ele.toDouble(); + } + } + + if (ptDateTime.isNull()) + continue; + + GPSDataContainer gpsData(ptAltitude, ptLatitude, ptLongitude, false); + m_GPSDataMap.insert( ptDateTime, gpsData ); + } + } + } + + kdDebug( 51001 ) << "GPX File " << url.fileName() + << " parsed with " << numPoints() + << " points extracted" << endl; + return true; +} + +} // NameSpace KIPIGPSSyncPlugin |