mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-17 00:09:36 -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 "qgscoordinateformatter.h"
|
||||
#include "qgscoordinateutils.h"
|
||||
#include "qgsexpressionfunction.h"
|
||||
#include "qgsexpressionutils.h"
|
||||
#include "qgsexpressionnodeimpl.h"
|
||||
@ -2100,6 +2101,15 @@ static QVariant fcnToDegreeMinute( const QVariantList &values, const QgsExpressi
|
||||
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 )
|
||||
{
|
||||
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_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_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( "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 )
|
||||
|
@ -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
|
||||
|
@ -67,6 +67,14 @@ class CORE_EXPORT QgsCoordinateUtils
|
||||
*/
|
||||
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 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( "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
|
||||
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