Skip to content

Commit 6b9eaf9

Browse files
committed
raster save as crs and resolution
1 parent 79b1189 commit 6b9eaf9

File tree

5 files changed

+704
-217
lines changed

5 files changed

+704
-217
lines changed

src/app/qgisapp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3924,7 +3924,7 @@ void QgisApp::saveAsRasterFile()
39243924
return;
39253925
}
39263926

3927-
QgsRasterLayerSaveAsDialog d( rasterLayer->dataProvider(), mMapCanvas->extent() );
3927+
QgsRasterLayerSaveAsDialog d( rasterLayer->dataProvider(), mMapCanvas->extent(), mMapCanvas->mapRenderer()->destinationCrs() );
39283928
if ( d.exec() == QDialog::Accepted )
39293929
{
39303930
QgsRasterFileWriter fileWriter( d.outputFileName() );
@@ -3950,7 +3950,7 @@ void QgisApp::saveAsRasterFile()
39503950
}
39513951
fileWriter.setCreateOptions( d.createOptions() );
39523952

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

src/gui/qgsrasterlayersaveasdialog.cpp

Lines changed: 288 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1+
#include "qgslogger.h"
2+
#include "qgscoordinatetransform.h"
13
#include "qgsrasterlayersaveasdialog.h"
24
#include "qgsrasterdataprovider.h"
35
#include "qgsrasterformatsaveoptionswidget.h"
6+
#include "qgsgenericprojectionselector.h"
47

58
#include <QFileDialog>
69
#include <QSettings>
710

811
QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* sourceProvider, const QgsRectangle& currentExtent,
9-
QWidget* parent, Qt::WindowFlags f ): QDialog( parent, f ),
10-
mDataProvider( sourceProvider ), mCurrentExtent( currentExtent )
11-
12+
const QgsCoordinateReferenceSystem& currentCrs,
13+
QWidget* parent, Qt::WindowFlags f ):
14+
QDialog( parent, f )
15+
, mDataProvider( sourceProvider )
16+
, mCurrentExtent( currentExtent )
17+
, mCurrentCrs( currentCrs )
18+
, mExtentState( OriginalExtent )
19+
, mResolutionState( OriginalResolution )
1220
{
1321
setupUi( this );
1422
setValidators();
23+
// Translated labels + EPSG are updated later
24+
mCrsComboBox->addItem( "Layer", OriginalCrs );
25+
mCrsComboBox->addItem( "Project", CurrentCrs );
26+
mCrsComboBox->addItem( "Selected", UserCrs );
27+
28+
toggleResolutionSize();
29+
mUserCrs.createFromOgcWmsCrs( "EPSG:4326" );
1530

1631
//only one hardcoded format at the moment
1732
QStringList myFormats;
@@ -24,12 +39,16 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
2439
//fill reasonable default values depending on the provider
2540
if ( mDataProvider )
2641
{
42+
//extent
43+
setOutputExtent( mDataProvider->extent(), mDataProvider->crs(), OriginalExtent );
44+
2745
if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactResolution )
2846
{
47+
setOriginalResolution();
2948
int xSize = mDataProvider->xSize();
3049
int ySize = mDataProvider->ySize();
31-
mColumnsLineEdit->setText( QString::number( xSize ) );
32-
mRowsLineEdit->setText( QString::number( ySize ) );
50+
//mColumnsLineEdit->setText( QString::number( xSize ) );
51+
//mRowsLineEdit->setText( QString::number( ySize ) );
3352
mMaximumSizeXLineEdit->setText( QString::number( xSize ) );
3453
mMaximumSizeYLineEdit->setText( QString::number( ySize ) );
3554
}
@@ -42,9 +61,6 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
4261
mMaximumSizeYLineEdit->setText( QString::number( 2000 ) );
4362
}
4463

45-
//extent
46-
setOutputExtent( mCurrentExtent );
47-
4864
mOptionsWidget->setProvider( mDataProvider->name() );
4965
if ( mDataProvider->name() == "gdal" )
5066
{
@@ -53,6 +69,7 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
5369
mOptionsWidget->update();
5470

5571
}
72+
updateCrsGroup();
5673

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

