8 #include "PositionTracking.h"
10 #include "GeoDataDocument.h"
11 #include "GeoDataMultiTrack.h"
12 #include "GeoDataPlacemark.h"
13 #include "GeoDataParser.h"
14 #include "GeoDataStyle.h"
15 #include "GeoDataLineStyle.h"
16 #include "GeoDataStyleMap.h"
17 #include "GeoDataTrack.h"
18 #include "GeoDataTreeModel.h"
19 #include "GeoDataLineString.h"
20 #include "GeoDataAccuracy.h"
21 #include "GeoDataDocumentWriter.h"
22 #include "KmlElementDictionary.h"
23 #include "FileManager.h"
24 #include "MarbleColors.h"
25 #include "MarbleDebug.h"
26 #include "MarbleDirs.h"
27 #include "PositionProviderPlugin.h"
34 class 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;
73 void 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 emit q->gpsLocation( position, speed );
100 void PositionTrackingPrivate::updateStatus()
102 Q_ASSERT( m_positionProvider !=
nullptr );
104 const PositionProviderStatus
status = m_positionProvider->status();
106 if (
status == PositionProviderStatusAvailable) {
107 m_currentTrack =
new GeoDataTrack;
108 m_treeModel->removeFeature( m_currentTrackPlacemark );
109 m_trackSegments->append( m_currentTrack );
110 m_treeModel->addFeature( &m_document, m_currentTrackPlacemark );
113 emit q->statusChanged(
status );
116 QString PositionTrackingPrivate::statusFile()
118 QString const subdir =
"tracking";
119 QDir dir( MarbleDirs::localPath() );
120 if ( !
dir.exists( subdir ) ) {
121 if ( !
dir.mkdir( subdir ) ) {
122 mDebug() <<
"Unable to create dir " <<
dir.absoluteFilePath( subdir );
123 return dir.absolutePath();
127 if ( !
dir.cd( subdir ) ) {
128 mDebug() <<
"Cannot change into " <<
dir.absoluteFilePath( subdir );
131 return dir.absoluteFilePath(
"track.kml" );
134 PositionTracking::PositionTracking( GeoDataTreeModel *model )
136 d( new PositionTrackingPrivate( model, this ) )
138 d->m_document.setDocumentRole( TrackingDocument );
139 d->m_document.setName(QStringLiteral(
"Position Tracking"));
142 d->m_currentPositionPlacemark->setName(QStringLiteral(
"Current Position"));
143 d->m_currentPositionPlacemark->setVisible(
false);
144 d->m_document.append( d->m_currentPositionPlacemark );
147 d->m_currentTrack =
new GeoDataTrack;
148 d->m_trackSegments->append(d->m_currentTrack);
150 d->m_currentTrackPlacemark->setGeometry(d->m_trackSegments);
151 d->m_currentTrackPlacemark->setName(QStringLiteral(
"Current Track"));
153 GeoDataStyle::Ptr style(
new GeoDataStyle);
154 GeoDataLineStyle lineStyle;
155 QColor transparentRed = Oxygen::brickRed4;
157 lineStyle.setColor( transparentRed );
158 lineStyle.setWidth( 4 );
159 style->setLineStyle(lineStyle);
160 style->setId(QStringLiteral(
"track"));
162 GeoDataStyleMap styleMap;
163 styleMap.setId(QStringLiteral(
"map-track"));
164 styleMap.insert(QStringLiteral(
"normal"),
QLatin1Char(
'#') + style->id());
165 d->m_document.addStyleMap(styleMap);
166 d->m_document.addStyle(style);
167 d->m_document.append( d->m_currentTrackPlacemark );
169 d->m_currentTrackPlacemark->setStyleUrl(
QLatin1Char(
'#') + styleMap.id());
171 d->m_treeModel->addDocument( &d->m_document );
175 PositionTracking::~PositionTracking()
177 d->m_treeModel->removeDocument( &d->m_document );
181 void PositionTracking::setPositionProviderPlugin( PositionProviderPlugin* plugin )
183 const PositionProviderStatus oldStatus =
status();
185 if ( d->m_positionProvider ) {
186 delete d->m_positionProvider;
189 d->m_positionProvider = plugin;
191 if ( d->m_positionProvider ) {
192 d->m_positionProvider->setParent(
this );
193 mDebug() <<
"Initializing position provider:" << d->m_positionProvider->name();
194 connect( d->m_positionProvider, SIGNAL(statusChanged(PositionProviderStatus)),
195 this, SLOT(updateStatus()) );
196 connect( d->m_positionProvider, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)),
197 this, SLOT(updatePosition()) );
199 d->m_positionProvider->initialize();
202 emit positionProviderPluginChanged( plugin );
204 if ( oldStatus !=
status() ) {
205 emit statusChanged(
status() );
208 if (
status() == PositionProviderStatusAvailable ) {
209 emit gpsLocation( d->m_positionProvider->position(), d->m_positionProvider->speed() );
213 PositionProviderPlugin* PositionTracking::positionProviderPlugin()
215 return d->m_positionProvider;
218 QString PositionTracking::error()
const
220 return d->m_positionProvider ? d->m_positionProvider->error() :
QString();
225 qreal PositionTracking::speed()
const
227 return d->m_positionProvider ? d->m_positionProvider->speed() : 0 ;
231 qreal PositionTracking::direction()
const
233 return d->m_positionProvider ? d->m_positionProvider->direction() : 0 ;
236 QDateTime PositionTracking::timestamp()
const
238 return d->m_positionProvider ? d->m_positionProvider->timestamp() :
QDateTime();
241 bool PositionTracking::trackVisible()
const
243 return d->m_currentTrackPlacemark->isVisible();
246 void PositionTracking::setTrackVisible(
bool visible )
248 d->m_currentTrackPlacemark->setVisible( visible );
249 d->m_treeModel->updateFeature( d->m_currentTrackPlacemark );
252 bool PositionTracking::saveTrack(
const QString& fileName )
259 GeoDataDocument *document =
new GeoDataDocument;
262 document->setName( name );
263 for(
const GeoDataStyle::Ptr &style: d->m_document.styles() ) {
264 document->addStyle( style );
266 for(
const GeoDataStyleMap &map: d->m_document.styleMaps() ) {
267 document->addStyleMap( map );
269 GeoDataPlacemark *track =
new GeoDataPlacemark( *d->m_currentTrackPlacemark );
271 document->append( track );
278 void PositionTracking::clearTrack()
280 d->m_treeModel->removeFeature( d->m_currentTrackPlacemark );
281 d->m_currentTrack =
new GeoDataTrack;
282 d->m_trackSegments->clear();
283 d->m_trackSegments->append( d->m_currentTrack );
284 d->m_treeModel->addFeature( &d->m_document, d->m_currentTrackPlacemark );
288 void PositionTracking::readSettings()
290 QFile file( d->statusFile() );
292 mDebug() <<
"Can not read track from " << file.fileName();
296 GeoDataParser parser( GeoData_KML );
297 if ( !parser.read( &file ) ) {
298 mDebug() <<
"Could not parse tracking file: " << parser.errorString();
302 GeoDataDocument *doc =
dynamic_cast<GeoDataDocument*
>( parser.releaseDocument() );
306 mDebug() <<
"tracking document not available";
310 GeoDataPlacemark *track =
dynamic_cast<GeoDataPlacemark*
>( doc->child( 0 ) );
312 mDebug() <<
"tracking document doesn't have a placemark";
317 d->m_trackSegments =
dynamic_cast<GeoDataMultiTrack*
>( track->geometry() );
318 if( !d->m_trackSegments ) {
319 mDebug() <<
"tracking document doesn't have a multitrack";
323 if( d->m_trackSegments->size() < 1 ) {
324 mDebug() <<
"tracking document doesn't have a track";
329 d->m_currentTrack =
dynamic_cast<GeoDataTrack*
>( d->m_trackSegments->child( d->m_trackSegments->size() - 1 ) );
330 if( !d->m_currentTrack ) {
331 mDebug() <<
"tracking document doesn't have a last track";
339 d->m_treeModel->removeDocument( &d->m_document );
340 d->m_document.remove( 1 );
341 delete d->m_currentTrackPlacemark;
342 d->m_currentTrackPlacemark = track;
343 d->m_currentTrackPlacemark->setName(QStringLiteral(
"Current Track"));
344 d->m_document.append( d->m_currentTrackPlacemark );
345 d->m_currentTrackPlacemark->setStyleUrl( d->m_currentTrackPlacemark->styleUrl() );
347 d->m_treeModel->addDocument( &d->m_document );
349 for (
int i = 0; i < d->m_trackSegments->size(); ++i ) {
350 d->m_length += d->m_trackSegments->at( i ).lineString()->length( 1 );
354 void PositionTracking::writeSettings()
356 saveTrack( d->statusFile() );
359 bool PositionTracking::isTrackEmpty()
const
361 if ( d->m_trackSegments->size() < 1 ) {
365 if ( d->m_trackSegments->size() == 1 ) {
366 return ( d->m_currentTrack->size() == 0 );
372 qreal PositionTracking::length( qreal planetRadius )
const
374 return d->m_length * planetRadius;
377 GeoDataAccuracy PositionTracking::accuracy()
const
379 return d->m_positionProvider ? d->m_positionProvider->accuracy() : GeoDataAccuracy();
382 GeoDataCoordinates PositionTracking::currentLocation()
const
384 return d->m_positionProvider ? d->m_positionProvider->position() : GeoDataCoordinates();
389 return d->m_positionProvider ? d->m_positionProvider->status() : PositionProviderStatusUnavailable;
394 #include "moc_PositionTracking.cpp"