8#include "PositionTracking.h" 
   10#include "FileManager.h" 
   11#include "GeoDataAccuracy.h" 
   12#include "GeoDataDocument.h" 
   13#include "GeoDataDocumentWriter.h" 
   14#include "GeoDataLineString.h" 
   15#include "GeoDataLineStyle.h" 
   16#include "GeoDataMultiTrack.h" 
   17#include "GeoDataParser.h" 
   18#include "GeoDataPlacemark.h" 
   19#include "GeoDataStyle.h" 
   20#include "GeoDataStyleMap.h" 
   21#include "GeoDataTrack.h" 
   22#include "GeoDataTreeModel.h" 
   23#include "KmlElementDictionary.h" 
   24#include "MarbleColors.h" 
   25#include "MarbleDebug.h" 
   26#include "MarbleDirs.h" 
   27#include "PositionProviderPlugin.h" 
   34class PositionTrackingPrivate
 
   37    PositionTrackingPrivate(GeoDataTreeModel *model, PositionTracking *parent)
 
   40        , m_currentPositionPlacemark(new GeoDataPlacemark)
 
   41        , m_currentTrackPlacemark(new GeoDataPlacemark)
 
   42        , m_trackSegments(new GeoDataMultiTrack)
 
   44        , m_currentTrack(nullptr)
 
   45        , m_positionProvider(nullptr)
 
   50    void updatePosition();
 
   54    static QString statusFile();
 
   56    PositionTracking *
const q;
 
   58    GeoDataTreeModel *
const m_treeModel;
 
   60    GeoDataPlacemark *
