Skip to content

Commit

Permalink
Hook up feature creation in QgsVectorLayerGpsLogger
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 14, 2022
1 parent d5c05e3 commit 154ab20
Show file tree
Hide file tree
Showing 8 changed files with 415 additions and 14 deletions.
19 changes: 19 additions & 0 deletions python/core/auto_generated/gps/qgsgpslogger.sip.in
Expand Up @@ -71,6 +71,12 @@ Returns the coordinate transform context to be used when transforming
GPS coordinates.

.. seealso:: :py:func:`setTransformContext`
%End

const QgsDistanceArea &distanceArea() const;
%Docstring
Returns the distance area calculator which should be used for
calculating distances associated with the GPS log.
%End

QVector<QgsPoint> currentTrack() const;
Expand All @@ -91,6 +97,14 @@ The returned point will always be in WGS84 coordinate reference system.
%Docstring
Returns the last recorded timestamp from the device.

The returned time value will respect all user settings regarding GPS time zone
handling.
%End

QDateTime trackStartTime() const;
%Docstring
Returns the timestamp at which the current track was started.

The returned time value will respect all user settings regarding GPS time zone
handling.
%End
Expand Down Expand Up @@ -143,6 +157,11 @@ Emitted whenever the current track is reset.
Emitted whenever a new vertex is added to the track.

The ``vertex`` point will be in WGS84 coordinate reference system.
%End

void stateChanged( const QgsGpsInformation &info );
%Docstring
Emitted whenever the associated GPS device state is changed.
%End

protected:
Expand Down
8 changes: 8 additions & 0 deletions python/core/auto_generated/gps/qgsvectorlayergpslogger.sip.in
Expand Up @@ -9,6 +9,7 @@




class QgsVectorLayerGpsLogger : QgsGpsLogger
{
%Docstring(signature="appended")
Expand Down Expand Up @@ -182,6 +183,13 @@ If specified, the total track length recorded tracks will be stored in this fiel
virtual void setTransformContext( const QgsCoordinateTransformContext &context );


public slots:

void endCurrentTrack();
%Docstring
Ends the current track, storing it in the :py:func:`~QgsVectorLayerGpsLogger.tracksLayer` if appropriate.
%End

};


Expand Down
31 changes: 24 additions & 7 deletions src/core/gps/qgsgpslogger.cpp
Expand Up @@ -17,7 +17,6 @@
#include "qgsgpsconnection.h"
#include "gmath.h"
#include "info.h"
#include "nmeatime.h"

#include <QTimer>
#include <QTimeZone>
Expand Down Expand Up @@ -80,6 +79,11 @@ QgsCoordinateTransformContext QgsGpsLogger::transformContext() const
return mTransformContext;
}

const QgsDistanceArea &QgsGpsLogger::distanceArea() const
{
return mDistanceCalculator;
}

QVector<QgsPoint> QgsGpsLogger::currentTrack() const
{
return mCaptureListWgs84;
Expand All @@ -102,6 +106,7 @@ void QgsGpsLogger::resetTrack()
const bool trackWasEmpty = mCaptureListWgs84.isEmpty();
mCaptureListWgs84.clear();
mBlockGpsStateChanged--;
mTrackStartTime = QDateTime();

if ( !trackWasEmpty )
emit trackIsEmptyChanged( true );
Expand Down Expand Up @@ -182,13 +187,15 @@ void QgsGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
double newAlt = 0.0;
if ( validFlag )
{
std::unique_ptr< nmeaTIME > newNmeaTime = std::make_unique< nmeaTIME >();
newLocationWgs84 = QgsPointXY( info.longitude, info.latitude );
newNmeaPosition.lat = nmea_degree2radian( info.latitude );
newNmeaPosition.lon = nmea_degree2radian( info.longitude );
newAlt = info.elevation;
nmea_time_now( newNmeaTime.get() );
mLastNmeaTime = std::move( newNmeaTime );

if ( info.utcDateTime.isValid() )
{
mLastTime = info.utcDateTime;
}
}
else
{
Expand Down Expand Up @@ -221,6 +228,8 @@ void QgsGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
addTrackVertex();
}
}

emit stateChanged( info );
}

