QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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->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 = QgsQuickUtils::transformPoint(
143  positionCRS(),
144  mMapSettings->destinationCrs(),
145  mMapSettings->transformContext(),
146  srcPoint );
147 
148  QgsPoint projectedPosition( projectedPositionXY );
149  projectedPosition.addZValue( mPosition.z() );
150 
151  if ( projectedPosition != mProjectedPosition )
152  {
153  mProjectedPosition = projectedPosition;
155  }
156 }
157 
158 void QgsQuickPositionKit::onPositionUpdated( const QGeoPositionInfo &info )
159 {
160  bool hasPosition = info.coordinate().isValid();
161  if ( hasPosition != mHasPosition )
162  {
163  mHasPosition = hasPosition;
164  emit hasPositionChanged();
165  }
166 
167  // Calculate position
169  info.coordinate().longitude(),
170  info.coordinate().latitude(),
171  info.coordinate().altitude() ); // can be NaN
172 
173  if ( position != mPosition )
174  {
175  mPosition = position;
176  emit positionChanged();
177  }
178  // calculate accuracy
179  double accuracy;
180  if ( info.hasAttribute( QGeoPositionInfo::HorizontalAccuracy ) )
181  accuracy = info.attribute( QGeoPositionInfo::HorizontalAccuracy );
182  else
183  accuracy = -1;
184  if ( !qgsDoubleNear( accuracy, mAccuracy ) )
185  {
186  mAccuracy = accuracy;
187  emit accuracyChanged();
188  }
189 
190  // calculate direction
191  double direction;
192  if ( info.hasAttribute( QGeoPositionInfo::Direction ) )
193  direction = info.attribute( QGeoPositionInfo::Direction );
194  else
195  direction = -1;
196  if ( !qgsDoubleNear( direction, mDirection ) )
197  {
198  mDirection = direction;
199  emit directionChanged();
200  }
201 
202  // recalculate projected/screen variables
203  onMapSettingsUpdated();
204 }
205 
206 void QgsQuickPositionKit::onMapSettingsUpdated()
207 {
208  updateProjectedPosition();
209 
210  updateScreenAccuracy();
211  updateScreenPosition();
212 }
213 
214 void QgsQuickPositionKit::onSimulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad )
215 {
216  if ( simulatePositionLongLatRad.size() > 2 )
217  {
218  double longitude = simulatePositionLongLatRad[0];
219  double latitude = simulatePositionLongLatRad[1];
220  double radius = simulatePositionLongLatRad[2];
221  QgsDebugMsg( QStringLiteral( "Use simulated position around longlat: %1, %2, %3" ).arg( longitude ).arg( latitude ).arg( radius ) );
222  useSimulatedLocation( longitude, latitude, radius );
223  }
224  else
225  {
226  QgsDebugMsg( QStringLiteral( "Unable to set simulated position due to the input errors." ) );
227  useGpsLocation();
228  }
229 }
230 
231 double QgsQuickPositionKit::calculateScreenAccuracy()
232 {
233  if ( !mMapSettings )
234  return 2.0;
235 
236  if ( accuracy() > 0 )
237  {
238  double scpm = QgsQuickUtils::screenUnitsToMeters( mMapSettings, 1 );
239  if ( scpm > 0 )
240  return 2 * ( accuracy() / scpm );
241  else
242  return 2.0;
243  }
244  return 2.0;
245 }
246 
247 void QgsQuickPositionKit::onUpdateTimeout()
248 {
249  if ( mHasPosition )
250  {
251  mHasPosition = false;
252  emit hasPositionChanged();
253  }
254 }
255 
257 {
258  return mScreenPosition;
259 }
260 
262 {
263  return mScreenAccuracy;
264 }
265 
267 {
268  return mSimulatePositionLongLatRad;
269 }
270 
272 {
273  mSimulatePositionLongLatRad = simulatePositionLongLatRad;
274  emit simulatePositionLongLatRadChanged( simulatePositionLongLatRad );
275 }
276 
278 {
280 }
281 
283 {
284  return mProjectedPosition;
285 }
286 
288 {
289  return mHasPosition;
290 }
291 
293 {
294  return mPosition;
295 }
296 
297 double QgsQuickPositionKit::accuracy() const
298 {
299  return mAccuracy;
300 }
301 
303 {
305 }
306 
307 double QgsQuickPositionKit::direction() const
308 {
309  return mDirection;
310 }
311 
313 {
314  return mIsSimulated;
315 }
316 
318 {
319  if ( mMapSettings == mapSettings )
320  return;
321 
322  if ( mMapSettings )
323  {
324  mMapSettings->disconnect();
325  }
326 
327  mMapSettings = mapSettings;
328 
329  if ( mMapSettings )
330  {
331  connect( mMapSettings, &QgsQuickMapSettings::extentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
332  connect( mMapSettings, &QgsQuickMapSettings::destinationCrsChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
333  connect( mMapSettings, &QgsQuickMapSettings::mapUnitsPerPixelChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
334  connect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
335  connect( mMapSettings, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
336  connect( mMapSettings, &QgsQuickMapSettings::outputDpiChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
337  }
338 
339  emit mapSettingsChanged();
340 }
void visibleExtentChanged()
Returns the actual extent derived from requested extent that takes takes output image size into accou...
void positionChanged()
GPS position in WGS84 coords.
double y
Definition: qgspoint.h:42
void setMapSettings(QgsQuickMapSettings *mapSettings)
Associated map settings.
double accuracy() const
GPS horizontal accuracy in accuracyUnits, -1 if not available.
QgsQuickPositionKit(QObject *parent=nullptr)
Creates new position kit.
Q_INVOKABLE void useGpsLocation()
Use real GPS source (not simulated)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void extentChanged()
Geographical coordinates of the rectangle that should be rendered.
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
QPointF screenPosition() const
GPS position in device coords (pixels).
void setSimulatePositionLongLatRad(const QVector< double > &simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
The QgsQuickMapSettings class encapsulates QgsMapSettings class to offer settings of configuration of...
static Q_INVOKABLE double screenUnitsToMeters(QgsQuickMapSettings *mapSettings, int baseLengthPixels)
Calculates the distance in meter representing baseLengthPixels pixels on the screen based on the curr...
void projectedPositionChanged()
GPS position in map coords.
void outputDpiChanged()
Output DPI used for conversion between real world units (e.g.
Q_INVOKABLE QPointF coordinateToScreen(const QgsPoint &point) const
Convert a map coordinate to screen pixel coordinates.
void mapUnitsPerPixelChanged()
Returns the distance in geographical coordinates that equals to one pixel in the map.
static Q_INVOKABLE QgsPointXY transformPoint(const QgsCoordinateReferenceSystem &srcCrs, const QgsCoordinateReferenceSystem &destCrs, const QgsCoordinateTransformContext &context, const QgsPointXY &srcPoint)
Transforms point between different crs from QML.
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
Q_INVOKABLE QgsCoordinateReferenceSystem positionCRS() const
Coordinate reference system of position - WGS84 (constant)
QGeoPositionInfoSource * source() const
Returns pointer to the internal QGeoPositionInfoSource object used to receive GPS location...
Q_INVOKABLE void useSimulatedLocation(double longitude, double latitude, double radius)
Use simulated GPS source.
void screenPositionChanged()
GPS position in device coords (pixels).
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).
QgsPoint projectedPosition() const
GPS position in map coords.
QVector< double > simulatePositionLongLatRad() const
Uses of GPS and simulated position and sets its parameters.
bool isSimulated() const
GPS position and accuracy is simulated (not real from GPS sensor).
void destinationCrsChanged()
CRS of destination coordinate reference system.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
bool hasPosition() const
GPS position in WGS84 coords.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:54
QgsCoordinateReferenceSystem destinationCrs
CRS of destination coordinate reference system.
double accuracyChanged() const
GPS horizontal accuracy in accuracyUnits, -1 if not available.
void sourceChanged()
Emitted when the internal source of GPS location data has been replaced.
double directionChanged() const
GPS direction, bearing in degrees clockwise from north to direction of travel.
void outputSizeChanged()
The size of the resulting map image.
QgsUnitTypes::DistanceUnit accuracyUnits() const
GPS horizontal accuracy units - meters (constant)
This class represents a coordinate reference system (CRS).
void simulatePositionLongLatRadChanged(QVector< double > simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
QgsPoint position() const
GPS position in WGS84 coords.
double direction() const
GPS direction, bearing in degrees clockwise from north to direction of travel.
void mapSettingsChanged()
Associated map settings.
double z
Definition: qgspoint.h:43
Q_INVOKABLE QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
void hasPositionChanged()
hasPosition changed
double screenAccuracy() const
Screen horizontal accuracy, 2 if not available or resolution is too small.
QgsQuickMapSettings * mapSettings() const
Associated map settings.
double x
Definition: qgspoint.h:41
double screenAccuracyChanged() const
Screen horizontal accuracy, 2 if not available or resolution is too small.