Skip to content
Permalink
Browse files

[processing] Allow encoding crs into text definitions of extents

  • Loading branch information
nyalldawson committed Sep 24, 2017
1 parent ec44e60 commit fb08b0a6e2b2697fa1ce6cff332524928a6f36da
Showing with 127 additions and 18 deletions.
  1. +87 −15 src/core/processing/qgsprocessingparameters.cpp
  2. +40 −3 tests/src/core/testqgsprocessing.cpp
@@ -524,19 +524,36 @@ QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingPara
if ( rectText.isEmpty() )
return QgsRectangle();

QStringList parts = rectText.split( ',' );
if ( parts.count() == 4 )
QRegularExpression rx( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" );
QRegularExpressionMatch match = rx.match( rectText );
if ( match.hasMatch() )
{
bool xMinOk = false;
double xMin = parts.at( 0 ).toDouble( &xMinOk );
double xMin = match.captured( 1 ).toDouble( &xMinOk );
bool xMaxOk = false;
double xMax = parts.at( 1 ).toDouble( &xMaxOk );
double xMax = match.captured( 2 ).toDouble( &xMaxOk );
bool yMinOk = false;
double yMin = parts.at( 2 ).toDouble( &yMinOk );
double yMin = match.captured( 3 ).toDouble( &yMinOk );
bool yMaxOk = false;
double yMax = parts.at( 3 ).toDouble( &yMaxOk );
double yMax = match.captured( 4 ).toDouble( &yMaxOk );
if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
return QgsRectangle( xMin, yMin, xMax, yMax );
{
QgsRectangle rect( xMin, yMin, xMax, yMax );
QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
{
QgsCoordinateTransform ct( rectCrs, crs );
try
{
return ct.transformBoundingBox( rect );
}
catch ( QgsCsException & )
{
QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
}
}
return rect;
}
}

// try as layer extent
@@ -573,6 +590,49 @@ QgsGeometry QgsProcessingParameters::parameterAsExtentGeometry( const QgsProcess
}
}

QString rectText;
if ( val.canConvert<QgsProperty>() )
rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
else
rectText = val.toString();

if ( !rectText.isEmpty() )
{
QRegularExpression rx( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" );
QRegularExpressionMatch match = rx.match( rectText );
if ( match.hasMatch() )
{
bool xMinOk = false;
double xMin = match.captured( 1 ).toDouble( &xMinOk );
bool xMaxOk = false;
double xMax = match.captured( 2 ).toDouble( &xMaxOk );
bool yMinOk = false;
double yMin = match.captured( 3 ).toDouble( &yMinOk );
bool yMaxOk = false;
double yMax = match.captured( 4 ).toDouble( &yMaxOk );
if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
{
QgsRectangle rect( xMin, yMin, xMax, yMax );
QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
QgsGeometry g = QgsGeometry::fromRect( rect );
if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
{
g = g.densifyByCount( 20 );
QgsCoordinateTransform ct( rectCrs, crs );
try
{
g.transform( ct );
}
catch ( QgsCsException & )
{
QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
}
return g;
}
}
}
}

return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
}

@@ -589,6 +649,17 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( cons
}
}

