QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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#include "moc_qgsvectorlayergpslogger.cpp"
18#include "qgsvectorlayer.h"
19#include "qgsvectorlayerutils.h"
20#include "qgsgpsconnection.h"
21#include "qgslinestring.h"
22
24 : QgsGpsLogger( connection, parent )
25{
26 connect( this, &QgsGpsLogger::stateChanged, this, &QgsVectorLayerGpsLogger::gpsStateChanged );
27}
28
33
35{
36 mPointsLayer = layer;
37
38 if ( mPointsLayer )
39 {
40 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
41 }
42}
43
45{
46 mTracksLayer = layer;
47
48 if ( mTracksLayer )
49 {
50 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
51 }
52}
53
55{
56 return mPointsLayer;
57}
58
60{
61 return mTracksLayer;
62}
63
65{
66 if ( field.isEmpty() )
67 mDestinationFields.remove( component );
68 else
69 mDestinationFields[ component ] = field;
70}
71
73{
74 return mDestinationFields.value( component );
75}
76
78{
80
81 if ( mPointsLayer )
82 {
83 mWgs84toPointLayerTransform = QgsCoordinateTransform( mWgs84CRS, mPointsLayer->crs(), transformContext() );
84 }
85 if ( mTracksLayer )
86 {
87 mWgs84toTrackLayerTransform = QgsCoordinateTransform( mWgs84CRS, mTracksLayer->crs(), transformContext() );
88 }
89}
90
92{
93 const QVector< QgsPoint > track = currentTrack();
94 if ( track.isEmpty() )
95 return;
96
97 if ( mTracksLayer )
98 {
99 // record track
100 QgsGeometry geometry = QgsGeometry( new QgsLineString( track ) );
101
102 try
103 {
104 geometry.transform( mWgs84toTrackLayerTransform );
105 }
106 catch ( QgsCsException & )
107 {
108 QgsDebugError( QStringLiteral( "Error transforming GPS track" ) );
109 }
110
111 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mTracksLayer->wkbType() ) )
112 {
113 geometry.get()->dropZValue();
114 }
115 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mTracksLayer->wkbType() ) )
116 {
117 geometry.get()->dropMValue();
118 }
119
120 QgsAttributeMap attributes;
121
122 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
123 {
124 if ( it.value().isEmpty() )
125 continue;
126
127 switch ( it.key() )
128 {
145 continue; // points layer fields
146
149 {
150 // time field
151 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
152 if ( fieldIdx >= 0 )
153 {
154 const QVariant value = componentValue( it.key() );
155 if ( value.toDateTime().isValid() )
156 {
157 attributes.insert( fieldIdx, timestamp( mTracksLayer, fieldIdx, value.toDateTime() ) );
158 }
159 }
160 break;
161 }
162
165 {
166 // non-time fields
167 const int fieldIdx = mTracksLayer->fields().lookupField( it.value() );
168 if ( fieldIdx >= 0 )
169 {
170 const QVariant value = componentValue( it.key() );
171 if ( !QgsVariantUtils::isNull( value ) )
172 {
173 attributes.insert( fieldIdx, value );
174 }
175 }
176 break;
177 }
178 }
179 }
180
181 QgsExpressionContext context = mTracksLayer->createExpressionContext();
182
183 QgsFeature feature = QgsVectorLayerUtils::createFeature( mTracksLayer, geometry, attributes, &context );
184
185 if ( mUseEditBuffer )
186 mTracksLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
187 else
188 mTracksLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
189 }
190 resetTrack();
191}
192
193void QgsVectorLayerGpsLogger::gpsStateChanged( const QgsGpsInformation &info )
194{
195 if ( mPointsLayer && info.isValid() )
196 {
197 // record point
198 const QgsPointXY newPosition = lastPosition();
199 QgsGeometry geometry( new QgsPoint( newPosition.x(), newPosition.y(), lastElevation(), lastMValue() ) );
200
201 if ( geometry.constGet()->is3D() && !QgsWkbTypes::hasZ( mPointsLayer->wkbType() ) )
202 {
203 geometry.get()->dropZValue();
204 }
205 if ( geometry.constGet()->isMeasure() && !QgsWkbTypes::hasM( mPointsLayer->wkbType() ) )
206 {
207 geometry.get()->dropMValue();
208 }
209
210 try
211 {
212 geometry.transform( mWgs84toPointLayerTransform );
213 }
214 catch ( QgsCsException & )
215 {
216 QgsDebugError( QStringLiteral( "Error transforming GPS point" ) );
217 }
218
219 QgsAttributeMap attributes;
220
221 for ( auto it = mDestinationFields.constBegin(); it != mDestinationFields.constEnd(); ++it )
222 {
223 if ( it.value().isEmpty() )
224 continue;
225
226 switch ( it.key() )
227 {
243 {
244 // non-time fields
245 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
246 if ( fieldIdx >= 0 )
247 {
248 const QVariant value = componentValue( it.key() );
249 if ( !QgsVariantUtils::isNull( value ) )
250 {
251 attributes.insert( fieldIdx, value );
252 }
253 }
254 break;
255 }
256
258 {
259 // time field
260 const int fieldIdx = mPointsLayer->fields().lookupField( it.value() );
261 if ( fieldIdx >= 0 )
262 {
263 const QVariant value = componentValue( it.key() );
264 if ( value.toDateTime().isValid() )
265 {
266 attributes.insert( fieldIdx, timestamp( mPointsLayer, fieldIdx, value.toDateTime() ) );
267 }
268 }
269 break;
270 }
271
276 continue; // track related field
277 }
278 }
279
280 QgsExpressionContext context = mPointsLayer->createExpressionContext();
281
282 QgsFeature feature = QgsVectorLayerUtils::createFeature( mPointsLayer, geometry, attributes, &context );
283
284 if ( mUseEditBuffer )
285 mPointsLayer->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
286 else
287 mPointsLayer->dataProvider()->addFeature( feature, QgsFeatureSink::Flag::FastInsert );
288 }
289}
290
291QVariant QgsVectorLayerGpsLogger::timestamp( QgsVectorLayer *vlayer, int idx, const QDateTime &time )
292{
293 QVariant value;
294 if ( idx != -1 && time.isValid() )
295 {
296 // Only string and datetime fields are supported
297 switch ( vlayer->fields().at( idx ).type() )
298 {
299 case QMetaType::Type::QString:
300 value = time.toString( Qt::DateFormat::ISODate );
301 break;
302 case QMetaType::Type::QDateTime:
303 value = time;
304 break;
305 default:
306 break;
307 }
308 }
309 return value;
310}
311
GpsInformationComponent
GPS information component.
Definition qgis.h:1803
@ 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.
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:60
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 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.
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.
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.
A class to represent 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 data sets.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
QMap< int, QVariant > QgsAttributeMap
#define QgsDebugError(str)
Definition qgslogger.h:38