QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 void QgsQuickPositionKit::useSimulatedLocation( double longitude, double latitude, double radius )
63 {
64  std::unique_ptr<QGeoPositionInfoSource> source( simulatedSource( longitude, latitude, radius ) );
65  mIsSimulated = true;
66  replacePositionSource( source.release() );
67 }
68 
69 void QgsQuickPositionKit::updateScreenPosition()
70 {
71  if ( !mMapSettings )
72  return;
73 
75  if ( screenPosition != mScreenPosition )
76  {
77  mScreenPosition = screenPosition;
78  emit screenPositionChanged();
79  }
80 }
81 
82 void QgsQuickPositionKit::updateScreenAccuracy()
83 {
84  if ( !mMapSettings )
85  return;
86 
87  double screenAccuracy = calculateScreenAccuracy();
88  if ( !qgsDoubleNear( screenAccuracy, mScreenAccuracy ) )
89  {
90  mScreenAccuracy = screenAccuracy;
91  emit screenAccuracyChanged();
92  }
93 }
94 
96 {
97  QGeoPositionInfoSource *source = gpsSource();
98  mIsSimulated = false;
99  replacePositionSource( source );
100 }
101 
102 void QgsQuickPositionKit::replacePositionSource( QGeoPositionInfoSource *source )
103 {
104  if ( mSource.get() == source )
105  return;
106 
107  if ( mSource )
108  {
109  mSource->disconnect();
110  }
111 
112  mSource.reset( source );
113 
114  if ( mSource )
115  {
116  connect( mSource.get(), &QGeoPositionInfoSource::positionUpdated, this, &QgsQuickPositionKit::onPositionUpdated );
117  connect( mSource.get(), &QGeoPositionInfoSource::updateTimeout, this, &QgsQuickPositionKit::onUpdateTimeout );
118 
119  mSource->startUpdates();
120 
121  QgsDebugMsg( QStringLiteral( "Position source changed: %1" ).arg( mSource->sourceName() ) );
122  }
123 }
124 
126 {
127  return mMapSettings;
128 }
129 
130 void QgsQuickPositionKit::updateProjectedPosition()
131 {
132  if ( !mMapSettings )
133  return;
134 
135  QgsPointXY srcPoint = QgsPointXY( mPosition.x(), mPosition.y() );
136  QgsPointXY projectedPositionXY = QgsQuickUtils::transformPoint(
137  positionCRS(),
138  mMapSettings->destinationCrs(),
139  mMapSettings->transformContext(),
140  srcPoint );
141 
142  QgsPoint projectedPosition( projectedPositionXY );
143  projectedPosition.addZValue( mPosition.z() );
144 
145  if ( projectedPosition != mProjectedPosition )
146  {
147  mProjectedPosition = projectedPosition;
149  }
150 }
151 
152 void QgsQuickPositionKit::onPositionUpdated( const QGeoPositionInfo &info )
153 {
154  bool hasPosition = info.coordinate().isValid();
155  if ( hasPosition != mHasPosition )
156  {
157  mHasPosition = hasPosition;
158  emit hasPositionChanged();
159  }
160 
161  // Calculate position
163  info.coordinate().longitude(),
164  info.coordinate().latitude(),
165  info.coordinate().altitude() ); // can be NaN
166 
167  if ( position != mPosition )
168  {
169  mPosition = position;
170  emit positionChanged();
171  }
172  // calculate accuracy
173  double accuracy;
174  if ( info.hasAttribute( QGeoPositionInfo::HorizontalAccuracy ) )
175  accuracy = info.attribute( QGeoPositionInfo::HorizontalAccuracy );
176  else
177  accuracy = -1;
178  if ( !qgsDoubleNear( accuracy, mAccuracy ) )
179  {
180  mAccuracy = accuracy;
181  emit accuracyChanged();
182  }
183 
184  // calculate direction
185  double direction;
186  if ( info.hasAttribute( QGeoPositionInfo::Direction ) )
187  direction = info.attribute( QGeoPositionInfo::Direction );
188  else
189  direction = -1;
190  if ( !qgsDoubleNear( direction, mDirection ) )
191  {
192  mDirection = direction;
193  emit directionChanged();
194  }
195 
196  // recalculate projected/screen variables
197  onMapSettingsUpdated();
198 }
199 
200 void QgsQuickPositionKit::onMapSettingsUpdated()
201 {
202  updateProjectedPosition();
203 
204  updateScreenAccuracy();
205  updateScreenPosition();
206 }
207 
208 void QgsQuickPositionKit::onSimulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad )
209 {
210  if ( simulatePositionLongLatRad.size() > 2 )
211  {
212  double longitude = simulatePositionLongLatRad[0];
213  double latitude = simulatePositionLongLatRad[1];
214  double radius = simulatePositionLongLatRad[2];
215  QgsDebugMsg( QStringLiteral( "Use simulated position around longlat: %1, %2, %3" ).arg( longitude ).arg( latitude ).arg( radius ) );
216  useSimulatedLocation( longitude, latitude, radius );
217  }
218  else
219  {
220  QgsDebugMsg( QStringLiteral( "Unable to set simulated position due to the input errors." ) );
221  useGpsLocation();
222  }
223 }
224 
225 double QgsQuickPositionKit::calculateScreenAccuracy()
226 {
227  if ( !mMapSettings )
228  return 2.0;
229 
230  if ( accuracy() > 0 )
231  {
232  double scpm = QgsQuickUtils::screenUnitsToMeters( mMapSettings, 1 );
233  if ( scpm > 0 )
234  return 2 * ( accuracy() / scpm );
235  else
236  return 2.0;
237  }
238  return 2.0;
239 }
240 
241 void QgsQuickPositionKit::onUpdateTimeout()
242 {
243  if ( mHasPosition )
244  {
245  mHasPosition = false;
246  emit hasPositionChanged();
247  }
248 }
249 
251 {
252  return mScreenPosition;
253 }
254 
256 {
257  return mScreenAccuracy;
258 }
259 
261 {
262  return mSimulatePositionLongLatRad;
263 }
264 
266 {
267  mSimulatePositionLongLatRad = simulatePositionLongLatRad;
268  emit simulatePositionLongLatRadChanged( simulatePositionLongLatRad );
269 }
270 
272 {
274 }
275 
277 {
278  return mProjectedPosition;
279 }
280 
282 {
283  return mHasPosition;
284 }
285 
287 {
288  return mPosition;
289 }
290 
291 double QgsQuickPositionKit::accuracy() const
292 {
293  return mAccuracy;
294 }
295 
297 {
299 }
300 
301 double QgsQuickPositionKit::direction() const
302 {
303  return mDirection;
304 }
305 
307 {
308  return mIsSimulated;
309 }
310 
312 {
313  if ( mMapSettings == mapSettings )
314  return;
315 
316  if ( mMapSettings )
317  {
318  mMapSettings->disconnect();
319  }
320 
321  mMapSettings = mapSettings;
322 
323  if ( mMapSettings )
324  {
325  connect( mMapSettings, &QgsQuickMapSettings::extentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
326  connect( mMapSettings, &QgsQuickMapSettings::destinationCrsChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
327  connect( mMapSettings, &QgsQuickMapSettings::mapUnitsPerPixelChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
328  connect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
329  connect( mMapSettings, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
330  connect( mMapSettings, &QgsQuickMapSettings::outputDpiChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
331  }
332 
333  emit mapSettingsChanged();
334 }
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 screenAccuracyChanged() const
Screen horizontal accuracy, 2 if not available or resolution is too small.
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:278
double direction() const
GPS direction, bearing in degrees clockwise from north to direction of travel.
void setSimulatePositionLongLatRad(const QVector< double > &simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
Q_INVOKABLE QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
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.
void mapUnitsPerPixelChanged()
Returns the distance in geographical coordinates that equals to one pixel in the map.
QgsQuickMapSettings * mapSettings() const
Associated map settings.
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.
double accuracy() const
GPS horizontal accuracy in accuracyUnits, -1 if not available.
bool hasPosition() const
GPS position in WGS84 coords.
QgsUnitTypes::DistanceUnit accuracyUnits() const
GPS horizontal accuracy units - meters (constant)
Q_INVOKABLE void useSimulatedLocation(double longitude, double latitude, double radius)
Use simulated GPS source.
void screenPositionChanged()
GPS position in device coords (pixels).
QgsPoint position() const
GPS position in WGS84 coords.
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).
void destinationCrsChanged()
CRS of destination coordinate reference system.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double directionChanged() const
GPS direction, bearing in degrees clockwise from north to direction of travel.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:53
QgsCoordinateReferenceSystem destinationCrs
CRS of destination coordinate reference system.
QgsPoint projectedPosition() const
GPS position in map coords.
void outputSizeChanged()
The size of the resulting map image.
bool isSimulated() const
GPS position and accuracy is simulated (not real from GPS sensor).
This class represents a coordinate reference system (CRS).
Q_INVOKABLE QPointF coordinateToScreen(const QgsPoint &point) const
Convert a map coordinate to screen pixel coordinates.
void simulatePositionLongLatRadChanged(QVector< double > simulatePositionLongLatRad)
Uses of GPS and simulated position and sets its parameters.
void mapSettingsChanged()
Associated map settings.
Q_INVOKABLE QgsCoordinateReferenceSystem positionCRS() const
Coordinate reference system of position - WGS84 (constant)
double screenAccuracy() const
Screen horizontal accuracy, 2 if not available or resolution is too small.
double z
Definition: qgspoint.h:43
QVector< double > simulatePositionLongLatRad() const
Uses of GPS and simulated position and sets its parameters.
double accuracyChanged() const
GPS horizontal accuracy in accuracyUnits, -1 if not available.
void hasPositionChanged()
hasPosition changed
double x
Definition: qgspoint.h:41
QPointF screenPosition() const
GPS position in device coords (pixels).