mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
Merge pull request #7045 from PeterPetrik/qgs-quick-position_and_transformer
[feature] [qgsquick] Add PositionKit, PositionMarker and CoordinateTransformer
This commit is contained in:
commit
569db8e069
@ -13,12 +13,13 @@ QGIS Quick consists of a Qt plugin that provides the QML components and of a sha
|
||||
|
||||
\subsection qgsquick_overview_widgets QML Classes
|
||||
\subsubsection qgsquick_overview_widgets_mapcanvas MapCanvas
|
||||
Similarly to QgsMapCanvas, this component can be used for displaying GIS data on a canvas. See also QgsQuickMapCanvasMap.
|
||||
\subsubsection qgsquick_overview_widgets_positionmarker PositionMarker
|
||||
The element refers to current position according gps location device connected to it. It holds information about longitude, latitude, altitude,
|
||||
direction of the movement and accuracy of the signal. See also QgsQuickPositionKit.
|
||||
\subsubsection qgsquick_overview_widgets_scalebar ScaleBar
|
||||
A QML component that shows the scale ratio between its length and distance on the MapCanvas. There are predefined rounded values
|
||||
for several zooming levels with 'm' or 'km' postfixes. After any zoom in/out event on canvas recalculates its properties and updates
|
||||
text. See also QgsQuickScaleBarKit.
|
||||
|
||||
\subsubsection qgsquick_overview_widgets_messagelog MessageLog
|
||||
A simple panel which can be used for publishing logs messages to a user such as basic information about the application or its status.
|
||||
See also QgsQuickMessageLogModel.
|
||||
|
@ -1,4 +1,5 @@
|
||||
# The following has been generated automatically from src/core/qgsunittypes.h
|
||||
QgsUnitTypes.SystemOfMeasurement.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.DistanceUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.AreaUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.AngleUnit.baseClass = QgsUnitTypes
|
||||
|
@ -26,6 +26,14 @@ Helper functions for various unit types.
|
||||
static const QMetaObject staticMetaObject;
|
||||
|
||||
public:
|
||||
enum SystemOfMeasurement
|
||||
{
|
||||
UnknownSystem,
|
||||
MetricSystem,
|
||||
ImperialSystem,
|
||||
USCSSystem
|
||||
};
|
||||
|
||||
enum DistanceUnit
|
||||
{
|
||||
DistanceMeters,
|
||||
|
@ -39,6 +39,16 @@ class CORE_EXPORT QgsUnitTypes
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
//! Systems of unit measurement
|
||||
enum SystemOfMeasurement
|
||||
{
|
||||
UnknownSystem = 0, //!< Unknown system of measurement
|
||||
MetricSystem, //!< International System of Units (SI)
|
||||
ImperialSystem, //!< British Imperial
|
||||
USCSSystem //!< United States customary system
|
||||
};
|
||||
Q_ENUM( SystemOfMeasurement )
|
||||
|
||||
//! Units of distance
|
||||
enum DistanceUnit
|
||||
{
|
||||
|
@ -2,13 +2,16 @@
|
||||
# sources
|
||||
SET(QGIS_QUICK_GUI_MOC_HDRS
|
||||
qgsquickfeaturelayerpair.h
|
||||
qgsquickcoordinatetransformer.h
|
||||
qgsquickfeaturehighlight.h
|
||||
qgsquickidentifykit.h
|
||||
qgsquickmapcanvasmap.h
|
||||
qgsquickmapsettings.h
|
||||
qgsquickmaptransform.h
|
||||
qgsquickmessagelogmodel.h
|
||||
qgsquickpositionkit.h
|
||||
qgsquickscalebarkit.h
|
||||
qgsquicksimulatedpositionsource.h
|
||||
qgsquickutils.h
|
||||
)
|
||||
|
||||
@ -18,6 +21,7 @@ SET(QGIS_QUICK_GUI_HDRS
|
||||
|
||||
SET(QGIS_QUICK_GUI_SRC
|
||||
qgsquickfeaturelayerpair.cpp
|
||||
qgsquickcoordinatetransformer.cpp
|
||||
qgsquickfeaturehighlight.cpp
|
||||
qgsquickhighlightsgnode.cpp
|
||||
qgsquickidentifykit.cpp
|
||||
@ -25,7 +29,9 @@ SET(QGIS_QUICK_GUI_SRC
|
||||
qgsquickmapsettings.cpp
|
||||
qgsquickmaptransform.cpp
|
||||
qgsquickmessagelogmodel.cpp
|
||||
qgsquickpositionkit.cpp
|
||||
qgsquickscalebarkit.cpp
|
||||
qgsquicksimulatedpositionsource.cpp
|
||||
qgsquickutils.cpp
|
||||
)
|
||||
|
||||
@ -69,6 +75,10 @@ INCLUDE_DIRECTORIES(SYSTEM
|
||||
|
||||
ADD_DEFINITIONS(-DCORE_EXPORT=)
|
||||
|
||||
|
||||
SET(QGIS_QUICK_GUI_IMAGE_RCCS ./images/images.qrc)
|
||||
QT5_ADD_RESOURCES(QGIS_QUICK_GUI_IMAGE_RCC_SRCS ${QGIS_QUICK_GUI_IMAGE_RCCS})
|
||||
|
||||
############################################################
|
||||
# qgis_quick shared library
|
||||
QT5_WRAP_CPP(QGIS_QUICK_GUI_MOC_SRCS ${QGIS_QUICK_GUI_MOC_HDRS})
|
||||
|
4
src/quickgui/images/ic_navigation_black.svg
Normal file
4
src/quickgui/images/ic_navigation_black.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg fill="#000000" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 208 B |
5
src/quickgui/images/images.qrc
Normal file
5
src/quickgui/images/images.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>ic_navigation_black.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -12,6 +12,7 @@ SET(QGIS_QUICK_PLUGIN_SRC
|
||||
SET(QGIS_QUICK_PLUGIN_RESOURCES
|
||||
qgsquickmapcanvas.qml
|
||||
qgsquickmessagelog.qml
|
||||
qgsquickpositionmarker.qml
|
||||
qgsquickscalebar.qml
|
||||
qmldir
|
||||
)
|
||||
@ -108,8 +109,9 @@ IF(QMLPLUGINDUMP_FOUND)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${QGIS_QUICK_TYPEINFO_GENERATE_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:qgis_quick_plugin> ${QGIS_QUICK_TYPEINFO_GENERATE_DIR}
|
||||
COMMAND ${QMLPLUGINDUMP_EXECUTABLE}
|
||||
ARGS QgsQuick ${QGIS_QUICK_VERSION} . --output ${QGIS_QUICK_PLUGIN_TYPEINFO}
|
||||
ARGS QgsQuick ${QGIS_QUICK_VERSION} . -noinstantiate --output ${QGIS_QUICK_PLUGIN_TYPEINFO}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
COMMENT "Generating qgsquick.qmltypes with qmlplugindump"
|
||||
POST_BUILD
|
||||
)
|
||||
ENDIF()
|
||||
|
@ -28,8 +28,10 @@
|
||||
#include "qgsrelationmanager.h"
|
||||
#include "qgscoordinatetransformcontext.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsunittypes.h"
|
||||
|
||||
#include "qgsquickfeaturehighlight.h"
|
||||
#include "qgsquickcoordinatetransformer.h"
|
||||
#include "qgsquickidentifykit.h"
|
||||
#include "qgsquickfeaturelayerpair.h"
|
||||
#include "qgsquickmapcanvasmap.h"
|
||||
@ -37,6 +39,7 @@
|
||||
#include "qgsquickmaptransform.h"
|
||||
#include "qgsquickmessagelogmodel.h"
|
||||
#include "qgsquickplugin.h"
|
||||
#include "qgsquickpositionkit.h"
|
||||
#include "qgsquickscalebarkit.h"
|
||||
#include "qgsquickutils.h"
|
||||
|
||||
@ -58,14 +61,22 @@ void QgsQuickPlugin::registerTypes( const char *uri )
|
||||
qRegisterMetaType< QgsPoint >( "QgsPoint" );
|
||||
qRegisterMetaType< QgsPointXY >( "QgsPointXY" );
|
||||
qRegisterMetaType< QgsQuickFeatureLayerPair >( "QgsQuickFeatureLayerPair" );
|
||||
qRegisterMetaType< QgsUnitTypes::SystemOfMeasurement >( "QgsUnitTypes::SystemOfMeasurement" );
|
||||
qRegisterMetaType< QgsUnitTypes::DistanceUnit >( "QgsUnitTypes::DistanceUnit" );
|
||||
qRegisterMetaType< QgsCoordinateFormatter::FormatFlags >( "QgsCoordinateFormatter::FormatFlags" );
|
||||
qRegisterMetaType< QgsCoordinateFormatter::Format >( "QgsCoordinateFormatter::Format" );
|
||||
|
||||
qmlRegisterUncreatableType< QgsUnitTypes >( uri, 0, 1, "QgsUnitTypes", "Only enums from QgsUnitTypes can be used" );
|
||||
|
||||
qmlRegisterType< QgsProject >( uri, 0, 1, "Project" );
|
||||
qmlRegisterType< QgsQuickFeatureHighlight >( uri, 0, 1, "FeatureHighlight" );
|
||||
qmlRegisterType< QgsQuickCoordinateTransformer >( uri, 0, 1, "CoordinateTransformer" );
|
||||
qmlRegisterType< QgsQuickIdentifyKit >( uri, 0, 1, "IdentifyKit" );
|
||||
qmlRegisterType< QgsQuickMapCanvasMap >( uri, 0, 1, "MapCanvasMap" );
|
||||
qmlRegisterType< QgsQuickMapSettings >( uri, 0, 1, "MapSettings" );
|
||||
qmlRegisterType< QgsQuickMapTransform >( uri, 0, 1, "MapTransform" );
|
||||
qmlRegisterType< QgsQuickMessageLogModel >( uri, 0, 1, "MessageLogModel" );
|
||||
qmlRegisterType< QgsQuickPositionKit >( uri, 0, 1, "PositionKit" );
|
||||
qmlRegisterType< QgsQuickScaleBarKit >( uri, 0, 1, "ScaleBarKit" );
|
||||
qmlRegisterType< QgsVectorLayer >( uri, 0, 1, "VectorLayer" );
|
||||
|
||||
|
115
src/quickgui/plugin/qgsquickpositionmarker.qml
Normal file
115
src/quickgui/plugin/qgsquickpositionmarker.qml
Normal file
@ -0,0 +1,115 @@
|
||||
/***************************************************************************
|
||||
qgsquickpositionmarker.qml
|
||||
--------------------------------------
|
||||
Date : Dec 2017
|
||||
Copyright : (C) 2017 by 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQml 2.2
|
||||
import QtGraphicalEffects 1.0
|
||||
import QgsQuick 0.1 as QgsQuick
|
||||
|
||||
/**
|
||||
* \brief Graphical representation of physical location on the map.
|
||||
*
|
||||
* Source position and accuracy taken from PositionKit is drawn as a marker on the map.
|
||||
* Marker is grayed out when position is not available. When PositionKit support reading of the accuracy,
|
||||
* the circle is drawn around the marker. PositionKit must be connected, for example GPS position source from QgsQuickPositionKit.
|
||||
*/
|
||||
Item {
|
||||
id: positionMarker
|
||||
property int size: 48 * QgsQuick.Utils.dp
|
||||
|
||||
/**
|
||||
* Utils for handling position.
|
||||
*/
|
||||
property QgsQuick.PositionKit positionKit
|
||||
|
||||
/**
|
||||
* Color of the marker when position is known.
|
||||
*/
|
||||
property color baseColor: "darkblue"
|
||||
/**
|
||||
* Color of the marker when position is unknown (e.g. GPS signal lost).
|
||||
*/
|
||||
property color unavailableColor: "gray"
|
||||
|
||||
/**
|
||||
* Whether circle representing accuracy of the position should be rendered.
|
||||
*/
|
||||
property bool withAccuracy: true
|
||||
|
||||
/**
|
||||
* Icon for position marker.
|
||||
*/
|
||||
property var markerIcon: QgsQuick.Utils.getThemeIcon("ic_navigation_black")
|
||||
|
||||
/**
|
||||
* Source position accuracy circle-shaped indicator around positionMarker.
|
||||
*/
|
||||
Rectangle {
|
||||
id: accuracyIndicator
|
||||
visible: withAccuracy &&
|
||||
positionKit.hasPosition &&
|
||||
(positionKit.accuracy > 0) &&
|
||||
(accuracyIndicator.width > positionMarker.size / 2.0)
|
||||
x: positionKit.screenPosition.x - width/2
|
||||
y: positionKit.screenPosition.y - height/2
|
||||
width:positionKit.screenAccuracy
|
||||
height: accuracyIndicator.width
|
||||
color: baseColor
|
||||
border.color: "black"
|
||||
border.width: 3 * QgsQuick.Utils.dp
|
||||
radius: width*0.5
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
/**
|
||||
* Position marker.
|
||||
*/
|
||||
Rectangle {
|
||||
id: navigationMarker
|
||||
property int borderWidth: 2 * QgsQuick.Utils.dp
|
||||
width: positionMarker.size + 20 * QgsQuick.Utils.dp
|
||||
height: width
|
||||
color: "white"
|
||||
border.color: baseColor
|
||||
border.width: borderWidth
|
||||
radius: width*0.5
|
||||
antialiasing: true
|
||||
x: positionKit.screenPosition.x - width/2
|
||||
y: positionKit.screenPosition.y - height/2
|
||||
|
||||
Image {
|
||||
id: navigation
|
||||
source: positionMarker.markerIcon
|
||||
fillMode: Image.PreserveAspectFit
|
||||
rotation: positionKit.direction
|
||||
anchors.centerIn: parent
|
||||
width: positionMarker.size
|
||||
height: width
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes positionMarker (navigation) grey if position is unknown.
|
||||
*/
|
||||
ColorOverlay {
|
||||
anchors.fill: navigation
|
||||
source: navigation
|
||||
color: positionKit.hasPosition ? baseColor : unavailableColor
|
||||
rotation: positionKit.direction
|
||||
visible: !(positionKit.hasPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ Item {
|
||||
* representation
|
||||
*/
|
||||
property alias preferredWidth: scaleBarKit.preferredWidth
|
||||
/**
|
||||
* Preferred system of measurement for the resulting distance. Default is metric system
|
||||
*/
|
||||
property alias systemOfMeasurement: scaleBarKit.systemOfMeasurement
|
||||
/**
|
||||
* Kit for all calculation of width and text of the scalebar
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ module QgsQuick
|
||||
plugin qgis_quick_plugin
|
||||
|
||||
MapCanvas 0.1 qgsquickmapcanvas.qml
|
||||
PositionMarker 0.1 qgsquickpositionmarker.qml
|
||||
ScaleBar 0.1 qgsquickscalebar.qml
|
||||
MessageLog 0.1 qgsquickmessagelog.qml
|
||||
|
||||
|
109
src/quickgui/qgsquickcoordinatetransformer.cpp
Normal file
109
src/quickgui/qgsquickcoordinatetransformer.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/***************************************************************************
|
||||
qgsquickcoordinatetransformer.cpp
|
||||
--------------------------------------
|
||||
Date : 1.6.2017
|
||||
Copyright : (C) 2017 by Matthias Kuhn
|
||||
Email : matthias (at) opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsquickcoordinatetransformer.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
QgsQuickCoordinateTransformer::QgsQuickCoordinateTransformer( QObject *parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
mCoordinateTransform.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ) );
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickCoordinateTransformer::projectedPosition() const
|
||||
{
|
||||
return mProjectedPosition;
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickCoordinateTransformer::sourcePosition() const
|
||||
{
|
||||
return mSourcePosition;
|
||||
}
|
||||
|
||||
void QgsQuickCoordinateTransformer::setSourcePosition( const QgsPoint &sourcePosition )
|
||||
{
|
||||
if ( mSourcePosition == sourcePosition )
|
||||
return;
|
||||
|
||||
mSourcePosition = sourcePosition;
|
||||
|
||||
emit sourcePositionChanged();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsQuickCoordinateTransformer::destinationCrs() const
|
||||
{
|
||||
return mCoordinateTransform.destinationCrs();
|
||||
}
|
||||
|
||||
void QgsQuickCoordinateTransformer::setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs )
|
||||
{
|
||||
if ( destinationCrs == mCoordinateTransform.destinationCrs() )
|
||||
return;
|
||||
|
||||
mCoordinateTransform.setDestinationCrs( destinationCrs );
|
||||
emit destinationCrsChanged();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsQuickCoordinateTransformer::sourceCrs() const
|
||||
{
|
||||
return mCoordinateTransform.sourceCrs();
|
||||
}
|
||||
|
||||
void QgsQuickCoordinateTransformer::setSourceCrs( const QgsCoordinateReferenceSystem &sourceCrs )
|
||||
{
|
||||
if ( sourceCrs == mCoordinateTransform.sourceCrs() )
|
||||
return;
|
||||
|
||||
mCoordinateTransform.setSourceCrs( sourceCrs );
|
||||
|
||||
emit sourceCrsChanged();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void QgsQuickCoordinateTransformer::setTransformContext( const QgsCoordinateTransformContext &context )
|
||||
{
|
||||
mCoordinateTransform.setContext( context );
|
||||
}
|
||||
|
||||
void QgsQuickCoordinateTransformer::updatePosition()
|
||||
{
|
||||
double x = mSourcePosition.x();
|
||||
double y = mSourcePosition.y();
|
||||
double z = mSourcePosition.z();
|
||||
|
||||
// If Z is NaN, coordinate transformation (proj4) will
|
||||
// also set X and Y to NaN. But we also want to get projected
|
||||
// coords if we do not have any Z coordinate.
|
||||
if ( std::isnan( z ) )
|
||||
{
|
||||
z = 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mCoordinateTransform.transformInPlace( x, y, z );
|
||||
}
|
||||
catch ( const QgsCsException &exp )
|
||||
{
|
||||
QgsDebugMsg( exp.what() );
|
||||
}
|
||||
|
||||
mProjectedPosition = QgsPoint( x, y );
|
||||
mProjectedPosition.addZValue( mSourcePosition.z() );
|
||||
|
||||
emit projectedPositionChanged();
|
||||
}
|
110
src/quickgui/qgsquickcoordinatetransformer.h
Normal file
110
src/quickgui/qgsquickcoordinatetransformer.h
Normal file
@ -0,0 +1,110 @@
|
||||
/***************************************************************************
|
||||
qgsquickcoordinatetransformer.h
|
||||
--------------------------------------
|
||||
Date : 1.6.2017
|
||||
Copyright : (C) 2017 by Matthias Kuhn
|
||||
Email : matthias (at) opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSQUICKCOORDINATETRANSFORMER_H
|
||||
#define QGSQUICKCOORDINATETRANSFORMER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qgspoint.h"
|
||||
|
||||
#include "qgis_quick.h"
|
||||
#include "qgscoordinatetransformcontext.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgspoint.h"
|
||||
|
||||
/**
|
||||
* \ingroup quick
|
||||
* Helper class for transform of coordinates (QgsPoint) to a different coordinate reference system.
|
||||
*
|
||||
* It requires connection of transformation context from mapSettings, source position and source CRS to
|
||||
* calculate projected position in desired destination CRS
|
||||
*
|
||||
* \note QML Type: CoordinateTransformer
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QUICK_EXPORT QgsQuickCoordinateTransformer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
//! Projected (destination) position (in destination CRS)
|
||||
Q_PROPERTY( QgsPoint projectedPosition READ projectedPosition NOTIFY projectedPositionChanged )
|
||||
|
||||
//! Source position (in source CRS)
|
||||
Q_PROPERTY( QgsPoint sourcePosition READ sourcePosition WRITE setSourcePosition NOTIFY sourcePositionChanged )
|
||||
|
||||
//! Destination CRS
|
||||
Q_PROPERTY( QgsCoordinateReferenceSystem destinationCrs READ destinationCrs WRITE setDestinationCrs NOTIFY destinationCrsChanged )
|
||||
|
||||
//! Source CRS, default 4326
|
||||
Q_PROPERTY( QgsCoordinateReferenceSystem sourceCrs READ sourceCrs WRITE setSourceCrs NOTIFY sourceCrsChanged )
|
||||
|
||||
//! Transformation context, can be set from QgsQuickMapSettings::transformContext()
|
||||
Q_PROPERTY( QgsCoordinateTransformContext transformContext WRITE setTransformContext )
|
||||
|
||||
public:
|
||||
//! Creates new coordinate transformer
|
||||
explicit QgsQuickCoordinateTransformer( QObject *parent = 0 );
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::projectedPosition
|
||||
QgsPoint projectedPosition() const;
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourcePosition
|
||||
QgsPoint sourcePosition() const;
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourcePosition
|
||||
void setSourcePosition( const QgsPoint &sourcePosition );
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::destinationCrs
|
||||
QgsCoordinateReferenceSystem destinationCrs() const;
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::destinationCrs
|
||||
void setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs );
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourceCrs
|
||||
QgsCoordinateReferenceSystem sourceCrs() const;
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourceCrs
|
||||
void setSourceCrs( const QgsCoordinateReferenceSystem &sourceCrs );
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::transformContext
|
||||
void setTransformContext( const QgsCoordinateTransformContext &context );
|
||||
|
||||
signals:
|
||||
//!\copydoc QgsQuickCoordinateTransformer::projectedPosition
|
||||
void projectedPositionChanged();
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourcePosition
|
||||
void sourcePositionChanged();
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::destinationCrs
|
||||
void destinationCrsChanged();
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::sourceCrs
|
||||
void sourceCrsChanged();
|
||||
|
||||
//!\copydoc QgsQuickCoordinateTransformer::transformContext
|
||||
void transformContextChanged();
|
||||
|
||||
private:
|
||||
void updatePosition();
|
||||
|
||||
QgsPoint mProjectedPosition;
|
||||
QgsPoint mSourcePosition;
|
||||
QgsCoordinateTransform mCoordinateTransform;
|
||||
};
|
||||
|
||||
#endif // QGSQUICKCOORDINATETRANSFORMER_H
|
334
src/quickgui/qgsquickpositionkit.cpp
Normal file
334
src/quickgui/qgsquickpositionkit.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
/***************************************************************************
|
||||
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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmessagelog.h"
|
||||
|
||||
#include "qgsquickpositionkit.h"
|
||||
#include "qgsquickutils.h"
|
||||
#include "qgsquicksimulatedpositionsource.h"
|
||||
|
||||
QgsQuickPositionKit::QgsQuickPositionKit( QObject *parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
connect( this,
|
||||
&QgsQuickPositionKit::simulatePositionLongLatRadChanged,
|
||||
this,
|
||||
&QgsQuickPositionKit::onSimulatePositionLongLatRadChanged );
|
||||
|
||||
useGpsLocation();
|
||||
}
|
||||
|
||||
QGeoPositionInfoSource *QgsQuickPositionKit::gpsSource()
|
||||
{
|
||||
// this should give us "true" position source
|
||||
// on Linux it comes from Geoclue library
|
||||
std::unique_ptr<QGeoPositionInfoSource> source( QGeoPositionInfoSource::createDefaultSource( nullptr ) );
|
||||
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
|
||||
{
|
||||
return source.release();
|
||||
}
|
||||
}
|
||||
|
||||
QGeoPositionInfoSource *QgsQuickPositionKit::simulatedSource( double longitude, double latitude, double radius )
|
||||
{
|
||||
return new QgsQuickSimulatedPositionSource( this, longitude, latitude, radius );
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::useSimulatedLocation( double longitude, double latitude, double radius )
|
||||
{
|
||||
std::unique_ptr<QGeoPositionInfoSource> source( simulatedSource( longitude, latitude, radius ) );
|
||||
mIsSimulated = true;
|
||||
replacePositionSource( source.release() );
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::updateScreenPosition()
|
||||
{
|
||||
if ( !mMapSettings )
|
||||
return;
|
||||
|
||||
QPointF screenPosition = mapSettings()->coordinateToScreen( projectedPosition() );
|
||||
if ( screenPosition != mScreenPosition )
|
||||
{
|
||||
mScreenPosition = screenPosition;
|
||||
emit screenPositionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::updateScreenAccuracy()
|
||||
{
|
||||
if ( !mMapSettings )
|
||||
return;
|
||||
|
||||
double screenAccuracy = calculateScreenAccuracy();
|
||||
if ( !qgsDoubleNear( screenAccuracy, mScreenAccuracy ) )
|
||||
{
|
||||
mScreenAccuracy = screenAccuracy;
|
||||
emit screenAccuracyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::useGpsLocation()
|
||||
{
|
||||
QGeoPositionInfoSource *source = gpsSource();
|
||||
mIsSimulated = false;
|
||||
replacePositionSource( source );
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::replacePositionSource( QGeoPositionInfoSource *source )
|
||||
{
|
||||
if ( mSource.get() == source )
|
||||
return;
|
||||
|
||||
if ( mSource )
|
||||
{
|
||||
mSource->disconnect();
|
||||
}
|
||||
|
||||
mSource.reset( source );
|
||||
|
||||
if ( mSource )
|
||||
{
|
||||
connect( mSource.get(), &QGeoPositionInfoSource::positionUpdated, this, &QgsQuickPositionKit::onPositionUpdated );
|
||||
connect( mSource.get(), &QGeoPositionInfoSource::updateTimeout, this, &QgsQuickPositionKit::onUpdateTimeout );
|
||||
|
||||
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() );
|
||||
QgsPointXY projectedPositionXY = QgsQuickUtils::transformPoint(
|
||||
positionCRS(),
|
||||
mMapSettings->destinationCrs(),
|
||||
mMapSettings->transformContext(),
|
||||
srcPoint );
|
||||
|
||||
QgsPoint projectedPosition( projectedPositionXY );
|
||||
projectedPosition.addZValue( mPosition.z() );
|
||||
|
||||
if ( projectedPosition != mProjectedPosition )
|
||||
{
|
||||
mProjectedPosition = projectedPosition;
|
||||
emit projectedPositionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::onPositionUpdated( const QGeoPositionInfo &info )
|
||||
{
|
||||
bool hasPosition = info.coordinate().isValid();
|
||||
if ( hasPosition != mHasPosition )
|
||||
{
|
||||
mHasPosition = hasPosition;
|
||||
emit hasPositionChanged();
|
||||
}
|
||||
|
||||
// Calculate position
|
||||
QgsPoint position = QgsPoint(
|
||||
info.coordinate().longitude(),
|
||||
info.coordinate().latitude(),
|
||||
info.coordinate().altitude() ); // can be NaN
|
||||
|
||||
if ( position != mPosition )
|
||||
{
|
||||
mPosition = position;
|
||||
emit positionChanged();
|
||||
}
|
||||
// calculate accuracy
|
||||
double accuracy;
|
||||
if ( info.hasAttribute( QGeoPositionInfo::HorizontalAccuracy ) )
|
||||
accuracy = info.attribute( QGeoPositionInfo::HorizontalAccuracy );
|
||||
else
|
||||
accuracy = -1;
|
||||
if ( !qgsDoubleNear( accuracy, mAccuracy ) )
|
||||
{
|
||||
mAccuracy = accuracy;
|
||||
emit accuracyChanged();
|
||||
}
|
||||
|
||||
// calculate direction
|
||||
double direction;
|
||||
if ( info.hasAttribute( QGeoPositionInfo::Direction ) )
|
||||
direction = info.attribute( QGeoPositionInfo::Direction );
|
||||
else
|
||||
direction = -1;
|
||||
if ( !qgsDoubleNear( direction, mDirection ) )
|
||||
{
|
||||
mDirection = direction;
|
||||
emit directionChanged();
|
||||
}
|
||||
|
||||
// recalculate projected/screen variables
|
||||
onMapSettingsUpdated();
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::onMapSettingsUpdated()
|
||||
{
|
||||
updateProjectedPosition();
|
||||
|
||||
updateScreenAccuracy();
|
||||
updateScreenPosition();
|
||||
}
|
||||
|
||||
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 ) );
|
||||
useSimulatedLocation( longitude, latitude, radius );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Unable to set simulated position due to the input errors." ) );
|
||||
useGpsLocation();
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsQuickPositionKit::positionCRS() const
|
||||
{
|
||||
return QgsCoordinateReferenceSystem::fromEpsgId( 4326 );
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickPositionKit::projectedPosition() const
|
||||
{
|
||||
return mProjectedPosition;
|
||||
}
|
||||
|
||||
bool QgsQuickPositionKit::hasPosition() const
|
||||
{
|
||||
return mHasPosition;
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickPositionKit::position() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
double QgsQuickPositionKit::accuracy() const
|
||||
{
|
||||
return mAccuracy;
|
||||
}
|
||||
|
||||
QgsUnitTypes::DistanceUnit QgsQuickPositionKit::accuracyUnits() const
|
||||
{
|
||||
return QgsUnitTypes::DistanceMeters;
|
||||
}
|
||||
|
||||
double QgsQuickPositionKit::direction() const
|
||||
{
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
bool QgsQuickPositionKit::isSimulated() const
|
||||
{
|
||||
return mIsSimulated;
|
||||
}
|
||||
|
||||
void QgsQuickPositionKit::setMapSettings( QgsQuickMapSettings *mapSettings )
|
||||
{
|
||||
if ( mMapSettings == mapSettings )
|
||||
return;
|
||||
|
||||
if ( mMapSettings )
|
||||
{
|
||||
mMapSettings->disconnect();
|
||||
}
|
||||
|
||||
mMapSettings = mapSettings;
|
||||
|
||||
if ( mMapSettings )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
emit mapSettingsChanged();
|
||||
}
|
252
src/quickgui/qgsquickpositionkit.h
Normal file
252
src/quickgui/qgsquickpositionkit.h
Normal file
@ -0,0 +1,252 @@
|
||||
/***************************************************************************
|
||||
qgsquickpositionkit.h
|
||||
--------------------------------------
|
||||
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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSQUICKPOSITIONKIT_H
|
||||
#define QGSQUICKPOSITIONKIT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtPositioning>
|
||||
|
||||
#include "qgspoint.h"
|
||||
|
||||
#include "qgis_quick.h"
|
||||
#include "qgsquickmapsettings.h"
|
||||
#include "qgsquickcoordinatetransformer.h"
|
||||
|
||||
/**
|
||||
* \ingroup quick
|
||||
* Convenient set of tools to read GPS position and accuracy.
|
||||
*
|
||||
* Also, if one can use use_simulated_location to specify simulated position.
|
||||
* Simulated position source generates random points in circles around the selected
|
||||
* point and radius. Real GPS position is not used in this mode.
|
||||
*
|
||||
* \note QML Type: PositionKit
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QUICK_EXPORT QgsQuickPositionKit : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* GPS position in WGS84 coords.
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( QgsPoint position READ position NOTIFY positionChanged )
|
||||
|
||||
/**
|
||||
* GPS position in map coords.
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( QgsPoint projectedPosition READ projectedPosition NOTIFY projectedPositionChanged )
|
||||
|
||||
/**
|
||||
* GPS position in device coords (pixels).
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( QPointF screenPosition READ screenPosition NOTIFY screenPositionChanged )
|
||||
|
||||
/**
|
||||
* GPS position is available (position property is a valid number).
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( bool hasPosition READ hasPosition NOTIFY hasPositionChanged )
|
||||
|
||||
/**
|
||||
* GPS horizontal accuracy in accuracyUnits, -1 if not available.
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( double accuracy READ accuracy NOTIFY accuracyChanged )
|
||||
|
||||
/**
|
||||
* Screen horizontal accuracy, 2 if not available or resolution is too small.
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( double screenAccuracy READ screenAccuracy NOTIFY screenAccuracyChanged )
|
||||
|
||||
/**
|
||||
* GPS direction, bearing in degrees clockwise from north to direction of travel. -1 if not available
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( double direction READ direction NOTIFY directionChanged )
|
||||
|
||||
/**
|
||||
* GPS position and accuracy is simulated (not real from GPS sensor). Default false (use real GPS)
|
||||
*
|
||||
* This is a readonly property. To change to simulated position, see QgsQuickPositionKit::simulatePositionLongLatRad
|
||||
*/
|
||||
Q_PROPERTY( bool isSimulated READ isSimulated NOTIFY isSimulatedChanged )
|
||||
|
||||
/**
|
||||
* Associated map settings. Should be initialized before the first use from mapcanvas map settings.
|
||||
*
|
||||
* This is a readonly property.
|
||||
*/
|
||||
Q_PROPERTY( QgsQuickMapSettings *mapSettings READ mapSettings WRITE setMapSettings NOTIFY mapSettingsChanged )
|
||||
|
||||
/**
|
||||
* Uses of GPS and simulated position and sets its parameters
|
||||
*
|
||||
* Vector containing longitude, latitude and radius (meters) of simulated position e.g. [-97.36, 36.93, 2]
|
||||
* If empty vector is assigned, GPS source will be used.
|
||||
*
|
||||
* From QML context, also functions useSimulatedLocation() or useGpsLocation() could be used instead
|
||||
*/
|
||||
Q_PROPERTY( QVector<double> simulatePositionLongLatRad READ simulatePositionLongLatRad WRITE setSimulatePositionLongLatRad NOTIFY simulatePositionLongLatRadChanged )
|
||||
|
||||
public:
|
||||
//! Creates new position kit
|
||||
explicit QgsQuickPositionKit( QObject *parent = 0 );
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::position
|
||||
bool hasPosition() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::position
|
||||
QgsPoint position() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::projectedPosition
|
||||
QgsPoint projectedPosition() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::screenPosition
|
||||
QPointF screenPosition() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::accuracy
|
||||
double accuracy() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::screenAccuracy
|
||||
double screenAccuracy() const;
|
||||
|
||||
/**
|
||||
* GPS horizontal accuracy units - meters (constant)
|
||||
*/
|
||||
QgsUnitTypes::DistanceUnit accuracyUnits() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::direction
|
||||
double direction() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::isSimulated
|
||||
bool isSimulated() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::mapSettings
|
||||
void setMapSettings( QgsQuickMapSettings *mapSettings );
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::mapSettings
|
||||
QgsQuickMapSettings *mapSettings() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::simulatePositionLongLatRad
|
||||
QVector<double> simulatePositionLongLatRad() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::simulatePositionLongLatRad
|
||||
void setSimulatePositionLongLatRad( const QVector<double> &simulatePositionLongLatRad );
|
||||
|
||||
/**
|
||||
* Coordinate reference system of position - WGS84 (constant)
|
||||
*/
|
||||
Q_INVOKABLE QgsCoordinateReferenceSystem positionCRS() const;
|
||||
|
||||
/**
|
||||
* Use simulated GPS source.
|
||||
*
|
||||
* Simulated GPS source emulates point on circle around defined point in specified radius
|
||||
*
|
||||
* We do not want to have the origin point as property
|
||||
* We basically want to set it once based on project/map cente and keep
|
||||
* it that way regardless of mapsettings change (e.g. zoom etc)
|
||||
*
|
||||
* \param longitude longitude of the centre of the emulated points
|
||||
* \param latitude latitude of the centre of the emulated points
|
||||
* \param radius distance of emulated points from the centre (in degrees WSG84)
|
||||
*/
|
||||
Q_INVOKABLE void useSimulatedLocation( double longitude, double latitude, double radius );
|
||||
|
||||
/**
|
||||
* Use real GPS source (not simulated)
|
||||
*/
|
||||
Q_INVOKABLE void useGpsLocation();
|
||||
|
||||
signals:
|
||||
//! \copydoc QgsQuickPositionKit::position
|
||||
void positionChanged();
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::projectedPosition
|
||||
void projectedPositionChanged();
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::screenPosition
|
||||
void screenPositionChanged();
|
||||
|
||||
//! hasPosition changed
|
||||
void hasPositionChanged();
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::accuracy
|
||||
double accuracyChanged() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::screenAccuracy
|
||||
double screenAccuracyChanged() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::accuracyUnits
|
||||
Q_INVOKABLE QString accuracyUnitsChanged() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::direction
|
||||
double directionChanged() const;
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::isSimulated
|
||||
void isSimulatedChanged();
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::mapSettings
|
||||
void mapSettingsChanged();
|
||||
|
||||
//! \copydoc QgsQuickPositionKit::simulatePositionLongLatRad
|
||||
void simulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad );
|
||||
|
||||
private slots:
|
||||
void onPositionUpdated( const QGeoPositionInfo &info );
|
||||
void onMapSettingsUpdated();
|
||||
void onUpdateTimeout();
|
||||
void onSimulatePositionLongLatRadChanged( QVector<double> simulatePositionLongLatRad );
|
||||
|
||||
private:
|
||||
void replacePositionSource( QGeoPositionInfoSource *source );
|
||||
QString calculateStatusLabel();
|
||||
double calculateScreenAccuracy();
|
||||
void updateProjectedPosition();
|
||||
void updateScreenPosition();
|
||||
void updateScreenAccuracy();
|
||||
|
||||
QGeoPositionInfoSource *gpsSource();
|
||||
QGeoPositionInfoSource *simulatedSource( double longitude, double latitude, double radius );
|
||||
|
||||
QgsPoint mPosition;
|
||||
QgsPoint mProjectedPosition;
|
||||
QPointF mScreenPosition;
|
||||
double mAccuracy = -1;
|
||||
double mScreenAccuracy = 2;
|
||||
double mDirection = -1;
|
||||
bool mHasPosition = false;
|
||||
bool mIsSimulated = false;
|
||||
QVector<double> mSimulatePositionLongLatRad;
|
||||
std::unique_ptr<QGeoPositionInfoSource> mSource;
|
||||
|
||||
QgsQuickMapSettings *mMapSettings = nullptr; // not owned
|
||||
};
|
||||
|
||||
#endif // QGSQUICKPOSITIONKIT_H
|
@ -82,16 +82,14 @@ void QgsQuickScaleBarKit::updateScaleBar()
|
||||
if ( !mMapSettings )
|
||||
return;
|
||||
|
||||
double dist = QgsQuickUtils().screenUnitsToMeters( mMapSettings, mPreferredWidth ); // meters
|
||||
if ( dist > 1000.0 )
|
||||
{
|
||||
dist = dist / 1000.0; // meters to kilometers
|
||||
mUnits = QgsUnitTypes::toAbbreviatedString( QgsUnitTypes::DistanceKilometers );
|
||||
}
|
||||
else
|
||||
{
|
||||
mUnits = QgsUnitTypes::toAbbreviatedString( QgsUnitTypes::DistanceMeters );
|
||||
}
|
||||
double distInMeters = QgsQuickUtils().screenUnitsToMeters( mMapSettings, mPreferredWidth ); // meters
|
||||
double dist;
|
||||
QgsUnitTypes::DistanceUnit distUnits;
|
||||
QgsQuickUtils().humanReadableDistance( distInMeters, QgsUnitTypes::DistanceMeters,
|
||||
mSystemOfMeasurement,
|
||||
dist, distUnits );
|
||||
|
||||
mUnits = QgsUnitTypes::toAbbreviatedString( distUnits );
|
||||
|
||||
// we want to show nice round distances e.g. 200 km instead of e.g. 273 km
|
||||
// so we determine which "nice" number to use and also update the scale bar
|
||||
|
@ -37,6 +37,9 @@ class QgsQuickMapSettings;
|
||||
* distance in meters or kilometers (int) rounded to "nice" number (e.g. 72.4 to 100)
|
||||
* and units text (e.g. km)
|
||||
*
|
||||
* System of measurement for result could be set too, so for example the resulting scalebar
|
||||
* can show results in the imperial units.
|
||||
*
|
||||
* \note QML Type: ScaleBarKit
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
@ -56,12 +59,19 @@ class QUICK_EXPORT QgsQuickScaleBarKit : public QObject
|
||||
Q_PROPERTY( int preferredWidth MEMBER mPreferredWidth NOTIFY preferredWidthChanged )
|
||||
|
||||
/**
|
||||
* Units of distance (e.g. km or m) Read-only (result).
|
||||
* Preferred system of measurement for the result
|
||||
*/
|
||||
Q_PROPERTY( QgsUnitTypes::SystemOfMeasurement systemOfMeasurement MEMBER mSystemOfMeasurement NOTIFY systemOfMeasurementChanged )
|
||||
|
||||
/**
|
||||
* Units of distance (e.g. km or m) of result in desired systemOfMeasurement Read-only (result).
|
||||
*/
|
||||
Q_PROPERTY( QString units READ units NOTIFY scaleBarChanged )
|
||||
|
||||
/**
|
||||
* Distance rounded to "nice" number (e.g. 100, 20) corresponding to width. To be used with units property for labels. Read-only (result).
|
||||
* Distance rounded to "nice" number (e.g. 100, 20) corresponding to width and system of measurement
|
||||
*
|
||||
* To be used with units property for labels. Read-only (result).
|
||||
*/
|
||||
Q_PROPERTY( int distance READ distance NOTIFY scaleBarChanged )
|
||||
|
||||
@ -107,6 +117,9 @@ class QUICK_EXPORT QgsQuickScaleBarKit : public QObject
|
||||
//! \copydoc QgsQuickScaleBarKit::preferredWidth
|
||||
void preferredWidthChanged();
|
||||
|
||||
//! \copydoc QgsQuickScaleBarKit::systemOfMeasurement
|
||||
void systemOfMeasurementChanged();
|
||||
|
||||
public slots:
|
||||
//! recalculate width, distance and units.
|
||||
void updateScaleBar();
|
||||
@ -116,7 +129,8 @@ class QUICK_EXPORT QgsQuickScaleBarKit : public QObject
|
||||
int mPreferredWidth; // pixels
|
||||
int mWidth; // pixels
|
||||
int mDistance; // in meters or kilometers, rounded
|
||||
QString mUnits; // km or m
|
||||
QString mUnits; // e.g. km or m
|
||||
QgsUnitTypes::SystemOfMeasurement mSystemOfMeasurement = QgsUnitTypes::MetricSystem;
|
||||
};
|
||||
|
||||
|
||||
|
104
src/quickgui/qgsquicksimulatedpositionsource.cpp
Normal file
104
src/quickgui/qgsquicksimulatedpositionsource.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/***************************************************************************
|
||||
qgsquicksimulatedpositionsource.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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsquicksimulatedpositionsource.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
/// @cond PRIVATE
|
||||
|
||||
QgsQuickSimulatedPositionSource::QgsQuickSimulatedPositionSource( QObject *parent, double longitude, double latitude, double flightRadius )
|
||||
: QGeoPositionInfoSource( parent )
|
||||
, mTimer( qgis::make_unique< QTimer >() )
|
||||
, mFlightRadius( flightRadius )
|
||||
, mLongitude( longitude )
|
||||
, mLatitude( latitude )
|
||||
{
|
||||
connect( mTimer.get(), &QTimer::timeout, this, &QgsQuickSimulatedPositionSource::readNextPosition );
|
||||
}
|
||||
|
||||
void QgsQuickSimulatedPositionSource::startUpdates()
|
||||
{
|
||||
int interval = updateInterval();
|
||||
if ( interval < minimumUpdateInterval() )
|
||||
interval = minimumUpdateInterval();
|
||||
|
||||
mTimer->start( interval );
|
||||
readNextPosition();
|
||||
}
|
||||
|
||||
void QgsQuickSimulatedPositionSource::stopUpdates()
|
||||
{
|
||||
mTimer->stop();
|
||||
}
|
||||
|
||||
void QgsQuickSimulatedPositionSource::requestUpdate( int /*timeout*/ )
|
||||
{
|
||||
readNextPosition();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QgsQuickSimulatedPositionSource::readNextPosition()
|
||||
{
|
||||
if ( mFlightRadius <= 0 )
|
||||
readConstantPosition();
|
||||
else
|
||||
readRandomPosition();
|
||||
}
|
||||
|
||||
void QgsQuickSimulatedPositionSource::readRandomPosition()
|
||||
{
|
||||
double latitude = mLatitude, longitude = mLongitude;
|
||||
latitude += sin( mAngle * M_PI / 180 ) * mFlightRadius;
|
||||
longitude += cos( mAngle * M_PI / 180 ) * mFlightRadius;
|
||||
mAngle += 1;
|
||||
|
||||
QGeoCoordinate coordinate( latitude, longitude );
|
||||
double altitude = std::rand() % 40 + 20; // rand altitude <20,55>m and lost (0)
|
||||
if ( altitude <= 55 )
|
||||
{
|
||||
coordinate.setAltitude( altitude ); // 3D
|
||||
}
|
||||
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
|
||||
QGeoPositionInfo info( coordinate, timestamp );
|
||||
if ( info.isValid() )
|
||||
{
|
||||
mLastPosition = info;
|
||||
info.setAttribute( QGeoPositionInfo::Direction, 360 - int( mAngle ) % 360 );
|
||||
int accuracy = std::rand() % 40 + 20; // rand accuracy <20,55>m and lost (-1)
|
||||
if ( accuracy > 55 )
|
||||
{
|
||||
accuracy = -1;
|
||||
}
|
||||
info.setAttribute( QGeoPositionInfo::HorizontalAccuracy, accuracy );
|
||||
emit positionUpdated( info );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsQuickSimulatedPositionSource::readConstantPosition()
|
||||
{
|
||||
QGeoCoordinate coordinate( mLatitude, mLongitude );
|
||||
coordinate.setAltitude( 20 );
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
QGeoPositionInfo info( coordinate, timestamp );
|
||||
info.setAttribute( QGeoPositionInfo::Direction, 0 );
|
||||
info.setAttribute( QGeoPositionInfo::HorizontalAccuracy, 20 );
|
||||
emit positionUpdated( info );
|
||||
}
|
||||
|
||||
/// @endcond
|
86
src/quickgui/qgsquicksimulatedpositionsource.h
Normal file
86
src/quickgui/qgsquicksimulatedpositionsource.h
Normal file
@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
qgsquicksimulatedpositionsource.h
|
||||
--------------------------------------
|
||||
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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSQUICKSIMULATEDPOSITIONSOURCE_H
|
||||
#define QGSQUICKSIMULATEDPOSITIONSOURCE_H
|
||||
|
||||
/// @cond PRIVATE
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the QGIS API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
|
||||
#include "qgis_quick.h"
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QtPositioning>
|
||||
#include <qgspoint.h>
|
||||
|
||||
/**
|
||||
* \ingroup quick
|
||||
* This is an internal (implementation) class used to generate (fake) GPS position source
|
||||
* Useful for for testing purposes (e.g. testing of the application with map for different
|
||||
* location then your physical (GPS) location)
|
||||
*
|
||||
* Simulated position source generates random points in circles around the selected
|
||||
* point and radius. Real GPS position is not used in this mode.
|
||||
*
|
||||
* For disabling (random) updates, use flight radius <= 0 (useful for testing)
|
||||
*
|
||||
* \note QML Type: not exported
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QUICK_NO_EXPORT QgsQuickSimulatedPositionSource : public QGeoPositionInfoSource
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsQuickSimulatedPositionSource( QObject *parent, double longitude, double latitude, double flightRadius );
|
||||
|
||||
QGeoPositionInfo lastKnownPosition( bool /*fromSatellitePositioningMethodsOnly = false*/ ) const { return mLastPosition; }
|
||||
PositioningMethods supportedPositioningMethods() const { return AllPositioningMethods; }
|
||||
int minimumUpdateInterval() const { return 1000; }
|
||||
Error error() const { return QGeoPositionInfoSource::NoError; }
|
||||
|
||||
public slots:
|
||||
virtual void startUpdates();
|
||||
virtual void stopUpdates();
|
||||
|
||||
virtual void requestUpdate( int timeout = 5000 );
|
||||
|
||||
private slots:
|
||||
void readNextPosition();
|
||||
|
||||
private:
|
||||
void readRandomPosition();
|
||||
void readConstantPosition();
|
||||
|
||||
std::unique_ptr< QTimer > mTimer;
|
||||
QGeoPositionInfo mLastPosition;
|
||||
double mAngle = 0;
|
||||
|
||||
double mFlightRadius = 0;
|
||||
double mLongitude = 0;
|
||||
double mLatitude = 0;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif // QGSQUICKSIMULATEDPOSITIONSOURCE_H
|
@ -16,6 +16,8 @@
|
||||
#include <QString>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsdistancearea.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
@ -32,7 +34,40 @@ QgsQuickUtils::QgsQuickUtils( QObject *parent )
|
||||
{
|
||||
}
|
||||
|
||||
double QgsQuickUtils::screenUnitsToMeters( QgsQuickMapSettings *mapSettings, int baseLengthPixels ) const
|
||||
/**
|
||||
* Makes QgsCoordinateReferenceSystem::fromEpsgId accessible for QML components
|
||||
*/
|
||||
QgsCoordinateReferenceSystem QgsQuickUtils::coordinateReferenceSystemFromEpsgId( long epsg )
|
||||
{
|
||||
return QgsCoordinateReferenceSystem::fromEpsgId( epsg );
|
||||
}
|
||||
|
||||
QgsPointXY QgsQuickUtils::pointXY( double x, double y ) const
|
||||
{
|
||||
return QgsPointXY( x, y );
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickUtils::point( double x, double y, double z, double m ) const
|
||||
{
|
||||
return QgsPoint( x, y, z, m );
|
||||
}
|
||||
|
||||
QgsPoint QgsQuickUtils::coordinateToPoint( const QGeoCoordinate &coor ) const
|
||||
{
|
||||
return QgsPoint( coor.longitude(), coor.latitude(), coor.altitude() );
|
||||
}
|
||||
|
||||
QgsPointXY QgsQuickUtils::transformPoint( const QgsCoordinateReferenceSystem &srcCrs,
|
||||
const QgsCoordinateReferenceSystem &destCrs,
|
||||
const QgsCoordinateTransformContext &context,
|
||||
const QgsPointXY &srcPoint )
|
||||
{
|
||||
QgsCoordinateTransform mTransform( srcCrs, destCrs, context );
|
||||
QgsPointXY pt = mTransform.transform( srcPoint );
|
||||
return pt;
|
||||
}
|
||||
|
||||
double QgsQuickUtils::screenUnitsToMeters( QgsQuickMapSettings *mapSettings, int baseLengthPixels )
|
||||
{
|
||||
if ( mapSettings == nullptr ) return 0.0;
|
||||
|
||||
@ -59,6 +94,169 @@ QgsQuickFeatureLayerPair QgsQuickUtils::featureFactory( const QgsFeature &featur
|
||||
return QgsQuickFeatureLayerPair( feature, layer );
|
||||
}
|
||||
|
||||
const QUrl QgsQuickUtils::getThemeIcon( const QString &name ) const
|
||||
{
|
||||
QString path = QStringLiteral( "qrc:/%1.svg" ).arg( name );
|
||||
QgsDebugMsg( QStringLiteral( "Using icon %1 from %2" ).arg( name, path ) );
|
||||
return QUrl( path );
|
||||
}
|
||||
|
||||
QString QgsQuickUtils::formatPoint(
|
||||
const QgsPoint &point,
|
||||
QgsCoordinateFormatter::Format format,
|
||||
int decimals,
|
||||
QgsCoordinateFormatter::FormatFlags flags )
|
||||
{
|
||||
return QgsCoordinateFormatter::format( point, format, decimals, flags );
|
||||
}
|
||||
|
||||
QString QgsQuickUtils::formatDistance( double distance,
|
||||
QgsUnitTypes::DistanceUnit units,
|
||||
int decimals,
|
||||
QgsUnitTypes::SystemOfMeasurement destSystem )
|
||||
{
|
||||
double destDistance;
|
||||
QgsUnitTypes::DistanceUnit destUnits;
|
||||
|
||||
humanReadableDistance( distance, units, destSystem, destDistance, destUnits );
|
||||
|
||||
return QStringLiteral( "%1 %2" )
|
||||
.arg( QString::number( destDistance, 'f', decimals ) )
|
||||
.arg( QgsUnitTypes::toAbbreviatedString( destUnits ) );
|
||||
}
|
||||
|
||||
|
||||
void QgsQuickUtils::humanReadableDistance( double srcDistance, QgsUnitTypes::DistanceUnit srcUnits,
|
||||
QgsUnitTypes::SystemOfMeasurement destSystem,
|
||||
double &destDistance, QgsUnitTypes::DistanceUnit &destUnits )
|
||||
{
|
||||
if ( ( destSystem == QgsUnitTypes::MetricSystem ) || ( destSystem == QgsUnitTypes::UnknownSystem ) )
|
||||
{
|
||||
return formatToMetricDistance( srcDistance, srcUnits, destDistance, destUnits );
|
||||
}
|
||||
else if ( destSystem == QgsUnitTypes::ImperialSystem )
|
||||
{
|
||||
return formatToImperialDistance( srcDistance, srcUnits, destDistance, destUnits );
|
||||
}
|
||||
else if ( destSystem == QgsUnitTypes::USCSSystem )
|
||||
{
|
||||
return formatToUSCSDistance( srcDistance, srcUnits, destDistance, destUnits );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false ); //should never happen
|
||||
}
|
||||
}
|
||||
|
||||
void QgsQuickUtils::formatToMetricDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits )
|
||||
{
|
||||
double dist = srcDistance * QgsUnitTypes::fromUnitToUnitFactor( srcUnits, QgsUnitTypes::DistanceMillimeters );
|
||||
if ( dist < 0 )
|
||||
{
|
||||
destDistance = 0;
|
||||
destUnits = QgsUnitTypes::DistanceMillimeters;
|
||||
return;
|
||||
}
|
||||
|
||||
double mmToKm = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceKilometers, QgsUnitTypes::DistanceMillimeters );
|
||||
if ( dist > mmToKm )
|
||||
{
|
||||
destDistance = dist / mmToKm;
|
||||
destUnits = QgsUnitTypes::DistanceKilometers;
|
||||
return;
|
||||
}
|
||||
|
||||
double mmToM = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMeters, QgsUnitTypes::DistanceMillimeters );
|
||||
if ( dist > mmToM )
|
||||
{
|
||||
destDistance = dist / mmToM;
|
||||
destUnits = QgsUnitTypes::DistanceMeters;
|
||||
return;
|
||||
}
|
||||
|
||||
double mmToCm = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceCentimeters, QgsUnitTypes::DistanceMillimeters );
|
||||
if ( dist > mmToCm )
|
||||
{
|
||||
destDistance = dist / mmToCm;
|
||||
destUnits = QgsUnitTypes::DistanceCentimeters;
|
||||
return;
|
||||
}
|
||||
|
||||
destDistance = dist;
|
||||
destUnits = QgsUnitTypes::DistanceMillimeters;
|
||||
}
|
||||
|
||||
void QgsQuickUtils::formatToImperialDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits )
|
||||
{
|
||||
double dist = srcDistance * QgsUnitTypes::fromUnitToUnitFactor( srcUnits, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist < 0 )
|
||||
{
|
||||
destDistance = 0;
|
||||
destUnits = QgsUnitTypes::DistanceFeet;
|
||||
return;
|
||||
}
|
||||
|
||||
double feetToMile = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMiles, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist > feetToMile )
|
||||
{
|
||||
destDistance = dist / feetToMile;
|
||||
destUnits = QgsUnitTypes::DistanceMiles;
|
||||
return;
|
||||
}
|
||||
|
||||
double feetToYard = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceYards, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist > feetToYard )
|
||||
{
|
||||
destDistance = dist / feetToYard;
|
||||
destUnits = QgsUnitTypes::DistanceYards;
|
||||
return;
|
||||
}
|
||||
|
||||
destDistance = dist;
|
||||
destUnits = QgsUnitTypes::DistanceFeet;
|
||||
return;
|
||||
}
|
||||
|
||||
void QgsQuickUtils::formatToUSCSDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits )
|
||||
{
|
||||
double dist = srcDistance * QgsUnitTypes::fromUnitToUnitFactor( srcUnits, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist < 0 )
|
||||
{
|
||||
destDistance = 0;
|
||||
destUnits = QgsUnitTypes::DistanceFeet;
|
||||
return;
|
||||
}
|
||||
|
||||
double feetToMile = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceNauticalMiles, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist > feetToMile )
|
||||
{
|
||||
destDistance = dist / feetToMile;
|
||||
destUnits = QgsUnitTypes::DistanceNauticalMiles;
|
||||
return;
|
||||
}
|
||||
|
||||
double feetToYard = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceYards, QgsUnitTypes::DistanceFeet );
|
||||
if ( dist > feetToYard )
|
||||
{
|
||||
destDistance = dist / feetToYard;
|
||||
destUnits = QgsUnitTypes::DistanceYards;
|
||||
return;
|
||||
}
|
||||
|
||||
destDistance = dist;
|
||||
destUnits = QgsUnitTypes::DistanceFeet;
|
||||
return;
|
||||
}
|
||||
|
||||
QString QgsQuickUtils::dumpScreenInfo() const
|
||||
{
|
||||
QRect rec = QApplication::desktop()->screenGeometry();
|
||||
|
@ -19,14 +19,20 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QtPositioning/QGeoCoordinate>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsmessagelog.h"
|
||||
|
||||
#include "qgspoint.h"
|
||||
#include "qgspointxy.h"
|
||||
#include "qgsunittypes.h"
|
||||
#include "qgsquickmapsettings.h"
|
||||
#include "qgsquickfeaturelayerpair.h"
|
||||
#include "qgis_quick.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgscoordinateformatter.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsCoordinateReferenceSystem;
|
||||
@ -60,16 +66,54 @@ class QUICK_EXPORT QgsQuickUtils: public QObject
|
||||
public:
|
||||
//! Create new utilities
|
||||
QgsQuickUtils( QObject *parent = nullptr );
|
||||
//! dtor
|
||||
//! Destructor
|
||||
~QgsQuickUtils() = default;
|
||||
|
||||
//! \copydoc QgsQuickUtils::dp
|
||||
qreal screenDensity() const;
|
||||
|
||||
/**
|
||||
* Calculate the distance in meter representing baseLengthPixels pixels on the screen based on the current map settings.
|
||||
* Creates crs from epsg code in QML
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE double screenUnitsToMeters( QgsQuickMapSettings *mapSettings, int baseLengthPixels ) const;
|
||||
Q_INVOKABLE static QgsCoordinateReferenceSystem coordinateReferenceSystemFromEpsgId( long epsg );
|
||||
|
||||
/**
|
||||
* Creates QgsPointXY in QML
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE QgsPointXY pointXY( double x, double y ) const;
|
||||
|
||||
/**
|
||||
* Creates QgsPoint in QML
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE QgsPoint point( double x, double y, double z = std::numeric_limits<double>::quiet_NaN(), double m = std::numeric_limits<double>::quiet_NaN() ) const;
|
||||
|
||||
/**
|
||||
* Converts QGeoCoordinate to QgsPoint
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE QgsPoint coordinateToPoint( const QGeoCoordinate &coor ) const;
|
||||
|
||||
/**
|
||||
* Transforms point between different crs from QML
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE static QgsPointXY transformPoint( const QgsCoordinateReferenceSystem &srcCrs,
|
||||
const QgsCoordinateReferenceSystem &destCrs,
|
||||
const QgsCoordinateTransformContext &context,
|
||||
const QgsPointXY &srcPoint );
|
||||
|
||||
/**
|
||||
* Calculates the distance in meter representing baseLengthPixels pixels on the screen based on the current map settings.
|
||||
*/
|
||||
Q_INVOKABLE static double screenUnitsToMeters( QgsQuickMapSettings *mapSettings, int baseLengthPixels );
|
||||
|
||||
//! Log message in QgsMessageLog
|
||||
Q_INVOKABLE void logMessage( const QString &message,
|
||||
@ -86,13 +130,84 @@ class QUICK_EXPORT QgsQuickUtils: public QObject
|
||||
Q_INVOKABLE QgsQuickFeatureLayerPair featureFactory( const QgsFeature &feature, QgsVectorLayer *layer = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Returns a string with information about screen size and resolution
|
||||
* Returns QUrl to image from library's /images folder.
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE const QUrl getThemeIcon( const QString &name ) const;
|
||||
|
||||
/**
|
||||
* \copydoc QgsCoordinateFormatter::format()
|
||||
*
|
||||
* Useful to log for debugging of graphical problems on various display sizes
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE static QString formatPoint(
|
||||
const QgsPoint &point,
|
||||
QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatPair,
|
||||
int decimals = 3,
|
||||
QgsCoordinateFormatter::FormatFlags flags = QgsCoordinateFormatter::FlagDegreesUseStringSuffix );
|
||||
|
||||
/**
|
||||
* Converts distance to human readable distance
|
||||
*
|
||||
* This is useful for scalebar texts or output of the GPS accuracy
|
||||
*
|
||||
* The resulting units are determined automatically,
|
||||
* based on requested system of measurement.
|
||||
* e.g. 1222.234 m is converted to 1.2 km
|
||||
*
|
||||
* \param distance distance in units
|
||||
* \param units units of dist
|
||||
* \param decimals decimal to use
|
||||
* \param destSystem system of measurement of the result
|
||||
* \returns string represetation of dist in desired destSystem. For distance less than 0, 0 is returned.
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
Q_INVOKABLE static QString formatDistance( double distance,
|
||||
QgsUnitTypes::DistanceUnit units,
|
||||
int decimals,
|
||||
QgsUnitTypes::SystemOfMeasurement destSystem = QgsUnitTypes::MetricSystem );
|
||||
|
||||
/**
|
||||
* Converts distance to human readable distance in destination system of measurement
|
||||
*
|
||||
* \sa QgsQuickUtils::formatDistance()
|
||||
*
|
||||
* \param srcDistance distance in units
|
||||
* \param srcUnits units of dist
|
||||
* \param destSystem system of measurement of the result
|
||||
* \param destDistance output: distance if desired system of measurement
|
||||
* \param destUnits output: unit of destDistance
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
static void humanReadableDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
QgsUnitTypes::SystemOfMeasurement destSystem,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits );
|
||||
|
||||
//! Returns a string with information about screen size and resolution - useful for debugging
|
||||
QString dumpScreenInfo() const;
|
||||
|
||||
private:
|
||||
static void formatToMetricDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits );
|
||||
|
||||
static void formatToImperialDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits );
|
||||
|
||||
static void formatToUSCSDistance( double srcDistance,
|
||||
QgsUnitTypes::DistanceUnit srcUnits,
|
||||
double &destDistance,
|
||||
QgsUnitTypes::DistanceUnit &destUnits );
|
||||
|
||||
|
||||
static qreal calculateScreenDensity();
|
||||
|
||||
qreal mScreenDensity;
|
||||
|
@ -81,6 +81,7 @@ ENDMACRO (ADD_QGIS_TEST)
|
||||
ADD_QGIS_TEST(qgsquickidentifykit testqgsquickidentifykit.cpp)
|
||||
ADD_QGIS_TEST(qgsquickutils testqgsquickutils.cpp)
|
||||
ADD_QGIS_TEST(qgsquickscalebarkit testqgsquickscalebarkit.cpp)
|
||||
ADD_QGIS_TEST(qgsquickpositionkit testqgsquickpositionkit.cpp)
|
||||
|
||||
|
||||
#############################################################
|
||||
|
@ -58,6 +58,10 @@ int main( int argc, char *argv[] )
|
||||
engine.rootContext()->setContextProperty( "__project", &project );
|
||||
engine.rootContext()->setContextProperty( "__layers", QVariant::fromValue( project.layerTreeRoot()->layerOrder() ) );
|
||||
|
||||
// Set simulated position for desktop builds
|
||||
bool use_simulated_position = true;
|
||||
engine.rootContext()->setContextProperty( "__use_simulated_position", use_simulated_position );
|
||||
|
||||
QQmlComponent component( &engine, QUrl( QStringLiteral( "qrc:/main.qml" ) ) );
|
||||
QObject *object = component.create();
|
||||
|
||||
|
@ -52,6 +52,7 @@ ApplicationWindow {
|
||||
z: 1
|
||||
}
|
||||
|
||||
/** Message Log */
|
||||
Drawer {
|
||||
id: logPanel
|
||||
visible: true
|
||||
@ -75,12 +76,79 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
/** Scale Bar in metric units*/
|
||||
QgsQuick.ScaleBar {
|
||||
id: scaleBar
|
||||
y: window.height - height
|
||||
height: 50
|
||||
height: 50 * QgsQuick.Utils.dp
|
||||
mapSettings: mapCanvas.mapSettings
|
||||
preferredWidth: 115 * QgsQuick.Utils.dp
|
||||
z: 1
|
||||
}
|
||||
|
||||
/** Scale Bar in imperial units*/
|
||||
QgsQuick.ScaleBar {
|
||||
id: scaleBarImperialUnits
|
||||
y: window.height - height
|
||||
x: window.width/2
|
||||
height: scaleBar.height
|
||||
mapSettings: mapCanvas.mapSettings
|
||||
preferredWidth: scaleBar.preferredWidth
|
||||
systemOfMeasurement: QgsQuick.QgsUnitTypes.ImperialSystem
|
||||
z: 1
|
||||
}
|
||||
|
||||
/** Position Kit and Marker */
|
||||
QgsQuick.PositionKit {
|
||||
id: positionKit
|
||||
mapSettings: mapCanvas.mapSettings
|
||||
simulatePositionLongLatRad: __use_simulated_position ? [-97.36, 36.93, 2] : undefined
|
||||
}
|
||||
|
||||
QgsQuick.PositionMarker {
|
||||
id: positionMarker
|
||||
positionKit: positionKit
|
||||
}
|
||||
|
||||
Label {
|
||||
id: gpsPositionLabel
|
||||
text: {
|
||||
var label = "Signal Lost"
|
||||
if ( positionKit.hasPosition )
|
||||
label = QgsQuick.Utils.formatPoint( positionKit.position )
|
||||
if (positionKit.accuracy > 0)
|
||||
label += " (" + QgsQuick.Utils.formatDistance( positionKit.accuracy, positionKit.accuracyUnits, 0 ) + ")"
|
||||
label;
|
||||
}
|
||||
height: scaleBar.height
|
||||
x: window.width - width
|
||||
font.pixelSize: 22 * QgsQuick.Utils.dp
|
||||
font.italic: true
|
||||
color: "steelblue"
|
||||
z: 1
|
||||
}
|
||||
|
||||
/** Coordinate transformater */
|
||||
QgsQuick.CoordinateTransformer {
|
||||
id: coordinateTransformer
|
||||
sourcePosition: positionKit.position
|
||||
sourceCrs: positionKit.positionCRS()
|
||||
destinationCrs: QgsQuick.Utils.coordinateReferenceSystemFromEpsgId( 3857 ) //web mercator
|
||||
transformContext: mapCanvas.mapSettings.transformContext()
|
||||
}
|
||||
|
||||
Label {
|
||||
id: webPositionLabel
|
||||
text: {
|
||||
if ( positionKit.hasPosition )
|
||||
QgsQuick.Utils.formatPoint( coordinateTransformer.projectedPosition ) + " (web mercator)"
|
||||
}
|
||||
height: scaleBar.height
|
||||
x: window.width - width
|
||||
y: gpsPositionLabel.height + 2 * QgsQuick.Utils.dp
|
||||
font.pixelSize: 22 * QgsQuick.Utils.dp
|
||||
font.italic: true
|
||||
color: "steelblue"
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
|
61
tests/src/quickgui/testqgsquickpositionkit.cpp
Normal file
61
tests/src/quickgui/testqgsquickpositionkit.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
testqgspositionkit.cpp
|
||||
--------------------------------------
|
||||
Date : May 2018
|
||||
Copyright : (C) 2017 by Viktor Sklencar
|
||||
Email : vsklencar 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgstest.h"
|
||||
#include "qgis.h"
|
||||
|
||||
#include "qgsquickpositionkit.h"
|
||||
#include "qgsquicksimulatedpositionsource.h"
|
||||
#include "qgsquickutils.h"
|
||||
|
||||
class TestQgsQuickUtils: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void init() {} // will be called before each testfunction is executed.
|
||||
void cleanup() {} // will be called after every testfunction.
|
||||
|
||||
void simulated_position();
|
||||
|
||||
private:
|
||||
QgsQuickUtils utils;
|
||||
QgsQuickPositionKit positionKit;
|
||||
};
|
||||
|
||||
void TestQgsQuickUtils::simulated_position()
|
||||
{
|
||||
QVERIFY( !positionKit.isSimulated() );
|
||||
positionKit.useSimulatedLocation( -92.36, 38.93, -1 );
|
||||
QVERIFY( positionKit.isSimulated() );
|
||||
|
||||
QVERIFY( positionKit.hasPosition() );
|
||||
QGSCOMPARENEAR( positionKit.position().y(), 38.93, 1e-4 );
|
||||
QVERIFY( positionKit.accuracy() > 0 );
|
||||
|
||||
const QVector<double> newPosition( { 90.36, 33.93, -1 } );
|
||||
positionKit.setSimulatePositionLongLatRad( newPosition );
|
||||
QVERIFY( positionKit.hasPosition() );
|
||||
QGSCOMPARENEAR( positionKit.position().y(), newPosition[1], 1e-4 );
|
||||
|
||||
positionKit.setSimulatePositionLongLatRad( QVector<double>() );
|
||||
QVERIFY( !positionKit.isSimulated() );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsQuickUtils )
|
||||
#include "testqgsquickpositionkit.moc"
|
@ -17,8 +17,13 @@
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgscoordinatetransformcontext.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgspointxy.h"
|
||||
#include "qgstest.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsunittypes.h"
|
||||
|
||||
#include "qgsquickutils.h"
|
||||
|
||||
@ -32,6 +37,9 @@ class TestQgsQuickUtils: public QObject
|
||||
void screen_density();
|
||||
void dump_screen_info();
|
||||
void screenUnitsToMeters();
|
||||
void transformedPoint();
|
||||
void formatPoint();
|
||||
void formatDistance();
|
||||
|
||||
private:
|
||||
QgsQuickUtils utils;
|
||||
@ -62,5 +70,71 @@ void TestQgsQuickUtils::screenUnitsToMeters()
|
||||
QGSCOMPARENEAR( sutm, 213, 1.0 );
|
||||
}
|
||||
|
||||
void TestQgsQuickUtils::transformedPoint()
|
||||
{
|
||||
QgsPointXY pointXY = utils.pointXY( 49.9, 16.3 );
|
||||
QGSCOMPARENEAR( pointXY.x(), 49.9, 1e-4 );
|
||||
QGSCOMPARENEAR( pointXY.y(), 16.3, 1e-4 );
|
||||
|
||||
QgsPoint point = utils.point( 1.0, -1.0 );
|
||||
QGSCOMPARENEAR( point.x(), 1.0, 1e-4 );
|
||||
QGSCOMPARENEAR( point.y(), -1.0, 1e-4 );
|
||||
|
||||
QgsCoordinateReferenceSystem crs3857 = QgsCoordinateReferenceSystem::fromEpsgId( 3857 );
|
||||
QVERIFY( crs3857.authid() == "EPSG:3857" );
|
||||
|
||||
QgsCoordinateReferenceSystem crsGPS = QgsCoordinateReferenceSystem::fromEpsgId( 4326 );
|
||||
QVERIFY( crsGPS.authid() == "EPSG:4326" );
|
||||
|
||||
QgsPointXY transformedPoint = utils.transformPoint( crsGPS,
|
||||
crs3857,
|
||||
QgsCoordinateTransformContext(),
|
||||
pointXY );
|
||||
QGSCOMPARENEAR( transformedPoint.x(), 5554843, 1.0 );
|
||||
QGSCOMPARENEAR( transformedPoint.y(), 1839491, 1.0 );
|
||||
}
|
||||
|
||||
void TestQgsQuickUtils::formatPoint()
|
||||
{
|
||||
QgsPoint point( -2.234521, 34.4444421 );
|
||||
QString point2str = utils.formatPoint( point );
|
||||
QVERIFY( point2str == "-2.235,34.444" );
|
||||
}
|
||||
|
||||
void TestQgsQuickUtils::formatDistance()
|
||||
{
|
||||
QString dist2str = utils.formatDistance( 1222.234, QgsUnitTypes::DistanceMeters, 2 );
|
||||
QVERIFY( dist2str == "1.22 km" );
|
||||
|
||||
dist2str = utils.formatDistance( 1222.234, QgsUnitTypes::DistanceMeters, 1 );
|
||||
QVERIFY( dist2str == "1.2 km" );
|
||||
|
||||
dist2str = utils.formatDistance( 1222.234, QgsUnitTypes::DistanceMeters, 0 );
|
||||
QVERIFY( dist2str == "1 km" );
|
||||
|
||||
dist2str = utils.formatDistance( 700.22, QgsUnitTypes::DistanceMeters, 1 );
|
||||
QVERIFY( dist2str == "700.2 m" );
|
||||
|
||||
dist2str = utils.formatDistance( 0.22, QgsUnitTypes::DistanceMeters, 0 );
|
||||
QVERIFY( dist2str == "22 cm" );
|
||||
|
||||
dist2str = utils.formatDistance( -0.22, QgsUnitTypes::DistanceMeters, 0 );
|
||||
QVERIFY( dist2str == "0 mm" );
|
||||
|
||||
dist2str = utils.formatDistance( 1.222234, QgsUnitTypes::DistanceKilometers, 2 );
|
||||
QVERIFY( dist2str == "1.22 km" );
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
dist2str = utils.formatDistance( 6000, QgsUnitTypes::DistanceFeet, 1, QgsUnitTypes::ImperialSystem );
|
||||
QVERIFY( dist2str == "1.1 mi" );
|
||||
|
||||
dist2str = utils.formatDistance( 5, QgsUnitTypes::DistanceFeet, 1, QgsUnitTypes::ImperialSystem );
|
||||
QVERIFY( dist2str == "1.7 yd" );
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
dist2str = utils.formatDistance( 7000, QgsUnitTypes::DistanceFeet, 1, QgsUnitTypes::USCSSystem );
|
||||
QVERIFY( dist2str == "1.2 NM" );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsQuickUtils )
|
||||
#include "testqgsquickutils.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user