Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

omgrasterthreshold.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005 by Tim Sutton   *
00003  *   tim@linfiniti.com   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include "omgrasterthreshold.h"
00022 #include "omglayerselector.h"
00023 
00024 #include <omgclimatefilereader.h>
00025 #include <omgfilewriter.h>
00026 #include <../lib/omgclimatedataprocessor.h>
00027 #include <omgclimatefilegroup.h>
00028 #include <omggdal.h>
00029 #include <omgui.h>
00030 
00031 //qt includes
00032 #include <QSettings>
00033 #include <QFileDialog>
00034 #include <QString>
00035 #include <QMessageBox>
00036 #include <QListWidget>
00037 #include <QListWidgetItem>
00038 #include <QHeaderView>
00039 #include <QLineEdit>
00040 #include <QCheckBox>
00041 
00042 
00043 OmgRasterThreshold::OmgRasterThreshold(QWidget* parent, Qt::WFlags fl)
00044     : QDialog(parent,fl)
00045 {
00046   //required by Qt4 to initialise the ui
00047   setupUi(this);
00048   readSettings();
00049 
00050   connect(&mOmgGdal, SIGNAL(error(QString)), this, SLOT(error(QString)));
00051   connect(&mOmgGdal, SIGNAL(updateProgress(int, int )), this, SLOT(updateProgress(int, int )));
00052   //connect(&mOmgGdal, SIGNAL(contourComplete()), this, SLOT(contourComplete()));
00053   // default sort mode
00054   //mSortMode=BY_TAXON; //or BY_ALGORITHM
00055   mSortMode = BY_ALGORITHM;
00056   treeExperiment->header()->resizeSection(0,treeExperiment->width());
00057 }
00058 
00059 OmgRasterThreshold::~OmgRasterThreshold()
00060 {
00061 }
00062 
00063 void OmgRasterThreshold::resizeEvent ( QResizeEvent * theEvent )
00064 {
00065   treeExperiment->header()->resizeSection(0,treeExperiment->width());
00066 }
00067 
00068 void OmgRasterThreshold::setExperiment(OmgExperiment * const thepExperiment)
00069 {
00070   mpExperiment=thepExperiment;
00071   populateTree();
00072 }
00073 
00074 void OmgRasterThreshold::populateTree()
00075 {
00076   if (!mpExperiment)
00077   {
00078     return ;
00079   }
00080   treeExperiment->clear();
00081   int myCount = mpExperiment->count();
00082   //make a node for the experiment
00083   QTreeWidgetItem * mypExperimentItem = new QTreeWidgetItem(treeExperiment);
00084   mypExperimentItem->setText(0,tr("Experiment"));
00085   QIcon myExperimentIcon;
00086   myExperimentIcon.addFile(":/filenewExperiment.png");
00087   mypExperimentItem->setIcon(0,myExperimentIcon);
00088   treeExperiment->setItemExpanded(mypExperimentItem,true);
00089   //select the experiemnt as active item 
00090   treeExperiment->setItemSelected(mypExperimentItem,true);
00091   //
00092   //make a parent node for each alg type or taxon (depending on sort order)
00093   //
00094   QMap <QString,QTreeWidgetItem *> myParentMap;
00095   for (int i=0; i<myCount; i++)
00096   {
00097     OmgModel * mypModel=mpExperiment->getModel(i);
00098     if (mypModel==NULL)
00099     {
00100       continue;
00101     }
00102     QString myName;
00103     QString myParentType;
00104     QString myIconFileName;
00105     if (mSortMode==BY_TAXON)
00106     {
00107       myName = mypModel->taxonName();
00108       myParentType = "Taxon";
00109       myIconFileName = ":/taxon.png";
00110     }
00111     else //BY_ALGORITHM
00112     {
00113       myName = mypModel->algorithm().name();
00114       myParentType = "Algorithm";
00115       myIconFileName = ":/algorithmmanager.png";
00116     }
00117     if (!myParentMap.contains(myName))
00118     {
00119       QTreeWidgetItem * mypParentItem = new QTreeWidgetItem(mypExperimentItem);
00120       mypParentItem->setText(0,myName);
00121       QIcon myParentIcon;
00122       myParentIcon.addFile(myIconFileName);
00123       mypParentItem->setIcon(0,myParentIcon);
00124       myParentMap[myName]=mypParentItem;
00125       //used later to detect if an alg/taxon node was clicked
00126       mypParentItem->setData(0,Qt::UserRole,myParentType); 
00127       
00128       //expand the tree
00129       treeExperiment->setItemExpanded(mypParentItem,true);
00130     }
00131   }
00132   //
00133   // Loop through all models now, adding a nore for each
00134   // to the appropriate parent.
00135   //
00136   for (int i=0; i<myCount; i++)
00137   {
00138     OmgModel * mypModel=mpExperiment->getModel(i);
00139     if (mypModel==NULL)
00140     {
00141       continue;
00142     }
00143     //determine the correct parent for this model in the tree
00144     QTreeWidgetItem * mypParentItem;
00145     QString myItemText;
00146     if (mSortMode==BY_TAXON)
00147     {
00148       mypParentItem = myParentMap.value(mypModel->taxonName());
00149       myItemText = mypModel->algorithm().name();
00150     }
00151     else // BY_ALGORITHM
00152     {
00153       mypParentItem = myParentMap.value(mypModel->algorithm().name());
00154       myItemText = mypModel->taxonName();
00155     }
00156     //now the model - only add it if its completed
00157     if (mypModel->isCompleted())
00158     {
00159       QTreeWidgetItem * mypItem = new QTreeWidgetItem(mypParentItem);
00160       mypItem->setText(0,myItemText);
00161       QIcon myIcon;
00162       myIcon.addFile(mypModel->workDir() + mypModel->thumbnailFileName());
00163       mypItem->setIcon(0,myIcon);
00164       mypItem->setData(0,Qt::UserRole,mypModel->guid());
00165     }
00166   }
00167   treeExperiment->sortItems (0, Qt::AscendingOrder );
00168 }
00169 
00170 void OmgRasterThreshold::on_cboSortBy_currentIndexChanged(QString theString)
00171 {
00172   if (theString==tr("Algorithm"))
00173   {
00174     mSortMode= BY_ALGORITHM;
00175   }
00176   else
00177   {
00178     mSortMode= BY_TAXON;
00179   }
00180   populateTree();
00181 }
00182 
00183 void OmgRasterThreshold::on_pbnThresholdOutputDir_clicked()
00184 {
00185   QSettings mySettings;
00186   QString myLastDir = mySettings.value("rasterthreshold/thresholdOutputDirectory","/tmp").toString(); //initial dir
00187   qDebug ("Last Dir: " + QString(myLastDir).toLocal8Bit());
00188   QString myDirName = QFileDialog::getExistingDirectory(
00189                         this,
00190                         "Choose a directory to save outputs to",
00191                         myLastDir
00192                       );
00193   if (!myDirName.isEmpty())
00194   {
00195     mySettings.setValue("rasterthreshold/thresholdOutputDirectory",myDirName);
00196     leThresholdOutputDir->setText(myDirName);
00197   }
00198 }
00199 
00200 void OmgRasterThreshold::on_pbnSelectThresholdAggregateFile_clicked()
00201 {
00202   QSettings mySettings;
00203   QString myLastFile = mySettings.value("rasterthreshold/aggregateFile","/tmp").toString();
00204   QFileInfo myFileInfo(myLastFile);
00205   QString myDir = myFileInfo.dir().path();
00206   qDebug ("Last Dir: " + QString(myDir).toLocal8Bit());
00207   QString myFileName = QFileDialog::getSaveFileName(
00208                          this,
00209                          "Choose a filename to aggregate file as",
00210                          myDir,
00211                          "Ascii Grid File (*.asc)");
00212   if (!myFileName.isEmpty())
00213   {
00214     mySettings.setValue("rasterthreshold/aggregateFile",myFileName);
00215     leThresholdAggregateFile->setText(myFileName);
00216   }
00217 }
00218 
00219 
00220 
00221 
00222 void OmgRasterThreshold::accept()
00223 {
00224   // Create hotspot map - where each cell is the sum of
00225   // all the thresholded input layers for that cell
00226   writeSettings();
00227   // Whether to save out each intermediate thresholded file
00228   bool myIntermediatesFlag = cbxCreateThresholdFiles->isChecked();
00229   // use the first rasters nulls as a test for invalid rasters
00230   // if a subsequent raster has nulls in a different place
00231   // we want to flag that raster as bad / corrupt
00232   //bool myNullsMustMatchFlag=true;
00233   
00234   int myThresholdPercent=spinThreshold->value();
00235   qDebug("Threshold set to " + QString::number(myThresholdPercent).toLocal8Bit());
00236   // Get a count of selected models
00237   // we conly consider items that are not 'Algorithm'
00238   // 'Experiment' or 'Taxon' to avoid non model items
00239   QStringList myList;
00240   QListIterator<QTreeWidgetItem*> myIterator(treeExperiment->selectedItems());
00241   while (myIterator.hasNext())
00242   {
00243     QString myId = myIterator.next()->data(0,Qt::UserRole).toString();
00244     if (!myId.isEmpty() && myId!=(tr("Algorithm")) && 
00245         myId!=(tr("Taxon")) && myId!=(tr("Experiment")))
00246     {
00247       myList << myId;
00248     }
00249   }
00250 
00251   //
00252   // Check we have at least one layer
00253   //
00254 
00255   if (myList.count() < 1)
00256   {
00257     QMessageBox::warning( this,tr("No Inputs Defined"),
00258         tr("Please select some models in the experiment tree!"));
00259     return;
00260   }
00261 
00262   if (myIntermediatesFlag && leThresholdOutputDir->text().isEmpty())
00263   {
00264     QMessageBox::warning( this,tr("Output directory not set"),
00265         tr("Please set the output directory before clicking Process"));
00266     return;
00267   }
00268   if ( leThresholdAggregateFile->text().isEmpty())
00269   {
00270     QMessageBox::warning( this,tr("Output aggregate file not set"),
00271         tr("Please set the output file for the hotspot map before clicking Process"));
00272     return;
00273   }
00274   //
00275   // Check if the user wants to overwrite existing file
00276   //
00277   QFileInfo myInfo(leThresholdAggregateFile->text());
00278   if (myInfo.exists())
00279   {
00280     QMessageBox myMessage;
00281     myMessage.setText(tr("The threshold file already exists."
00282           "Would you like to overwrite it?"));
00283     myMessage.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
00284     switch (myMessage.exec()) {
00285       case QMessageBox::No:
00286         // no was clicked
00287         return;
00288         break;
00289       case QMessageBox::Yes:
00290         // do nothing
00291         break;
00292       default:
00293         // should never be reached
00294         break;
00295     }
00296 
00297   }
00298   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
00299 
00300   OmgModel * mypFirstModel = mpExperiment->getModel( myList.at(0) );
00301   QString myFirstFile(mypFirstModel->workDir() + mypFirstModel->rawImageFileName());
00302   qDebug("File Name" + myFirstFile.toLocal8Bit());
00303   QString myHeader = mOmgGdal.getAsciiHeader(myFirstFile);
00304   //get the dimensions of the first file - we assume all files have same dimensions!
00305   OmgClimateFileReader myFirstFileReader(myFirstFile,OmgClimateFileReader::GDAL);
00306   int myXDim = myFirstFileReader.xDim();
00307   int myYDim = myFirstFileReader.yDim();
00308   int myArrayLength=myYDim * myXDim;
00309 
00310   // NOTE: declaring an array dynamically like this: int myThresholdArray[myYDim][myXDim];
00311   // is illegal in C++ and will cause segfaults etc, so we allocate our memory like this:
00312   int * myThresholdArray = new int [myArrayLength];
00313 
00314   float myOutputNoData=-9999; //for the aggregate and threshold output files
00315   QString myFormat = mypFirstModel->modelRasterFormat();
00316   float myInputNoData = Omgui::getOutputFormatNoData().value(myFormat);
00317 
00318   OmgClimateDataProcessor myDataProcessor(myInputNoData);
00319   OmgFileWriter * myFileWriter=0;
00320   //initialise the aggegate matrix because who knows what default values it has
00321   //NOTE we dont initialise to nodata - only when we encounter a cell with nodata
00322   //does the aggregate value for that cell become nodata
00323   //memset (myAggregateArray,0,myYDim*myXDim);
00324   memset (myThresholdArray,0,myYDim*myXDim);
00325   
00326   // Iterate through file list and process
00327   for ( int myFileInt = 0; myFileInt < myList.count(); myFileInt++ )
00328   {
00329     OmgModel * mypModel = mpExperiment->getModel( myList.at(myFileInt) );
00330     //calculate teh actual threshold value given the file format
00331     //for this model and the required threshold percent
00332     myFormat = mypModel->modelRasterFormat();
00333     myInputNoData = Omgui::getOutputFormatNoData().value(myFormat);
00334     float myFormatMinimum = Omgui::getOutputFormatRanges().value(myFormat).first;
00335     float myFormatMaximum = Omgui::getOutputFormatRanges().value(myFormat).second;
00336     int myThresholdPercent = spinThreshold->value();
00337     float myThreshold = myFormatMinimum + 
00338       (((myFormatMaximum - myFormatMinimum)/100) * myThresholdPercent);
00339     QString myFormula("Threshold converted to raster range:\n " + 
00340         QString::number(myFormatMaximum) +
00341         "+ (((" + QString::number(myFormatMaximum) + 
00342         " - " + QString::number(myFormatMinimum) +
00343         ")/100) * " + QString::number(myThresholdPercent) + ")");
00344     qDebug(myFormula.toLocal8Bit());
00345     qDebug("Threshold set to " + QString::number(myThreshold).toLocal8Bit());
00346     QString myFileName(mypModel->workDir() + mypModel->rawImageFileName());
00347     //
00348     OmgClimateFileReader myFileReader(myFileName,OmgClimateFileReader::GDAL);
00349     if (myIntermediatesFlag)
00350     {
00351       QFileInfo myFileInfo(myFileName);
00352       QString myBaseString = leThresholdOutputDir->text()+QString("/")+myFileInfo.baseName();  // excludes any extension
00353       QString myOutFileName(myBaseString+"_Threshold_" + 
00354           QString::number(spinThreshold->value()) +".asc");
00355       myFileWriter = new OmgFileWriter(myOutFileName,OmgFileWriter::ESRI_ASCII);
00356       myFileWriter->writeString(myHeader);
00357     }
00358     //
00359     while (!myFileReader.isAtMatrixEnd())
00360     {
00361       //threshold will return 1, 0 or the output nodata value
00362       float myElement = myFileReader.getElement();
00363       int myThresholdedElement = static_cast<int>(myDataProcessor.threshold(myElement,myThreshold));
00364       //write this element to the individual threshold file for a species
00365       if (myIntermediatesFlag)
00366       {
00367         if (myFileReader.currentCol()==0 && myFileReader.currentRow()>0)
00368         {
00369           myFileWriter->sendLineBreak();
00370         }
00371         myFileWriter->writeElement(myThresholdedElement);
00372       }
00373       // write it to the threshold array
00374       int y=myFileReader.currentRow();
00375       int x=myFileReader.currentCol();
00376       int myPos=(y*myXDim)+x;
00377       int myThresholdValue=myThresholdArray[myPos];
00378       //if the output matrix is already marked as nodata dont bother trying to change it!
00379       if (myOutputNoData!=myThresholdValue)
00380       {
00381         //any time we get a nodata back from threshold, that cell should always be marked nodata!
00382 
00383         if (myInputNoData==myElement)
00384         {
00385           myThresholdArray[myPos]=static_cast<int>(myOutputNoData);
00386         }
00387         else
00388         {
00389           myThresholdArray[myPos]=static_cast<int>(myThresholdValue+myThresholdedElement);
00390         }
00391       }
00392     }
00393     qDebug("Written rows: " + QString::number(myFileReader.currentRow()));
00394     qDebug("Written cols: " + QString::number(myFileReader.currentCol()));
00395     emit updateProgress(myFileInt,myList.count());
00396     if (myIntermediatesFlag)
00397     {
00398       OmgGdal myGdal;
00399       QFileInfo myFileInfo(myFileWriter->fileName());
00400       //get the raw name but without its extension
00401       QString myBaseName=myFileInfo.baseName();
00402       QString myImageFileName = myBaseName+".png";
00403       //convert asc generated by threshold to pseudocolor png
00404       //qDebug("Calling omggdal::writeImage(" +  mypModel->rawImageFileName().toLocal8Bit() + ","
00405       //+ myImageFileName.toLocal8Bit()+")");
00406       QString myPreviewFile(mypModel->workDir() + myBaseName + ".png");
00407       myGdal.writeImage(myFileWriter->fileName(),myPreviewFile, 300, 400);
00408       qDebug("Writing threshold preview to : " + myPreviewFile.toLocal8Bit());
00409       lblPreview->setPixmap(QPixmap(myPreviewFile));
00410 
00411       myFileWriter->close();
00412       delete myFileWriter;
00413     }
00414 
00415   }
00416   //now write out the final threshold hotspot matrix
00417   OmgFileWriter myHotspotWriter (leThresholdAggregateFile->text(),OmgFileWriter::ESRI_ASCII);
00418   // make sure the header for the generated files has our output no data
00419   myHeader.replace(QString::number(myInputNoData),QString::number(myOutputNoData));;
00420   myHotspotWriter.writeString(myHeader);
00421   for (int y=0;y<myYDim;y++)
00422   {
00423     for (int x=0;x<myXDim;x++)
00424     {
00425       int myPos=(y*myXDim)+x;
00426       myHotspotWriter.writeElement(myThresholdArray[myPos]);
00427     }
00428     myHotspotWriter.sendLineBreak();
00429   }
00430   myHotspotWriter.close();
00431 
00432   delete[] myThresholdArray;
00433   progressBar->reset();
00434   QApplication::restoreOverrideCursor();
00435   //done(1);
00436   buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
00437   QMessageBox::information( this,QString(tr("Threshold result")),QString(tr("Thresholding completed successfully.")));
00438   close();
00439 
00440 }
00441 
00442 void OmgRasterThreshold::readSettings()
00443 {
00444   QSettings mySettings;
00445   spinThreshold->setValue(mySettings.value("rasterthreshold/thresholdLevel",70).toInt());
00446   cbxCreateThresholdFiles->setChecked(mySettings.value("rasterthreshold/createThresholdFiles","0").toBool());
00447   leThresholdOutputDir->setText(mySettings.value("rasterthreshold/thresholdOutputDir","").toString());
00448 
00449   leThresholdAggregateFile->setText(mySettings.value("rasterthreshold/thresholdAggregateFile",".").toString());
00450 
00451 
00452 }
00453 
00454 void OmgRasterThreshold::writeSettings()
00455 {
00456   QSettings mySettings;
00457 
00458 
00459   mySettings.setValue("rasterthreshold/thresholdLevel",spinThreshold->value());
00460   mySettings.setValue("rasterthreshold/createThresholdFiles",cbxCreateThresholdFiles->isChecked());
00461   mySettings.setValue("rasterthreshold/thresholdOutputDir",leThresholdOutputDir->text());
00462   mySettings.setValue("rasterthreshold/thresholdAggregateFile",leThresholdAggregateFile->text());
00463 
00464 }
00465 
00466 void OmgRasterThreshold::error(QString theError)
00467 {
00468   QMessageBox::warning( this,QString(tr("File Format Converter Error")),theError);
00469 }
00470 
00471 
00472 void OmgRasterThreshold::updateProgress (int theValue, int theMaximumValue)
00473 {
00474   progressBar->setMaximum(theMaximumValue);
00475   progressBar->setValue(theValue);
00476   QApplication::processEvents();
00477 }

Generated on Mon Apr 28 15:07:38 2008 for openModellerDesktop by  doxygen 1.4.1-20050210