Skip to content

Commit

Permalink
raster save as crs and resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Aug 15, 2012
1 parent 79b1189 commit 6b9eaf9
Show file tree
Hide file tree
Showing 5 changed files with 704 additions and 217 deletions.
4 changes: 2 additions & 2 deletions src/app/qgisapp.cpp
Expand Up @@ -3924,7 +3924,7 @@ void QgisApp::saveAsRasterFile()
return;
}

QgsRasterLayerSaveAsDialog d( rasterLayer->dataProvider(), mMapCanvas->extent() );
QgsRasterLayerSaveAsDialog d( rasterLayer->dataProvider(), mMapCanvas->extent(), mMapCanvas->mapRenderer()->destinationCrs() );
if ( d.exec() == QDialog::Accepted )
{
QgsRasterFileWriter fileWriter( d.outputFileName() );
Expand All @@ -3950,7 +3950,7 @@ void QgisApp::saveAsRasterFile()
}
fileWriter.setCreateOptions( d.createOptions() );

fileWriter.writeRaster( &iterator, d.nColumns(), nRows, d.outputRectangle(), rasterLayer->crs(), &pd );
fileWriter.writeRaster( &iterator, d.nColumns(), nRows, d.outputRectangle(), d.outputCrs(), &pd );
}
}

Expand Down
304 changes: 288 additions & 16 deletions src/gui/qgsrasterlayersaveasdialog.cpp
@@ -1,17 +1,32 @@
#include "qgslogger.h"
#include "qgscoordinatetransform.h"
#include "qgsrasterlayersaveasdialog.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterformatsaveoptionswidget.h"
#include "qgsgenericprojectionselector.h"

#include <QFileDialog>
#include <QSettings>

QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* sourceProvider, const QgsRectangle& currentExtent,
QWidget* parent, Qt::WindowFlags f ): QDialog( parent, f ),
mDataProvider( sourceProvider ), mCurrentExtent( currentExtent )

const QgsCoordinateReferenceSystem& currentCrs,
QWidget* parent, Qt::WindowFlags f ):
QDialog( parent, f )
, mDataProvider( sourceProvider )
, mCurrentExtent( currentExtent )
, mCurrentCrs( currentCrs )
, mExtentState( OriginalExtent )
, mResolutionState( OriginalResolution )
{
setupUi( this );
setValidators();
// Translated labels + EPSG are updated later
mCrsComboBox->addItem( "Layer", OriginalCrs );
mCrsComboBox->addItem( "Project", CurrentCrs );
mCrsComboBox->addItem( "Selected", UserCrs );

toggleResolutionSize();
mUserCrs.createFromOgcWmsCrs( "EPSG:4326" );

//only one hardcoded format at the moment
QStringList myFormats;
Expand All @@ -24,12 +39,16 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
//fill reasonable default values depending on the provider
if ( mDataProvider )
{
//extent
setOutputExtent( mDataProvider->extent(), mDataProvider->crs(), OriginalExtent );

if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactResolution )
{
setOriginalResolution();
int xSize = mDataProvider->xSize();
int ySize = mDataProvider->ySize();
mColumnsLineEdit->setText( QString::number( xSize ) );
mRowsLineEdit->setText( QString::number( ySize ) );
//mColumnsLineEdit->setText( QString::number( xSize ) );
//mRowsLineEdit->setText( QString::number( ySize ) );
mMaximumSizeXLineEdit->setText( QString::number( xSize ) );
mMaximumSizeYLineEdit->setText( QString::number( ySize ) );
}
Expand All @@ -42,9 +61,6 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
mMaximumSizeYLineEdit->setText( QString::number( 2000 ) );
}

//extent
setOutputExtent( mCurrentExtent );

mOptionsWidget->setProvider( mDataProvider->name() );
if ( mDataProvider->name() == "gdal" )
{
Expand All @@ -53,6 +69,7 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
mOptionsWidget->update();

}
updateCrsGroup();

QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
if ( okButton )
Expand All @@ -63,6 +80,8 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s

