Skip to content

Commit

Permalink
Use geometry of reproject extent parameters for more accurate clipping
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 14, 2017
1 parent 60b56db commit cfdc3c7
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 3 deletions.
16 changes: 16 additions & 0 deletions python/core/processing/qgsprocessingalgorithm.sip
Expand Up @@ -669,9 +669,25 @@ class QgsProcessingAlgorithm

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. In this case the extent of the reproject rectangle will be returned.

.. seealso:: parameterAsExtentGeometry()
:rtype: QgsRectangle
%End

QgsGeometry parameterAsExtentGeometry( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%Docstring
Evaluates the parameter with matching ``name`` to a rectangular extent, and returns a geometry covering this extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
just the extent of the reprojected rectangle).

.. seealso:: parameterAsExtent()
:rtype: QgsGeometry
%End

QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
%Docstring
Evaluates the parameter with matching ``name`` to a point.
Expand Down
16 changes: 16 additions & 0 deletions python/core/processing/qgsprocessingparameters.sip
Expand Up @@ -541,9 +541,25 @@ class QgsProcessingParameters

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. In this case the extent of the reproject rectangle will be returned.

.. seealso:: parameterAsExtentGeometry()
:rtype: QgsRectangle
%End

static QgsGeometry parameterAsExtentGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%Docstring
Evaluates the parameter with matching ``definition`` to a rectangular extent, and returns a geometry covering this extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
just the extent of the reprojected rectangle).

.. seealso:: parameterAsExtent()
:rtype: QgsGeometry
%End

static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
%Docstring
Evaluates the parameter with matching ``definition`` to a point.
Expand Down
2 changes: 1 addition & 1 deletion src/core/processing/qgsnativealgorithms.cpp
Expand Up @@ -1854,7 +1854,7 @@ QVariantMap QgsExtractByExtentAlgorithm::processAlgorithm( const QVariantMap &pa
if ( !sink )
return QVariantMap();

QgsGeometry clipGeom = QgsGeometry::fromRect( extent );
QgsGeometry clipGeom = parameterAsExtentGeometry( parameters, QStringLiteral( "EXTENT" ), context, featureSource->sourceCrs() );

double step = featureSource->featureCount() > 0 ? 100.0 / featureSource->featureCount() : 1;
QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( extent ).setFlags( QgsFeatureRequest::ExactIntersect ) );
Expand Down
5 changes: 5 additions & 0 deletions src/core/processing/qgsprocessingalgorithm.cpp
Expand Up @@ -555,6 +555,11 @@ QgsRectangle QgsProcessingAlgorithm::parameterAsExtent( const QVariantMap &param
return QgsProcessingParameters::parameterAsExtent( parameterDefinition( name ), parameters, context, crs );
}

QgsGeometry QgsProcessingAlgorithm::parameterAsExtentGeometry( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
{
return QgsProcessingParameters::parameterAsExtentGeometry( parameterDefinition( name ), parameters, context, crs );
}

QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const
{
return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context );
Expand Down
15 changes: 15 additions & 0 deletions src/core/processing/qgsprocessingalgorithm.h
Expand Up @@ -651,10 +651,25 @@ class CORE_EXPORT QgsProcessingAlgorithm
*
* If \a crs is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
* reprojected so that it is in the specified \a crs. In this case the extent of the reproject rectangle will be returned.
*
* \see parameterAsExtentGeometry()
*/
QgsRectangle parameterAsExtent( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;

/**
* Evaluates the parameter with matching \a name to a rectangular extent, and returns a geometry covering this extent.
*
* If \a crs is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
* reprojected so that it is in the specified \a crs. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
* will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
* just the extent of the reprojected rectangle).
*
* \see parameterAsExtent()
*/
QgsGeometry parameterAsExtentGeometry( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );

/**
* Evaluates the parameter with matching \a name to a point.
*/
Expand Down
30 changes: 30 additions & 0 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -539,6 +539,36 @@ QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingPara
return QgsRectangle();
}

QgsGeometry QgsProcessingParameters::parameterAsExtentGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
{
if ( !definition )
return QgsGeometry();

QVariant val = parameters.value( definition->name() );

if ( val.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
QgsGeometry g = QgsGeometry::fromRect( rr );
if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
{
g = g.densifyByCount( 20 );
QgsCoordinateTransform ct( rr.crs(), 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 ) );
}

QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
{
if ( !definition )
Expand Down
15 changes: 15 additions & 0 deletions src/core/processing/qgsprocessingparameters.h
Expand Up @@ -568,10 +568,25 @@ class CORE_EXPORT QgsProcessingParameters
*
* If \a crs is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
* reprojected so that it is in the specified \a crs. In this case the extent of the reproject rectangle will be returned.
*
* \see parameterAsExtentGeometry()
*/
static QgsRectangle parameterAsExtent( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );

/**
* Evaluates the parameter with matching \a definition to a rectangular extent, and returns a geometry covering this extent.
*
* If \a crs is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
* reprojected so that it is in the specified \a crs. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
* will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
* just the extent of the reprojected rectangle).
*
* \see parameterAsExtent()
*/
static QgsGeometry parameterAsExtentGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );

/**
* Evaluates the parameter with matching \a definition to a point.
*/
Expand Down
16 changes: 14 additions & 2 deletions tests/src/core/testqgsprocessing.cpp
Expand Up @@ -1912,6 +1912,9 @@ 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" ) );
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))" ) );

// 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 All @@ -1927,13 +1930,22 @@ void TestQgsProcessing::parameterExtent()
QGSCOMPARENEAR( ext.yMinimum(), 244963, 100 );
QGSCOMPARENEAR( ext.yMaximum(), 490287, 100 );

// as reprojected geometry
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 );

QCOMPARE( def->valueAsPythonString( "1,2,3,4", context ), QStringLiteral( "'1,2,3,4'" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
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.1, 12.2, 13.3, 14.4 ), context ), QStringLiteral( "QgsRectangle( 11.1, 12.2, 13.3, 14.4 )" ) );
QCOMPARE( def->valueAsPythonString( QgsReferencedRectangle( QgsRectangle( 11.1, 12.2, 13.3, 14.4 ), QgsCoordinateReferenceSystem( "epsg:4326" ) ), context ), QStringLiteral( "QgsReferencedRectangle( QgsRectangle( 11.1, 12.2, 13.3, 14.4 ), QgsCoordinateReferenceSystem( 'EPSG:4326' ) )" ) );
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' ) )" ) );

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

0 comments on commit cfdc3c7

Please sign in to comment.