QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsquickpositionkit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsquickpositionkit.cpp
3  --------------------------------------
4  Date : Dec. 2017
5  Copyright : (C) 2017 Peter Petrik
6  Email : zilolv 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 
16 #include <memory>
17 
18 #include "qgis.h"
19 #include "qgslogger.h"
20 #include "qgsmessagelog.h"
21 
22 #include "qgsquickpositionkit.h"
23 #include "qgsquickutils.h"
25 
27  : QObject( parent )
28 {
29  connect( this,
31  this,
32  &QgsQuickPositionKit::onSimulatePositionLongLatRadChanged );
33 
35 }
36 
37 QGeoPositionInfoSource *QgsQuickPositionKit::gpsSource()
38 {
39  // this should give us "true" position source
40  // on Linux it comes from Geoclue library
41  std::unique_ptr<QGeoPositionInfoSource> source( QGeoPositionInfoSource::createDefaultSource( nullptr ) );
42  if ( ( !source ) || ( source->error() != QGeoPositionInfoSource::NoError ) )
43  {
44  QgsMessageLog::logMessage( QStringLiteral( "%1 (%2)" )
45  .arg( tr( "Unable to create default GPS Position Source" ) )
46  .arg( QString::number( ( long )source->error() ) )
47  , QStringLiteral( "QgsQuick" )
48  , Qgis::Warning );
49  return nullptr;
50  }
51  else
52  {
53  return source.release();
54  }
55 }
56 
57 QGeoPositionInfoSource *QgsQuickPositionKit::simulatedSource( double longitude, double latitude, double radius )
58 {
59  return new QgsQuickSimulatedPositionSource( this, longitude, latitude, radius );
60 }
61 
62 QGeoPositionInfoSource *QgsQuickPositionKit::source() const
63 {
64  return mSource.get();
65 }
66 
67 void QgsQuickPositionKit::useSimulatedLocation( double longitude, double latitude, double radius )
68 {
69  std::unique_ptr<QGeoPositionInfoSource> source( simulatedSource( longitude, latitude, radius ) );
70  mIsSimulated = true;
71  replacePositionSource( source.release() );
72 }
73 
74 void QgsQuickPositionKit::updateScreenPosition()
75 {
76  if ( !mMapSettings )
77  return;
78 
80  if ( screenPosition != mScreenPosition )
81  {
82  mScreenPosition = screenPosition;
83  emit screenPositionChanged();
84  }
85 }
86 
87 void QgsQuickPositionKit::updateScreenAccuracy()
88 {
89  if ( !mMapSettings )
90  return;
91 
92  double screenAccuracy = calculateScreenAccuracy();
93  if ( !qgsDoubleNear( screenAccuracy, mScreenAccuracy ) )
94  {
95  mScreenAccuracy = screenAccuracy;
96  emit screenAccuracyChanged();
97  }
98 }
99 
101 {
102  QGeoPositionInfoSource *source = gpsSource();
103  mIsSimulated = false;
104  replacePositionSource( source );
105 }
106 
107 void QgsQuickPositionKit::replacePositionSource( QGeoPositionInfoSource *source )
108 {
109  if ( mSource.get() == source )
110  return;
111 
112  if ( mSource )
113  {
114  mSource->disconnect();
115  }
116 
117  mSource.reset( source );
118  emit sourceChanged();
119 
120  if ( mSource )
121  {
122  connect( mSource.get(), &QGeoPositionInfoSource::positionUpdated, this, &QgsQuickPositionKit::onPositionUpdated );
123  connect( mSource.get(), &QGeoPositionInfoSource::updateTimeout, this, &QgsQuickPositionKit::onUpdateTimeout );
124 
125  mSource->startUpdates();
126 
127  QgsDebugMsg( QStringLiteral( "Position source changed: %1" ).arg( mSource->sourceName() ) );
128  }
129 }
130 
132 {
133  return mMapSettings;
134 }
135 
136 void QgsQuickPositionKit::updateProjectedPosition()
137 {
138  if ( !mMapSettings )
139  return;
140 
141  QgsPointXY srcPoint = QgsPointXY( mPosition.x(), mPosition.y() );
142  QgsPointXY projectedPositionXY = srcPoint;
143  try
144  {
145  projectedPositionXY = QgsQuickUtils::transformPoint(
146  positionCRS(),
147  mMapSettings->destinationCrs(),
148  mMapSettings->transformContext(),
149  srcPoint );
150  }
151  catch ( const QgsCsException & )
152  {
153  QgsDebugMsg( QStringLiteral( "Failed to transform GPS position: " ) + srcPoint.toString() );
154  }
155 
156  QgsPoint projectedPosition( projectedPositionXY );
157  projectedPosition.addZValue( mPosition.z() );
158 
159  if ( projectedPosition != mProjectedPosition )
160  {
161  mProjectedPosition = projectedPosition;
163  }
164 }
165 
166 void QgsQuickPositionKit::onPositionUpdated( const QGeoPositionInfo &info )
167 {
168  bool hasPosition = info.coordinate().isValid();
169  if ( hasPosition != mHasPosition )
170  {
171  mHasPosition = hasPosition;
172  emit hasPositionChanged();
173  }
174 
175  // Calculate position
177  info.coordinate().longitude(),
178  info.coordinate().latitude(),
179  info.coordinate().altitude() ); // can be NaN
180 
181  if ( position != mPosition )
182  {
183  mPosition = position;
184  emit positionChanged();
185  }
186  // calculate accuracy
187  double accuracy;
188  if ( info.hasAttribute( QGeoPositionInfo::HorizontalAccuracy ) )
189  accuracy = info.attribute( QGeoPositionInfo::HorizontalAccuracy );
190  else
191  accuracy = -1;
192  if ( !qgsDoubleNear( accuracy, mAccuracy ) )
193  {
194  mAccuracy = accuracy;
195  emit accuracyChanged();
196  }
197 
198  // calculate direction
199  double direction;
200  if ( info.hasAttribute( QGeoPositionInfo::Direction ) )
201  direction = info.attribute( QGeoPositionInfo::Direction );
202  else
203  direction = -1;
204  if ( !qgsDoubleNear( direction, mDirection ) )
205  {
206  mDirection = direction;
207  emit directionChanged();
208  }
209 
210  // recalculate projected/screen variables
211  onMapSettingsUpdated();
212 }
213 
214 void QgsQuickPositionKit::onMapSettingsUpdated()
215 {
216  updateProjectedPosition();
217 
218  updateScreenAccuracy();
219  updateScreenPosition();
220 }
221 
222 void QgsQuickPositionKit::onSimulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad )
223 {
224  if ( simulatePositionLongLatRad.size() > 2 )
225  {
226  double longitude = simulatePositionLongLatRad[0];
227  double latitude = simulatePositionLongLatRad[1];
228  double radius = simulatePositionLongLatRad[2];
229  QgsDebugMsg( QStringLiteral( "Use simulated position around longlat: %1, %2, %3" ).arg( longitude ).arg( latitude ).arg( radius ) );
230  useSimulatedLocation( longitude, latitude, radius );
231  }
232  else if ( mIsSimulated )
233  {
234  QgsDebugMsg( QStringLiteral( "Switching from simulated to GPS location" ) );
235  useGpsLocation();
236  }
237 }
238 
239 double QgsQuickPositionKit::calculateScreenAccuracy()
240 {
241  if ( !mMapSettings )
242  return 2.0;
243 
244  if ( accuracy() > 0 )
245  {
246  double scpm = QgsQuickUtils::screenUnitsToMeters( mMapSettings, 1 );
247  if ( scpm > 0 )
248  return 2 * ( accuracy() / scpm );
249  else
250  return 2.0;
251  }
252  return 2.0;
253 }
254 
255 void QgsQuickPositionKit::onUpdateTimeout()
256 {
257  if ( mHasPosition )
258  {
259  mHasPosition = false;
260  emit hasPositionChanged();
261  }
262 }
263 
265 {
266  return mScreenPosition;
267 }
268 
270 {
271  return mScreenAccuracy;
272 }
273 
275 {
276  return mSimulatePositionLongLatRad;
277 }
278 
279 void QgsQuickPositionKit::setSimulatePositionLongLatRad( const QVector<double> &simulatePositionLongLatRad )
280 {
281  mSimulatePositionLongLatRad = simulatePositionLongLatRad;
283 }
284 
286 {
288 }
289 
291 {
292  return mProjectedPosition;
293 }
294 
296 {
297  return mHasPosition;
298 }
299 
301 {
302  return mPosition;
303 }
304 
306 {
307  return mAccuracy;
308 }
309 
311 {
313 }
314 
316 {
317  return mDirection;
318 }
319 
321 {
322  return mIsSimulated;
323 }
324 
326 {
327  if ( mMapSettings == mapSettings )
328  return;
329 
330  if ( mMapSettings )
331  {
332  mMapSettings->disconnect();
333  }
334 
335  mMapSettings = mapSettings;
336 
337  if ( mMapSettings )
338  {
339  connect( mMapSettings, &QgsQuickMapSettings::extentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
340  connect( mMapSettings, &QgsQuickMapSettings::destinationCrsChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
341  connect( mMapSettings, &QgsQuickMapSettings::mapUnitsPerPixelChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
342  connect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
343  connect( mMapSettings, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
344  connect( mMapSettings, &QgsQuickMapSettings::outputDpiChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
345  }
346 
347  emit mapSettingsChanged();
348 }
QgsQuickPositionKit::projectedPositionChanged
void projectedPositionChanged()
GPS position in map coords.
QgsQuickPositionKit::directionChanged
double directionChanged() const
GPS direction, bearing in degrees clockwise from north to direction of travel.
QgsQuickPositionKit::useGpsLocation
Q_INVOKABLE void useGpsLocation()
Use real GPS source (not simulated)
Definition: qgsquickpositionkit.cpp:100
QgsQuickPositionKit::hasPositionChanged
void hasPositionChanged()
hasPosition changed
QgsQuickMapSettings::extentChanged
void extentChanged()
Geographical coordinates of the rectangle that should be rendered.
QgsQuickMapSettings::destinationCrsChanged
void destinationCrsChanged()
CRS of destination coordinate reference system.
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
QgsPoint::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:541
QgsQuickPositionKit::accuracyChanged
double accuracyChanged() const
GPS horizontal accuracy in accuracyUnits, -1 if not available.
QgsQuickPositionKit::positionChanged
void positionChanged()
GPS position in WGS84 coords.
QgsQuickPositionKit::useSimulatedLocation
Q_INVOKABLE void useSimulatedLocation(double longitude, double latitude, double radius)
Use simulated GPS source.
Definition: qgsquickpositionkit.cpp:67
QgsQuickPositionKit::screenPositionChanged
void screenPositionChanged()
GPS position in device coords (pixels).
Qgis::Warning
@ Warning
Definition: qgis.h:91
QgsPoint::z
double z
Definition: qgspoint.h:43
qgis.h
QgsQuickPositionKit::position
QgsPoint position
GPS position in WGS84 coords.
Definition: qgsquickpositionkit.h:49
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsQuickMapSettings::coordinateToScreen
Q_INVOKABLE QPointF coordinateToScreen(const QgsPoint &point) const
Convert a map coordinate to screen pixel coordinates.
Definition: qgsquickmapsettings.cpp:112
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
QgsQuickPositionKit::source
QGeoPositionInfoSource * source
Internal source of GPS location data.
Definition: qgsquickpositionkit.h:121
QgsQuickPositionKit::mapSettings
QgsQuickMapSettings * mapSettings
Associated map settings.
Definition: qgsquickpositionkit.h:105
QgsQuickPositionKit::accuracy
double accuracy
GPS horizontal accuracy in accuracyUnits, -1 if not available.
Definition: qgsquickpositionkit.h:77
QgsQuickMapSettings
The QgsQuickMapSettings class encapsulates QgsMapSettings class to offer settings of configuration of...
Definition: qgsquickmapsettings.h:47
QgsPoint::y
double y
Definition: qgspoint.h:42
QgsQuickPositionKit::simulatePositionLongLatRad
QVector< double > simulatePositionLongLatRad
Uses of GPS and simulated position and sets its parameters.
Definition: qgsquickpositionkit.h:115
QgsQuickMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs
CRS of destination coordinate reference system.
Definition: qgsquickmapsettings.h:105
QgsQuickPositionKit::screenPosition
QPointF screenPosition
GPS position in device coords (pixels).
Definition: qgsquickpositionkit.h:63
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsQuickMapSettings::outputDpiChanged
void outputDpiChanged()
Output DPI used for conversion between real world units (e.g.
QgsPointXY::toString
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:51
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsQuickPositionKit::simulatePositionLongLatRadChanged
void simulatePositionLongLatRadChanged(QVector< double > simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
QgsQuickPositionKit::mapSettingsChanged
void mapSettingsChanged()
Associated map settings.
QgsPoint::x
Q_GADGET double x
Definition: qgspoint.h:41
QgsUnitTypes::DistanceMeters
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
QgsQuickPositionKit::setMapSettings
void setMapSettings(QgsQuickMapSettings *mapSettings)
Associated map settings.
Definition: qgsquickpositionkit.cpp:325
qgsquicksimulatedpositionsource.h
QgsQuickMapSettings::mapUnitsPerPixelChanged
void mapUnitsPerPixelChanged()
Returns the distance in geographical coordinates that equals to one pixel in the map.
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsQuickPositionKit::direction
double direction
GPS direction, bearing in degrees clockwise from north to direction of travel.
Definition: qgsquickpositionkit.h:91
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsQuickMapSettings::transformContext
Q_INVOKABLE QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Definition: qgsquickmapsettings.cpp:70
QgsQuickMapSettings::outputSizeChanged
void outputSizeChanged()
The size of the resulting map image.
QgsQuickPositionKit::screenAccuracyChanged
double screenAccuracyChanged() const
Screen horizontal accuracy, 2 if not available or resolution is too small.
QgsQuickPositionKit::positionCRS
Q_INVOKABLE QgsCoordinateReferenceSystem positionCRS() const
Coordinate reference system of position - WGS84 (constant)
Definition: qgsquickpositionkit.cpp:285
QgsQuickPositionKit::hasPosition
bool hasPosition
GPS position is available (position property is a valid number).
Definition: qgsquickpositionkit.h:70
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsQuickPositionKit::screenAccuracy
double screenAccuracy
Screen horizontal accuracy, 2 if not available or resolution is too small.
Definition: qgsquickpositionkit.h:84
QgsQuickPositionKit::sourceChanged
void sourceChanged()
Emitted when the internal source of GPS location data has been replaced.
QgsQuickUtils::screenUnitsToMeters
static Q_INVOKABLE double screenUnitsToMeters(QgsQuickMapSettings *mapSettings, int baseLengthPixels)
Calculates the distance in meter representing baseLengthPixels pixels on the screen based on the curr...
Definition: qgsquickutils.cpp:76
QgsQuickPositionKit::QgsQuickPositionKit
QgsQuickPositionKit(QObject *parent=nullptr)
Creates new position kit.
Definition: qgsquickpositionkit.cpp:26
qgsquickpositionkit.h
qgsquickutils.h
QgsCoordinateReferenceSystem::fromEpsgId
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
Definition: qgscoordinatereferencesystem.cpp:207
qgslogger.h
QgsQuickPositionKit::accuracyUnits
QgsUnitTypes::DistanceUnit accuracyUnits() const
GPS horizontal accuracy units - meters (constant)
Definition: qgsquickpositionkit.cpp:310
QgsQuickUtils::transformPoint
static Q_INVOKABLE QgsPointXY transformPoint(const QgsCoordinateReferenceSystem &srcCrs, const QgsCoordinateReferenceSystem &destCrs, const QgsCoordinateTransformContext &context, const QgsPointXY &srcPoint)
Transforms point between different crs from QML.
Definition: qgsquickutils.cpp:66
QgsQuickMapSettings::visibleExtentChanged
void visibleExtentChanged()
Returns the actual extent derived from requested extent that takes takes output image size into accou...
QgsQuickPositionKit::projectedPosition
QgsPoint projectedPosition
GPS position in map coords.
Definition: qgsquickpositionkit.h:56
QgsQuickPositionKit::setSimulatePositionLongLatRad
void setSimulatePositionLongLatRad(const QVector< double > &simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
Definition: qgsquickpositionkit.cpp:279
qgsmessagelog.h
QgsQuickPositionKit::isSimulated
bool isSimulated
GPS position and accuracy is simulated (not real from GPS sensor).
Definition: qgsquickpositionkit.h:98