diff --git a/python/analysis/raster/qgsalignraster.sip b/python/analysis/raster/qgsalignraster.sip
index d8f7611534b..e133a015f66 100644
--- a/python/analysis/raster/qgsalignraster.sip
+++ b/python/analysis/raster/qgsalignraster.sip
@@ -31,6 +31,8 @@ class QgsAlignRaster
QPointF gridOffset() const;
//! Return extent of the raster
QgsRectangle extent() const;
+ //! Return origin of the raster
+ QPointF origin() const;
//! write contents of the object to standard error stream - for debugging
void dump() const;
@@ -109,10 +111,6 @@ class QgsAlignRaster
//! Get the output CRS in WKT format
QString destinationCRS() const;
- // TODO: first need to run determineTransformAndSize() before this
- //QSize rasterSize() const { return QSize(mXSize, mYSize); }
- // TODO: add method for access to final extent
-
//! Configure clipping extent (region of interest).
//! No extra clipping is done if the rectangle is null
void setClipExtent( double xmin, double ymin, double xmax, double ymax );
@@ -123,10 +121,19 @@ class QgsAlignRaster
//! No extra clipping is done if the rectangle is null
QgsRectangle clipExtent() const;
- //! Set destination CRS, cell size and grid offset from a raster file
- bool setParametersFromRaster( const RasterInfo& rasterInfo, const QString& destWkt = QString() );
- //! Set destination CRS, cell size and grid offset from a raster file
- bool setParametersFromRaster( const QString& filename, const QString& destWkt = QString() );
+ //! Set destination CRS, cell size and grid offset from a raster file.
+ //! The user may provide custom values for some of the parameters - in such case
+ //! only the remaining parameters are calculated.
+ //!
+ //! If default CRS is used, the parameters are set according to the raster file's geo-transform.
+ //! If a custom CRS is provided, suggested reprojection is calculated first (using GDAL) in order
+ //! to determine suitable defaults for cell size and grid offset.
+ //!
+ //! @return true on success (may fail if it is not possible to reproject raster to given CRS)
+ bool setParametersFromRaster( const RasterInfo& rasterInfo, const QString& customCRSWkt = QString(), QSizeF customCellSize = QSizeF(), QPointF customGridOffset = QPointF( -1, -1 ) );
+ //! Overridden variant for convenience, taking filename instead RasterInfo object.
+ //! See the other variant for details.
+ bool setParametersFromRaster( const QString& filename, const QString& customCRSWkt = QString(), QSizeF customCellSize = QSizeF(), QPointF customGridOffset = QPointF( -1, -1 ) );
//! Determine destination extent from the input rasters and calculate derived values
//! @return true on success, sets error on error (see errorMessage())
diff --git a/src/analysis/raster/qgsalignraster.cpp b/src/analysis/raster/qgsalignraster.cpp
index e126205c2a3..f307209d963 100644
--- a/src/analysis/raster/qgsalignraster.cpp
+++ b/src/analysis/raster/qgsalignraster.cpp
@@ -149,34 +149,86 @@ QgsRectangle QgsAlignRaster::clipExtent() const
}
-bool QgsAlignRaster::setParametersFromRaster( const QString& filename, const QString& destWkt )
+bool QgsAlignRaster::setParametersFromRaster( const QString& filename, const QString& destWkt, QSizeF customCellSize, QPointF customGridOffset )
{
- return setParametersFromRaster( RasterInfo( filename ), destWkt );
+ return setParametersFromRaster( RasterInfo( filename ), destWkt, customCellSize, customGridOffset );
}
-bool QgsAlignRaster::setParametersFromRaster( const RasterInfo& rasterInfo, const QString& destWkt )
+bool QgsAlignRaster::setParametersFromRaster( const RasterInfo& rasterInfo, const QString& customCRSWkt, QSizeF customCellSize, QPointF customGridOffset )
{
- if ( destWkt.isEmpty() || destWkt.toAscii() == rasterInfo.crs() )
+ if ( customCRSWkt.isEmpty() || customCRSWkt.toAscii() == rasterInfo.crs() )
{
// use ref. layer to init input
mCrsWkt = rasterInfo.crs();
- mCellSizeX = rasterInfo.cellSize().width();
- mCellSizeY = rasterInfo.cellSize().height();
- mGridOffsetX = rasterInfo.gridOffset().x();
- mGridOffsetY = rasterInfo.gridOffset().y();
+
+ if ( !customCellSize.isValid() )
+ {
+ mCellSizeX = rasterInfo.cellSize().width();
+ mCellSizeY = rasterInfo.cellSize().height();
+ }
+ else
+ {
+ mCellSizeX = customCellSize.width();
+ mCellSizeY = customCellSize.height();
+ }
+
+ if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
+ {
+ if ( !customCellSize.isValid() )
+ {
+ // using original raster's grid offset to be aligned with origin
+ mGridOffsetX = rasterInfo.gridOffset().x();
+ mGridOffsetY = rasterInfo.gridOffset().y();
+ }
+ else
+ {
+ // if using custom cell size: offset so that we are aligned
+ // with the original raster's origin point
+ mGridOffsetX = fmod_with_tolerance( rasterInfo.origin().x(), customCellSize.width() );
+ mGridOffsetY = fmod_with_tolerance( rasterInfo.origin().y(), customCellSize.height() );
+ }
+ }
+ else
+ {
+ mGridOffsetX = customGridOffset.x();
+ mGridOffsetY = customGridOffset.x();
+ }
}
else
{
QSizeF cs;
QPointF go;
- if ( !suggestedWarpOutput( rasterInfo, destWkt.toAscii(), &cs, &go ) )
+ if ( !suggestedWarpOutput( rasterInfo, customCRSWkt.toAscii(), &cs, &go ) )
+ {
+ mCrsWkt = "_error_";
+ mCellSizeX = mCellSizeY = 0;
+ mGridOffsetX = mGridOffsetY = 0;
return false;
+ }
- mCrsWkt = destWkt.toAscii();
- mCellSizeX = cs.width();
- mCellSizeY = cs.height();
- mGridOffsetX = go.x();
- mGridOffsetY = go.y();
+ mCrsWkt = customCRSWkt.toAscii();
+
+ if ( !customCellSize.isValid() )
+ {
+ mCellSizeX = cs.width();
+ mCellSizeY = cs.height();
+ }
+ else
+ {
+ mCellSizeX = customCellSize.width();
+ mCellSizeY = customCellSize.height();
+ }
+
+ if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
+ {
+ mGridOffsetX = go.x();
+ mGridOffsetY = go.y();
+ }
+ else
+ {
+ mGridOffsetX = customGridOffset.x();
+ mGridOffsetY = customGridOffset.x();
+ }
}
return true;
}
@@ -186,6 +238,12 @@ bool QgsAlignRaster::checkInputParameters()
{
mErrorMessage.clear();
+ if ( mCrsWkt == "_error_" )
+ {
+ mErrorMessage = QObject::tr( "Unable to reproject." );
+ return false;
+ }
+
if ( mCellSizeX == 0 || mCellSizeY == 0 )
{
mErrorMessage = QObject::tr( "Cell size must not be zero." );
@@ -502,6 +560,11 @@ QgsRectangle QgsAlignRaster::RasterInfo::extent() const
return transform_to_extent( mGeoTransform, mXSize, mYSize );
}
+QPointF QgsAlignRaster::RasterInfo::origin() const
+{
+ return QPointF( mGeoTransform[0], mGeoTransform[3] );
+}
+
void QgsAlignRaster::RasterInfo::dump() const
{
qDebug( "---RASTER INFO------------------" );
diff --git a/src/analysis/raster/qgsalignraster.h b/src/analysis/raster/qgsalignraster.h
index c72185fa9e8..0d311c589ad 100644
--- a/src/analysis/raster/qgsalignraster.h
+++ b/src/analysis/raster/qgsalignraster.h
@@ -63,6 +63,8 @@ class ANALYSIS_EXPORT QgsAlignRaster
QPointF gridOffset() const;
//! Return extent of the raster
QgsRectangle extent() const;
+ //! Return origin of the raster
+ QPointF origin() const;
//! write contents of the object to standard error stream - for debugging
void dump() const;
@@ -167,10 +169,19 @@ class ANALYSIS_EXPORT QgsAlignRaster
//! No extra clipping is done if the rectangle is null
QgsRectangle clipExtent() const;
- //! Set destination CRS, cell size and grid offset from a raster file
- bool setParametersFromRaster( const RasterInfo& rasterInfo, const QString& destWkt = QString() );
- //! Set destination CRS, cell size and grid offset from a raster file
- bool setParametersFromRaster( const QString& filename, const QString& destWkt = QString() );
+ //! Set destination CRS, cell size and grid offset from a raster file.
+ //! The user may provide custom values for some of the parameters - in such case
+ //! only the remaining parameters are calculated.
+ //!
+ //! If default CRS is used, the parameters are set according to the raster file's geo-transform.
+ //! If a custom CRS is provided, suggested reprojection is calculated first (using GDAL) in order
+ //! to determine suitable defaults for cell size and grid offset.
+ //!
+ //! @return true on success (may fail if it is not possible to reproject raster to given CRS)
+ bool setParametersFromRaster( const RasterInfo& rasterInfo, const QString& customCRSWkt = QString(), QSizeF customCellSize = QSizeF(), QPointF customGridOffset = QPointF( -1, -1 ) );
+ //! Overridden variant for convenience, taking filename instead RasterInfo object.
+ //! See the other variant for details.
+ bool setParametersFromRaster( const QString& filename, const QString& customCRSWkt = QString(), QSizeF customCellSize = QSizeF(), QPointF customGridOffset = QPointF( -1, -1 ) );
//! Determine destination extent from the input rasters and calculate derived values
//! @return true on success, sets error on error (see errorMessage())
diff --git a/src/app/qgsalignrasterdialog.cpp b/src/app/qgsalignrasterdialog.cpp
index 16838b7f07a..343164e6725 100644
--- a/src/app/qgsalignrasterdialog.cpp
+++ b/src/app/qgsalignrasterdialog.cpp
@@ -73,12 +73,22 @@ QgsAlignRasterDialog::QgsAlignRasterDialog( QWidget *parent )
connect( mBtnRemove, SIGNAL( clicked( bool ) ), this, SLOT( removeLayer() ) );
connect( mBtnEdit, SIGNAL( clicked( bool ) ), this, SLOT( editLayer() ) );
- connect( mCboReferenceLayer, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateConfigFromReferenceLayer() ) );
+ connect( mCboReferenceLayer, SIGNAL( currentIndexChanged( int ) ), this, SLOT( referenceLayerChanged() ) );
connect( mCrsSelector, SIGNAL( crsChanged( QgsCoordinateReferenceSystem ) ), this, SLOT( destinationCrsChanged() ) );
+ connect( mSpinCellSizeX, SIGNAL( valueChanged( double ) ), this, SLOT( updateParametersFromReferenceLayer() ) );
+ connect( mSpinCellSizeY, SIGNAL( valueChanged( double ) ), this, SLOT( updateParametersFromReferenceLayer() ) );
+ connect( mSpinGridOffsetX, SIGNAL( valueChanged( double ) ), this, SLOT( updateParametersFromReferenceLayer() ) );
+ connect( mSpinGridOffsetY, SIGNAL( valueChanged( double ) ), this, SLOT( updateParametersFromReferenceLayer() ) );
+
+ connect( mChkCustomCRS, SIGNAL( clicked( bool ) ), this, SLOT( updateCustomCRS() ) );
+ connect( mChkCustomCellSize, SIGNAL( clicked( bool ) ), this, SLOT( updateCustomCellSize() ) );
+ connect( mChkCustomGridOffset, SIGNAL( clicked( bool ) ), this, SLOT( updateCustomGridOffset() ) );
mClipExtentGroupBox->setChecked( false );
mClipExtentGroupBox->setCollapsed( true );
mClipExtentGroupBox->setTitleBase( tr( "Clip to Extent" ) );
+ QgsMapCanvas* mc = QgisApp::instance()->mapCanvas();
+ mClipExtentGroupBox->setCurrentExtent( mc->extent(), mc->mapSettings().destinationCrs() );
connect( mClipExtentGroupBox, SIGNAL( extentChanged( QgsRectangle ) ), this, SLOT( clipExtentChanged() ) );
// TODO: auto-detect reference layer
@@ -86,6 +96,10 @@ QgsAlignRasterDialog::QgsAlignRasterDialog( QWidget *parent )
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( runAlign() ) );
populateLayersView();
+
+ updateCustomCRS();
+ updateCustomCellSize();
+ updateCustomGridOffset();
}
QgsAlignRasterDialog::~QgsAlignRasterDialog()
@@ -130,6 +144,67 @@ void QgsAlignRasterDialog::updateAlignedRasterInfo()
mEditOutputSize->setText( msg );
}
+void QgsAlignRasterDialog::updateParametersFromReferenceLayer()
+{
+ QString customCRSWkt;
+ QSizeF customCellSize;
+ QPointF customGridOffset( -1, -1 );
+
+ int index = mCboReferenceLayer->currentIndex();
+ if ( index < 0 )
+ return;
+
+ QgsAlignRaster::RasterInfo refInfo( mAlign->rasters().at( index ).inputFilename );
+ if ( !refInfo.isValid() )
+ return;
+
+ // get custom values from the GUI (if any)
+ if ( mChkCustomCRS->isChecked() )
+ {
+ QgsCoordinateReferenceSystem refCRS( QString::fromAscii( refInfo.crs() ) );
+ if ( refCRS != mCrsSelector->crs() )
+ customCRSWkt = mCrsSelector->crs().toWkt();
+ }
+
+ if ( mChkCustomCellSize->isChecked() )
+ {
+ customCellSize = QSizeF( mSpinCellSizeX->value(), mSpinCellSizeY->value() );
+ }
+
+ if ( mChkCustomGridOffset->isChecked() )
+ {
+ customGridOffset = QPointF( mSpinGridOffsetX->value(), mSpinGridOffsetY->value() );
+ }
+
+ // calculate the parameters which are not customized already
+ bool res = mAlign->setParametersFromRaster( refInfo, customCRSWkt, customCellSize, customGridOffset );
+
+ // refresh values that may have changed
+ if ( res )
+ {
+ QgsCoordinateReferenceSystem destCRS( mAlign->destinationCRS() );
+ mClipExtentGroupBox->setOutputCrs( destCRS );
+ if ( !mChkCustomCRS->isChecked() )
+ {
+ mCrsSelector->setCrs( destCRS );
+ }
+ }
+ if ( !mChkCustomCellSize->isChecked() )
+ {
+ QSizeF cellSize = mAlign->cellSize();
+ mSpinCellSizeX->setValue( cellSize.width() );
+ mSpinCellSizeY->setValue( cellSize.height() );
+ }
+ if ( !mChkCustomGridOffset->isChecked() )
+ {
+ QPointF gridOffset = mAlign->gridOffset();
+ mSpinGridOffsetX->setValue( gridOffset.x() );
+ mSpinGridOffsetY->setValue( gridOffset.y() );
+ }
+
+ updateAlignedRasterInfo();
+}
+
void QgsAlignRasterDialog::addLayer()
{
@@ -185,7 +260,7 @@ void QgsAlignRasterDialog::editLayer()
populateLayersView();
}
-void QgsAlignRasterDialog::updateConfigFromReferenceLayer()
+void QgsAlignRasterDialog::referenceLayerChanged()
{
int index = mCboReferenceLayer->currentIndex();
if ( index < 0 )
@@ -195,25 +270,11 @@ void QgsAlignRasterDialog::updateConfigFromReferenceLayer()
if ( !refInfo.isValid() )
return;
- mAlign->setParametersFromRaster( refInfo );
+ QgsCoordinateReferenceSystem layerCRS( QString::fromAscii( refInfo.crs() ) );
+ mCrsSelector->setLayerCrs( layerCRS );
+ mClipExtentGroupBox->setOriginalExtent( refInfo.extent(), layerCRS );
- QgsCoordinateReferenceSystem destCRS( mAlign->destinationCRS() );
- mCrsSelector->setCrs( destCRS );
-
- QSizeF cellSize = mAlign->cellSize();
- mSpinCellSizeX->setValue( cellSize.width() );
- mSpinCellSizeY->setValue( cellSize.height() );
-
- QPointF gridOffset = mAlign->gridOffset();
- mSpinGridOffsetX->setValue( gridOffset.x() );
- mSpinGridOffsetY->setValue( gridOffset.y() );
-
- QgsMapCanvas* mc = QgisApp::instance()->mapCanvas();
- mClipExtentGroupBox->setCurrentExtent( mc->extent(), mc->mapSettings().destinationCrs() );
- mClipExtentGroupBox->setOriginalExtent( refInfo.extent(), QgsCoordinateReferenceSystem( QString::fromAscii( refInfo.crs() ) ) );
- mClipExtentGroupBox->setOutputCrs( destCRS );
-
- updateAlignedRasterInfo();
+ updateParametersFromReferenceLayer();
}
@@ -230,23 +291,7 @@ void QgsAlignRasterDialog::destinationCrsChanged()
if ( !refInfo.isValid() )
return;
- if ( !mAlign->setParametersFromRaster( refInfo, mCrsSelector->crs().toWkt() ) )
- {
- QMessageBox::warning( this, tr( "Align Rasters" ), tr( "Cannot reproject reference layer to the chosen destination CRS.\n\nPlease select a different CRS" ) );
- return;
- }
-
- QSizeF cellSize = mAlign->cellSize();
- mSpinCellSizeX->setValue( cellSize.width() );
- mSpinCellSizeY->setValue( cellSize.height() );
-
- QPointF gridOffset = mAlign->gridOffset();
- mSpinGridOffsetX->setValue( gridOffset.x() );
- mSpinGridOffsetY->setValue( gridOffset.y() );
-
- mClipExtentGroupBox->setOutputCrs( mCrsSelector->crs() );
-
- updateAlignedRasterInfo();
+ updateParametersFromReferenceLayer();
}
void QgsAlignRasterDialog::clipExtentChanged()
@@ -256,6 +301,26 @@ void QgsAlignRasterDialog::clipExtentChanged()
updateAlignedRasterInfo();
}
+void QgsAlignRasterDialog::updateCustomCRS()
+{
+ mCrsSelector->setEnabled( mChkCustomCRS->isChecked() );
+ updateParametersFromReferenceLayer();
+}
+
+void QgsAlignRasterDialog::updateCustomCellSize()
+{
+ mSpinCellSizeX->setEnabled( mChkCustomCellSize->isChecked() );
+ mSpinCellSizeY->setEnabled( mChkCustomCellSize->isChecked() );
+ updateParametersFromReferenceLayer();
+}
+
+void QgsAlignRasterDialog::updateCustomGridOffset()
+{
+ mSpinGridOffsetX->setEnabled( mChkCustomGridOffset->isChecked() );
+ mSpinGridOffsetY->setEnabled( mChkCustomGridOffset->isChecked() );
+ updateParametersFromReferenceLayer();
+}
+
void QgsAlignRasterDialog::runAlign()
{
diff --git a/src/app/qgsalignrasterdialog.h b/src/app/qgsalignrasterdialog.h
index ce9ee987647..2184c4f6e96 100644
--- a/src/app/qgsalignrasterdialog.h
+++ b/src/app/qgsalignrasterdialog.h
@@ -22,7 +22,7 @@ class QgsAlignRasterDialog : public QDialog, private Ui::QgsAlignRasterDialog
void removeLayer();
void editLayer();
- void updateConfigFromReferenceLayer();
+ void referenceLayerChanged();
void runAlign();
@@ -30,6 +30,12 @@ class QgsAlignRasterDialog : public QDialog, private Ui::QgsAlignRasterDialog
void clipExtentChanged();
+ void updateCustomCRS();
+ void updateCustomCellSize();
+ void updateCustomGridOffset();
+
+ void updateParametersFromReferenceLayer();
+
protected:
void populateLayersView();
void updateAlignedRasterInfo();
diff --git a/src/ui/qgsalignrasterdialog.ui b/src/ui/qgsalignrasterdialog.ui
index f97a9c5e303..ab10c31daa4 100644
--- a/src/ui/qgsalignrasterdialog.ui
+++ b/src/ui/qgsalignrasterdialog.ui
@@ -80,44 +80,27 @@
-
-
-
+
-
Output Size
- -
-
-
- Grid Offset
-
-
-
- -
+
-
Reference Layer
- -
+
-
- -
+
-
- -
-
-
- Cell Size
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
-
-
-
- -
+
-
-
@@ -141,14 +124,7 @@
- -
-
-
- CRS
-
-
-
- -
+
-
-
@@ -172,7 +148,7 @@
- -
+
-
Add aligned rasters to map canvas
@@ -182,7 +158,7 @@
- -
+
-
true
@@ -190,13 +166,34 @@
- -
+
-
true
+ -
+
+
+ CRS
+
+
+
+ -
+
+
+ Cell Size
+
+
+
+ -
+
+
+ Grid Offset
+
+
+
-
@@ -239,10 +236,15 @@
mBtnRemove
mViewLayers
mCboReferenceLayer
+ mChkCustomCRS
+ mChkCustomCellSize
mSpinCellSizeX
mSpinCellSizeY
+ mChkCustomGridOffset
mSpinGridOffsetX
mSpinGridOffsetY
+ mClipExtentGroupBox
+ mEditOutputSize
mChkAddToCanvas
buttonBox
diff --git a/tests/src/analysis/testqgsalignraster.cpp b/tests/src/analysis/testqgsalignraster.cpp
index 073afde0af0..38c46f5271b 100644
--- a/tests/src/analysis/testqgsalignraster.cpp
+++ b/tests/src/analysis/testqgsalignraster.cpp
@@ -171,12 +171,7 @@ class TestAlignRaster : public QObject
rasters << QgsAlignRaster::Item( SRC_FILE, tmpFile );
rasters[0].resampleMethod = QgsAlignRaster::RA_Bilinear;
align.setRasters( rasters );
- align.setParametersFromRaster( SRC_FILE );
- align.setCellSize( 0.4, 0.4 );
- // a technicality: the raster's origin is at y=-7 so we need to shift the offset,
- // because with zero Y offset the grid goes -6.8 ... -7.2 - with offset of 0.2
- // the grid will start at -7 (with X axis no need for shift as 106 % 0.4 == 0)
- align.setGridOffset( QPointF( 0.0, 0.2 ) );
+ align.setParametersFromRaster( SRC_FILE, QString(), QSizeF( 0.4, 0.4 ) );
bool res = align.run();
QVERIFY( res );
@@ -198,12 +193,7 @@ class TestAlignRaster : public QObject
rasters[0].resampleMethod = QgsAlignRaster::RA_Bilinear;
rasters[0].rescaleValues = true;
align.setRasters( rasters );
- align.setParametersFromRaster( SRC_FILE );
- align.setCellSize( 0.4, 0.4 );
- // a technicality: the raster's origin is at y=-7 so we need to shift the offset,
- // because with zero Y offset the grid goes -6.8 ... -7.2 - with offset of 0.2
- // the grid will start at -7 (with X axis no need for shift as 106 % 0.4 == 0)
- align.setGridOffset( QPointF( 0.0, 0.2 ) );
+ align.setParametersFromRaster( SRC_FILE, QString(), QSizeF( 0.4, 0.4 ) );
bool res = align.run();
QVERIFY( res );