2018-05-16 11:01:00 +02:00
|
|
|
/***************************************************************************
|
|
|
|
qgsquickpositionkit.cpp
|
|
|
|
--------------------------------------
|
|
|
|
Date : Dec. 2017
|
|
|
|
Copyright : (C) 2017 Peter Petrik
|
|
|
|
Email : zilolv at gmail dot com
|
|
|
|
***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
#include <memory>
|
|
|
|
|
2018-05-16 11:01:00 +02:00
|
|
|
#include "qgis.h"
|
|
|
|
#include "qgslogger.h"
|
|
|
|
#include "qgsmessagelog.h"
|
|
|
|
|
|
|
|
#include "qgsquickpositionkit.h"
|
|
|
|
#include "qgsquickutils.h"
|
|
|
|
#include "qgsquicksimulatedpositionsource.h"
|
|
|
|
|
|
|
|
QgsQuickPositionKit::QgsQuickPositionKit( QObject *parent )
|
|
|
|
: QObject( parent )
|
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
connect( this,
|
|
|
|
&QgsQuickPositionKit::simulatePositionLongLatRadChanged,
|
|
|
|
this,
|
|
|
|
&QgsQuickPositionKit::onSimulatePositionLongLatRadChanged );
|
2018-05-16 11:01:00 +02:00
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
useGpsLocation();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QGeoPositionInfoSource *QgsQuickPositionKit::gpsSource()
|
|
|
|
{
|
|
|
|
// this should give us "true" position source
|
|
|
|
// on Linux it comes from Geoclue library
|
2018-05-23 11:39:17 +02:00
|
|
|
std::unique_ptr<QGeoPositionInfoSource> source( QGeoPositionInfoSource::createDefaultSource( nullptr ) );
|
2018-05-16 11:01:00 +02:00
|
|
|
if ( source->error() != QGeoPositionInfoSource::NoError )
|
|
|
|
{
|
|
|
|
QgsMessageLog::logMessage( QStringLiteral( "%1 (%2)" )
|
|
|
|
.arg( tr( "Unable to create default GPS Position Source" ) )
|
|
|
|
.arg( QString::number( ( long )source->error() ) )
|
|
|
|
, QStringLiteral( "QgsQuick" )
|
|
|
|
, Qgis::Warning );
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
return source.release();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QGeoPositionInfoSource *QgsQuickPositionKit::simulatedSource( double longitude, double latitude, double radius )
|
|
|
|
{
|
|
|
|
return new QgsQuickSimulatedPositionSource( this, longitude, latitude, radius );
|
|
|
|
}
|
|
|
|
|
2018-12-07 15:35:52 +01:00
|
|
|
QGeoPositionInfoSource *QgsQuickPositionKit::source() const
|
|
|
|
{
|
|
|
|
return mSource.get();
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
void QgsQuickPositionKit::useSimulatedLocation( double longitude, double latitude, double radius )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
std::unique_ptr<QGeoPositionInfoSource> source( simulatedSource( longitude, latitude, radius ) );
|
2018-05-16 11:01:00 +02:00
|
|
|
mIsSimulated = true;
|
2018-05-23 11:39:17 +02:00
|
|
|
replacePositionSource( source.release() );
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::updateScreenPosition()
|
|
|
|
{
|
|
|
|
if ( !mMapSettings )
|
|
|
|
return;
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
QPointF screenPosition = mapSettings()->coordinateToScreen( projectedPosition() );
|
|
|
|
if ( screenPosition != mScreenPosition )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
mScreenPosition = screenPosition;
|
|
|
|
emit screenPositionChanged();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
void QgsQuickPositionKit::updateScreenAccuracy()
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
if ( !mMapSettings )
|
|
|
|
return;
|
|
|
|
|
|
|
|
double screenAccuracy = calculateScreenAccuracy();
|
|
|
|
if ( !qgsDoubleNear( screenAccuracy, mScreenAccuracy ) )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
mScreenAccuracy = screenAccuracy;
|
|
|
|
emit screenAccuracyChanged();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
void QgsQuickPositionKit::useGpsLocation()
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
|
|
|
QGeoPositionInfoSource *source = gpsSource();
|
|
|
|
mIsSimulated = false;
|
|
|
|
replacePositionSource( source );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::replacePositionSource( QGeoPositionInfoSource *source )
|
|
|
|
{
|
|
|
|
if ( mSource.get() == source )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( mSource )
|
|
|
|
{
|
|
|
|
mSource->disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
mSource.reset( source );
|
2018-12-07 15:35:52 +01:00
|
|
|
emit sourceChanged();
|
2018-05-16 11:01:00 +02:00
|
|
|
|
|
|
|
if ( mSource )
|
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
connect( mSource.get(), &QGeoPositionInfoSource::positionUpdated, this, &QgsQuickPositionKit::onPositionUpdated );
|
2018-05-16 11:01:00 +02:00
|
|
|
connect( mSource.get(), &QGeoPositionInfoSource::updateTimeout, this, &QgsQuickPositionKit::onUpdateTimeout );
|
2018-05-23 11:39:17 +02:00
|
|
|
|
2018-05-16 11:01:00 +02:00
|
|
|
mSource->startUpdates();
|
|
|
|
|
|
|
|
QgsDebugMsg( QStringLiteral( "Position source changed: %1" ).arg( mSource->sourceName() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QgsQuickMapSettings *QgsQuickPositionKit::mapSettings() const
|
|
|
|
{
|
|
|
|
return mMapSettings;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::updateProjectedPosition()
|
|
|
|
{
|
|
|
|
if ( !mMapSettings )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QgsPointXY srcPoint = QgsPointXY( mPosition.x(), mPosition.y() );
|
2018-05-23 11:39:17 +02:00
|
|
|
QgsPointXY projectedPositionXY = QgsQuickUtils::transformPoint(
|
|
|
|
positionCRS(),
|
|
|
|
mMapSettings->destinationCrs(),
|
|
|
|
mMapSettings->transformContext(),
|
|
|
|
srcPoint );
|
|
|
|
|
|
|
|
QgsPoint projectedPosition( projectedPositionXY );
|
|
|
|
projectedPosition.addZValue( mPosition.z() );
|
|
|
|
|
|
|
|
if ( projectedPosition != mProjectedPosition )
|
|
|
|
{
|
|
|
|
mProjectedPosition = projectedPosition;
|
|
|
|
emit projectedPositionChanged();
|
|
|
|
}
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
void QgsQuickPositionKit::onPositionUpdated( const QGeoPositionInfo &info )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
bool hasPosition = info.coordinate().isValid();
|
|
|
|
if ( hasPosition != mHasPosition )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
mHasPosition = hasPosition;
|
2018-05-16 11:01:00 +02:00
|
|
|
emit hasPositionChanged();
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
// Calculate position
|
|
|
|
QgsPoint position = QgsPoint(
|
|
|
|
info.coordinate().longitude(),
|
2018-05-16 11:01:00 +02:00
|
|
|
info.coordinate().latitude(),
|
|
|
|
info.coordinate().altitude() ); // can be NaN
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
if ( position != mPosition )
|
|
|
|
{
|
|
|
|
mPosition = position;
|
|
|
|
emit positionChanged();
|
|
|
|
}
|
|
|
|
// calculate accuracy
|
|
|
|
double accuracy;
|
2018-05-16 11:01:00 +02:00
|
|
|
if ( info.hasAttribute( QGeoPositionInfo::HorizontalAccuracy ) )
|
2018-05-23 11:39:17 +02:00
|
|
|
accuracy = info.attribute( QGeoPositionInfo::HorizontalAccuracy );
|
2018-05-16 11:01:00 +02:00
|
|
|
else
|
2018-05-23 11:39:17 +02:00
|
|
|
accuracy = -1;
|
|
|
|
if ( !qgsDoubleNear( accuracy, mAccuracy ) )
|
|
|
|
{
|
|
|
|
mAccuracy = accuracy;
|
|
|
|
emit accuracyChanged();
|
|
|
|
}
|
2018-05-16 11:01:00 +02:00
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
// calculate direction
|
|
|
|
double direction;
|
2018-05-16 11:01:00 +02:00
|
|
|
if ( info.hasAttribute( QGeoPositionInfo::Direction ) )
|
2018-05-23 11:39:17 +02:00
|
|
|
direction = info.attribute( QGeoPositionInfo::Direction );
|
2018-05-16 11:01:00 +02:00
|
|
|
else
|
2018-05-23 11:39:17 +02:00
|
|
|
direction = -1;
|
|
|
|
if ( !qgsDoubleNear( direction, mDirection ) )
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
mDirection = direction;
|
|
|
|
emit directionChanged();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
2018-05-23 11:39:17 +02:00
|
|
|
|
|
|
|
// recalculate projected/screen variables
|
|
|
|
onMapSettingsUpdated();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::onMapSettingsUpdated()
|
|
|
|
{
|
|
|
|
updateProjectedPosition();
|
|
|
|
|
|
|
|
updateScreenAccuracy();
|
|
|
|
updateScreenPosition();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
2018-05-23 11:39:17 +02:00
|
|
|
|
2018-05-16 11:01:00 +02:00
|
|
|
void QgsQuickPositionKit::onSimulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad )
|
|
|
|
{
|
|
|
|
if ( simulatePositionLongLatRad.size() > 2 )
|
|
|
|
{
|
|
|
|
double longitude = simulatePositionLongLatRad[0];
|
|
|
|
double latitude = simulatePositionLongLatRad[1];
|
|
|
|
double radius = simulatePositionLongLatRad[2];
|
|
|
|
QgsDebugMsg( QStringLiteral( "Use simulated position around longlat: %1, %2, %3" ).arg( longitude ).arg( latitude ).arg( radius ) );
|
2018-05-23 11:39:17 +02:00
|
|
|
useSimulatedLocation( longitude, latitude, radius );
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QgsDebugMsg( QStringLiteral( "Unable to set simulated position due to the input errors." ) );
|
2018-05-23 11:39:17 +02:00
|
|
|
useGpsLocation();
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double QgsQuickPositionKit::calculateScreenAccuracy()
|
|
|
|
{
|
|
|
|
if ( !mMapSettings )
|
|
|
|
return 2.0;
|
|
|
|
|
|
|
|
if ( accuracy() > 0 )
|
|
|
|
{
|
|
|
|
double scpm = QgsQuickUtils::screenUnitsToMeters( mMapSettings, 1 );
|
|
|
|
if ( scpm > 0 )
|
|
|
|
return 2 * ( accuracy() / scpm );
|
|
|
|
else
|
|
|
|
return 2.0;
|
|
|
|
}
|
|
|
|
return 2.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::onUpdateTimeout()
|
|
|
|
{
|
|
|
|
if ( mHasPosition )
|
|
|
|
{
|
|
|
|
mHasPosition = false;
|
|
|
|
emit hasPositionChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QPointF QgsQuickPositionKit::screenPosition() const
|
|
|
|
{
|
|
|
|
return mScreenPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
double QgsQuickPositionKit::screenAccuracy() const
|
|
|
|
{
|
|
|
|
return mScreenAccuracy;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<double> QgsQuickPositionKit::simulatePositionLongLatRad() const
|
|
|
|
{
|
|
|
|
return mSimulatePositionLongLatRad;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::setSimulatePositionLongLatRad( const QVector<double> &simulatePositionLongLatRad )
|
|
|
|
{
|
|
|
|
mSimulatePositionLongLatRad = simulatePositionLongLatRad;
|
|
|
|
emit simulatePositionLongLatRadChanged( simulatePositionLongLatRad );
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
QgsCoordinateReferenceSystem QgsQuickPositionKit::positionCRS() const
|
|
|
|
{
|
|
|
|
return QgsCoordinateReferenceSystem::fromEpsgId( 4326 );
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:01:00 +02:00
|
|
|
QgsPoint QgsQuickPositionKit::projectedPosition() const
|
|
|
|
{
|
|
|
|
return mProjectedPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QgsQuickPositionKit::hasPosition() const
|
|
|
|
{
|
|
|
|
return mHasPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
QgsPoint QgsQuickPositionKit::position() const
|
|
|
|
{
|
|
|
|
return mPosition;
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
double QgsQuickPositionKit::accuracy() const
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
|
|
|
return mAccuracy;
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
QgsUnitTypes::DistanceUnit QgsQuickPositionKit::accuracyUnits() const
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
return QgsUnitTypes::DistanceMeters;
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
double QgsQuickPositionKit::direction() const
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
|
|
|
return mDirection;
|
|
|
|
}
|
|
|
|
|
2018-05-23 11:39:17 +02:00
|
|
|
bool QgsQuickPositionKit::isSimulated() const
|
2018-05-16 11:01:00 +02:00
|
|
|
{
|
|
|
|
return mIsSimulated;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsQuickPositionKit::setMapSettings( QgsQuickMapSettings *mapSettings )
|
|
|
|
{
|
|
|
|
if ( mMapSettings == mapSettings )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( mMapSettings )
|
|
|
|
{
|
|
|
|
mMapSettings->disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
mMapSettings = mapSettings;
|
|
|
|
|
|
|
|
if ( mMapSettings )
|
|
|
|
{
|
2018-05-23 11:39:17 +02:00
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::extentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::destinationCrsChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::mapUnitsPerPixelChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::outputSizeChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
|
|
|
connect( mMapSettings, &QgsQuickMapSettings::outputDpiChanged, this, &QgsQuickPositionKit::onMapSettingsUpdated );
|
2018-05-16 11:01:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
emit mapSettingsChanged();
|
|
|
|
}
|