diff --git a/python/core/processing/qgsprocessingalgorithm.sip b/python/core/processing/qgsprocessingalgorithm.sip index b35bb52c08f..4a84c2f2665 100644 --- a/python/core/processing/qgsprocessingalgorithm.sip +++ b/python/core/processing/qgsprocessingalgorithm.sip @@ -696,12 +696,26 @@ class QgsProcessingAlgorithm :rtype: QgsCoordinateReferenceSystem %End - QgsPointXY parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const; + QgsPointXY parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, + const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const; %Docstring Evaluates the parameter with matching ``name`` to a point. + + If ``crs`` is set then the point will be automatically + reprojected so that it is in the specified ``crs``. + +.. seealso:: parameterAsPointCrs() :rtype: QgsPointXY %End + QgsCoordinateReferenceSystem parameterAsPointCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ); +%Docstring + Returns the coordinate reference system associated with an point parameter value. + +.. seealso:: parameterAsPoint() + :rtype: QgsCoordinateReferenceSystem +%End + QString parameterAsFile( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const; %Docstring Evaluates the parameter with matching ``name`` to a file/folder name. diff --git a/python/core/processing/qgsprocessingparameters.sip b/python/core/processing/qgsprocessingparameters.sip index 0fc0773d7c4..da7215c7aa9 100644 --- a/python/core/processing/qgsprocessingparameters.sip +++ b/python/core/processing/qgsprocessingparameters.sip @@ -570,12 +570,25 @@ class QgsProcessingParameters :rtype: QgsCoordinateReferenceSystem %End - static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ); + static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, + const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ); %Docstring Evaluates the parameter with matching ``definition`` to a point. + + If ``crs`` is set then the point will be automatically reprojected so that it is in the specified ``crs``. + +.. seealso:: parameterAsPointCrs() :rtype: QgsPointXY %End + static QgsCoordinateReferenceSystem parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ); +%Docstring + Returns the coordinate reference system associated with an point parameter value. + +.. seealso:: parameterAsPoint() + :rtype: QgsCoordinateReferenceSystem +%End + static QString parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ); %Docstring Evaluates the parameter with matching ``definition`` to a file/folder name. @@ -817,6 +830,8 @@ class QgsProcessingParameterPoint : QgsProcessingParameterDefinition virtual QString type() const; virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const; + virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const; + static QgsProcessingParameterPoint *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) /Factory/; %Docstring diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index 703c202fc6a..8ebadca65ea 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -565,9 +565,14 @@ QgsGeometry QgsProcessingAlgorithm::parameterAsExtentGeometry( const QVariantMap return QgsProcessingParameters::parameterAsExtentGeometry( parameterDefinition( name ), parameters, context, crs ); } -QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const +QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) const { - return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context ); + return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context, crs ); +} + +QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsPointCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) +{ + return QgsProcessingParameters::parameterAsPointCrs( parameterDefinition( name ), parameters, context ); } QString QgsProcessingAlgorithm::parameterAsFile( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const diff --git a/src/core/processing/qgsprocessingalgorithm.h b/src/core/processing/qgsprocessingalgorithm.h index a9fbf2074c3..d13aa80b639 100644 --- a/src/core/processing/qgsprocessingalgorithm.h +++ b/src/core/processing/qgsprocessingalgorithm.h @@ -680,8 +680,21 @@ class CORE_EXPORT QgsProcessingAlgorithm /** * Evaluates the parameter with matching \a name to a point. + * + * If \a crs is set then the point will be automatically + * reprojected so that it is in the specified \a crs. + * + * \see parameterAsPointCrs() */ - QgsPointXY parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const; + QgsPointXY parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, + const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const; + + /** + * Returns the coordinate reference system associated with an point parameter value. + * + * \see parameterAsPoint() + */ + QgsCoordinateReferenceSystem parameterAsPointCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ); /** * Evaluates the parameter with matching \a name to a file/folder name. diff --git a/src/core/processing/qgsprocessingparameters.cpp b/src/core/processing/qgsprocessingparameters.cpp index 634b8a43bb1..008b5b25dc0 100644 --- a/src/core/processing/qgsprocessingparameters.cpp +++ b/src/core/processing/qgsprocessingparameters.cpp @@ -503,7 +503,14 @@ QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingPara if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() ) { QgsCoordinateTransform ct( rr.crs(), crs ); - return ct.transformBoundingBox( rr ); + try + { + return ct.transformBoundingBox( rr ); + } + catch ( QgsCsException & ) + { + QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) ); + } } return rr; } @@ -588,11 +595,34 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( cons return QgsCoordinateReferenceSystem(); } -QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ) +QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) { if ( !definition ) return QgsPointXY(); + QVariant val = parameters.value( definition->name() ); + if ( val.canConvert< QgsPointXY >() ) + { + return val.value(); + } + if ( val.canConvert< QgsReferencedPointXY >() ) + { + QgsReferencedPointXY rp = val.value(); + if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() ) + { + QgsCoordinateTransform ct( rp.crs(), crs ); + try + { + return ct.transform( rp ); + } + catch ( QgsCsException & ) + { + QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) ); + } + } + return rp; + } + QString pointText = parameterAsString( definition, parameters, context ); if ( pointText.isEmpty() ) pointText = definition->defaultValue().toString(); @@ -614,6 +644,25 @@ QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParamet return QgsPointXY(); } +QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ) +{ + QVariant val = parameters.value( definition->name() ); + + if ( val.canConvert< QgsReferencedPointXY >() ) + { + QgsReferencedPointXY rr = val.value(); + if ( rr.crs().isValid() ) + { + return rr.crs(); + } + } + + if ( context.project() ) + return context.project()->crs(); + else + return QgsCoordinateReferenceSystem(); +} + QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ) { if ( !definition ) @@ -1296,6 +1345,15 @@ bool QgsProcessingParameterPoint::checkValueIsAcceptable( const QVariant &input, return true; } + if ( input.canConvert< QgsPointXY >() ) + { + return true; + } + if ( input.canConvert< QgsReferencedPointXY >() ) + { + return true; + } + if ( input.type() == QVariant::String ) { if ( input.toString().isEmpty() ) @@ -1315,6 +1373,28 @@ bool QgsProcessingParameterPoint::checkValueIsAcceptable( const QVariant &input, return false; } +QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const +{ + if ( value.canConvert() ) + return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() ); + + if ( value.canConvert< QgsPointXY >() ) + { + QgsPointXY r = value.value(); + return QStringLiteral( "QgsPointXY( %1, %2 )" ).arg( qgsDoubleToString( r.x() ), + qgsDoubleToString( r.y() ) ); + } + if ( value.canConvert< QgsReferencedPointXY >() ) + { + QgsReferencedPointXY r = value.value(); + return QStringLiteral( "QgsReferencedPointXY( QgsPointXY( %1, %2 ), QgsCoordinateReferenceSystem( '%3' ) )" ).arg( qgsDoubleToString( r.x() ), + qgsDoubleToString( r.y() ), + r.crs().authid() ); + } + + return QgsProcessingParameterDefinition::valueAsPythonString( value, context ); +} + QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) { return new QgsProcessingParameterPoint( name, description, definition, isOptional ); diff --git a/src/core/processing/qgsprocessingparameters.h b/src/core/processing/qgsprocessingparameters.h index 7591ca8a513..014105f2482 100644 --- a/src/core/processing/qgsprocessingparameters.h +++ b/src/core/processing/qgsprocessingparameters.h @@ -598,8 +598,20 @@ class CORE_EXPORT QgsProcessingParameters /** * Evaluates the parameter with matching \a definition to a point. + * + * If \a crs is set then the point will be automatically reprojected so that it is in the specified \a crs. + * + * \see parameterAsPointCrs() */ - static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ); + static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, + const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ); + + /** + * Returns the coordinate reference system associated with an point parameter value. + * + * \see parameterAsPoint() + */ + static QgsCoordinateReferenceSystem parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ); /** * Evaluates the parameter with matching \a definition to a file/folder name. @@ -804,6 +816,7 @@ class CORE_EXPORT QgsProcessingParameterPoint : public QgsProcessingParameterDef QgsProcessingParameterDefinition *clone() const override SIP_FACTORY; QString type() const override { return typeName(); } bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override; + QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override; /** * Creates a new parameter using the definition from a script code. diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index 8720c61632d..67e9ae83c2a 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -151,7 +151,6 @@ void QgsApplication::init( QString profileFolder ) qRegisterMetaType( "QgsFeatureIds" ); qRegisterMetaType( "QgsMessageLog::MessageLevel" ); qRegisterMetaType( "QgsReferencedRectangle" ); - qRegisterMetaType( "QgsReferencedPoint" ); QString prefixPath( getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : applicationDirPath() ); // QgsDebugMsg( QString( "prefixPath(): %1" ).arg( prefixPath ) ); diff --git a/tests/src/core/testqgsprocessing.cpp b/tests/src/core/testqgsprocessing.cpp index 0279d49fa24..a3eadca3946 100644 --- a/tests/src/core/testqgsprocessing.cpp +++ b/tests/src/core/testqgsprocessing.cpp @@ -2010,6 +2010,8 @@ void TestQgsProcessing::parameterPoint() QVERIFY( !def->checkValueIsAcceptable( "layer12312312" ) ); QVERIFY( !def->checkValueIsAcceptable( "" ) ); QVERIFY( !def->checkValueIsAcceptable( QVariant() ) ); + QVERIFY( def->checkValueIsAcceptable( QgsPointXY( 1, 2 ) ) ); + QVERIFY( def->checkValueIsAcceptable( QgsReferencedPointXY( QgsPointXY( 1, 2 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) ); // string representing a point QVariantMap params; @@ -2019,13 +2021,43 @@ void TestQgsProcessing::parameterPoint() QGSCOMPARENEAR( point.x(), 1.1, 0.001 ); QGSCOMPARENEAR( point.y(), 2.2, 0.001 ); + // with target CRS - should make no difference, because source CRS is unknown + point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) ); + QGSCOMPARENEAR( point.x(), 1.1, 0.001 ); + QGSCOMPARENEAR( point.y(), 2.2, 0.001 ); + // nonsense string params.insert( "non_optional", QString( "i'm not a crs, and nothing you can do will make me one" ) ); point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context ); QCOMPARE( point.x(), 0.0 ); QCOMPARE( point.y(), 0.0 ); + // QgsPointXY + params.insert( "non_optional", QgsPointXY( 11.1, 12.2 ) ); + point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context ); + QGSCOMPARENEAR( point.x(), 11.1, 0.001 ); + QGSCOMPARENEAR( point.y(), 12.2, 0.001 ); + + // with target CRS - should make no difference, because source CRS is unknown + point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) ); + QGSCOMPARENEAR( point.x(), 11.1, 0.001 ); + QGSCOMPARENEAR( point.y(), 12.2, 0.001 ); + + // QgsReferencedPointXY + params.insert( "non_optional", QgsReferencedPointXY( QgsPointXY( 1.1, 2.2 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ); + point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context ); + QGSCOMPARENEAR( point.x(), 1.1, 0.001 ); + QGSCOMPARENEAR( point.y(), 2.2, 0.001 ); + QCOMPARE( QgsProcessingParameters::parameterAsPointCrs( def.get(), params, context ).authid(), QStringLiteral( "EPSG:4326" ) ); + + // with target CRS + point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) ); + QGSCOMPARENEAR( point.x(), 122451, 100 ); + QGSCOMPARENEAR( point.y(), 244963, 100 ); + QCOMPARE( def->valueAsPythonString( "1,2", context ), QStringLiteral( "'1,2'" ) ); + QCOMPARE( def->valueAsPythonString( QgsPointXY( 11, 12 ), context ), QStringLiteral( "QgsPointXY( 11, 12 )" ) ); + QCOMPARE( def->valueAsPythonString( QgsReferencedPointXY( QgsPointXY( 11, 12 ), QgsCoordinateReferenceSystem( "epsg:4326" ) ), context ), QStringLiteral( "QgsReferencedPointXY( QgsPointXY( 11, 12 ), QgsCoordinateReferenceSystem( 'EPSG:4326' ) )" ) ); QString code = def->asScriptCode(); QCOMPARE( code, QStringLiteral( "##non_optional=point 1,2" ) );