QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsvectorlayergpslogger.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayergpslogger.cpp
3 -------------------
4 begin : November 2022
5 copyright : (C) 2022 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "qgsvectorlayer.h"
18#include "qgsvectorlayerutils.h"
19#include "qgsgpsconnection.h"
20#include "qgslinestring.h"
21
23 : QgsGpsLogger( connection, parent )
24{
25 connect( this, &QgsGpsLogger::stateChanged, this, &QgsVectorLayerGpsLogger::gpsStateChanged );
26}
27
29{
31}
32
34{
35 mPointsLayer = layer;
36
37 if ( mPointsLayer )
38 {
39 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
40 }
41}
42
44{
45 mTracksLayer = layer;
46
47 if ( mTracksLayer )
48 {
49 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
50 }
51}
52
54{
55 return mPointsLayer;
56}
57
59{
60 return mTracksLayer;
61}
62
64{
65 if ( field.isEmpty() )
66 mDestinationFields.remove( component );
67 else
68 mDestinationFields[ component ] = field;
69}
70
72{
73 return mDestinationFields.value( component );
74}
75
77{
79
80 if ( mPointsLayer )
81 {
82 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
83 }
84 if ( mTracksLayer )
85 {
86 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
87 }
88}
89
91{
92 const QVector< QgsPoint > track = currentTrack();
93 if ( track.isEmpty() )
94 return;
95
96 if ( mTracksLayer )
97 {
98 // record track
99 QgsGeometry geometry = QgsGeometry( new QgsLineString( track ) );
100
101 try
102 {
103 geometry.transform( mWgs84toTrackLayerTransform );
104 }
105 catch ( QgsCsException & )
106 {
107 QgsDebugError( QStringLiteral( "Error transforming GPS track" ) );
108 }
109
110 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mTracksLayer->wkbType() ) )
111 {
112 geometry.get()->dropZValue();
113 }
114 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mTracksLayer->wkbType() ) )
115 {
116 geometry.get()->dropMValue();
117 }
118
119 QgsAttributeMap attributes;
120
121 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
122 {
123 if ( it.value().isEmpty() )
124 continue;
125
126 switch ( it.key() )
127 {
144 continue; // points layer fields
145
148 {
149 // time field
150 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
151 if ( fieldIdx >= 0 )
152 {
153 const QVariant value = componentValue( it.key() );
154 if ( value.toDateTime().isValid() )
155 {
156 attributes.insert( fieldIdx, timestamp( mTracksLayer, fieldIdx, value.toDateTime() ) );
157 }
158 }
159 break;
160 }
161
164 {
165 // non-time fields
166 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
167 if ( fieldIdx >= 0 )
168 {
169 const QVariant value = componentValue( it.key() );
170 if ( !QgsVariantUtils::isNull( value ) )
171 {
172 attributes.insert( fieldIdx, value );
173 }
174 }
175 break;
176 }
177 }
178 }
179
180 QgsExpressionContext context = mTracksLayer->createExpressionContext();
181
182 QgsFeature feature = QgsVectorLayerUtils::createFeature( mTracksLayer, geometry, attributes, &context );
183
184 if ( mUseEditBuffer )
185 mTracksLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
186 else
187 mTracksLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
188 }
189 resetTrack();
190}
191
192void QgsVectorLayerGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
193{
194 if ( mPointsLayer && info.isValid() )
195 {
196 // record point
197 const QgsPointXY newPosition = lastPosition();
198 QgsGeometry geometry( new QgsPoint( newPosition.x(), newPosition.y(), lastElevation(), lastMValue() ) );
199
200 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mPointsLayer->wkbType() ) )
201 {
202 geometry.get()->dropZValue();
203 }
204 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mPointsLayer->wkbType() ) )
205 {
206 geometry.get()->dropMValue();
207 }
208
209 try
210 {
211 geometry.transform( mWgs84toPointLayerTransform );
212 }
213 catch ( QgsCsException & )
214 {
215 QgsDebugError( QStringLiteral( "Error transforming GPS point" ) );
216 }
217
218 QgsAttributeMap attributes;
219
220 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
221 {
222 if ( it.value().isEmpty() )
223 continue;
224
225 switch ( it.key() )
226 {
242 {
243 // non-time fields
244 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
245 if ( fieldIdx >= 0 )
246 {
247 const QVariant value = componentValue( it.key() );
248 if ( !QgsVariantUtils::isNull( value ) )
249 {
250 attributes.insert( fieldIdx, value );
251 }
252 }
253 break;
254 }
255
257 {
258 // time field
259 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
260 if ( fieldIdx >= 0 )
261 {
262 const QVariant value = componentValue( it.key() );
263 if ( value.toDateTime().isValid() )
264 {
265 attributes.insert( fieldIdx, timestamp( mPointsLayer, fieldIdx, value.toDateTime() ) );
266 }
267 }
268 break;
269 }
270
275 continue; // track related field
276 }
277 }
278
279 QgsExpressionContext context = mPointsLayer->createExpressionContext();
280
281 QgsFeature feature = QgsVectorLayerUtils::createFeature( mPointsLayer, geometry, attributes, &context );
282
283 if ( mUseEditBuffer )
284 mPointsLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
285 else
286 mPointsLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
287 }
288}
289
290QVariant QgsVectorLayerGpsLogger::timestamp( QgsVectorLayer *vlayer, int idx, const QDateTime &time )
291{
292 QVariant value;
293 if ( idx != -1 && time.isValid() )
294 {
295 // Only string and datetime fields are supported
296 switch ( vlayer->fields().at( idx ).type() )
297 {
298 case QVariant::String:
299 value = time.toString( Qt::DateFormat::ISODate );
300 break;
301 case QVariant::DateTime:
302 value = time;
303 break;
304 default:
305 break;
306 }
307 }
308 return value;
309}
310
GpsInformationComponent
GPS information component.
Definition: qgis.h:1529
@ TrackStartTime
Timestamp at start of current track (available from QgsGpsLogger class only)
@ TrackTimeSinceLastPoint
Time since last recorded location (available from QgsGpsLogger class only)
@ Pdop
Dilution of precision.
@ TrackEndTime
Timestamp at end (current point) of current track (available from QgsGpsLogger class only)
@ Altitude
Altitude/elevation above or below the mean sea level.
@ TrackDistanceFromStart
Direct distance from first vertex in current GPS track to last vertex (available from QgsGpsLogger cl...
@ TotalTrackLength
Total distance of current GPS track (available from QgsGpsLogger class only)
@ Hdop
Horizontal dilution of precision.
@ EllipsoidAltitude
Altitude/elevation above or below the WGS-84 Earth ellipsoid.
@ Bearing
Bearing measured in degrees clockwise from true north to the direction of travel.
@ Vdop
Vertical dilution of precision.
@ GeoidalSeparation
Geoidal separation, the difference between the WGS-84 Earth ellipsoid and mean-sea-level (geoid),...
@ VerticalAccuracy
Vertical accuracy in meters.
@ Location
2D location (latitude/longitude), as a QgsPointXY value
@ TrackDistanceSinceLastPoint
Distance since last recorded location (available from QgsGpsLogger class only)
@ HorizontalAccuracy
Horizontal accuracy in meters.
@ SatellitesUsed
Count of satellites used in obtaining the fix.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant::Type type
Definition: qgsfield.h:60
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Abstract base class for connection to a GPS device.
Encapsulates information relating to a GPS position fix.
bool isValid() const
Returns whether the connection information is valid.
Base class for objects which log incoming GPS data.
Definition: qgsgpslogger.h:56
virtual void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context to be used when transforming GPS coordinates.
void stateChanged(const QgsGpsInformation &info)
Emitted whenever the associated GPS device state is changed.
double lastElevation() const
Returns the last recorded elevation the device.
QgsCoordinateReferenceSystem mWgs84CRS
WGS84 coordinate reference system.
Definition: qgsgpslogger.h:260
QVector< QgsPoint > currentTrack() const
Returns the recorded points in the current track.
void resetTrack()
Resets the current track, discarding all recorded points.
double lastMValue() const
Returns the last recorded value corresponding to the QgsGpsLogger::settingsGpsMValueComponent setting...
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context to be used when transforming GPS coordinates.
QVariant componentValue(Qgis::GpsInformationComponent component) const
Returns the value of the corresponding GPS information component.
QgsPointXY lastPosition() const
Returns the last recorded position of the device.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
A class to represent a 2D point.
Definition: qgspointxy.h:60
double y
Definition: qgspointxy.h:64
Q_GADGET double x
Definition: qgspointxy.h:63
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
QgsVectorLayer * pointsLayer()
Returns the layer in which recorded GPS points will be stored.
void setDestinationField(Qgis::GpsInformationComponent component, const QString &field)
Sets a destination field name for a specific GPS information component.
QgsVectorLayerGpsLogger(QgsGpsConnection *connection, QObject *parent=nullptr)
Constructor for QgsVectorLayerGpsLogger with the specified parent object.
void setPointsLayer(QgsVectorLayer *layer)
Sets the layer in which recorded GPS points should be stored.
void setTracksLayer(QgsVectorLayer *layer)
Sets the layer in which recorded GPS tracks should be stored.
void setTransformContext(const QgsCoordinateTransformContext &context) override
Sets the coordinate transform context to be used when transforming GPS coordinates.
QString destinationField(Qgis::GpsInformationComponent component) const
Returns the destination field name for a specific GPS information component.
QgsVectorLayer * tracksLayer()
Returns the layer in which recorded GPS tracks will be stored.
void endCurrentTrack()
Ends the current track, storing it in the tracksLayer() if appropriate.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:973
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1023
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:42
#define QgsDebugError(str)
Definition: qgslogger.h:38