Skip to content

Commit 7bdbbb8

Browse files
committed
Started GUI for alignment of rasters
1 parent 515de28 commit 7bdbbb8

File tree

7 files changed

+650
-1
lines changed

7 files changed

+650
-1
lines changed

src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ SET(QGIS_APP_SRCS
33
qgisappinterface.cpp
44
qgisappstylesheet.cpp
55
qgsabout.cpp
6+
qgsalignrasterdialog.cpp
67
qgsapplayertreeviewmenuprovider.cpp
78
qgssponsors.cpp
89
qgsaddattrdialog.cpp
@@ -164,6 +165,7 @@ SET (QGIS_APP_MOC_HDRS
164165
qgisappstylesheet.h
165166
qgsabout.h
166167
qgsaddattrdialog.h
168+
qgsalignrasterdialog.h
167169
qgsjoindialog.h
168170
qgsaddtaborgroup.h
169171
qgsannotationwidget.h

src/app/qgisapp.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#include "qgis.h"
101101
#include "qgisplugin.h"
102102
#include "qgsabout.h"
103+
#include "qgsalignrasterdialog.h"
103104
#include "qgsapplayertreeviewmenuprovider.h"
104105
#include "qgsapplication.h"
105106
#include "qgsattributeaction.h"
@@ -1232,6 +1233,7 @@ void QgisApp::createActions()
12321233
connect( mActionNewSpatiaLiteLayer, SIGNAL( triggered() ), this, SLOT( newSpatialiteLayer() ) );
12331234
connect( mActionNewMemoryLayer, SIGNAL( triggered() ), this, SLOT( newMemoryLayer() ) );
12341235
connect( mActionShowRasterCalculator, SIGNAL( triggered() ), this, SLOT( showRasterCalculator() ) );
1236+
connect( mActionShowAlignRasterTool, SIGNAL( triggered() ), this, SLOT( showAlignRasterTool() ) );
12351237
connect( mActionEmbedLayers, SIGNAL( triggered() ), this, SLOT( embedLayers() ) );
12361238
connect( mActionAddLayerDefinition, SIGNAL( triggered() ), this, SLOT( addLayerDefinition() ) );
12371239
connect( mActionAddOgrLayer, SIGNAL( triggered() ), this, SLOT( addVectorLayer() ) );
@@ -4001,6 +4003,14 @@ void QgisApp::showRasterCalculator()
40014003
}
40024004
}
40034005