QRegularExpression rx( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" );

QString valueAsString = parameterAsString( definition, parameters, context );
QRegularExpressionMatch match = rx.match( valueAsString );
if ( match.hasMatch() )
{
QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
if ( crs.isValid() )
return crs;
}

if ( context.project() )
return context.project()->crs();
else
@@ -1301,17 +1372,18 @@ bool QgsProcessingParameterExtent::checkValueIsAcceptable( const QVariant &input
return true;
}

QStringList parts = input.toString().split( ',' );
if ( parts.count() == 4 )
QRegularExpression rx( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" );
QRegularExpressionMatch match = rx.match( input.toString() );
if ( match.hasMatch() )
{
bool xMinOk = false;
( void )parts.at( 0 ).toDouble( &xMinOk );
( void )match.captured( 1 ).toDouble( &xMinOk );
bool xMaxOk = false;
( void )parts.at( 1 ).toDouble( &xMaxOk );
( void )match.captured( 2 ).toDouble( &xMaxOk );
bool yMinOk = false;
( void )parts.at( 2 ).toDouble( &yMinOk );
( void )match.captured( 3 ).toDouble( &yMinOk );
bool yMaxOk = false;
( void )parts.at( 3 ).toDouble( &yMaxOk );
( void )match.captured( 4 ).toDouble( &yMaxOk );
if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
return true;
}
@@ -1328,15 +1400,15 @@ QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value
if ( value.canConvert< QgsRectangle >() )
{
QgsRectangle r = value.value<QgsRectangle>();
return QStringLiteral( "QgsRectangle( %1, %2, %3, %4 )" ).arg( qgsDoubleToString( r.xMinimum() ),
return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
qgsDoubleToString( r.yMinimum() ),
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ) );
}
if ( value.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
return QStringLiteral( "QgsReferencedRectangle( QgsRectangle( %1, %2, %3, %4 ), QgsCoordinateReferenceSystem( '%5' ) )" ).arg( qgsDoubleToString( r.xMinimum() ),
return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
qgsDoubleToString( r.yMinimum() ),
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
@@ -1844,6 +1844,21 @@ void TestQgsProcessing::parameterExtent()
QVERIFY( !def->checkValueIsAcceptable( true ) );
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
QVERIFY( def->checkValueIsAcceptable( "1,2,3,4" ) );
QVERIFY( def->checkValueIsAcceptable( " 1, 2 ,3 , 4 " ) );
QVERIFY( def->checkValueIsAcceptable( " 1, 2 ,3 , 4 ", &context ) );
QVERIFY( def->checkValueIsAcceptable( "-1.1,2,-3,-4" ) );
QVERIFY( def->checkValueIsAcceptable( "-1.1,2,-3,-4", &context ) );
QVERIFY( def->checkValueIsAcceptable( "-1.1,-2.2,-3.3,-4.4" ) );
QVERIFY( def->checkValueIsAcceptable( "-1.1,-2.2,-3.3,-4.4", &context ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2,3,4.4[EPSG:4326]" ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2,3,4.4[EPSG:4326]", &context ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2,3,4.4 [EPSG:4326]" ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2,3,4.4 [EPSG:4326]", &context ) );
QVERIFY( def->checkValueIsAcceptable( " -1.1, -2, -3, -4.4 [EPSG:4326] " ) );
QVERIFY( def->checkValueIsAcceptable( " -1.1, -2, -3, -4.4 [EPSG:4326] ", &context ) );
QVERIFY( def->checkValueIsAcceptable( "121774.38859446358,948723.6921024882,-264546.200347173,492749.6672022904 [EPSG:3785]" ) );
QVERIFY( def->checkValueIsAcceptable( "121774.38859446358,948723.6921024882,-264546.200347173,492749.6672022904 [EPSG:3785]", &context ) );

QVERIFY( !def->checkValueIsAcceptable( "" ) );
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( def->checkValueIsAcceptable( QgsRectangle( 1, 2, 3, 4 ) ) );
@@ -1894,6 +1909,27 @@ void TestQgsProcessing::parameterExtent()
QGSCOMPARENEAR( ext.yMinimum(), 3.3, 0.001 );
QGSCOMPARENEAR( ext.yMaximum(), 4.4, 0.001 );

// with crs in string
params.insert( "non_optional", QString( "1.1,3.3,2.2,4.4 [EPSG:4326]" ) );
QCOMPARE( QgsProcessingParameters::parameterAsExtentCrs( def.get(), params, context ).authid(), QStringLiteral( "EPSG:4326" ) );
ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context );
QGSCOMPARENEAR( ext.xMinimum(), 1.1, 0.001 );
QGSCOMPARENEAR( ext.xMaximum(), 3.3, 0.001 );
QGSCOMPARENEAR( ext.yMinimum(), 2.2, 0.001 );
QGSCOMPARENEAR( ext.yMaximum(), 4.4, 0.001 );
ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QGSCOMPARENEAR( ext.xMinimum(), 122451, 100 );
QGSCOMPARENEAR( ext.xMaximum(), 367354, 100 );
QGSCOMPARENEAR( ext.yMinimum(), 244963, 100 );
QGSCOMPARENEAR( ext.yMaximum(), 490287, 100 );
QgsGeometry gExt = QgsProcessingParameters::parameterAsExtentGeometry( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QCOMPARE( gExt.geometry()->vertexCount(), 85 );
ext = gExt.boundingBox();
QGSCOMPARENEAR( ext.xMinimum(), 122451, 100 );
QGSCOMPARENEAR( ext.xMaximum(), 367354, 100 );
QGSCOMPARENEAR( ext.yMinimum(), 244963, 100 );
QGSCOMPARENEAR( ext.yMaximum(), 490287, 100 );

// nonsense string
params.insert( "non_optional", QString( "i'm not a crs, and nothing you can do will make me one" ) );
QVERIFY( QgsProcessingParameters::parameterAsExtent( def.get(), params, context ).isNull() );
@@ -1913,7 +1949,7 @@ void TestQgsProcessing::parameterExtent()
QGSCOMPARENEAR( ext.yMinimum(), 12.2, 0.001 );
QGSCOMPARENEAR( ext.yMaximum(), 14.4, 0.001 );

QgsGeometry gExt = QgsProcessingParameters::parameterAsExtentGeometry( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
gExt = QgsProcessingParameters::parameterAsExtentGeometry( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:3785" ) );
QCOMPARE( gExt.exportToWkt( 1 ), QStringLiteral( "Polygon ((11.1 12.2, 13.3 12.2, 13.3 14.4, 11.1 14.4, 11.1 12.2))" ) );

p.setCrs( QgsCoordinateReferenceSystem( "EPSG:3785" ) );
@@ -1949,8 +1985,9 @@ void TestQgsProcessing::parameterExtent()
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( r1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( raster2, context ), QString( "'" ) + testDataDir + QStringLiteral( "landsat.tif'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
QCOMPARE( def->valueAsPythonString( QgsRectangle( 11, 12, 13, 14 ), context ), QStringLiteral( "QgsRectangle( 11, 12, 13, 14 )" ) );
QCOMPARE( def->valueAsPythonString( QgsReferencedRectangle( QgsRectangle( 11, 12, 13, 14 ), QgsCoordinateReferenceSystem( "epsg:4326" ) ), context ), QStringLiteral( "QgsReferencedRectangle( QgsRectangle( 11, 12, 13, 14 ), QgsCoordinateReferenceSystem( 'EPSG:4326' ) )" ) );
QCOMPARE( def->valueAsPythonString( QgsRectangle( 11, 12, 13, 14 ), context ), QStringLiteral( "'11, 13, 12, 14'" ) );
QCOMPARE( def->valueAsPythonString( QgsReferencedRectangle( QgsRectangle( 11, 12, 13, 14 ), QgsCoordinateReferenceSystem( "epsg:4326" ) ), context ), QStringLiteral( "'11, 13, 12, 14 [EPSG:4326]'" ) );
QCOMPARE( def->valueAsPythonString( "1,2,3,4 [EPSG:4326]", context ), QStringLiteral( "'1,2,3,4 [EPSG:4326]'" ) );

QString code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##non_optional=extent 1,2,3,4" ) );

0 comments on commit fb08b0a

Please sign in to comment.
You can’t perform that action at this time.