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();
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()) {
86 m_currentTrack->
addPoint(timestamp, position);
90 if (m_gpsPreviousPosition != 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"));
133PositionTracking::PositionTracking(GeoDataTreeModel *model)
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();
378GeoDataCoordinates PositionTracking::currentLocation()
const
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"
qreal sphericalDistanceTo(const GeoDataCoordinates &other) const
This method calculates the shortest distance between two points on a sphere.
void setCoordinate(qreal longitude, qreal latitude, qreal altitude=0, GeoDataCoordinates::Unit _unit=GeoDataCoordinates::Radian)
Set the coordinate of the placemark in longitude and latitude.
int size() const
Returns the number of points in the track.
void addPoint(const QDateTime &when, const GeoDataCoordinates &coord)
Add a new point with coordinates coord associated with the time value when.
GeoDataCoordinates coordinatesAt(const QDateTime &when) const
If interpolate() is true, return the coordinates interpolated from the time values before and after w...
virtual qreal speed() const =0
Returns the speed of the gps device in meters per second.
Q_SCRIPTABLE CaptureState status()
QString name(GameStandardAction id)
KIOCORE_EXPORT QString dir(const QString &fileClass)
Binds a QML item to a specific geodetic location in screen coordinates.
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)