From 6614a003e7975f12766dbefd58c39c6debb63138 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Thu, 6 Feb 2025 11:54:31 +0000 Subject: [PATCH] add expression functions to create CRS from string definition and to get CRS authid (refs #58313) --- src/core/expression/qgsexpression.cpp | 5 ++++ src/core/expression/qgsexpressionfunction.cpp | 28 +++++++++++++++++++ src/core/expression/qgsexpressionutils.h | 11 ++++++++ tests/src/core/testqgsexpression.cpp | 13 +++++++++ 4 files changed, 57 insertions(+) diff --git a/src/core/expression/qgsexpression.cpp b/src/core/expression/qgsexpression.cpp index a97860f2e1e..31463f6c834 100644 --- a/src/core/expression/qgsexpression.cpp +++ b/src/core/expression/qgsexpression.cpp @@ -1047,6 +1047,11 @@ QString QgsExpression::formatPreviewString( const QVariant &value, const bool ht QgsFeature feat = value.value(); return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken; } + else if ( value.userType() == qMetaTypeId< QgsCoordinateReferenceSystem>() ) + { + QgsCoordinateReferenceSystem crs = value.value(); + return startToken + tr( "crs: %1" ).arg( crs.authid() ) + endToken; + } else if ( value.userType() == qMetaTypeId< QgsInterval>() ) { QgsInterval interval = value.value(); diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index 3060b69bcb6..b2f5995741e 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -2583,6 +2583,28 @@ static QVariant fcnSqliteFetchAndIncrement( const QVariantList &values, const Qg return functionResult; } +static QVariant fcnGetCrsAuthid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) +{ + const QgsCoordinateReferenceSystem crs = QgsExpressionUtils::getCrs( values.at( 0 ), parent ); + if ( !crs.isValid() ) + return QVariant(); + return crs.authid(); +} + +static QVariant fcnCrs( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) +{ + QString definition = QgsExpressionUtils::getStringValue( values.at( 0 ), parent ); + QgsCoordinateReferenceSystem crs( definition ); + + if ( !crs.isValid() ) + { + parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to cordinate reference system" ).arg( definition ) ); + crs = QgsCoordinateReferenceSystem(); + } + + return QVariant::fromValue( crs ); +} + static QVariant fcnConcat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) { QString concat; @@ -9384,6 +9406,12 @@ const QList &QgsExpression::Functions() QStringLiteral( "Record and Attributes" ) ); + // **CRS** functions + functions + << new QgsStaticExpressionFunction( QStringLiteral( "crs_authid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "crs" ) ), fcnGetCrsAuthid, QStringLiteral( "CRS" ), QString(), true ) + << new QgsStaticExpressionFunction( QStringLiteral( "crs" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "definition" ) ), fcnCrs, QStringLiteral( "CRS" ) ); + + // **Fields and Values** functions QgsStaticExpressionFunction *representValueFunc = new QgsStaticExpressionFunction( QStringLiteral( "represent_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "field_name" ), true ), fcnRepresentValue, QStringLiteral( "Record and Attributes" ) ); diff --git a/src/core/expression/qgsexpressionutils.h b/src/core/expression/qgsexpressionutils.h index 0c3512b1f55..608db954c08 100644 --- a/src/core/expression/qgsexpressionutils.h +++ b/src/core/expression/qgsexpressionutils.h @@ -24,6 +24,7 @@ #include "qgsvariantutils.h" #include "qgsfeaturerequest.h" #include "qgsreferencedgeometry.h" +#include "qgscoordinatereferencesystem.h" #include #include @@ -365,6 +366,16 @@ class CORE_EXPORT QgsExpressionUtils return 0; } + static QgsCoordinateReferenceSystem getCrs( const QVariant &value, QgsExpression *parent ) + { + if ( value.userType() == qMetaTypeId() ) + return value.value(); + + if ( parent ) + parent->setEvalErrorString( QStringLiteral( "Cannot convert to coordinate reference system" ) ); + return QgsCoordinateReferenceSystem(); + } + static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent ) { if ( value.canConvert() ) diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index 5e54ee90ec1..0692c3be6f1 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -2287,6 +2287,10 @@ class TestQgsExpression : public QObject // Test NULL -> FALSE QTest::newRow( "between nulls FALSE" ) << QStringLiteral( "'c' between NULL AND 'b'" ) << false << QVariant( false ); QTest::newRow( "between nulls FALSE 2" ) << QStringLiteral( "'a' between 'b' AND NULL" ) << false << QVariant( false ); + + // CRS functions + QTest::newRow( "crs epsg id" ) << "crs('EPSG:4326')" << false << QVariant( QgsCoordinateReferenceSystem( "EPSG:4326" ) ); + QTest::newRow( "crs_authid" ) << "crs_authid(crs('EPSG:3857'))" << false << QVariant( "EPSG:3857" ); } void run_evaluation_test( QgsExpression &exp, bool evalError, QVariant &expected ) @@ -2401,6 +2405,12 @@ class TestQgsExpression : public QObject QgsInterval gotinter = expected.value(); QCOMPARE( inter.seconds(), gotinter.seconds() ); } + else if ( result.userType() == qMetaTypeId() ) + { + QgsCoordinateReferenceSystem crs = result.value(); + QgsCoordinateReferenceSystem expectedCrs = expected.value(); + QCOMPARE( crs.authid(), expectedCrs.authid() ); + } else if ( result.userType() >= QMetaType::Type::User ) { QFAIL( "unexpected user type" ); @@ -5278,6 +5288,9 @@ class TestQgsExpression : public QObject color = QColor::fromHsvF( 0.90, 0.5f, 0.25f, 0.1f ); QCOMPARE( QgsExpression::formatPreviewString( QVariant( color ) ), "HSVA: 0.90,0.50,0.25,0.10" ); + + QgsCoordinateReferenceSystem crs( "EPSG:4326" ); + QCOMPARE( QgsExpression::formatPreviewString( QVariant( crs ) ), QStringLiteral( "<crs: EPSG:4326>" ) ); } void test_formatPreviewStringWithLocale()