Skip to content

Commit

Permalink
[FEATURE] add conversion from float to DMS format
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustry authored and nyalldawson committed Sep 13, 2018
1 parent 23f1e43 commit 1409547
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 0 deletions.
15 changes: 15 additions & 0 deletions resources/function_help/json/to_dm
@@ -0,0 +1,15 @@
{
"name": "to_dm",
"type": "function",
"description": "Convert a coordinate to degree, minute.",
"arguments": [
{"arg":"coordinate","description":"A latitude or longitude value."},
{"arg":"axis","description":"The axis of the coordinate. Either 'x' or 'y'."},
{"arg":"precision", "description":"Number of decimals."},
{"arg":"formatting", "optional": true, "default":"", "description":"Designates the formatting type. Acceptable values are NULL, 'aligned' or 'suffix'."}
],
"examples": [
{ "expression":"to_dm(6.3545681, 'x', 3)", "returns":"6°21.274′"},
{ "expression":"to_dm(6.3545681, 'y', 4, 'suffix')", "returns":"6°21.2741′N"}
]
}
15 changes: 15 additions & 0 deletions resources/function_help/json/to_dms
@@ -0,0 +1,15 @@
{
"name": "to_dms",
"type": "function",
"description": "Convert a coordinate to degree, minute, second.",
"arguments": [
{"arg":"coordinate","description":"A latitude or longitude value."},
{"arg":"axis","description":"The axis of the coordinate. Either 'x' or 'y'."},
{"arg":"precision", "description":"Number of decimals."},
{"arg":"formatting", "optional": true, "default":"", "description":"Designates the formatting type. Acceptable values are NULL, 'aligned' or 'suffix'."}
],
"examples": [
{ "expression":"to_dms(6.3545681, 'x', 3)", "returns":"6°21′16.445″"},
{ "expression":"to_dms(6.3545681, 'y', 4, 'suffix')", "returns":"6°21′16.4452″N"}
]
}
59 changes: 59 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -13,6 +13,7 @@
* *
***************************************************************************/

#include "qgscoordinateformatter.h"
#include "qgsexpressionfunction.h"
#include "qgsexpressionutils.h"
#include "qgsexpressionnodeimpl.h"
Expand Down Expand Up @@ -1498,6 +1499,62 @@ static QVariant fcnToInterval( const QVariantList &values, const QgsExpressionCo
return QVariant::fromValue( QgsExpressionUtils::getInterval( values.at( 0 ), parent ) );
}

/*
* DMS functions
*/

static QVariant floatToDegreeFormat( const QgsCoordinateFormatter::Format format, const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
double value = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
QString axis = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
int precision = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );

QString formatString;
if ( values.count() > 3 )
formatString = QgsExpressionUtils::getStringValue( values.at( 3 ), parent );

QgsCoordinateFormatter::FormatFlags flags = nullptr;
if ( formatString.compare( QLatin1String( "suffix" ), Qt::CaseInsensitive ) == 0 )
{
flags = QgsCoordinateFormatter::FlagDegreesUseStringSuffix;
}
else if ( formatString.compare( QLatin1String( "aligned" ), Qt::CaseInsensitive ) == 0 )
{
flags = QgsCoordinateFormatter::FlagDegreesUseStringSuffix | QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds;
}
else if ( ! formatString.isEmpty() )
{
parent->setEvalErrorString( QObject::tr( "Invalid formatting parameter: '%1'. It must be empty, or 'suffix' or 'aligned'." ).arg( formatString ) );
return QVariant();
}

if ( axis.compare( QLatin1String( "x" ), Qt::CaseInsensitive ) == 0 )
{
return QVariant::fromValue( QgsCoordinateFormatter::formatX( value, format, precision, flags ) );
}
else if ( axis.compare( QLatin1String( "y" ), Qt::CaseInsensitive ) == 0 )
{
return QVariant::fromValue( QgsCoordinateFormatter::formatY( value, format, precision, flags ) );
}
else
{
parent->setEvalErrorString( QObject::tr( "Invalid axis name: '%1'. It must be either 'x' or 'y'." ).arg( axis ) );
return QVariant();
}
}

static QVariant fcnToDegreeMinute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
{
QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutes;
return floatToDegreeFormat( format, values, context, parent, node );
}

static QVariant fcnToDegreeMinuteSecond( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
{
QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutesSeconds;
return floatToDegreeFormat( format, values, context, parent, node );
}

static QVariant fcnAge( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QDateTime d1 = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
Expand Down Expand Up @@ -4415,6 +4472,8 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "to_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToDate, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todate" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "to_time" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "totime" ) )
<< 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( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
<< new QgsStaticExpressionFunction( QStringLiteral( "if" ), 3, fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )

Expand Down
10 changes: 10 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -709,6 +709,16 @@ class TestQgsExpression: public QObject
QTest::newRow( "double to text" ) << "tostring(1.23)" << false << QVariant( "1.23" );
QTest::newRow( "null to text" ) << "tostring(null)" << false << QVariant();

// DMS conversion
QTest::newRow( "X coordinate to degree minute aligned" ) << "to_dm(6.3545681,'x',2,'aligned')" << false << QVariant( "6°21.27′E" );
QTest::newRow( "X coordinate to degree minute with suffix" ) << "to_dm(6.3545681,'x',2,'suffix')" << false << QVariant( "6°21.27′E" );
QTest::newRow( "X coordinate to degree minute without formatting" ) << "to_dm(6.3545681,'x',2,'')" << false << QVariant( "6°21.27′" );
QTest::newRow( "X coordinate to degree minute" ) << "to_dm(6.3545681,'x',2)" << false << QVariant( "6°21.27′" );
QTest::newRow( "Y coordinate to degree minute second aligned" ) << "to_dms(6.3545681,'y',2,'aligned')" << 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" ) << "to_dms(6.3545681,'y',2)" << false << QVariant( "6°21′16.45″" );

// geometry functions
QTest::newRow( "num_points" ) << "num_points(geom_from_wkt('GEOMETRYCOLLECTION(LINESTRING(0 0, 1 0),POINT(6 5))'))" << false << QVariant( 3 );
QTest::newRow( "num_interior_rings not geom" ) << "num_interior_rings('g')" << true << QVariant();
Expand Down

0 comments on commit 1409547

Please sign in to comment.