Skip to content

Commit

Permalink
[processing] Allow QgsGeometry values for point parameter values
Browse files Browse the repository at this point in the history
The centroid of the geometry is used for the point parameter value.
This makes it easier to write expressions for the value of point
parameters, since all the QGIS expression functions for working
with geometry types return QgsGeometry value themselves (e.g.
make_point, centroid, ...). In this case it's much nicer to
allow expression values like `make_point(3,4)` within a precalculated
expression based value in a Processing model.
  • Loading branch information
nyalldawson committed Mar 21, 2019
1 parent c66159b commit acdb368
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 3 deletions.
21 changes: 20 additions & 1 deletion src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -1126,6 +1126,12 @@ QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParamet
{
return val.value<QgsPointXY>();
}
if ( val.canConvert< QgsGeometry >() )
{
const QgsGeometry geom = val.value<QgsGeometry>();
if ( !geom.isNull() )
return geom.centroid().asPoint();
}
if ( val.canConvert< QgsReferencedPointXY >() )
{
QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
Expand Down Expand Up @@ -2129,6 +2135,10 @@ bool QgsProcessingParameterPoint::checkValueIsAcceptable( const QVariant &input,
{
return true;
}
if ( input.canConvert< QgsGeometry >() )
{
return true;
}

if ( input.type() == QVariant::String )
{
Expand Down Expand Up @@ -2165,13 +2175,22 @@ QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value,
return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
qgsDoubleToString( r.y() ) );
}
if ( value.canConvert< QgsReferencedPointXY >() )
else if ( value.canConvert< QgsReferencedPointXY >() )
{
QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
qgsDoubleToString( r.y() ),
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 );
}
}

return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/processing/qgsprocessingparametertypeimpl.h
Expand Up @@ -508,7 +508,8 @@ class CORE_EXPORT QgsProcessingParameterTypePoint : public QgsProcessingParamete
return QStringList() << QObject::tr( "str: as an 'x,y' string, e.g. '1.5,10.1'" )
<< QStringLiteral( "QgsPointXY" )
<< QStringLiteral( "QgsProperty" )
<< QStringLiteral( "QgsReferencedPointXY" );
<< QStringLiteral( "QgsReferencedPointXY" )
<< QStringLiteral( "QgsGeometry: centroid of geometry is used" );
}

QStringList acceptedStringValues() const override
Expand Down
2 changes: 1 addition & 1 deletion src/gui/processing/qgsprocessingwidgetwrapperimpl.cpp
Expand Up @@ -2373,7 +2373,7 @@ QList<int> QgsProcessingPointWidgetWrapper::compatibleDataTypes() const

QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
{
return tr( "string of the format 'x,y'" );
return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
}

QString QgsProcessingPointWidgetWrapper::parameterType() const
Expand Down
19 changes: 19 additions & 0 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -2774,6 +2774,8 @@ void TestQgsProcessing::parameterPoint()
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( def->checkValueIsAcceptable( QgsPointXY( 1, 2 ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsReferencedPointXY( QgsPointXY( 1, 2 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromWkt( QStringLiteral( "LineString(10 10, 20 20)" ) ) ) );

// string representing a point
QVariantMap params;
Expand Down Expand Up @@ -2847,15 +2849,32 @@ void TestQgsProcessing::parameterPoint()
QCOMPARE( QgsProcessingParameters::parameterAsPointCrs( def.get(), params, context ).authid(), QStringLiteral( "EPSG:4326" ) );

// with target CRS
params.insert( "non_optional", QgsReferencedPointXY( QgsPointXY( 1.1, 2.2 ), QgsCoordinateReferenceSystem( "EPSG:4326" ) ) );
point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QGSCOMPARENEAR( point.x(), 122451, 100 );
QGSCOMPARENEAR( point.y(), 244963, 100 );

// QgsGeometry
params.insert( "non_optional", QgsGeometry::fromPointXY( QgsPointXY( 13.1, 14.2 ) ) );
point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context );
QGSCOMPARENEAR( point.x(), 13.1, 0.001 );
QGSCOMPARENEAR( point.y(), 14.2, 0.001 );
// non point geometry should use centroid
params.insert( "non_optional", QgsGeometry::fromWkt( QStringLiteral( "LineString( 10 10, 20 10)" ) ) );
point = QgsProcessingParameters::parameterAsPoint( def.get(), params, context );
QGSCOMPARENEAR( point.x(), 15.0, 0.001 );
QGSCOMPARENEAR( point.y(), 10.0, 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(), 15.0, 0.001 );
QGSCOMPARENEAR( point.y(), 10.0, 0.001 );

QCOMPARE( def->valueAsPythonString( QVariant(), context ), QStringLiteral( "None" ) );
QCOMPARE( def->valueAsPythonString( "1,2", context ), QStringLiteral( "'1,2'" ) );
QCOMPARE( def->valueAsPythonString( "1,2 [EPSG:4326]", context ), QStringLiteral( "'1,2 [EPSG:4326]'" ) );
QCOMPARE( def->valueAsPythonString( QgsPointXY( 11, 12 ), context ), QStringLiteral( "'11,12'" ) );
QCOMPARE( def->valueAsPythonString( QgsReferencedPointXY( QgsPointXY( 11, 12 ), QgsCoordinateReferenceSystem( "epsg:4326" ) ), context ), QStringLiteral( "'11,12 [EPSG:4326]'" ) );
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( "QgsProcessingParameterPoint('non_optional', '', defaultValue='1,2')" ) );
Expand Down

0 comments on commit acdb368

Please sign in to comment.