mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-02 00:26:05 -04:00
[FEATURE][expression] Add a to_decimal() function to convert degree/minute/second strings
This commit is contained in:
parent
f7ca8b6786
commit
07ab4b3255
12
resources/function_help/json/to_decimal
Normal file
12
resources/function_help/json/to_decimal
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "to_decimal",
|
||||||
|
"type": "function",
|
||||||
|
"groups": ["Conversions"],
|
||||||
|
"description": "Converts a degree, minute, second coordinate to its decimal equivalent.",
|
||||||
|
"arguments": [
|
||||||
|
{"arg":"value","description":"A degree, minute, second string."}
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
{ "expression":"to_decimal('6°21\\'16.445')", "returns":"6.3545680555"}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "qgscoordinateformatter.h"
|
#include "qgscoordinateformatter.h"
|
||||||
|
#include "qgscoordinateutils.h"
|
||||||
#include "qgsexpressionfunction.h"
|
#include "qgsexpressionfunction.h"
|
||||||
#include "qgsexpressionutils.h"
|
#include "qgsexpressionutils.h"
|
||||||
#include "qgsexpressionnodeimpl.h"
|
#include "qgsexpressionnodeimpl.h"
|
||||||
@ -2100,6 +2101,15 @@ static QVariant fcnToDegreeMinute( const QVariantList &values, const QgsExpressi
|
|||||||
return floatToDegreeFormat( format, values, context, parent, node );
|
return floatToDegreeFormat( format, values, context, parent, node );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVariant fcnToDecimal( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||||
|
{
|
||||||
|
double value = 0.0;
|
||||||
|
bool ok = false;
|
||||||
|
value = QgsCoordinateUtils::dmsToDecimal( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), &ok );
|
||||||
|
|
||||||
|
return ok ? QVariant( value ) : QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
static QVariant fcnToDegreeMinuteSecond( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
|
static QVariant fcnToDegreeMinuteSecond( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
|
||||||
{
|
{
|
||||||
QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutesSeconds;
|
QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutesSeconds;
|
||||||
@ -5737,6 +5747,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
|
|||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "to_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToInterval, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tointerval" ) )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "to_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToInterval, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tointerval" ) )
|
||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "to_dm" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinute, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todm" ) )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "to_dm" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinute, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todm" ) )
|
||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "to_dms" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinuteSecond, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todms" ) )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "to_dms" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinuteSecond, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todms" ) )
|
||||||
|
<< new QgsStaticExpressionFunction( QStringLiteral( "to_decimal" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToDecimal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todecimal" ) )
|
||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
|
||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "nullif" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value2" ) ), fcnNullIf, QStringLiteral( "Conditionals" ) )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "nullif" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value2" ) ), fcnNullIf, QStringLiteral( "Conditionals" ) )
|
||||||
<< new QgsStaticExpressionFunction( QStringLiteral( "if" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "condition" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_true" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_false" ) ), fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
|
<< new QgsStaticExpressionFunction( QStringLiteral( "if" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "condition" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_true" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_false" ) ), fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
|
||||||
|
|||||||
@ -106,4 +106,60 @@ QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double QgsCoordinateUtils::dmsToDecimal( const QString &string, bool *ok )
|
||||||
|
{
|
||||||
|
const QString negative( QStringLiteral( "swSW-" ) );
|
||||||
|
double value = 0.0;
|
||||||
|
bool okValue = false;
|
||||||
|
|
||||||
|
if ( ok )
|
||||||
|
{
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = &okValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression dms( "^\\s*(?:([-+nsew])\\s*)?(\\d{1,3})(?:[^0-9.]+([0-5]?\\d))?[^0-9.]+([0-5]?\\d(?:\\.\\d+)?)[^0-9.]*?([-+nsew])?\\s*$", QRegularExpression::CaseInsensitiveOption );
|
||||||
|
QRegularExpressionMatch match = dms.match( string.trimmed() );
|
||||||
|
if ( match.hasMatch() )
|
||||||
|
{
|
||||||
|
QString dms1 = match.captured( 2 );
|
||||||
|
QString dms2 = match.captured( 3 );
|
||||||
|
QString dms3 = match.captured( 4 );
|
||||||
|
|
||||||
|
double v = dms3.toDouble( ok );
|
||||||
|
if ( *ok == false )
|
||||||
|
return value;
|
||||||
|
// Allow for Degrees/minutes format as well as DMS
|
||||||
|
if ( !dms2.isEmpty() )
|
||||||
|
{
|
||||||
|
v = dms2.toInt( ok ) + v / 60.0;
|
||||||
|
if ( *ok == false )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
v = dms1.toInt( ok ) + v / 60.0;
|
||||||
|
if ( *ok == false )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
QString sign1 = match.captured( 1 );
|
||||||
|
QString sign2 = match.captured( 5 );
|
||||||
|
|
||||||
|
if ( sign1.isEmpty() )
|
||||||
|
{
|
||||||
|
value = !sign2.isEmpty() && negative.contains( sign2 ) ? -v : v;
|
||||||
|
}
|
||||||
|
else if ( sign2.isEmpty() )
|
||||||
|
{
|
||||||
|
value = !sign1.isEmpty() && negative.contains( sign1 ) ? -v : v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
///@endcond
|
///@endcond
|
||||||
|
|||||||
@ -67,6 +67,14 @@ class CORE_EXPORT QgsCoordinateUtils
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE static QString formatCoordinateForProject( QgsProject *project, const QgsPointXY &point, const QgsCoordinateReferenceSystem &destCrs, int precision );
|
Q_INVOKABLE static QString formatCoordinateForProject( QgsProject *project, const QgsPointXY &point, const QgsCoordinateReferenceSystem &destCrs, int precision );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a degree minute second coordinate string to its decimal equivalent.
|
||||||
|
* \param string degree minute second string to convert
|
||||||
|
* \returns Double decimal value
|
||||||
|
* \since QGIS 3.16
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE static double dmsToDecimal( const QString &string, bool *ok );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -869,6 +869,8 @@ class TestQgsExpression: public QObject
|
|||||||
QTest::newRow( "Y coordinate to degree minute second with suffix" ) << "to_dms(6.3545681,'y',2,'suffix')" << false << QVariant( "6°21′16.45″N" );
|
QTest::newRow( "Y coordinate to degree minute second with suffix" ) << "to_dms(6.3545681,'y',2,'suffix')" << false << QVariant( "6°21′16.45″N" );
|
||||||
QTest::newRow( "Y coordinate to degree minute second without formatting" ) << "to_dms(6.3545681,'y',2,'')" << false << QVariant( "6°21′16.45″" );
|
QTest::newRow( "Y coordinate to degree minute second without formatting" ) << "to_dms(6.3545681,'y',2,'')" << false << QVariant( "6°21′16.45″" );
|
||||||
QTest::newRow( "Y coordinate to degree minute second" ) << "to_dms(6.3545681,'y',2)" << false << QVariant( "6°21′16.45″" );
|
QTest::newRow( "Y coordinate to degree minute second" ) << "to_dms(6.3545681,'y',2)" << false << QVariant( "6°21′16.45″" );
|
||||||
|
QTest::newRow( "degree minute second string to decimal" ) << "to_decimal('6°21′16.45″N')" << false << QVariant( 6.35456944444 );
|
||||||
|
QTest::newRow( "wrong degree minute second string to decimal" ) << "to_decimal('qgis')" << false << QVariant();
|
||||||
|
|
||||||
// geometry functions
|
// geometry functions
|
||||||
QTest::newRow( "geom_to_wkb" ) << "geom_to_wkt(geom_from_wkb(geom_to_wkb(make_point(4,5))))" << false << QVariant( "Point (4 5)" );
|
QTest::newRow( "geom_to_wkb" ) << "geom_to_wkt(geom_from_wkb(geom_to_wkb(make_point(4,5))))" << false << QVariant( "Point (4 5)" );
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user