void QgsRasterLayerSaveAsDialog::setValidators()
{
mXResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
mYResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
mColumnsLineEdit->setValidator( new QIntValidator( this ) );
mRowsLineEdit->setValidator( new QIntValidator( this ) );
mMaximumSizeXLineEdit->setValidator( new QIntValidator( this ) );
Expand Down Expand Up @@ -108,14 +127,14 @@ void QgsRasterLayerSaveAsDialog::on_mSaveAsLineEdit_textChanged( const QString&

void QgsRasterLayerSaveAsDialog::on_mCurrentExtentButton_clicked()
{
setOutputExtent( mCurrentExtent );
setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
}

void QgsRasterLayerSaveAsDialog::on_mProviderExtentButton_clicked()
void QgsRasterLayerSaveAsDialog::on_mOriginalExtentButton_clicked()
{
if ( mDataProvider )
{
setOutputExtent( mDataProvider->extent() );
setOutputExtent( mDataProvider->extent(), mDataProvider->crs(), OriginalExtent );
}
}

Expand All @@ -139,6 +158,16 @@ int QgsRasterLayerSaveAsDialog::nRows() const
return mRowsLineEdit->text().toInt();
}

double QgsRasterLayerSaveAsDialog::xResolution() const
{
return mXResolutionLineEdit->text().toDouble();
}

double QgsRasterLayerSaveAsDialog::yResolution() const
{
return mYResolutionLineEdit->text().toDouble();
}

int QgsRasterLayerSaveAsDialog::maximumTileSizeX() const
{
return mMaximumSizeXLineEdit->text().toInt();
Expand Down Expand Up @@ -174,12 +203,26 @@ QgsRectangle QgsRasterLayerSaveAsDialog::outputRectangle() const
return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(), mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
}

void QgsRasterLayerSaveAsDialog::setOutputExtent( const QgsRectangle& r )
void QgsRasterLayerSaveAsDialog::setOutputExtent( const QgsRectangle& r, const QgsCoordinateReferenceSystem& srcCrs, ExtentState state )
{
mXMinLineEdit->setText( QString::number( r.xMinimum() ) );
mXMaxLineEdit->setText( QString::number( r.xMaximum() ) );
mYMinLineEdit->setText( QString::number( r.yMinimum() ) );
mYMaxLineEdit->setText( QString::number( r.yMaximum() ) );
QgsRectangle extent;
if ( outputCrs() == srcCrs )
{
extent = r;
}
else
{
QgsCoordinateTransform ct( srcCrs, outputCrs() );
extent = ct.transformBoundingBox( r );
}

mXMinLineEdit->setText( QString::number( extent.xMinimum() ) );
mXMaxLineEdit->setText( QString::number( extent.xMaximum() ) );
mYMinLineEdit->setText( QString::number( extent.yMinimum() ) );
mYMaxLineEdit->setText( QString::number( extent.yMaximum() ) );

mExtentState = state;
extentChanged();
}

void QgsRasterLayerSaveAsDialog::hideFormat()
Expand All @@ -199,3 +242,232 @@ void QgsRasterLayerSaveAsDialog::hideOutput()
okButton->setEnabled( true );
}
}

void QgsRasterLayerSaveAsDialog::toggleResolutionSize()
{
bool on = mResolutionRadioButton->isChecked();
mXResolutionLineEdit->setEnabled( on );
mYResolutionLineEdit->setEnabled( on );
mOriginalResolutionPushButton->setEnabled( on );
mColumnsLineEdit->setEnabled( !on );
mRowsLineEdit->setEnabled( !on );
mOriginalSizePushButton->setEnabled( !on );
}

void QgsRasterLayerSaveAsDialog::setOriginalResolution()
{
double xRes = mDataProvider->extent().width() / mDataProvider->xSize();
double yRes = mDataProvider->extent().height() / mDataProvider->ySize();
setResolution( xRes, yRes, mDataProvider->crs() );
mResolutionState = OriginalResolution;
recalcSize();
}

void QgsRasterLayerSaveAsDialog::setResolution( double xRes, double yRes, const QgsCoordinateReferenceSystem& srcCrs )
{
if ( srcCrs != outputCrs() )
{
// We reproject pixel rectangle from center of selected extent, of course, it gives
// bigger xRes,yRes than reprojected edges (envelope), it may also be that
// close to margins are higher resolutions (even very, too high)
// TODO: consider more precise resolution calculation

QgsPoint center = outputRectangle().center();
QgsCoordinateTransform ct( srcCrs, outputCrs() );
QgsPoint srsCenter = ct.transform( center, QgsCoordinateTransform::ReverseTransform );

QgsRectangle srcExtent( srsCenter.x() - xRes / 2, srsCenter.y() - yRes / 2, srsCenter.x() + xRes / 2, srsCenter.y() + yRes / 2 );

QgsRectangle extent = ct.transform( srcExtent );
xRes = extent.width();
yRes = extent.height();
}
mXResolutionLineEdit->setText( QString::number( xRes ) );
mYResolutionLineEdit->setText( QString::number( yRes ) );
}

void QgsRasterLayerSaveAsDialog::recalcSize()
{
QgsDebugMsg( "Entered" );
QgsRectangle extent = outputRectangle();
int xSize = xResolution() != 0 ? static_cast<int>( qRound( extent.width() / xResolution() ) ) : 0;
int ySize = yResolution() != 0 ? static_cast<int>( qRound( extent.height() / yResolution() ) ) : 0;
mColumnsLineEdit->setText( QString::number( xSize ) );
mRowsLineEdit->setText( QString::number( ySize ) );
updateResolutionStateMsg();
}

void QgsRasterLayerSaveAsDialog::setOriginalSize()
{
mColumnsLineEdit->setText( QString::number( mDataProvider->xSize() ) );
mRowsLineEdit->setText( QString::number( mDataProvider->ySize() ) );
recalcResolution();
}

