QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <QString>
24
25#include "moc_qgsvectorlayergpslogger.cpp"
26
27using namespace Qt::StringLiterals;
28
30 : QgsGpsLogger( connection, parent )
31{
32 connect( this, &QgsGpsLogger::stateChanged, this, &QgsVectorLayerGpsLogger::gpsStateChanged );
33}
34
39
41{
42 mPointsLayer = layer;
43
44 if ( mPointsLayer )
45 {
46 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
47 }
48}
49
51{
52 mTracksLayer = layer;
53
54 if ( mTracksLayer )
55 {
56 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
57 }
58}
59
61{
62 return mPointsLayer;
63}
64
66{
67 return mTracksLayer;
68}
69
71{
72 if ( field.isEmpty() )
73 mDestinationFields.remove( component );
74 else
75 mDestinationFields[ component ] = field;
76}
77
79{
80 return mDestinationFields.value( component );
81}
82
84{
86
87 if ( mPointsLayer )
88 {
89 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
90 }
91 if ( mTracksLayer )
92 {
93 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
94 }
95}
96
98{
99 const QVector< QgsPoint > track = currentTrack();
100 if ( track.isEmpty() )
101 return;
102
103 if ( mTracksLayer )
104 {
105 // record track
106 QgsGeometry geometry = QgsGeometry( new QgsLineString( track ) );
107
108 try
109 {
110 geometry.transform( mWgs84toTrackLayerTransform );
111 }
112 catch ( QgsCsException & )
113 {
114 QgsDebugError( u"Error transforming GPS track"_s );
115 }
116
117 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mTracksLayer->wkbType() ) )
118 {
119 geometry.get()->dropZValue();
120 }
121 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mTracksLayer->wkbType() ) )
122 {
123 geometry.get()->dropMValue();
124 }
125
126 QgsAttributeMap attributes;
127
128 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
129 {
130 if ( it.value().isEmpty() )
131 continue;
132
133 switch ( it.key() )
134 {
151 continue; // points layer fields
152
155 {
156 // time field
157 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
158 if ( fieldIdx >= 0 )
159 {
160 const QVariant value = componentValue( it.key() );
161 if ( value.toDateTime().isValid() )
162 {
163 attributes.insert( fieldIdx, timestamp( mTracksLayer, fieldIdx, value.toDateTime() ) );
164 }
165 }
166 break;
167 }
168
171 {
172 // non-time fields
173 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
174 if ( fieldIdx >= 0 )
175 {
176 const QVariant value = componentValue( it.key() );
177 if ( !QgsVariantUtils::isNull( value ) )
178 {
179 attributes.insert( fieldIdx, value );
180 }
181 }
182 break;
183 }
184 }
185 }
186
187 QgsExpressionContext context = mTracksLayer->createExpressionContext();
188
189 QgsFeature feature = QgsVectorLayerUtils::createFeature( mTracksLayer, geometry, attributes, &context );
190
191 if ( mUseEditBuffer )
192 mTracksLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
193 else
194 mTracksLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
195 }
196 resetTrack();
197}
198
199void QgsVectorLayerGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
200{
201 if ( mPointsLayer && info.isValid() )
202 {
203 // record point
204 const QgsPointXY newPosition = lastPosition();
205 QgsGeometry geometry( new QgsPoint( newPosition.x(), newPosition.y(), lastElevation(), lastMValue() ) );
206
207 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mPointsLayer->wkbType() ) )
208 {
209 geometry.get()->dropZValue();
210 }
211 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mPointsLayer->wkbType() ) )
212 {
213 geometry.get()->dropMValue();
214 }
215
216 try
217 {
218 geometry.transform( mWgs84toPointLayerTransform );
219 }
220 catch ( QgsCsException & )
221 {
222 QgsDebugError( u"Error transforming GPS point"_s );
223 }
224
225 QgsAttributeMap attributes;
226
227 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
228 {
229 if ( it.value().isEmpty() )
230 continue;
231
232 switch ( it.key() )
233 {
249 {
250 // non-time fields
251 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
252 if ( fieldIdx >= 0 )
253 {
254 const QVariant value = componentValue( it.key() );
255 if ( !QgsVariantUtils::isNull( value ) )
256 {
257 attributes.insert( fieldIdx, value );
258 }
259 }
260 break;
261 }
262
264 {
265 // time field
266 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
267 if ( fieldIdx >= 0 )
268 {
269 const QVariant value = componentValue( it.key() );
270 if ( value.toDateTime().isValid() )
271 {
272 attributes.insert( fieldIdx, timestamp( mPointsLayer, fieldIdx, value.toDateTime() ) );
273 }
274 }
275 break;
276 }
277
282 continue; // track related field
283 }
284 }
285
286 QgsExpressionContext context = mPointsLayer->createExpressionContext();
287
288 QgsFeature feature = QgsVectorLayerUtils::createFeature( mPointsLayer, geometry, attributes, &context );
289
290 if ( mUseEditBuffer )
291 mPointsLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
292 else
293 mPointsLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
294 }
295}
296
297QVariant QgsVectorLayerGpsLogger::timestamp( QgsVectorLayer *vlayer, int idx, const QDateTime &time )
298{
299 QVariant value;
300 if ( idx != -1 && time.isValid() )
301 {
302 // Only string and datetime fields are supported
303 switch ( vlayer->fields().at( idx ).type() )
304 {
305 case QMetaType::Type::QString:
306 value = time.toString( Qt::DateFormat::ISODate );
307 break;
308 case QMetaType::Type::QDateTime:
309 value = time;
310 break;
311 default:
312 break;
313 }
314 }
315 return value;
316}
317
GpsInformationComponent
GPS information component.
Definition qgis.h:2014
@ TrackStartTime
Timestamp at start of current track (available from QgsGpsLogger class only).
Definition qgis.h:2029
@ GroundSpeed
Ground speed.
Definition qgis.h:2017
@ TrackTimeSinceLastPoint
Time since last recorded location (available from QgsGpsLogger class only).
Definition qgis.h:2032
@ Pdop
Dilution of precision.
Definition qgis.h:2021
@ TrackEndTime
Timestamp at end (current point) of current track (available from QgsGpsLogger class only).
Definition qgis.h:2030
@ Altitude
Altitude/elevation above or below the mean sea level.
Definition qgis.h:2016
@ TrackDistanceFromStart
Direct distance from first vertex in current GPS track to last vertex (available from QgsGpsLogger cl...
Definition qgis.h:2020
@ TotalTrackLength
Total distance of current GPS track (available from QgsGpsLogger class only).
Definition qgis.h:2019
@ Hdop
Horizontal dilution of precision.
Definition qgis.h:2022
@ EllipsoidAltitude
Altitude/elevation above or below the WGS-84 Earth ellipsoid.
Definition qgis.h:2034
@ Bearing
Bearing measured in degrees clockwise from true north to the direction of travel.
Definition qgis.h:2018
@ Vdop
Vertical dilution of precision.
Definition qgis.h:2023
@ GeoidalSeparation
Geoidal separation, the difference between the WGS-84 Earth ellipsoid and mean-sea-level (geoid),...
Definition qgis.h:2033
@ VerticalAccuracy
Vertical accuracy in meters.
Definition qgis.h:2025
@ Location
2D location (latitude/longitude), as a QgsPointXY value
Definition qgis.h:2015
@ TrackDistanceSinceLastPoint
Distance since last recorded location (available from QgsGpsLogger class only).
Definition qgis.h:2031
@ HorizontalAccuracy
Horizontal accuracy in meters.
Definition qgis.h:2024
@ SatellitesUsed
Count of satellites used in obtaining the fix.
Definition qgis.h:2027
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:60
QMetaType::Type type
Definition qgsfield.h:63
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:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
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:59