4006+
4007+
void QgisApp::showAlignRasterTool()
4008+
{
4009+
QgsAlignRasterDialog dlg( this );
4010+
dlg.exec();
4011+
}
4012+
4013+
40044014
void QgisApp::fileOpen()
40054015
{
40064016
// possibly save any pending work before opening a new project

src/app/qgisapp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
904904
void fileNewFromDefaultTemplate();
905905
//! Calculate new rasters from existing ones
906906
void showRasterCalculator();
907+
//! Open dialog to align raster layers
908+
void showAlignRasterTool();
907909
void embedLayers();
908910

909911
//! Create a new empty vector layer

src/app/qgsalignrasterdialog.cpp

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#include "qgsalignrasterdialog.h"
2+
3+
#include "qgsapplication.h"
4+
#include "qgsalignraster.h"
5+
#include "qgsdataitem.h"
6+
#include "qgsmaplayercombobox.h"
7+
#include "qgsmaplayerregistry.h"
8+
#include "qgsrasterlayer.h"
9+
10+
#include <QCheckBox>
11+
#include <QFileDialog>
12+
#include <QFileInfo>
13+
#include <QLineEdit>
14+
#include <QMessageBox>
15+
#include <QPushButton>
16+
#include <QStandardItemModel>
17+
#include <QVBoxLayout>
18+
19+
20+
static QgsMapLayer* _rasterLayer( const QString& filename )
21+
{
22+
QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers();
23+
foreach ( QgsMapLayer* layer, layers.values() )
24+
{
25+
if ( layer->type() == QgsMapLayer::RasterLayer && layer->source() == filename )
26+
return layer;
27+
}
28+
return 0;
29+
}
30+
31+
static QString _rasterLayerName( const QString& filename )
32+
{
33+
if ( QgsMapLayer* layer = _rasterLayer( filename ) )
34+
return layer->name();
35+
36+
QFileInfo fi( filename );
37+
return fi.baseName();
38+
}
39+
40+
41+
42+
/** Helper class to report progress */
43+
struct QgsAlignRasterDialogProgress : public QgsAlignRaster::ProgressHandler
44+
{
45+
QgsAlignRasterDialogProgress( QProgressBar* pb ) : mPb( pb ) {}
46+
virtual bool progress( double complete )
47+
{
48+
mPb->setValue(( int ) qRound( complete * 100 ) );
49+
qApp->processEvents(); // to actually show the progress in GUI
50+
return true;
51+
}
52+
53+
protected:
54+
QProgressBar* mPb;
55+
};
56+
57+
58+
QgsAlignRasterDialog::QgsAlignRasterDialog( QWidget *parent )
59+
: QDialog( parent )
60+
{
61+
setupUi( this );
62+
63+
mBtnAdd->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
64+
mBtnEdit->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.png" ) ) );
65+
mBtnRemove->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
66+
67+
mAlign = new QgsAlignRaster;
68+
mAlign->setProgressHandler( new QgsAlignRasterDialogProgress( mProgress ) );
69+
70+
connect( mBtnAdd, SIGNAL( clicked( bool ) ), this, SLOT( addLayer() ) );
71+
connect( mBtnRemove, SIGNAL( clicked( bool ) ), this, SLOT( removeLayer() ) );
72+
connect( mBtnEdit, SIGNAL( clicked( bool ) ), this, SLOT( editLayer() ) );
73+
74+
connect( mCboReferenceLayer, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateConfigFromReferenceLayer() ) );
75+
76+
mClipExtentGroupBox->setChecked( false );
77+
78+
// TODO: auto-detect reference layer
79+
80+
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( runAlign() ) );
81+
82+
populateLayersView();
83+
}
84+
85+
QgsAlignRasterDialog::~QgsAlignRasterDialog()
86+
{
87+
delete mAlign;
88+
}
89+
90+
91+
void QgsAlignRasterDialog::populateLayersView()
92+
{
93+
mCboReferenceLayer->clear();
94+
95+
QStandardItemModel* model = new QStandardItemModel();
96+
foreach ( QgsAlignRaster::Item item, mAlign->rasters() )
97+
{
98+
QString layerName = _rasterLayerName( item.inputFilename );
99+
100+
QStandardItem* si = new QStandardItem( QgsLayerItem::iconRaster(), layerName );
101+
model->appendRow( si );
102+
103+
mCboReferenceLayer->addItem( layerName );
104+
}
105+
106+
mViewLayers->setModel( model );
107+
108+
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( model->rowCount() > 0 );
109+
}
110+
111+
void QgsAlignRasterDialog::addLayer()
112+
{
113+
QgsAlignRasterLayerConfigDialog d;
114+
if ( !d.exec() )
115+
return;
116+
117+
QgsAlignRaster::List list = mAlign->rasters();
118+
119+
QgsAlignRaster::Item item( d.inputFilename(), d.outputFilename() );
120+
item.resampleMethod = ( QgsAlignRaster::ResampleAlg ) d.resampleMethod();
121+
item.rescaleValues = d.rescaleValues();
122+
list.append( item );
123+
124+
mAlign->setRasters( list );
125+
126+
populateLayersView();
127+
}
128+
129+
void QgsAlignRasterDialog::removeLayer()
130+
{
131+
QModelIndex current = mViewLayers->currentIndex();
132+
if ( !current.isValid() )
133+
return;
134+
135+
QgsAlignRaster::List list = mAlign->rasters();
136+
list.removeAt( current.row() );
137+
mAlign->setRasters( list );
138+
139+
populateLayersView();
140+
}
141+
142+
void QgsAlignRasterDialog::editLayer()
143+
{
144+
QModelIndex current = mViewLayers->currentIndex();
145+
if ( !current.isValid() )
146+
return;
147+
148+
QgsAlignRaster::List list = mAlign->rasters();
149+
QgsAlignRaster::Item item = list.at( current.row() );
150+
151+
QgsAlignRasterLayerConfigDialog d;
152+
d.setItem( item.inputFilename, item.outputFilename, item.resampleMethod, item.rescaleValues );
153+
if ( !d.exec() )
154+
return;
155+
156+
QgsAlignRaster::Item itemNew( d.inputFilename(), d.outputFilename() );
157+
itemNew.resampleMethod = ( QgsAlignRaster::ResampleAlg ) d.resampleMethod();
158+
itemNew.rescaleValues = d.rescaleValues();
159+
list[current.row()] = itemNew;
160+
161+
populateLayersView();
162+
}
163+
164+
void QgsAlignRasterDialog::updateConfigFromReferenceLayer()
165+
{
166+
int index = mCboReferenceLayer->currentIndex();
167+
if ( index < 0 )
168+
return;
169+
170+
mAlign->setParametersFromRaster( mAlign->rasters().at( index ).inputFilename );
171+
172+
QgsCoordinateReferenceSystem destCRS( mAlign->destinationCRS() );
173+
mCrsSelector->setCrs( destCRS );
174+
175+
QSizeF cellSize = mAlign->cellSize();
176+
mSpinCellSizeX->setValue( cellSize.width() );
177+
mSpinCellSizeY->setValue( cellSize.height() );
178+
179+
QPointF gridOffset = mAlign->gridOffset();
180+
mSpinGridOffsetX->setValue( gridOffset.x() );
181+
mSpinGridOffsetY->setValue( gridOffset.y() );
182+
183+
mClipExtentGroupBox->setOriginalExtent( mAlign->clipExtent(), destCRS );
184+
}
185+
186+
void QgsAlignRasterDialog::runAlign()
187+
{
188+
setEnabled( false );
189+
190+
bool res = mAlign->run();
191+
192+
setEnabled( true );
193+
194+
if ( res )
195+
{
196+
if ( mChkAddToCanvas->isChecked() )
197+
{
198+
foreach ( const QgsAlignRaster::Item& item, mAlign->rasters() )
199+
{
200+
QgsRasterLayer* layer = new QgsRasterLayer( item.outputFilename, QFileInfo( item.outputFilename ).baseName() );
201+
if ( layer->isValid() )
202+
QgsMapLayerRegistry::instance()->addMapLayer( layer );
203+
else
204+
delete layer;
205+
}
206+
}
207+
}
208+
else
209+
{
210+
// TODO: error message with reason
211+
QMessageBox::critical( this, tr( "Align Rasters" ), tr( "Failed to align rasters." ) );
212+
}
213+
}
214+
215+
216+
// ------
217+
218+
219+
QgsAlignRasterLayerConfigDialog::QgsAlignRasterLayerConfigDialog()
220+
{
221+
QVBoxLayout* layout = new QVBoxLayout();
222+
223+
cboLayers = new QgsMapLayerComboBox( this );
224+
cboLayers->setFilters( QgsMapLayerProxyModel::RasterLayer );
225+
226+
cboResample = new QComboBox( this );
227+
QStringList methods;
228+
methods << tr( "Nearest neighbour" ) << tr( "Bilinear (2x2 kernel)" )
229+
<< tr( "Cubic (4x4 kernel)" ) << tr( "Cubic B-Spline (4x4 kernel)" ) << tr( "Lanczos (6x6 kernel)" )
230+
<< tr( "Average" ) << tr( "Mode" );
231+
cboResample->addItems( methods );
232+
233+
editOutput = new QLineEdit( this );
234+
btnBrowse = new QPushButton( tr( "Browse..." ), this );
235+
connect( btnBrowse, SIGNAL( clicked( bool ) ), this, SLOT( browseOutputFilename() ) );
236+
237+
QHBoxLayout* layoutOutput = new QHBoxLayout();
238+
layoutOutput->addWidget( editOutput );
239+
layoutOutput->addWidget( btnBrowse );
240+
241+
chkRescale = new QCheckBox( tr( "Rescale values according to the cell size" ), this );
242+
243+
btnBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this );
244+
connect( btnBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
245+
connect( btnBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
246+
247+
layout->addWidget( new QLabel( tr( "Input raster layer:" ), this ) );
248+
layout->addWidget( cboLayers );
249+
layout->addWidget( new QLabel( tr( "Output raster filename:" ), this ) );
250+
layout->addLayout( layoutOutput );
251+
layout->addWidget( new QLabel( tr( "Resampling method:" ), this ) );
252+
layout->addWidget( cboResample );
253+
layout->addWidget( chkRescale );
254+
layout->addWidget( btnBox );
255+
setLayout( layout );
256+
}
257+
258+
QString QgsAlignRasterLayerConfigDialog::inputFilename() const
259+
{
260+
QgsRasterLayer* l = qobject_cast<QgsRasterLayer*>( cboLayers->currentLayer() );
261+
return l ? l->source() : QString();
262+
}
263+
264+
QString QgsAlignRasterLayerConfigDialog::outputFilename() const
265+
{
266+
return editOutput->text();
267+
}
268+
269+
int QgsAlignRasterLayerConfigDialog::resampleMethod() const
270+
{
271+
return cboResample->currentIndex();
272+
}
273+
274+
bool QgsAlignRasterLayerConfigDialog::rescaleValues() const
275+
{
276+
return chkRescale->isChecked();
277+
}
278+
279+
void QgsAlignRasterLayerConfigDialog::setItem( const QString& inputFilename, const QString& outputFilename,
280+
int resampleMethod, bool rescaleValues )
281+
{
282+
cboLayers->setLayer( _rasterLayer( inputFilename ) );
283+
editOutput->setText( outputFilename );
284+
cboResample->setCurrentIndex( resampleMethod );
285+
chkRescale->setChecked( rescaleValues );
286+
}
287+
288+
void QgsAlignRasterLayerConfigDialog::browseOutputFilename()
289+
{
290+
QSettings settings;
291+
QString dirName = editOutput->text().isEmpty() ? settings.value( "/UI/lastRasterFileDir", "." ).toString() : editOutput->text();
292+
293+
QString fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
294+
295+
if ( !fileName.isEmpty() )
296+
{
297+
// ensure the user never ommited the extension from the file name
298+
if ( !fileName.toLower().endsWith( ".tif" ) && !fileName.toLower().endsWith( ".tiff" ) )
299+
{
300+
fileName += ".tif";
301+
}
302+
editOutput->setText( fileName );
303+
}
304+
}

0 commit comments

Comments
 (0)