|
| 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