Log File Position Source (C++)

The Logfile Position Source shows how to create and work with a custom NMEA position source, for platforms without GPS.

The data is read from a file which has positional data in NMEA format. The resulting time and position information is then displayed to the screen as simple text in date/time and latitude/longitude format.

This example class reads position data from a text file, log.txt. The file specifies position data using a simple text format: it contains one position update per line, where each line contains a date/time, a latitude and a longitude, separated by spaces. The date/time is in ISO 8601 format and the latitude and longitude are in degrees decimal format. Here is an excerpt from log.txt:

 2009-08-24T22:25:01 -27.576082 153.092415
 2009-08-24T22:25:02 -27.576223 153.092530
 2009-08-24T22:25:03 -27.576364 153.092648

The class reads this data and distributes it via the positionUpdated() signal.

Here is the definition of the LogFilePositionSource class:

 class LogFilePositionSource : public QGeoPositionInfoSource
 {
     Q_OBJECT
 public:
     LogFilePositionSource(QObject *parent = 0);

     QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const;

     PositioningMethods supportedPositioningMethods() const;
     int minimumUpdateInterval() const;
     Error error() const;

 public slots:
     virtual void startUpdates();
     virtual void stopUpdates();

     virtual void requestUpdate(int timeout = 5000);

 private slots:
     void readNextPosition();

 private:
     QFile *logFile;
     QTimer *timer;
     QGeoPositionInfo lastPosition;
 };

The main methods overrided by the subclass are:

  • startUpdates(): called by client applications to start regular position updates.
  • stopUpdates(): called by client applications to stop regular position updates.
  • requestUpdate(): called by client applications to request a single update, with a specified timeout.

When a position update is available, the subclass emits the positionUpdated() signal.

Here are the key methods in the class implementation:

 LogFilePositionSource::LogFilePositionSource(QObject *parent)
     : QGeoPositionInfoSource(parent),
       logFile(new QFile(this)),
       timer(new QTimer(this))
 {
     connect(timer, SIGNAL(timeout()), this, SLOT(readNextPosition()));

     logFile->setFileName(":/simplelog.txt");
     if (!logFile->open(QIODevice::ReadOnly))
         qWarning() << "Error: cannot open source file" << logFile->fileName();
 }

 void LogFilePositionSource::startUpdates()
 {
     int interval = updateInterval();
     if (interval < minimumUpdateInterval())
         interval = minimumUpdateInterval();

     timer->start(interval);
 }

 void LogFilePositionSource::stopUpdates()
 {
     timer->stop();
 }

 void LogFilePositionSource::requestUpdate(int /*timeout*/)
 {
     // For simplicity, ignore timeout - assume that if data is not available
     // now, no data will be added to the file later
     if (logFile->canReadLine())
         readNextPosition();
     else
         emit updateTimeout();
 }

 void LogFilePositionSource::readNextPosition()
 {
     QByteArray line = logFile->readLine().trimmed();
     if (!line.isEmpty()) {
         QList<QByteArray> data = line.split(' ');
         double latitude;
         double longitude;
         bool hasLatitude = false;
         bool hasLongitude = false;
         QDateTime timestamp = QDateTime::fromString(QString(data.value(0)), Qt::ISODate);
         latitude = data.value(1).toDouble(&hasLatitude);
         longitude = data.value(2).toDouble(&hasLongitude);

         if (hasLatitude && hasLongitude && timestamp.isValid()) {
             QGeoCoordinate coordinate(latitude, longitude);
             QGeoPositionInfo info(coordinate, timestamp);
             if (info.isValid()) {
                 lastPosition = info;
                 emit positionUpdated(info);
             }
         }
     }
 }

Example project @ code.qt.io