void QgsGpsLogger::addTrackVertex()
Expand All @@ -233,7 +242,10 @@ void QgsGpsLogger::addTrackVertex()
emit trackVertexAdded( pointWgs84 );

if ( trackWasEmpty )
{
mTrackStartTime = lastTimestamp();
emit trackIsEmptyChanged( false );
}
}

bool QgsGpsLogger::automaticallyAddTrackVertices() const
Expand All @@ -248,11 +260,11 @@ void QgsGpsLogger::setAutomaticallyAddTrackVertices( bool enabled )

QDateTime QgsGpsLogger::lastTimestamp() const
{
if ( !mLastNmeaTime )
if ( !mLastTime.isValid() )
return QDateTime();

QDateTime time( QDate( 1900 + mLastNmeaTime->year, mLastNmeaTime->mon + 1, mLastNmeaTime->day ),
QTime( mLastNmeaTime->hour, mLastNmeaTime->min, mLastNmeaTime->sec, mLastNmeaTime->msec ) );
QDateTime time = mLastTime;

// Time from GPS is UTC time
time.setTimeSpec( Qt::UTC );
// Apply leap seconds correction
Expand Down Expand Up @@ -288,3 +300,8 @@ QDateTime QgsGpsLogger::lastTimestamp() const

return time;
}

QDateTime QgsGpsLogger::trackStartTime() const
{
return mTrackStartTime;
}
24 changes: 23 additions & 1 deletion src/core/gps/qgsgpslogger.h
Expand Up @@ -25,6 +25,7 @@

#include <QObject>
#include <QPointer>
#include <QDateTime>

class QgsGpsConnection;
class QTimer;
Expand Down Expand Up @@ -93,6 +94,12 @@ class CORE_EXPORT QgsGpsLogger : public QObject
*/
QgsCoordinateTransformContext transformContext() const;

/**
* Returns the distance area calculator which should be used for
* calculating distances associated with the GPS log.
*/
const QgsDistanceArea &distanceArea() const;

/**
* Returns the recorded points in the current track.
*
Expand All @@ -115,6 +122,14 @@ class CORE_EXPORT QgsGpsLogger : public QObject
*/
QDateTime lastTimestamp() const;

/**
* Returns the timestamp at which the current track was started.
*
* The returned time value will respect all user settings regarding GPS time zone
* handling.
*/
QDateTime trackStartTime() const;

/**
* Returns the last recorded elevation the device.
*/
Expand Down Expand Up @@ -165,6 +180,11 @@ class CORE_EXPORT QgsGpsLogger : public QObject
*/
void trackVertexAdded( const QgsPoint &vertex );

/**
* Emitted whenever the associated GPS device state is changed.
*/
void stateChanged( const QgsGpsInformation &info );

protected:

//! WGS84 coordinate reference system
Expand Down Expand Up @@ -195,7 +215,9 @@ class CORE_EXPORT QgsGpsLogger : public QObject
double mLastElevation = 0.0;

std::unique_ptr< nmeaPOS > mLastNmeaPosition;
std::unique_ptr< nmeaTIME > mLastNmeaTime;
QDateTime mLastTime;

QDateTime mTrackStartTime;

QVector<QgsPoint> mCaptureListWgs84;

Expand Down
135 changes: 132 additions & 3 deletions src/core/gps/qgsvectorlayergpslogger.cpp
Expand Up @@ -15,17 +15,19 @@

#include "qgsvectorlayergpslogger.h"
#include "qgsvectorlayer.h"

#include "qgsvectorlayerutils.h"
#include "qgsgpsconnection.h"
#include "qgslinestring.h"

QgsVectorLayerGpsLogger::QgsVectorLayerGpsLogger( QgsGpsConnection *connection, QObject *parent )
: QgsGpsLogger( connection, parent )
{

connect( this, &QgsGpsLogger::stateChanged, this, &QgsVectorLayerGpsLogger::gpsStateChanged );
}

QgsVectorLayerGpsLogger::~QgsVectorLayerGpsLogger()
{

endCurrentTrack();
}

void QgsVectorLayerGpsLogger::setPointsLayer( QgsVectorLayer *layer )
Expand Down Expand Up @@ -132,3 +134,130 @@ void QgsVectorLayerGpsLogger::setTransformContext( const QgsCoordinateTransformC
}
}