6481
void QgsRasterLayerSaveAsDialog::setValidators()
6582
{
83+
mXResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
84+
mYResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
6685
mColumnsLineEdit->setValidator( new QIntValidator( this ) );
6786
mRowsLineEdit->setValidator( new QIntValidator( this ) );
6887
mMaximumSizeXLineEdit->setValidator( new QIntValidator( this ) );
@@ -108,14 +127,14 @@ void QgsRasterLayerSaveAsDialog::on_mSaveAsLineEdit_textChanged( const QString&
108127

109128
void QgsRasterLayerSaveAsDialog::on_mCurrentExtentButton_clicked()
110129
{
111-
setOutputExtent( mCurrentExtent );
130+
setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
112131
}
113132

114-
void QgsRasterLayerSaveAsDialog::on_mProviderExtentButton_clicked()
133+
void QgsRasterLayerSaveAsDialog::on_mOriginalExtentButton_clicked()
115134
{
116135
if ( mDataProvider )
117136
{
118-
setOutputExtent( mDataProvider->extent() );
137+
setOutputExtent( mDataProvider->extent(), mDataProvider->crs(), OriginalExtent );
119138
}
120139
}
121140

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

161+
double QgsRasterLayerSaveAsDialog::xResolution() const
162+
{
163+
return mXResolutionLineEdit->text().toDouble();
164+
}
165+
166+
double QgsRasterLayerSaveAsDialog::yResolution() const
167+
{
168+
return mYResolutionLineEdit->text().toDouble();
169+
}
170+
142171
int QgsRasterLayerSaveAsDialog::maximumTileSizeX() const
143172
{
144173
return mMaximumSizeXLineEdit->text().toInt();
@@ -174,12 +203,26 @@ QgsRectangle QgsRasterLayerSaveAsDialog::outputRectangle() const
174203
return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(), mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
175204
}
176205

177-
void QgsRasterLayerSaveAsDialog::setOutputExtent( const QgsRectangle& r )
206+
void QgsRasterLayerSaveAsDialog::setOutputExtent( const QgsRectangle& r, const QgsCoordinateReferenceSystem& srcCrs, ExtentState state )
178207
{
179-
mXMinLineEdit->setText( QString::number( r.xMinimum() ) );
180-
mXMaxLineEdit->setText( QString::number( r.xMaximum() ) );
181-
mYMinLineEdit->setText( QString::number( r.yMinimum() ) );
182-
mYMaxLineEdit->setText( QString::number( r.yMaximum() ) );
208+
QgsRectangle extent;
209+
if ( outputCrs() == srcCrs )
210+
{
211+
extent = r;
212+
}
213+
else
214+
{
215+
QgsCoordinateTransform ct( srcCrs, outputCrs() );
216+
extent = ct.transformBoundingBox( r );
217+
}
218+
219+
mXMinLineEdit->setText( QString::number( extent.xMinimum() ) );
220+
mXMaxLineEdit->setText( QString::number( extent.xMaximum() ) );
221+
mYMinLineEdit->setText( QString::number( extent.yMinimum() ) );
222+
mYMaxLineEdit->setText( QString::number( extent.yMaximum() ) );
223+
224+
mExtentState = state;
225+
extentChanged();
183226
}
184227

185228
void QgsRasterLayerSaveAsDialog::hideFormat()
@@ -199,3 +242,232 @@ void QgsRasterLayerSaveAsDialog::hideOutput()
199242
okButton->setEnabled( true );
200243
}
201244
}
245+
246+
void QgsRasterLayerSaveAsDialog::toggleResolutionSize()
247+
{
248+
bool on = mResolutionRadioButton->isChecked();
249+
mXResolutionLineEdit->setEnabled( on );
250+
mYResolutionLineEdit->setEnabled( on );
251+
mOriginalResolutionPushButton->setEnabled( on );
252+
mColumnsLineEdit->setEnabled( !on );
253+
mRowsLineEdit->setEnabled( !on );
254+
mOriginalSizePushButton->setEnabled( !on );
255+
}
256+
257+
void QgsRasterLayerSaveAsDialog::setOriginalResolution()
258+
{
259+
double xRes = mDataProvider->extent().width() / mDataProvider->xSize();
260+
double yRes = mDataProvider->extent().height() / mDataProvider->ySize();
261+
setResolution( xRes, yRes, mDataProvider->crs() );
262+
mResolutionState = OriginalResolution;
263+
recalcSize();
264+
}
265+
266+
void QgsRasterLayerSaveAsDialog::setResolution( double xRes, double yRes, const QgsCoordinateReferenceSystem& srcCrs )
267+
{
268+
if ( srcCrs != outputCrs() )
269+
{
270+
// We reproject pixel rectangle from center of selected extent, of course, it gives
271+
// bigger xRes,yRes than reprojected edges (envelope), it may also be that
272+
// close to margins are higher resolutions (even very, too high)
273+
// TODO: consider more precise resolution calculation
274+
275+
QgsPoint center = outputRectangle().center();
276+
QgsCoordinateTransform ct( srcCrs, outputCrs() );
277+
QgsPoint srsCenter = ct.transform( center, QgsCoordinateTransform::ReverseTransform );
278+
279+
QgsRectangle srcExtent( srsCenter.x() - xRes / 2, srsCenter.y() - yRes / 2, srsCenter.x() + xRes / 2, srsCenter.y() + yRes / 2 );
280+
281+
QgsRectangle extent = ct.transform( srcExtent );
282+
xRes = extent.width();
283+
yRes = extent.height();
284+
}
285+
mXResolutionLineEdit->setText( QString::number( xRes ) );
286+
mYResolutionLineEdit->setText( QString::number( yRes ) );
287+
}
288+
289+
void QgsRasterLayerSaveAsDialog::recalcSize()
290+
{
291+
QgsDebugMsg( "Entered" );
292+
QgsRectangle extent = outputRectangle();
293+
int xSize = xResolution() != 0 ? static_cast<int>( qRound( extent.width() / xResolution() ) ) : 0;
294+
int ySize = yResolution() != 0 ? static_cast<int>( qRound( extent.height() / yResolution() ) ) : 0;
295+
mColumnsLineEdit->setText( QString::number( xSize ) );
296+
mRowsLineEdit->setText( QString::number( ySize ) );
297+
updateResolutionStateMsg();
298+
}
299+
300+
void QgsRasterLayerSaveAsDialog::setOriginalSize()
301+
{
302+
mColumnsLineEdit->setText( QString::number( mDataProvider->xSize() ) );
303+
mRowsLineEdit->setText( QString::number( mDataProvider->ySize() ) );
304+
recalcResolution();
305+
}
306+
307+
void QgsRasterLayerSaveAsDialog::recalcResolution()
308+
{
309+
QgsDebugMsg( "Entered" );
310+
QgsRectangle extent = outputRectangle();
311+
double xRes = nColumns() != 0 ? extent.width() / nColumns() : 0;
312+
double yRes = nRows() != 0 ? extent.height() / nRows() : 0;
313+
mXResolutionLineEdit->setText( QString::number( xRes ) );
314+
mYResolutionLineEdit->setText( QString::number( yRes ) );
315+
updateResolutionStateMsg();
316+
}
317+
318+
void QgsRasterLayerSaveAsDialog::recalcResolutionSize()
319+
{
320+
QgsDebugMsg( "Entered" );
321+
if ( mResolutionRadioButton->isChecked() )
322+
{
323+
recalcSize();
324+
}
325+
else
326+
{
327+
mResolutionState = UserResolution;
328+
recalcResolution();
329+
}
330+
}
331+
332+
void QgsRasterLayerSaveAsDialog::updateResolutionStateMsg()
333+
{
334+
QString msg;
335+
switch ( mResolutionState )
336+
{
337+
case OriginalResolution:
338+
msg = tr( "layer" );
339+
break;
340+
case UserResolution:
341+
msg = tr( "user defined" );
342+
break;
343+
default:
344+
break;
345+
}
346+
msg = tr( "Resolution" ) + " (" + tr( "current" ) + ": " + msg + ")";
347+
mResolutionGroupBox->setTitle( msg );
348+
}
349+
350+
void QgsRasterLayerSaveAsDialog::extentChanged()
351+
{
352+
updateExtentStateMsg();
353+
// Whenever extent changes with fixed size, original resolution is lost
354+
if ( mSizeRadioButton->isChecked() )
355+
{
356+
mResolutionState = UserResolution;
357+
}
358+
recalcResolutionSize();
359+
}
360+
361+
void QgsRasterLayerSaveAsDialog::updateExtentStateMsg()
362+
{
363+
QString msg;
364+
switch ( mExtentState )
365+
{
366+
case OriginalExtent:
367+
msg = tr( "layer" );
368+
break;
369+
case CurrentExtent:
370+
msg = tr( "map view" );
371+
break;
372+
case UserExtent:
373+
msg = tr( "user defined" );
374+
break;
375+
default:
376+
break;
377+
}
378+
msg = tr( "Extent" ) + " (" + tr( "current" ) + ": " + msg + ")";
379+
mExtentGroupBox->setTitle( msg );
380+
}
381+
382+
void QgsRasterLayerSaveAsDialog::on_mChangeCrsPushButton_clicked()
383+
{
384+
QgsGenericProjectionSelector * selector = new QgsGenericProjectionSelector( this );
385+
selector->setMessage();
386+
selector->setSelectedCrsId( mUserCrs.srsid() );
387+
if ( selector->exec() )
388+
{
389+
mUserCrs.createFromId( selector->selectedCrsId(), QgsCoordinateReferenceSystem::InternalCrsId );
390+
}
391+
delete selector;
392+
crsChanged();
393+
}
394+
395+
void QgsRasterLayerSaveAsDialog::crsChanged()
396+
{
397+
QgsDebugMsg( "Entered" );
398+
if ( outputCrs() != mPreviousCrs )
399+
{
400+
// Reset extent
401+
QgsRectangle previousExtent;
402+
QgsCoordinateReferenceSystem previousCrs;
403+
// We could reproject previous but that would add additional space also if
404+
// it is was not necessary or at leas it could decrease accuracy
405+
if ( mExtentState == OriginalExtent )
406+
{
407+
previousExtent = mDataProvider->extent();
408+
previousCrs = mDataProvider->crs();
409+
}
410+
else if ( mExtentState == CurrentExtent )
411+
{
412+
previousExtent = mCurrentExtent;
413+
previousCrs = mCurrentCrs;
414+
}
415+
else
416+
{
417+
previousExtent = outputRectangle();
418+
previousCrs = mPreviousCrs;
419+
}
420+
setOutputExtent( previousExtent, previousCrs, mExtentState );
421+
422+
// Reset resolution
423+
if ( mResolutionRadioButton->isChecked() )
424+
{
425+
if ( mResolutionState == OriginalResolution )
426+
{
427+
setOriginalResolution();
428+
}
429+
else
430+
{
431+
// reset from present resolution and present crs
432+
setResolution( xResolution(), yResolution(), mPreviousCrs );
433+
}
434+
}
435+
else
436+
{
437+
// Size does not change, we just recalc resolution from new extent
438+
recalcResolution();
439+
}
440+
}
441+
mPreviousCrs = outputCrs();
442+
updateCrsGroup();
443+
}
444+
445+
void QgsRasterLayerSaveAsDialog::updateCrsGroup()
446+
{
447+
QgsDebugMsg( "Entered" );
448+
449+
mCrsComboBox->setItemText( mCrsComboBox->findData( OriginalCrs ),
450+
tr( "Layer" ) + " (" + mDataProvider->crs().description() + ", " + mDataProvider->crs().authid() + ")" );
451+
452+
mCrsComboBox->setItemText( mCrsComboBox->findData( CurrentCrs ),
453+
tr( "Project" ) + " (" + mCurrentCrs.description() + ", " + mCurrentCrs.authid() + ")" );
454+
455+
mCrsComboBox->setItemText( mCrsComboBox->findData( UserCrs ),
456+
tr( "Selected" ) + " (" + mUserCrs.description() + ", " + mUserCrs.authid() + ")" );
457+
458+
mChangeCrsPushButton->setEnabled( mCrsComboBox->findData( UserCrs ) == mCrsComboBox->currentIndex() );
459+
}
460+
461+
QgsCoordinateReferenceSystem QgsRasterLayerSaveAsDialog::outputCrs()
462+
{
463+
int state = mCrsComboBox->itemData( mCrsComboBox->currentIndex() ).toInt();
464+
if ( state == OriginalCrs )
465+
{
466+
return mDataProvider->crs();
467+
}
468+
else if ( state == CurrentCrs )
469+
{
470+
return mCurrentCrs;
471+
}
472+
return mUserCrs;
473+
}

0 commit comments

Comments
 (0)