void QgsRasterLayerSaveAsDialog::recalcResolution()
{
QgsDebugMsg( "Entered" );
QgsRectangle extent = outputRectangle();
double xRes = nColumns() != 0 ? extent.width() / nColumns() : 0;
double yRes = nRows() != 0 ? extent.height() / nRows() : 0;
mXResolutionLineEdit->setText( QString::number( xRes ) );
mYResolutionLineEdit->setText( QString::number( yRes ) );
updateResolutionStateMsg();
}

void QgsRasterLayerSaveAsDialog::recalcResolutionSize()
{
QgsDebugMsg( "Entered" );
if ( mResolutionRadioButton->isChecked() )
{
recalcSize();
}
else
{
mResolutionState = UserResolution;
recalcResolution();
}
}

void QgsRasterLayerSaveAsDialog::updateResolutionStateMsg()
{
QString msg;
switch ( mResolutionState )
{
case OriginalResolution:
msg = tr( "layer" );
break;
case UserResolution:
msg = tr( "user defined" );
break;
default:
break;
}
msg = tr( "Resolution" ) + " (" + tr( "current" ) + ": " + msg + ")";
mResolutionGroupBox->setTitle( msg );
}

void QgsRasterLayerSaveAsDialog::extentChanged()
{
updateExtentStateMsg();
// Whenever extent changes with fixed size, original resolution is lost
if ( mSizeRadioButton->isChecked() )
{
mResolutionState = UserResolution;
}
recalcResolutionSize();
}

void QgsRasterLayerSaveAsDialog::updateExtentStateMsg()
{
QString msg;
switch ( mExtentState )
{
case OriginalExtent:
msg = tr( "layer" );
break;
case CurrentExtent:
msg = tr( "map view" );
break;
case UserExtent:
msg = tr( "user defined" );
break;
default:
break;
}
msg = tr( "Extent" ) + " (" + tr( "current" ) + ": " + msg + ")";
mExtentGroupBox->setTitle( msg );
}

void QgsRasterLayerSaveAsDialog::on_mChangeCrsPushButton_clicked()
{
QgsGenericProjectionSelector * selector = new QgsGenericProjectionSelector( this );
selector->setMessage();
selector->setSelectedCrsId( mUserCrs.srsid() );
if ( selector->exec() )
{
mUserCrs.createFromId( selector->selectedCrsId(), QgsCoordinateReferenceSystem::InternalCrsId );
}
delete selector;
crsChanged();
}

void QgsRasterLayerSaveAsDialog::crsChanged()
{
QgsDebugMsg( "Entered" );
if ( outputCrs() != mPreviousCrs )
{
// Reset extent
QgsRectangle previousExtent;
QgsCoordinateReferenceSystem previousCrs;
// We could reproject previous but that would add additional space also if
// it is was not necessary or at leas it could decrease accuracy
if ( mExtentState == OriginalExtent )
{
previousExtent = mDataProvider->extent();
previousCrs = mDataProvider->crs();
}
else if ( mExtentState == CurrentExtent )
{
previousExtent = mCurrentExtent;
previousCrs = mCurrentCrs;
}
else
{
previousExtent = outputRectangle();
previousCrs = mPreviousCrs;
}
setOutputExtent( previousExtent, previousCrs, mExtentState );

// Reset resolution
if ( mResolutionRadioButton->isChecked() )
{
if ( mResolutionState == OriginalResolution )
{
setOriginalResolution();
}
else
{
// reset from present resolution and present crs
setResolution( xResolution(), yResolution(), mPreviousCrs );
}
}
else
{
// Size does not change, we just recalc resolution from new extent
recalcResolution();
}
}
mPreviousCrs = outputCrs();
updateCrsGroup();
}

void QgsRasterLayerSaveAsDialog::updateCrsGroup()
{
QgsDebugMsg( "Entered" );

mCrsComboBox->setItemText( mCrsComboBox->findData( OriginalCrs ),
tr( "Layer" ) + " (" + mDataProvider->crs().description() + ", " + mDataProvider->crs().authid() + ")" );

mCrsComboBox->setItemText( mCrsComboBox->findData( CurrentCrs ),
tr( "Project" ) + " (" + mCurrentCrs.description() + ", " + mCurrentCrs.authid() + ")" );

mCrsComboBox->setItemText( mCrsComboBox->findData( UserCrs ),
tr( "Selected" ) + " (" + mUserCrs.description() + ", " + mUserCrs.authid() + ")" );

mChangeCrsPushButton->setEnabled( mCrsComboBox->findData( UserCrs ) == mCrsComboBox->currentIndex() );
}

QgsCoordinateReferenceSystem QgsRasterLayerSaveAsDialog::outputCrs()
{
int state = mCrsComboBox->itemData( mCrsComboBox->currentIndex() ).toInt();
if ( state == OriginalCrs )
{
return mDataProvider->crs();
}
else if ( state == CurrentCrs )
{
return mCurrentCrs;
}
return mUserCrs;
}

0 comments on commit 6b9eaf9

Please sign in to comment.