Skip to content

Commit

Permalink
[processing] Accept geometry values for extent parameters
Browse files Browse the repository at this point in the history
The bounding box of the geometry is used for the extent

This allows simple expression based values for extent parameters,
utilising Qgis expression's rich geometry handling methods
  • Loading branch information
nyalldawson committed Mar 25, 2020
1 parent 1915a16 commit 9771b15
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
21 changes: 20 additions & 1 deletion src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -956,6 +956,12 @@ QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingPara
{
return val.value<QgsRectangle>();
}
if ( val.canConvert< QgsGeometry >() )
{
const QgsGeometry geom = val.value<QgsGeometry>();
if ( !geom.isNull() )
return geom.boundingBox();
}
if ( val.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
Expand Down Expand Up @@ -2545,6 +2551,10 @@ bool QgsProcessingParameterExtent::checkValueIsAcceptable( const QVariant &input
QgsRectangle r = input.value<QgsRectangle>();
return !r.isNull();
}
if ( input.canConvert< QgsGeometry >() )
{
return true;
}
if ( input.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle r = input.value<QgsReferencedRectangle>();
Expand Down Expand Up @@ -2600,14 +2610,23 @@ QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ) );
}
if ( value.canConvert< QgsReferencedRectangle >() )
else if ( value.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
qgsDoubleToString( r.yMinimum() ),
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
}
else if ( value.canConvert< QgsGeometry >() )
{
const QgsGeometry g = value.value<QgsGeometry>();
if ( !g.isNull() )
{
const QString wkt = g.asWkt();
return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
}
}

QVariantMap p;
p.insert( name(), value );
Expand Down
3 changes: 2 additions & 1 deletion src/core/processing/qgsprocessingparametertypeimpl.h
Expand Up @@ -620,7 +620,8 @@ class CORE_EXPORT QgsProcessingParameterTypeExtent : public QgsProcessingParamet
<< QObject::tr( "QgsProcessingFeatureSourceDefinition: Extent of source is used" )
<< QStringLiteral( "QgsProperty" )
<< QStringLiteral( "QgsRectangle" )
<< QStringLiteral( "QgsReferencedRectangle" );
<< QStringLiteral( "QgsReferencedRectangle" )
<< QStringLiteral( "QgsGeometry: bounding box of geometry is used" );;
}

QStringList acceptedStringValues() const override
Expand Down
17 changes: 17 additions & 0 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -2690,6 +2690,8 @@ void TestQgsProcessing::parameterExtent()
QVERIFY( !def->checkValueIsAcceptable( QgsRectangle() ) );
QVERIFY( def->checkValueIsAcceptable( QgsReferencedRectangle( QgsRectangle( 1, 2, 3, 4 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) );
QVERIFY( !def->checkValueIsAcceptable( QgsReferencedRectangle( QgsRectangle(), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromRect( QgsRectangle( 1, 2, 3, 4 ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromWkt( QStringLiteral( "LineString(10 10, 20 20)" ) ) ) );

// these checks require a context - otherwise we could potentially be referring to a layer source
QVERIFY( def->checkValueIsAcceptable( "1,2,3" ) );
Expand Down Expand Up @@ -2866,6 +2868,20 @@ void TestQgsProcessing::parameterExtent()
p.setCrs( QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QCOMPARE( QgsProcessingParameters::parameterAsExtentCrs( def.get(), params, context ).authid(), QStringLiteral( "EPSG:3785" ) );

// QgsGeometry
params.insert( "non_optional", QgsGeometry::fromRect( QgsRectangle( 13, 14, 15, 16 ) ) );
ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context );
QGSCOMPARENEAR( ext.xMinimum(), 13, 0.001 );
QGSCOMPARENEAR( ext.xMaximum(), 15, 0.001 );
QGSCOMPARENEAR( ext.yMinimum(), 14, 0.001 );
QGSCOMPARENEAR( ext.yMaximum(), 16, 0.001 );
// with target CRS - should make no difference, because source CRS is unknown
ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QGSCOMPARENEAR( ext.xMinimum(), 13, 0.001 );
QGSCOMPARENEAR( ext.xMaximum(), 15, 0.001 );
QGSCOMPARENEAR( ext.yMinimum(), 14, 0.001 );
QGSCOMPARENEAR( ext.yMaximum(), 16, 0.001 );

// QgsReferencedRectangle
params.insert( "non_optional", QgsReferencedRectangle( QgsRectangle( 1.1, 2.2, 3.3, 4.4 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) );
ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context );
Expand Down Expand Up @@ -2902,6 +2918,7 @@ void TestQgsProcessing::parameterExtent()
QCOMPARE( def->valueAsPythonString( "1,2,3,4 [EPSG:4326]", context ), QStringLiteral( "'1,2,3,4 [EPSG:4326]'" ) );
QCOMPARE( def->valueAsPythonString( "uri='complex' username=\"complex\"", context ), QStringLiteral( "'uri=\\'complex\\' username=\\\"complex\\\"'" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "c:\\test\\new data\\test.dat" ), context ), QStringLiteral( "'c:\\\\test\\\\new data\\\\test.dat'" ) );
QCOMPARE( def->valueAsPythonString( QgsGeometry::fromWkt( QStringLiteral( "LineString( 10 10, 20 20)" ) ), context ), QStringLiteral( "QgsGeometry.fromWkt('LineString (10 10, 20 20)')" ) );

QString pythonCode = def->asPythonString();
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterExtent('non_optional', '', defaultValue='1,2,3,4')" ) );
Expand Down

0 comments on commit 9771b15

Please sign in to comment.