QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
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
18#include "qgsgpsconnection.h"
19#include "qgslinestring.h"
20#include "qgsvectorlayer.h"
21#include "qgsvectorlayerutils.h"
22
23#include "moc_qgsvectorlayergpslogger.cpp"
24
26 : QgsGpsLogger( connection, parent )
27{
28 connect( this, &QgsGpsLogger::stateChanged, this, &QgsVectorLayerGpsLogger::gpsStateChanged );
29}
30
35
37{
38 mPointsLayer = layer;
39
40 if ( mPointsLayer )
41 {
42 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
43 }
44}
45
47{
48 mTracksLayer = layer;
49
50 if ( mTracksLayer )
51 {
52 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
53 }
54}
55
57{
58 return mPointsLayer;
59}
60
62{
63 return mTracksLayer;
64}
65
67{
68 if ( field.isEmpty() )
69 mDestinationFields.remove( component );
70 else
71 mDestinationFields[ component ] = field;
72}
73
75{
76 return mDestinationFields.value( component );
77}
78
80{
82
83 if ( mPointsLayer )
84 {
85 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
86 }
87 if ( mTracksLayer )
88 {
89 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
90 }
91}
92
94{
95 const QVector< QgsPoint > track = currentTrack();
96 if ( track.isEmpty() )
97 return;
98
99 if ( mTracksLayer )
100 {
101 // record track
102 QgsGeometry geometry = QgsGeometry( new QgsLineString( track ) );
103
104 try
105 {
106 geometry.transform( mWgs84toTrackLayerTransform );
107 }
108 catch ( QgsCsException & )
109 {
110 QgsDebugError( QStringLiteral( "Error transforming GPS track" ) );
111 }
112
113 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mTracksLayer->wkbType() ) )
114 {
115 geometry.get()->dropZValue();
116 }
117 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mTracksLayer->wkbType() ) )
118 {
119 geometry.get()->dropMValue();
120 }
121
122 QgsAttributeMap attributes;
123
124 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
125 {
126 if ( it.value().isEmpty() )
127 continue;
128
129 switch ( it.key() )
130 {
147 continue; // points layer fields
148
151 {
152 // time field
153 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
154 if ( fieldIdx >= 0 )
155 {
156 const QVariant value = componentValue( it.key() );
157 if ( value.toDateTime().isValid() )
158 {
159 attributes.insert( fieldIdx, timestamp( mTracksLayer, fieldIdx, value.toDateTime() ) );
160 }
161 }
162 break;
163 }
164
167 {
168 // non-time fields
169 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
170 if ( fieldIdx >= 0 )
171 {
172 const QVariant value = componentValue( it.key() );
173 if ( !QgsVariantUtils::isNull( value ) )
174 {
175 attributes.insert( fieldIdx, value );
176 }
177 }
178 break;
179 }
180 }
181 }
182
183 QgsExpressionContext context = mTracksLayer->createExpressionContext();
184
185 QgsFeature feature = QgsVectorLayerUtils::createFeature( mTracksLayer, geometry, attributes, &context );
186
187 if ( mUseEditBuffer )
188 mTracksLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
189 else
190 mTracksLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
191 }
192 resetTrack();
193}
194
195void QgsVectorLayerGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
196{
197 if ( mPointsLayer && info.isValid() )
198 {
199 // record point
200 const QgsPointXY newPosition = lastPosition();
201 QgsGeometry geometry( new QgsPoint( newPosition.x(), newPosition.y(), lastElevation(), lastMValue() ) );
202
203 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mPointsLayer->wkbType() ) )
204 {
205 geometry.get()->dropZValue();
206 }
207 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mPointsLayer->wkbType() ) )
208 {
209 geometry.get()->dropMValue();
210 }
211
212 try
213 {
214 geometry.transform( mWgs84toPointLayerTransform );
215 }
216 catch ( QgsCsException & )
217 {
218 QgsDebugError( QStringLiteral( "Error transforming GPS point" ) );
219 }
220
221 QgsAttributeMap attributes;
222
223 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
224 {
225 if ( it.value().isEmpty() )
226 continue;
227
228 switch ( it.key() )
229 {
245 {
246 // non-time fields
247 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
248 if ( fieldIdx >= 0 )
249 {
250 const QVariant value = componentValue( it.key() );
251 if ( !QgsVariantUtils::isNull( value ) )
252 {
253 attributes.insert( fieldIdx, value );
254 }
255 }
256 break;
257 }
258
260 {
261 // time field
262 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
263 if ( fieldIdx >= 0 )
264 {
265 const QVariant value = componentValue( it.key() );
266 if ( value.toDateTime().isValid() )
267 {
268 attributes.insert( fieldIdx, timestamp( mPointsLayer, fieldIdx, value.toDateTime() ) );
269 }
270 }
271 break;
272 }
273
278 continue; // track related field
279 }
280 }
281
282 QgsExpressionContext context = mPointsLayer->createExpressionContext();
283
284 QgsFeature feature = QgsVectorLayerUtils::createFeature( mPointsLayer, geometry, attributes, &context );
285
286 if ( mUseEditBuffer )
287 mPointsLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
288 else
289 mPointsLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
290 }
291}
292
293QVariant QgsVectorLayerGpsLogger::timestamp( QgsVectorLayer *vlayer, int idx, const QDateTime &time )
294{
295 QVariant value;
296 if ( idx != -1 && time.isValid() )
297 {
298 // Only string and datetime fields are supported
299 switch ( vlayer->fields().at( idx ).type() )
300 {
301 case QMetaType::Type::QString:
302 value = time.toString( Qt::DateFormat::ISODate );
303 break;
304 case QMetaType::Type::QDateTime:
305 value = time;
306 break;
307 default:
308 break;
309 }
310 }
311 return value;
312}
313
GpsInformationComponent
GPS information component.
Definition qgis.h:1956
@ TrackStartTime
Timestamp at start of current track (available from QgsGpsLogger class only).
Definition qgis.h:1971
@ GroundSpeed
Ground speed.
Definition qgis.h:1959
@ TrackTimeSinceLastPoint
Time since last recorded location (available from QgsGpsLogger class only).
Definition qgis.h:1974
@ Pdop
Dilution of precision.
Definition qgis.h:1963
@ TrackEndTime
Timestamp at end (current point) of current track (available from QgsGpsLogger class only).
Definition qgis.h:1972
@ Altitude
Altitude/elevation above or below the mean sea level.
Definition qgis.h:1958
@ TrackDistanceFromStart
Direct distance from first vertex in current GPS track to last vertex (available from QgsGpsLogger cl...
Definition qgis.h:1962
@ TotalTrackLength
Total distance of current GPS track (available from QgsGpsLogger class only).
Definition qgis.h:1961
@ Hdop
Horizontal dilution of precision.
Definition qgis.h:1964
@ EllipsoidAltitude
Altitude/elevation above or below the WGS-84 Earth ellipsoid.
Definition qgis.h:1976
@ Bearing
Bearing measured in degrees clockwise from true north to the direction of travel.
Definition qgis.h:1960
@ Vdop
Vertical dilution of precision.
Definition qgis.h:1965
@ GeoidalSeparation
Geoidal separation, the difference between the WGS-84 Earth ellipsoid and mean-sea-level (geoid),...
Definition qgis.h:1975
@ VerticalAccuracy
Vertical accuracy in meters.
Definition qgis.h:1967
@ Location
2D location (latitude/longitude), as a QgsPointXY value
Definition qgis.h:1957
@ TrackDistanceSinceLastPoint
Distance since last recorded location (available from QgsGpsLogger class only).
Definition qgis.h:1973
@ HorizontalAccuracy
Horizontal accuracy in meters.
Definition qgis.h:1966
@ SatellitesUsed
Count of satellites used in obtaining the fix.
Definition qgis.h:1969
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.
Handles coordinate transforms between two coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QMetaType::Type type
Definition qgsfield.h:61
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
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 connections to a GPS device.
Encapsulates information relating to a GPS position fix.
bool isValid() const
Returns whether the connection information is valid.
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.
QgsGpsLogger(QgsGpsConnection *connection, QObject *parent=nullptr)
Constructor for QgsGpsLogger with the specified parent object.
QgsCoordinateReferenceSystem mWgs84CRS
WGS84 coordinate reference system.
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.
QgsGpsConnection * connection()
Returns the associated GPS connection.
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.
Represents a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
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 dataset.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
QMap< int, QVariant > QgsAttributeMap
#define QgsDebugError(str)
Definition qgslogger.h:57