const m_currentPositionPlacemark;
 
   61    GeoDataPlacemark *m_currentTrackPlacemark;
 
   62    GeoDataMultiTrack *m_trackSegments;
 
   63    GeoDataDocument m_document;
 
   65    GeoDataCoordinates m_gpsPreviousPosition;
 
   66    GeoDataTrack *m_currentTrack;
 
   68    PositionProviderPlugin *m_positionProvider;
 
   73void PositionTrackingPrivate::updatePosition()
 
   75    Q_ASSERT(m_positionProvider != 
nullptr);
 
   77    const GeoDataAccuracy accuracy = m_positionProvider->accuracy();
 
   78    const GeoDataCoordinates position = m_positionProvider->position();
 
   79    const QDateTime timestamp = m_positionProvider->timestamp();
 
   81    if (m_positionProvider->status() == PositionProviderStatusAvailable) {
 
   82        if (accuracy.horizontal < 250) {
 
   83            if (m_currentTrack->size()) {
 
   84                m_length += m_currentTrack->coordinatesAt(m_currentTrack->size() - 1).sphericalDistanceTo(position);
 
   86            m_currentTrack->addPoint(timestamp, position);
 
   90        if (m_gpsPreviousPosition != position) {
 
   91            m_currentPositionPlacemark->setCoordinate(position);
 
   93            qreal speed = m_positionProvider->speed();
 
   94            Q_EMIT q->gpsLocation(position, speed);
 
   99void PositionTrackingPrivate::updateStatus()
 
  101    Q_ASSERT(m_positionProvider != 
nullptr);
 
  103    const PositionProviderStatus 
status = m_positionProvider->status();
 
  105    if (
status == PositionProviderStatusAvailable) {
 
  106        m_currentTrack = 
new GeoDataTrack;
 
  107        m_treeModel->removeFeature(m_currentTrackPlacemark);
 
  108        m_trackSegments->append(m_currentTrack);
 
  109        m_treeModel->addFeature(&m_document, m_currentTrackPlacemark);
 
  112    Q_EMIT q->statusChanged(
status);
 
  115QString PositionTrackingPrivate::statusFile()
 
  117    QString 
const subdir = QStringLiteral(
"tracking");
 
  118    QDir 
dir(MarbleDirs::localPath());
 
  119    if (!
dir.exists(subdir)) {
 
  120        if (!
dir.mkdir(subdir)) {
 
  121            mDebug() << 
"Unable to create dir " << 
dir.absoluteFilePath(subdir);
 
  122            return dir.absolutePath();
 
  126    if (!
dir.cd(subdir)) {
 
  127        mDebug() << 
"Cannot change into " << 
dir.absoluteFilePath(subdir);
 
  130    return dir.absoluteFilePath(QStringLiteral(
"track.kml"));
 
  135    , d(new PositionTrackingPrivate(model, this))
 
  137    d->m_document.setDocumentRole(TrackingDocument);
 
  138    d->m_document.setName(QStringLiteral(
"Position Tracking"));
 
  141    d->m_currentPositionPlacemark->setName(QStringLiteral(
"Current Position"));
 
  142    d->m_currentPositionPlacemark->setVisible(
false);
 
  143    d->m_document.append(d->m_currentPositionPlacemark);
 
  146    d->m_currentTrack = 
new GeoDataTrack;
 
  147    d->m_trackSegments->append(d->m_currentTrack);
 
  149    d->m_currentTrackPlacemark->setGeometry(d->m_trackSegments);
 
  150    d->m_currentTrackPlacemark->setName(QStringLiteral(
"Current Track"));
 
  152    GeoDataStyle::Ptr style(
new GeoDataStyle);
 
  153    GeoDataLineStyle lineStyle;
 
  154    QColor transparentRed = Oxygen::brickRed4;
 
  156    lineStyle.setColor(transparentRed);
 
  157    lineStyle.setWidth(4);
 
  158    style->setLineStyle(lineStyle);
 
  159    style->setId(QStringLiteral(
"track"));
 
  161    GeoDataStyleMap styleMap;
 
  162    styleMap.setId(QStringLiteral(
"map-track"));
 
  163    styleMap.insert(QStringLiteral(
"normal"), 
QLatin1Char(
'#') + style->id());
 
  164    d->m_document.addStyleMap(styleMap);
 
  165    d->m_document.addStyle(style);
 
  166    d->m_document.append(d->m_currentTrackPlacemark);
 
  168    d->m_currentTrackPlacemark->setStyleUrl(
QLatin1Char(
'#') + styleMap.id());
 
  170    d->m_treeModel->addDocument(&d->m_document);
 
  173PositionTracking::~PositionTracking()
 
  175    d->m_treeModel->removeDocument(&d->m_document);
 
  179void PositionTracking::setPositionProviderPlugin(PositionProviderPlugin *plugin)
 
  181    const PositionProviderStatus oldStatus = 
status();
 
  183    if (d->m_positionProvider) {
 
  184        delete d->m_positionProvider;
 
  187    d->m_positionProvider = plugin;
 
  189    if (d->m_positionProvider) {
 
  190        d->m_positionProvider->setParent(
this);
 
  191        mDebug() << 
"Initializing position provider:" << d->m_positionProvider->name();
 
  192        connect(d->m_positionProvider, SIGNAL(statusChanged(PositionProviderStatus)), 
this, SLOT(updateStatus()));
 
  193        connect(d->m_positionProvider, SIGNAL(positionChanged(
GeoDataCoordinates, GeoDataAccuracy)), 
this, SLOT(updatePosition()));
 
  195        d->m_positionProvider->initialize();
 
  198    Q_EMIT positionProviderPluginChanged(plugin);
 
  200    if (oldStatus != 
status()) {
 
  201        Q_EMIT statusChanged(
status());
 
  204    if (
status() == PositionProviderStatusAvailable) {
 
  205        Q_EMIT gpsLocation(d->m_positionProvider->position(), d->m_positionProvider->speed());
 
  209PositionProviderPlugin *PositionTracking::positionProviderPlugin()
 
  211    return d->m_positionProvider;
 
  214QString PositionTracking::error()
 const 
  216    return d->m_positionProvider ? d->m_positionProvider->error() : 
QString();
 
  220qreal PositionTracking::speed()
 const 
  222    return d->m_positionProvider ? d->m_positionProvider->speed() : 0;
 
  226qreal PositionTracking::direction()
 const 
  228    return d->m_positionProvider ? d->m_positionProvider->direction() : 0;
 
  231QDateTime PositionTracking::timestamp()
 const 
  233    return d->m_positionProvider ? d->m_positionProvider->timestamp() : 
QDateTime();
 
  236bool PositionTracking::trackVisible()
 const 
  238    return d->m_currentTrackPlacemark->isVisible();
 
  241void PositionTracking::setTrackVisible(
bool visible)
 
  243    d->m_currentTrackPlacemark->setVisible(visible);
 
  244    d->m_treeModel->updateFeature(d->m_currentTrackPlacemark);
 
  247bool PositionTracking::saveTrack(
const QString &fileName)
 
  253    auto document = 
new GeoDataDocument;
 
  256    document->setName(name);
 
  257    const auto styles = d->m_document.styles();
 
  258    for (
const GeoDataStyle::Ptr &style : styles) {
 
  259        document->addStyle(style);
 
  261    const auto styleMaps = d->m_document.styleMaps();
 
  262    for (
const GeoDataStyleMap &map : styleMaps) {
 
  263        document->addStyleMap(map);
 
  265    auto track = 
new GeoDataPlacemark(*d->m_currentTrackPlacemark);
 
  267    document->append(track);
 
  269    bool const result = GeoDataDocumentWriter::write(fileName, *document);
 
  274void PositionTracking::clearTrack()
 
  276    d->m_treeModel->removeFeature(d->m_currentTrackPlacemark);
 
  277    d->m_currentTrack = 
new GeoDataTrack;
 
  278    d->m_trackSegments->clear();
 
  279    d->m_trackSegments->append(d->m_currentTrack);
 
  280    d->m_treeModel->addFeature(&d->m_document, d->m_currentTrackPlacemark);
 
  284void PositionTracking::readSettings()
 
  286    QFile file(d->statusFile());
 
  288        mDebug() << 
"Can not read track from " << file.fileName();
 
  292    GeoDataParser parser(GeoData_KML);
 
  293    if (!parser.read(&file)) {
 
  294        mDebug() << 
"Could not parse tracking file: " << parser.errorString();
 
  298    auto doc = 
dynamic_cast<GeoDataDocument *
>(parser.releaseDocument());
 
  302        mDebug() << 
"tracking document not available";
 
  306    auto track = 
dynamic_cast<GeoDataPlacemark *
>(doc->child(0));
 
  308        mDebug() << 
"tracking document doesn't have a placemark";
 
  313    d->m_trackSegments = 
dynamic_cast<GeoDataMultiTrack *
>(track->geometry());
 
  314    if (!d->m_trackSegments) {
 
  315        mDebug() << 
"tracking document doesn't have a multitrack";
 
  319    if (d->m_trackSegments->size() < 1) {
 
  320        mDebug() << 
"tracking document doesn't have a track";
 
  325    d->m_currentTrack = 
dynamic_cast<GeoDataTrack *
>(d->m_trackSegments->child(d->m_trackSegments->size() - 1));
 
  326    if (!d->m_currentTrack) {
 
  327        mDebug() << 
"tracking document doesn't have a last track";
 
  335    d->m_treeModel->removeDocument(&d->m_document);
 
  336    d->m_document.remove(1);
 
  337    delete d->m_currentTrackPlacemark;
 
  338    d->m_currentTrackPlacemark = track;
 
  339    d->m_currentTrackPlacemark->setName(QStringLiteral(
"Current Track"));
 
  340    d->m_document.append(d->m_currentTrackPlacemark);
 
  341    d->m_currentTrackPlacemark->setStyleUrl(d->m_currentTrackPlacemark->styleUrl());
 
  343    d->m_treeModel->addDocument(&d->m_document);
 
  345    for (
int i = 0; i < d->m_trackSegments->size(); ++i) {
 
  346        d->m_length += d->m_trackSegments->at(i).lineString()->length(1);
 
  350void PositionTracking::writeSettings()
 
  352    saveTrack(d->statusFile());
 
  355bool PositionTracking::isTrackEmpty()
 const 
  357    if (d->m_trackSegments->size() < 1) {
 
  361    if (d->m_trackSegments->size() == 1) {
 
  362        return (d->m_currentTrack->size() == 0);
 
  368qreal PositionTracking::length(qreal planetRadius)
 const 
  370    return d->m_length * planetRadius;
 
  373GeoDataAccuracy PositionTracking::accuracy()
 const 
  375    return d->m_positionProvider ? d->m_positionProvider->accuracy() : GeoDataAccuracy();
 
  380    return d->m_positionProvider ? d->m_positionProvider->position() : 
GeoDataCoordinates();
 
  383PositionProviderStatus PositionTracking::status()
 const 
  385    return d->m_positionProvider ? d->m_positionProvider->status() : PositionProviderStatusUnavailable;
 
  390#include "moc_PositionTracking.cpp" 
A 3d point representation.
 
The representation of GeoData in a model This class represents all available data given by kml-data f...
 
Q_SCRIPTABLE CaptureState status()
 
KIOCORE_EXPORT QString dir(const QString &fileClass)
 
QString name(StandardAction id)
 
Binds a QML item to a specific geodetic location in screen coordinates.
 
bool isEmpty() const const
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)