2
/***************************************************************************
3
qgsinterpolationdialog.cpp
4
--------------------------
6
copyright : (C) 2008 by Marco Hugentobler
7
email : marco dot hugentobler at karto dot baug dot ethz dot ch
8
***************************************************************************/
10
/***************************************************************************
12
* This program is free software; you can redistribute it and/or modify *
13
* it under the terms of the GNU General Public License as published by *
14
* the Free Software Foundation; either version 2 of the License, or *
15
* (at your option) any later version. *
17
***************************************************************************/
19
#include "qgsinterpolationdialog.h"
20
#include "qgsinterpolatordialog.h"
22
#include "qgsgridfilewriter.h"
23
#include "qgsidwinterpolatordialog.h"
24
#include "qgstininterpolatordialog.h"
25
#include "qgsmapcanvas.h"
26
#include "qgsmaplayerregistry.h"
27
#include "qgsvectordataprovider.h"
28
#include "qgsvectorlayer.h"
30
#include <QFileDialog>
31
#include <QMessageBox>
35
QgsInterpolationDialog::QgsInterpolationDialog( QWidget* parent, QgisInterface* iface ): QDialog( parent ), mIface( iface ), mInterpolatorDialog( 0 )
39
//enter available layers into the combo box
40
QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
41
QMap<QString, QgsMapLayer*>::iterator layer_it = mapLayers.begin();
43
for ( ; layer_it != mapLayers.end(); ++layer_it )
45
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( layer_it.value() );
48
mInputLayerComboBox->insertItem( 0, vl->name() );
52
//default resolution 300 * 300
53
mNumberOfColumnsSpinBox->setValue( 300 );
54
mNumberOfRowsSpinBox->setValue( 300 );
56
//only inverse distance weighting available for now
57
mInterpolationMethodComboBox->insertItem( 0, tr( "Triangular interpolation (TIN)" ) );
58
mInterpolationMethodComboBox->insertItem( 1, tr( "Inverse Distance Weighting (IDW)" ) );
60
enableOrDisableOkButton();
63
QgsInterpolationDialog::~QgsInterpolationDialog()
68
void QgsInterpolationDialog::enableOrDisableOkButton()
73
if ( mLayersTreeWidget->topLevelItemCount() < 1 )
79
QString fileName = mOutputFileLineEdit->text();
80
QFileInfo theFileInfo( fileName );
81
if ( fileName.isEmpty() || !theFileInfo.dir().exists() )
87
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
90
void QgsInterpolationDialog::on_buttonBox_accepted()
92
if ( !mInterpolatorDialog )
97
QgsRectangle outputBBox = currentBoundingBox();
98
if ( outputBBox.isEmpty() )
103
//warn the user if there isn't any input layer
104
if ( mLayersTreeWidget->topLevelItemCount() < 1 )
106
QMessageBox::information( 0, tr( "No input data for interpolation" ), tr( "Please add one or more input layers" ) );
111
QString fileName = mOutputFileLineEdit->text();
112
QFileInfo theFileInfo( fileName );
113
if ( fileName.isEmpty() || !theFileInfo.dir().exists() )
115
QMessageBox::information( 0, tr( "Output file name invalid" ), tr( "Please enter a valid output file name" ) );
119
//add .asc suffix if the user did not provider it already
120
QString suffix = theFileInfo.suffix();
121
if ( suffix.isEmpty() )
123
fileName.append( ".asc" );
126
int nLayers = mLayersTreeWidget->topLevelItemCount();
127
QList< QgsInterpolator::LayerData > inputLayerList;
129
for ( int i = 0; i < nLayers; ++i )
131
QString layerName = mLayersTreeWidget->topLevelItem( i )->text( 0 );
132
QgsVectorLayer* theVectorLayer = vectorLayerFromName( layerName );
133
if ( !theVectorLayer )
138
QgsVectorDataProvider* theProvider = theVectorLayer->dataProvider();
144
QgsInterpolator::LayerData currentLayerData;
145
currentLayerData.vectorLayer = theVectorLayer;
147
QString interpolationAttString = mLayersTreeWidget->topLevelItem( i )->text( 1 );
148
if ( interpolationAttString == "Z_COORD" )
150
currentLayerData.zCoordInterpolation = true;
151
currentLayerData.interpolationAttribute = -1;
155
currentLayerData.zCoordInterpolation = false;
156
int attributeIndex = theProvider->fieldNameIndex( interpolationAttString );
157
currentLayerData.interpolationAttribute = attributeIndex;
160
//type (point/structure line/ breakline)
161
QComboBox* itemCombo = qobject_cast<QComboBox *>( mLayersTreeWidget->itemWidget( mLayersTreeWidget->topLevelItem( i ), 2 ) );
164
QString typeString = itemCombo->currentText();
165
if ( typeString == tr( "Break lines" ) )
167
currentLayerData.mInputType = QgsInterpolator::BREAK_LINES;
169
else if ( typeString == tr( "Structure lines" ) )
171
currentLayerData.mInputType = QgsInterpolator::STRUCTURE_LINES;
175
currentLayerData.mInputType = QgsInterpolator::POINTS;
180
currentLayerData.mInputType = QgsInterpolator::POINTS;
182
inputLayerList.push_back( currentLayerData );
185
mInterpolatorDialog->setInputData( inputLayerList );
186
QgsInterpolator* theInterpolator = mInterpolatorDialog->createInterpolator();
188
if ( !theInterpolator )
193
//create grid file writer
194
QgsGridFileWriter theWriter( theInterpolator, fileName, outputBBox, mNumberOfColumnsSpinBox->value(), \
195
mNumberOfRowsSpinBox->value(), mCellsizeXSpinBox->value(), mCellSizeYSpinBox->value() );
196
if ( theWriter.writeFile( true ) == 0 )
198
mIface->addRasterLayer( fileName, "Interpolation" );
202
delete theInterpolator;
205
void QgsInterpolationDialog::on_mInputLayerComboBox_currentIndexChanged( const QString& text )
207
mInterpolationAttributeComboBox->clear();
208
mUseZCoordCheckBox->setEnabled( false );
210
//get current vector layer
211
QString currentComboText = mInputLayerComboBox->currentText();
212
QgsVectorLayer* theVectorLayer = vectorLayerFromName( currentComboText );
214
if ( !theVectorLayer )
219
QgsVectorDataProvider* provider = theVectorLayer->dataProvider();
225
//find out if the layer has 25D type
226
QGis::WkbType geomType = provider->geometryType();
227
if ( geomType == QGis::WKBPoint25D ||
228
geomType == QGis::WKBLineString25D ||
229
geomType == QGis::WKBPolygon25D ||
230
geomType == QGis::WKBMultiPoint25D ||
231
geomType == QGis::WKBMultiLineString25D ||
232
geomType == QGis::WKBMultiPolygon25D )
234
mUseZCoordCheckBox->setEnabled( true );
237
//insert numeric attributes of layer into mInterpolationAttributesComboBox
238
const QgsFieldMap& fields = provider->fields();
239
QgsFieldMap::const_iterator field_it = fields.constBegin();
240
for ( ; field_it != fields.constEnd(); ++field_it )
242
QgsField currentField = field_it.value();
243
QVariant::Type currentType = currentField.type();
244
if ( currentType == QVariant::Int || currentType == QVariant::Double )
246
mInterpolationAttributeComboBox->insertItem( 0, currentField.name() );
251
void QgsInterpolationDialog::on_mAddPushButton_clicked()
253
//read active layer in mInputLayerComboBox
254
QString inputLayer = mInputLayerComboBox->currentText();
256
//read attribute / z-coordinate interpolation
257
QString interpolationAttribute;
258
if ( mUseZCoordCheckBox->checkState() == Qt::Checked )
260
interpolationAttribute = "Z_COORD";
264
interpolationAttribute = mInterpolationAttributeComboBox->currentText();
267
QTreeWidgetItem* newLayerItem = new QTreeWidgetItem();
268
newLayerItem->setText( 0, inputLayer );
269
newLayerItem->setText( 1, interpolationAttribute );
271
mLayersTreeWidget->addTopLevelItem( newLayerItem );
272
QComboBox* typeComboBox = new QComboBox();
273
typeComboBox->addItem( tr( "Points" ) );
274
typeComboBox->addItem( tr( "Structure lines" ) );
275
typeComboBox->addItem( tr( "Break lines" ) );
276
typeComboBox->setCurrentIndex( 0 );
277
mLayersTreeWidget->setItemWidget( newLayerItem, 2, typeComboBox );
279
//keep bounding box up to date
280
setLayersBoundingBox();
282
enableOrDisableOkButton();
285
void QgsInterpolationDialog::on_mRemovePushButton_clicked()
287
QTreeWidgetItem* currentItem = mLayersTreeWidget->currentItem();
293
enableOrDisableOkButton();
297
void QgsInterpolationDialog::on_mOutputFileButton_clicked()
299
//get last output file dir
301
QString lastOutputDir = s.value( "/Interpolation/lastOutputDir", "" ).toString();
303
QString rasterFileName = QFileDialog::getSaveFileName( 0, tr( "Save interpolated raster as..." ), lastOutputDir );
304
if ( !rasterFileName.isEmpty() )
306
mOutputFileLineEdit->setText( rasterFileName );
307
QFileInfo rasterFileInfo( rasterFileName );
308
QDir fileDir = rasterFileInfo.absoluteDir();
309
if ( fileDir.exists() )
311
s.setValue( "/Interpolation/lastOutputDir", rasterFileInfo.absolutePath() );
314
enableOrDisableOkButton();
317
void QgsInterpolationDialog::on_mOutputFileLineEdit_textChanged()
319
if ( mOutputFileLineEdit->text().endsWith( ".asc" ) )
321
enableOrDisableOkButton();
325
void QgsInterpolationDialog::on_mConfigureInterpolationButton_clicked()
327
if ( mInterpolatorDialog )
329
mInterpolatorDialog->exec();
333
QgsVectorLayer* QgsInterpolationDialog::vectorLayerFromName( const QString& name )
335
QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
336
QMap<QString, QgsMapLayer*>::iterator layer_it = mapLayers.begin();
338
for ( ; layer_it != mapLayers.end(); ++layer_it )
340
if ( layer_it.value()->name() == name )
342
return qobject_cast<QgsVectorLayer *>( layer_it.value() );
350
void QgsInterpolationDialog::on_mInterpolationMethodComboBox_currentIndexChanged( const QString &text )
352
delete mInterpolatorDialog;
353
if ( text == tr( "Inverse Distance Weighting (IDW)" ) )
355
mInterpolatorDialog = new QgsIDWInterpolatorDialog( 0, mIface );
357
else if ( text == tr( "Triangular interpolation (TIN)" ) )
359
mInterpolatorDialog = new QgsTINInterpolatorDialog( 0, mIface );
363
void QgsInterpolationDialog::on_mNumberOfColumnsSpinBox_valueChanged( int value )
365
setNewCellsizeXOnNColumnsChange();
368
void QgsInterpolationDialog::on_mNumberOfRowsSpinBox_valueChanged( int value )
370
setNewCellsizeYOnNRowschange();
373
void QgsInterpolationDialog::on_mCellsizeXSpinBox_valueChanged( double value )
375
setNColsOnCellsizeXChange();
378
void QgsInterpolationDialog::on_mCellSizeYSpinBox_valueChanged( double value )
380
setNRowsOnCellsizeYChange();
383
void QgsInterpolationDialog::on_mXMinLineEdit_textEdited( const QString& text )
385
setNewCellsizeOnBoundingBoxChange();
388
void QgsInterpolationDialog::on_mXMaxLineEdit_textEdited( const QString& text )
390
setNewCellsizeOnBoundingBoxChange();
393
void QgsInterpolationDialog::on_mYMinLineEdit_textEdited( const QString& text )
395
setNewCellsizeOnBoundingBoxChange();
398
void QgsInterpolationDialog::on_mYMaxLineEdit_textEdited( const QString& text )
400
setNewCellsizeOnBoundingBoxChange();
403
void QgsInterpolationDialog::on_mBBoxToCurrentExtent_clicked()
407
QgsMapCanvas* canvas = mIface->mapCanvas();
410
QgsRectangle extent = canvas->extent();
411
mXMinLineEdit->setText( QString::number( extent.xMinimum() ) );
412
mXMaxLineEdit->setText( QString::number( extent.xMaximum() ) );
413
mYMinLineEdit->setText( QString::number( extent.yMinimum() ) );
414
mYMaxLineEdit->setText( QString::number( extent.yMaximum() ) );
415
setNewCellsizeOnBoundingBoxChange();
420
QgsRectangle QgsInterpolationDialog::boundingBoxOfLayers()
422
int nLayers = mLayersTreeWidget->topLevelItemCount();
423
QList< QgsInterpolator::LayerData > inputLayerList;
424
QgsRectangle combinedLayerExtent;
426
for ( int i = 0; i < nLayers; ++i )
428
QString layerName = mLayersTreeWidget->topLevelItem( i )->text( 0 );
429
QgsVectorLayer* theVectorLayer = vectorLayerFromName( layerName );
430
if ( !theVectorLayer )
435
QgsVectorDataProvider* theProvider = theVectorLayer->dataProvider();
442
QgsRectangle currentLayerExtent = theVectorLayer->extent();
443
if ( combinedLayerExtent.isEmpty() )
445
combinedLayerExtent = currentLayerExtent;
449
combinedLayerExtent.combineExtentWith( ¤tLayerExtent );
452
return combinedLayerExtent;
455
void QgsInterpolationDialog::setLayersBoundingBox()
457
QgsRectangle layersBoundingBox = boundingBoxOfLayers();
458
mXMinLineEdit->setText( QString::number( layersBoundingBox.xMinimum() ) );
459
mXMaxLineEdit->setText( QString::number( layersBoundingBox.xMaximum() ) );
460
mYMinLineEdit->setText( QString::number( layersBoundingBox.yMinimum() ) );
461
mYMaxLineEdit->setText( QString::number( layersBoundingBox.yMaximum() ) );
462
setNewCellsizeOnBoundingBoxChange();
465
void QgsInterpolationDialog::setNewCellsizeOnBoundingBoxChange()
467
QgsRectangle currentBbox = currentBoundingBox();
468
if ( currentBbox.isEmpty() )
473
if ( currentBbox.width() > 0 && mNumberOfColumnsSpinBox->value() > 0 )
475
mCellsizeXSpinBox->blockSignals( true );
476
mCellsizeXSpinBox->setValue( currentBbox.width() / mNumberOfColumnsSpinBox->value() );
477
mCellsizeXSpinBox->blockSignals( false );
479
if ( currentBbox.height() > 0 && mNumberOfRowsSpinBox->value() > 0 )
481
mCellSizeYSpinBox->blockSignals( true );
482
mCellSizeYSpinBox->setValue( currentBbox.height() / mNumberOfRowsSpinBox->value() );
483
mCellSizeYSpinBox->blockSignals( false );
487
void QgsInterpolationDialog::setNewCellsizeXOnNColumnsChange()
489
QgsRectangle currentBBox = currentBoundingBox();
490
if ( !currentBBox.isEmpty() && mNumberOfColumnsSpinBox->value() > 0 )
492
mCellsizeXSpinBox->blockSignals( true );
493
mCellsizeXSpinBox->setValue( currentBBox.width() / mNumberOfColumnsSpinBox->value() );
494
mCellsizeXSpinBox->blockSignals( false );
498
void QgsInterpolationDialog::setNewCellsizeYOnNRowschange()
500
QgsRectangle currentBBox = currentBoundingBox();
501
if ( !currentBBox.isEmpty() && mNumberOfRowsSpinBox->value() > 0 )
503
mCellSizeYSpinBox->blockSignals( true );
504
mCellSizeYSpinBox->setValue( currentBBox.height() / mNumberOfRowsSpinBox->value() );
505
mCellSizeYSpinBox->blockSignals( false );
509
void QgsInterpolationDialog::setNColsOnCellsizeXChange()
511
QgsRectangle currentBBox = currentBoundingBox();
514
if ( mCellsizeXSpinBox->value() <= 0 )
519
if ( currentBBox.width() <= 0 )
525
newSize = ( int )( currentBBox.width() / mCellsizeXSpinBox->value() );
528
mNumberOfColumnsSpinBox->blockSignals( true );
529
mNumberOfColumnsSpinBox->setValue( newSize );
530
mNumberOfColumnsSpinBox->blockSignals( false );
533
void QgsInterpolationDialog::setNRowsOnCellsizeYChange()
535
QgsRectangle currentBBox = currentBoundingBox();
538
if ( mCellSizeYSpinBox->value() <= 0 )
543
if ( currentBBox.height() <= 0 )
549
newSize = ( int )( currentBBox.height() / mCellSizeYSpinBox->value() );
552
mNumberOfRowsSpinBox->blockSignals( true );
553
mNumberOfRowsSpinBox->setValue( newSize );
554
mNumberOfRowsSpinBox->blockSignals( false );
557
QgsRectangle QgsInterpolationDialog::currentBoundingBox()
559
QString xMinString = mXMinLineEdit->text();
560
QString xMaxString = mXMaxLineEdit->text();
561
QString yMinString = mYMinLineEdit->text();
562
QString yMaxString = mYMaxLineEdit->text();
564
bool xMinOk, xMaxOk, yMinOk, yMaxOk;
565
double xMin = xMinString.toDouble( &xMinOk );
566
double xMax = xMaxString.toDouble( &xMaxOk );
567
double yMin = yMinString.toDouble( &yMinOk );
568
double yMax = yMaxString.toDouble( &yMaxOk );
570
if ( !xMinOk || !xMaxOk || !yMinOk || !yMaxOk )
572
QgsRectangle emptyBbox;
573
return emptyBbox; //error, return empty bounding box
576
return QgsRectangle( xMin, yMin, xMax, yMax );