/* ============================================================ * * 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 * * 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 #include // TQt includes. #include #include #include #include #include // KDE includes. #include // 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 TQDateTime& 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. TQDateTime 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. TQDateTime prevDateTime = findPrevDate(cameraGMTDateTime, interpolationDstTime); TQDateTime 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; } TQDateTime GPSDataParser::findNextDate(const TQDateTime& 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. TQDateTime 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 TQDateTime(); } TQDateTime GPSDataParser::findPrevDate(const TQDateTime& 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. TQDateTime 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 TQDateTime(); } bool GPSDataParser::loadGPXFile(const KURL& url) { TQFile gpxfile(url.path()); if (!gpxfile.open(IO_ReadOnly)) return false; TQDomDocument gpxDoc("gpx"); if (!gpxDoc.setContent(&gpxfile)) return false; TQDomElement gpxDocElem = gpxDoc.documentElement(); if (gpxDocElem.tagName()!="gpx") return false; for (TQDomNode nTrk = gpxDocElem.firstChild(); !nTrk.isNull(); nTrk = nTrk.nextSibling()) { TQDomElement trkElem = nTrk.toElement(); if (trkElem.isNull()) continue; if (trkElem.tagName() != "trk") continue; for (TQDomNode nTrkseg = trkElem.firstChild(); !nTrkseg.isNull(); nTrkseg = nTrkseg.nextSibling()) { TQDomElement trksegElem = nTrkseg.toElement(); if (trksegElem.isNull()) continue; if (trksegElem.tagName() != "trkseg") continue; for (TQDomNode nTrkpt = trksegElem.firstChild(); !nTrkpt.isNull(); nTrkpt = nTrkpt.nextSibling()) { TQDomElement trkptElem = nTrkpt.toElement(); if (trkptElem.isNull()) continue; if (trkptElem.tagName() != "trkpt") continue; TQDateTime ptDateTime; double ptAltitude = 0.0; double ptLatitude = 0.0; double ptLongitude = 0.0; // Get GPS position. If not available continue to next point. TQString lat = trkptElem.attribute("lat"); TQString 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 (TQDomNode nTrkptMeta = trkptElem.firstChild(); !nTrkptMeta.isNull(); nTrkptMeta = nTrkptMeta.nextSibling()) { TQDomElement trkptMetaElem = nTrkptMeta.toElement(); if (trkptMetaElem.isNull()) continue; if (trkptMetaElem.tagName() == TQString("time")) { // Get GPS point time stamp. If not available continue to next point. TQString time = trkptMetaElem.text(); if (time.isEmpty()) continue; ptDateTime = TQDateTime::fromString(time, TQt::ISODate); } if (trkptMetaElem.tagName() == TQString("ele")) { // Get GPS point altitude. If not available continue to next point. TQString 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