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);
              }
          }
      }
  }

Files: