You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
8.6 KiB
276 lines
8.6 KiB
15 years ago
|
/* ============================================================
|
||
|
*
|
||
|
* 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
|