void QgsVectorLayerGpsLogger::endCurrentTrack()
{
const QVector< QgsPoint > track = currentTrack();
if ( track.isEmpty() )
return;

if ( mTracksLayer )
{
// record track
const QgsGeometry geometryWgs84 = QgsGeometry( new QgsLineString( track ) );
QgsGeometry geometry = geometryWgs84;

try
{
geometry.transform( mWgs84toTrackLayerTransform );
}
catch ( QgsCsException & )
{
QgsDebugMsg( QStringLiteral( "Error transforming GPS track" ) );
}

QgsAttributeMap attributes;

const int trackStartFieldIdx = mTracksLayer->fields().lookupField( mTrackStartTimeField );
if ( trackStartFieldIdx >= 0 )
{
attributes.insert( trackStartFieldIdx, timestamp( mTracksLayer, trackStartFieldIdx, trackStartTime() ) );
}

const int trackEndFieldIdx = mTracksLayer->fields().lookupField( mTrackEndTimeField );
if ( trackEndFieldIdx >= 0 )
{
attributes.insert( trackEndFieldIdx, timestamp( mTracksLayer, trackStartFieldIdx, lastTimestamp() ) );
}

const int trackLengthFieldIdx = mTracksLayer->fields().lookupField( mTrackLengthField );
if ( trackLengthFieldIdx >= 0 )
{
const double length = distanceArea().measureLength( geometryWgs84 );
attributes.insert( trackLengthFieldIdx, length );
}

QgsExpressionContext context = mTracksLayer->createExpressionContext();

QgsFeature feature = QgsVectorLayerUtils::createFeature( mTracksLayer, geometry, attributes, &context );

mTracksLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
}
resetTrack();
}

void QgsVectorLayerGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
{
if ( mPointsLayer && info.isValid() )
{
// record point
const QgsPointXY newPosition = lastPosition();
const QDateTime newTime = lastTimestamp();
QgsGeometry geometry( new QgsPoint( newPosition.x(), newPosition.y(), lastElevation() ) );

try
{
geometry.transform( mWgs84toPointLayerTransform );
}
catch ( QgsCsException & )
{
QgsDebugMsg( QStringLiteral( "Error transforming GPS point" ) );
}

QgsAttributeMap attributes;

const int pointTimeFieldIdx = mPointsLayer->fields().lookupField( mPointTimeField );
if ( pointTimeFieldIdx >= 0 )
{
attributes.insert( pointTimeFieldIdx, timestamp( mPointsLayer, pointTimeFieldIdx, lastTimestamp() ) );
}

const int pointDistanceFromPreviousIdx = mPointsLayer->fields().lookupField( mPointDistanceFromPreviousField );
if ( pointDistanceFromPreviousIdx >= 0 )
{
if ( !mLastPoint.isEmpty() )
{
const double distanceSinceLast = distanceArea().measureLine( mLastPoint, newPosition );
attributes.insert( pointDistanceFromPreviousIdx, distanceSinceLast );
}
}
mLastPoint = newPosition;

const int pointTimeSincePreviousFieldIdx = mPointsLayer->fields().lookupField( mPointTimeDeltaFromPreviousField );
if ( pointTimeFieldIdx >= 0 )
{
if ( mLastTime.isValid() )
{
attributes.insert( pointTimeSincePreviousFieldIdx, static_cast< double >( mLastTime.msecsTo( newTime ) ) / 1000 );
}
}
mLastTime = newTime;

QgsExpressionContext context = mPointsLayer->createExpressionContext();

QgsFeature feature = QgsVectorLayerUtils::createFeature( mPointsLayer, geometry, attributes, &context );

mPointsLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
}
}

QVariant QgsVectorLayerGpsLogger::timestamp( QgsVectorLayer *vlayer, int idx, const QDateTime &time )
{
QVariant value;
if ( idx != -1 && time.isValid() )
{
// Only string and datetime fields are supported
switch ( vlayer->fields().at( idx ).type() )
{
case QVariant::String:
value = time.toString( Qt::DateFormat::ISODate );
break;
case QVariant::DateTime:
value = time;
break;
default:
break;
}
}
return value;
}

0 comments on commit 154ab20

Please sign in to comment.