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

omggdal.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 "omggdal.h"
00022 
00023 #include <QFileInfo>
00024 #include <QStringList>
00025 #include <QFile>
00026 #include <QTextStream>
00027 #include <QString>
00028 #include <QDir>
00029 #include <QImage>
00030 #include <QPainter>
00031 #include <QPen>
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <iostream>
00036 
00037 //gdal includes
00038 #include <gdal_priv.h>
00039 #include <cpl_string.h>
00040 #include <gdal.h>
00041 #include <gdal_alg.h>
00042 #include <cpl_conv.h>
00043 #include <gdalwarper.h>
00044 
00045 //ogr includes (used e.g. for contouring output)
00046 #include <cpl_conv.h>
00047 #include <ogr_api.h>
00048 #include <ogr_srs_api.h>
00049 
00050 // QGIS includes
00051 #include <qgsrasterlayer.h> 
00052 #include <qgsrasterbandstats.h> 
00053 #include <qgsmaplayerregistry.h> 
00054 #include <qgsapplication.h>
00055 #include <qgsmaprender.h> 
00056 //
00057 // global callback function
00058 //
00059 int CPL_STDCALL progressCallback( double dfComplete, const char * pszMessage,
00060                       void * pProgressArg)
00061 {
00062   static double dfLastComplete = -1.0;
00063 
00064   OmgGdal * mypOmgGdal = (OmgGdal *) pProgressArg;
00065 
00066   if( dfLastComplete > dfComplete )
00067   {
00068     if( dfLastComplete >= 1.0 )
00069       dfLastComplete = -1.0;
00070     else
00071       dfLastComplete = dfComplete;
00072   }
00073 
00074   if( floor(dfLastComplete*10) != floor(dfComplete*10) )
00075   {
00076     int    nPercent = (int) floor(dfComplete*100);
00077 
00078     if( nPercent == 0 && pszMessage != NULL )
00079     {
00080       //fprintf( stdout, "%s:", pszMessage );
00081     }
00082 
00083     if( nPercent == 100 )
00084     {
00085       //fprintf( stdout, "%d - done.\n", (int) floor(dfComplete*100) );
00086       mypOmgGdal->showProgress(100,100);
00087     }
00088     else
00089     {
00090       int myProgress = (int) floor(dfComplete*100);
00091       //fprintf( stdout, "%d.", myProgress);
00092       mypOmgGdal->showProgress(myProgress,100);
00093       //fflush( stdout );
00094     }
00095   }
00096   else if( floor(dfLastComplete*30) != floor(dfComplete*30) )
00097   {
00098     //fprintf( stdout, "." );
00099     //fflush( stdout );
00100   }
00101 
00102   dfLastComplete = dfComplete;
00103 
00104   return TRUE;
00105 }
00106 
00107 
00108 
00109 
00110 OmgGdal::OmgGdal() : QObject()
00111 {
00112   //qDebug ("OmgGdal ctor called");
00113   GDALAllRegister();
00114   OGRRegisterAll();
00115 }
00116 
00117 OmgGdal::~OmgGdal()
00118 {}
00119 
00120 
00121 const QString  OmgGdal::getWorldFile(const QString theFileName)
00122 {
00123   GDALDataset  *gdalDataset = (GDALDataset *) GDALOpen( theFileName.toLocal8Bit(), GA_ReadOnly );
00124   if ( gdalDataset == NULL )
00125   {
00126     return QString("");
00127   }
00128   //get the geotransform stuff from gdal
00129   double myTransform[6];
00130   if (gdalDataset->GetGeoTransform(myTransform) != CE_None)
00131   {
00132     std::cout << "Failed to get geo transform from GDAL, aborting" << std::endl;
00133     GDALClose(gdalDataset);
00134     return QString("");
00135   }
00136   else
00137   {
00138     GDALClose(gdalDataset);
00139   }
00140   QString myHeader;
00141   myHeader += "Pixel XDim " + QString::number(myTransform[1]) + "\r\n";
00142   myHeader += "Rot 0 \r\n";
00143   myHeader += "Rot 0 \r\n";
00144   myHeader += "Pixel YDim " + QString::number(myTransform[5]) + "\r\n";
00145   myHeader += "Origin X   " + QString::number(myTransform[0]) + "\r\n";
00146   myHeader += "Origin Y   " + QString::number(myTransform[3]) + "\r\n";
00147   return myHeader;
00148 }
00149 
00150 const QString  OmgGdal::getAsciiHeader(const QString theFileName)
00151 {
00152   GDALDataset  *gdalDataset = (GDALDataset *) GDALOpen( theFileName.toLocal8Bit(), GA_ReadOnly );
00153   if ( gdalDataset == NULL )
00154   {
00155     return QString("");
00156   }
00157 
00158   //get dimesnions and no data value
00159   int myColsInt = gdalDataset->GetRasterXSize();
00160   int myRowsInt = gdalDataset->GetRasterYSize();
00161   double myNullValue=gdalDataset->GetRasterBand(1)->GetNoDataValue();
00162   //get the geotransform stuff from gdal
00163   double myTransform[6];
00164   if (gdalDataset->GetGeoTransform(myTransform) != CE_None)
00165   {
00166     std::cout << "Failed to get geo transform from GDAL, aborting" << std::endl;
00167     GDALClose(gdalDataset);
00168     return QString("");
00169   }
00170   else
00171   {
00172     GDALClose(gdalDataset);
00173   }
00174 
00175   QString myHeader;
00176 
00177   myHeader =  "NCOLS "        + QString::number(myColsInt) + "\r\n";
00178   myHeader += "NROWS "        + QString::number(myRowsInt) + "\r\n";
00179   float myYTop = myTransform[3];
00180   float myXLeft = myTransform[0];
00181   float myCellHeight = myTransform[5];
00182   float myAbsCellHeight = fabs(myCellHeight);
00183   float myHeight = myAbsCellHeight * myRowsInt;
00184   float myYBottom = myYTop - myHeight;
00185   //qDebug("YTop: " + QString::number(myYTop).toLocal8Bit());
00186   //qDebug("XLeft: " + QString::number(myXLeft).toLocal8Bit());
00187   //qDebug("CellHeight: " + QString::number(myCellHeight).toLocal8Bit());
00188   //qDebug("RowCount: " + QString::number(myRowsInt).toLocal8Bit());
00189   //qDebug("YBottom = YTop - (fabs(CellHeight) * fabs(RowsCount))");
00190   //qDebug("YBottom: " + QString::number(myYBottom).toLocal8Bit());
00191   myHeader += "XLLCORNER "    + QString::number(myXLeft) +  "\r\n";;
00192   myHeader += "YLLCORNER "   + QString::number(myYBottom) +  "\r\n";
00193   myHeader += "CELLSIZE "     + QString::number(myTransform[1]) +  "\r\n";
00194   myHeader += "NODATA_VALUE " + QString::number(myNullValue) +  "\r\n";
00195 
00196   return myHeader;
00197 }
00198 
00199 
00200 /*
00201 Builds the list of file filter strings to later be used by
00202 QgisApp::addRasterLayer()
00203  
00204 We query GDAL for a list of supported raster formats; we then build
00205 a list of file filter strings from that list.  We return a string
00206 that contains this list that is suitable for use in a a
00207 QFileDialog::getOpenFileNames() call.
00208  
00209 This method was filched from QGIS QgsRasterLayer class and tweaked a bit
00210 */
00211 void OmgGdal::buildSupportedRasterFileFilter(QString & theFileFiltersString)
00212 {
00213   // first get the GDAL driver manager
00214 
00215   GDALDriverManager *myGdalDriverManager = GetGDALDriverManager();
00216 
00217   if (!myGdalDriverManager)
00218   {
00219     std::cerr << "unable to get GDALDriverManager\n";
00220     return;                   // XXX good place to throw exception if we
00221   }                           // XXX decide to do exceptions
00222 
00223   // then iterate through all of the supported drivers, adding the
00224   // corresponding file filter
00225 
00226   GDALDriver *myGdalDriver;           // current driver
00227 
00228   char **myGdalDriverMetadata;        // driver metadata strings
00229 
00230   QString myGdalDriverLongName("");   // long name for the given driver
00231   QString myGdalDriverExtension("");  // file name extension for given driver
00232   QString myGdalDriverDescription;    // QString wrapper of GDAL driver description
00233 
00234   QStringList metadataTokens;   // essentially the metadata string delimited by '='
00235 
00236   QString catchallFilter;       // for Any file(*.*), but also for those
00237   // drivers with no specific file
00238   // filter
00239 
00240   // Grind through all the drivers and their respective metadata.
00241   // We'll add a file filter for those drivers that have a file
00242   // extension defined for them; the others, welll, even though
00243   // theoreticaly we can open those files because there exists a
00244   // driver for them, the user will have to use the "All Files" to
00245   // open datasets with no explicitly defined file name extension.
00246   // Note that file name extension strings are of the form
00247   // "DMD_EXTENSION=.*".  We'll also store the long name of the
00248   // driver, which will be found in DMD_LONGNAME, which will have the
00249   // same form.
00250 
00251   for (int i = 0; i < myGdalDriverManager->GetDriverCount(); ++i)
00252   {
00253     myGdalDriver = myGdalDriverManager->GetDriver(i);
00254 
00255     Q_CHECK_PTR(myGdalDriver);
00256 
00257     if (!myGdalDriver)
00258     {
00259       qWarning("unable to get driver %d", i);
00260       continue;
00261     }
00262     // now we need to see if the driver is for something currently
00263     // supported; if not, we give it a miss for the next driver
00264 
00265     myGdalDriverDescription = myGdalDriver->GetDescription();
00266 
00267     // std::cerr << "got driver string " << myGdalDriver->GetDescription() << "\n";
00268 
00269     myGdalDriverMetadata = myGdalDriver->GetMetadata();
00270 
00271     // presumably we know we've run out of metadta if either the
00272     // address is 0, or the first character is null
00273     while (myGdalDriverMetadata && '\0' != myGdalDriverMetadata[0])
00274     {
00275       metadataTokens = QString(*myGdalDriverMetadata).split("=");
00276       // std::cerr << "\t" << *myGdalDriverMetadata << "\n";
00277 
00278       // XXX add check for malformed metadataTokens
00279 
00280       // Note that it's oddly possible for there to be a
00281       // DMD_EXTENSION with no corresponding defined extension
00282       // string; so we check that there're more than two tokens.
00283 
00284       if (metadataTokens.count() > 1)
00285       {
00286         if ("DMD_EXTENSION" == metadataTokens[0])
00287         {
00288           myGdalDriverExtension = metadataTokens[1];
00289 
00290         }
00291         else if ("DMD_LONGNAME" == metadataTokens[0])
00292         {
00293           myGdalDriverLongName = metadataTokens[1];
00294 
00295           // remove any superfluous (.*) strings at the end as
00296           // they'll confuse QFileDialog::getOpenFileNames()
00297 
00298           myGdalDriverLongName.remove(QRegExp("\\(.*\\)$"));
00299         }
00300       }
00301       // if we have both the file name extension and the long name,
00302       // then we've all the information we need for the current
00303       // driver; therefore emit a file filter string and move to
00304       // the next driver
00305       if (!(myGdalDriverExtension.isEmpty() || myGdalDriverLongName.isEmpty()))
00306       {
00307         // XXX add check for SDTS; in that case we want (*CATD.DDF)
00308         QString glob = "*." + myGdalDriverExtension;
00309         theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
00310 
00311         break;            // ... to next driver, if any.
00312       }
00313 
00314       ++myGdalDriverMetadata;
00315 
00316     }                       // each metadata item
00317 
00318     if (myGdalDriverExtension.isEmpty() && !myGdalDriverLongName.isEmpty())
00319     {
00320       // Then what we have here is a driver with no corresponding
00321       // file extension; e.g., GRASS.  In which case we append the
00322       // string to the "catch-all" which will match all file types.
00323       // (I.e., "*.*") We use the driver description intead of the
00324       // long time to prevent the catch-all line from getting too
00325       // large.
00326 
00327       // ... OTOH, there are some drivers with missing
00328       // DMD_EXTENSION; so let's check for them here and handle
00329       // them appropriately
00330 
00331       // USGS DEMs use "*.dem"
00332       if (myGdalDriverDescription.startsWith("USGSDEM"))
00333       {
00334         QString glob = "*.dem";
00335         theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
00336       }
00337       else if (myGdalDriverDescription.startsWith("DTED"))
00338       {
00339         // DTED use "*.dt0"
00340         QString glob = "*.dt0";
00341         theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
00342       }
00343       else if (myGdalDriverDescription.startsWith("MrSID"))
00344       {
00345         // MrSID use "*.sid"
00346         QString glob = "*.sid";
00347         theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
00348       }
00349       else
00350       {
00351         catchallFilter += QString(myGdalDriver->GetDescription()) + " ";
00352       }
00353     }
00354 
00355     // A number of drivers support JPEG 2000. Add it in for those.
00356     if (  myGdalDriverDescription.startsWith("MrSID")
00357           || myGdalDriverDescription.startsWith("ECW")
00358           || myGdalDriverDescription.startsWith("JPEG2000")
00359           || myGdalDriverDescription.startsWith("JP2KAK") )
00360     {
00361       QString glob = "*.jp2 *.j2k";
00362       theFileFiltersString += "JPEG 2000 (" + glob.toLower() + " " + glob.toUpper() + ");;";
00363     }
00364 
00365     // A number of drivers support JPEG 2000. Add it in for those.
00366     if (  myGdalDriverDescription.startsWith("MrSID")
00367           || myGdalDriverDescription.startsWith("ECW")
00368           || myGdalDriverDescription.startsWith("JPEG2000")
00369           || myGdalDriverDescription.startsWith("JP2KAK") )
00370     {
00371       QString glob = "*.jp2 *.j2k";
00372       theFileFiltersString += "JPEG 2000 (" + glob.toLower() + " " + glob.toUpper() + ");;";
00373     }
00374 
00375     myGdalDriverExtension = myGdalDriverLongName = "";  // reset for next driver
00376 
00377   }                           // each loaded GDAL driver
00378 
00379   // can't forget the default case
00380   theFileFiltersString += catchallFilter + "All other files (*)";
00381 #ifdef QGISDEBUG
00382   std::cout << "Raster filter list built: " << theFileFiltersString.local8Bit() << std::endl;
00383 #endif
00384 }  // buildSupportedRasterFileFilter
00385 
00386 const QString OmgGdal::contour(const QString theInputFile)
00387 {
00388   QString myOutputFileDir = "/tmp";
00389   QString myOutputFileName = "contour";
00390   GDALDatasetH hSrcDS;
00391   int  b3D = FALSE, bNoDataSet = FALSE;
00392   int myBandNumber = 1;
00393   double dfInterval = 1.0;
00394   double  dfNoData = 0.0;
00395   double dfOffset = 0.0;
00396 
00397   const char *pszDstFilename = myOutputFileDir.toLocal8Bit();
00398   const char *pszElevAttrib = NULL;
00399   QString myFormat = "ESRI Shapefile";
00400   double adfFixedLevels[1000];
00401   int    nFixedLevelCount = 0;
00402 
00403   //      Open source raster file.
00404 
00405   GDALRasterBandH hBand;
00406 
00407   hSrcDS = GDALOpen( theInputFile.toLocal8Bit(), GA_ReadOnly );
00408   if( hSrcDS == NULL )
00409   {
00410     emit error ("Unable to open source file");
00411   }
00412 
00413   hBand = GDALGetRasterBand( hSrcDS, myBandNumber );
00414   if( hBand == NULL )
00415   {
00416     CPLError( CE_Failure, CPLE_AppDefined,
00417               "Band %d does not exist on dataset.",
00418               myBandNumber );
00419   }
00420   dfNoData = GDALGetRasterNoDataValue( hBand, &bNoDataSet );
00421   //     Try to get a coordinate system from the raster.
00422 
00423   OGRSpatialReferenceH hSRS = NULL;
00424 
00425   const char *pszWKT = GDALGetProjectionRef( hBand );
00426 
00427   if( pszWKT != NULL && strlen(pszWKT) != 0 )
00428     hSRS = OSRNewSpatialReference( pszWKT );
00429 
00430   //      Create the outputfile
00431   OGRDataSourceH hDS;
00432   OGRSFDriverH hDriver = OGRGetDriverByName( myFormat.toLocal8Bit() );
00433   OGRFieldDefnH hFld;
00434   OGRLayerH hLayer;
00435   int nElevField = -1;
00436 
00437   if( hDriver == NULL )
00438   {
00439     fprintf( stderr, "Unable to find format driver named %s.\n",
00440              myFormat.toLocal8Bit().data() );
00441     return QString();
00442   }
00443 
00444   hDS = OGR_Dr_CreateDataSource( hDriver, pszDstFilename, NULL );
00445   if( hDS == NULL )
00446   {
00447     return QString();
00448   }
00449 
00450   hLayer = OGR_DS_CreateLayer( hDS, myOutputFileName.toLocal8Bit(), hSRS,
00451                                b3D ? wkbLineString25D : wkbLineString,
00452                                NULL );
00453   if( hLayer == NULL )
00454   {
00455     return QString();
00456   }
00457 
00458 
00459   hFld = OGR_Fld_Create( "ID", OFTInteger );
00460   OGR_Fld_SetWidth( hFld, 8 );
00461   OGR_L_CreateField( hLayer, hFld, FALSE );
00462   OGR_Fld_Destroy( hFld );
00463 
00464   if( pszElevAttrib )
00465   {
00466     hFld = OGR_Fld_Create( pszElevAttrib, OFTReal );
00467     OGR_Fld_SetWidth( hFld, 12 );
00468     OGR_Fld_SetPrecision( hFld, 3 );
00469     OGR_L_CreateField( hLayer, hFld, FALSE );
00470     OGR_Fld_Destroy( hFld );
00471     nElevField = 1;
00472   }
00473   // -------------------------------------------------------------------- */
00474   //      Invoke.                                                         */
00475   // -------------------------------------------------------------------- */
00476   CPLErr eErr;
00477 
00478   eErr = GDALContourGenerate( hBand, dfInterval, dfOffset,
00479                               nFixedLevelCount, adfFixedLevels,
00480                               bNoDataSet, dfNoData,
00481                               hLayer, 0, nElevField,
00482                               GDALTermProgress, NULL );
00483   //progressCallback, NULL );
00484 
00485   OGR_DS_Destroy( hDS );
00486   GDALClose( hSrcDS );
00487   return myOutputFileDir + "/" + myOutputFileName;
00488 }
00489 
00490 const bool OmgGdal::convert(const QString theInputFile, const QString theOutputPath, const FileType theOutputFileType)
00491 {
00492   bool myResult=false;
00493   //Compile output filename from input file and output path
00494   QFileInfo myFileInfo(theInputFile);
00495   QString myBaseString = theOutputPath +QString("/")+myFileInfo.baseName();  // excludes any extension
00496 
00497   QString myFileName;
00498 
00499   switch (theOutputFileType)
00500   {
00501     case GeoTiff :
00502       //compute outfile name
00503       myFileName = myBaseString+".tif";
00504       //qDebug("OmgGdal::convert - converting " + theInputFile.toLocal8Bit() 
00505       //    + " to " + myFileName.toLocal8Bit());
00506       myResult=gdal2Tiff (theInputFile, myFileName);
00507       break;
00508     case ArcInfoAscii :
00509       //compute outfile name
00510       myFileName = myBaseString+".asc";
00511       //qDebug("OmgGdal::convert - converting " + theInputFile.toLocal8Bit() 
00512       //    + " to " + myFileName.toLocal8Bit());
00513       myResult=gdal2Ascii (theInputFile, myFileName);
00514       break;
00515     default :
00516       emit error( tr("Output file type not supported!"));
00517       break;
00518   }
00519   return myResult;
00520 }
00521 
00522 
00523 //
00524 // Private methods only below this point please!
00525 //
00526 
00527 const bool OmgGdal::gdal2gdal(const QString theFileName, 
00528     const QString theOutputFileName,
00529     const QString theFormat)
00530 {
00531   //const QString myFormat = "GTiff";
00532   GDALDriver * mypDriver;
00533   char **papszMetadata;
00534 
00535   mypDriver = GetGDALDriverManager()->GetDriverByName(theFormat.toLocal8Bit());
00536 
00537   if( mypDriver == NULL )
00538   {
00539     emit error ("Unknown GDAL Driver!");
00540     return true;
00541   }
00542 
00543   papszMetadata = mypDriver->GetMetadata();
00544   if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) )
00545   {
00546     //printf( "Driver supports Create() method.\n" );
00547   }
00548   else
00549   {
00550     //printf( "Driver does not support Create() method.\n" );
00551   }
00552   if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) )
00553   {
00554     //printf( "Driver supports CreateCopy() method.\n" );
00555   }
00556   else
00557   {
00558     //printf( "Driver does not support CreateCopy() method.\n" );
00559   }
00560 
00561   GDALDataset *mypSourceDataset =
00562     (GDALDataset *) GDALOpen( theFileName.toLocal8Bit(), GA_ReadOnly );
00563   GDALDataset *mypDestinationDataset;
00564 
00565   mypDestinationDataset = mypDriver->CreateCopy( theOutputFileName.toLocal8Bit(),
00566                           mypSourceDataset, FALSE,
00567                                                   NULL, progressCallback, this );
00568   if( mypDestinationDataset != NULL )
00569   {
00570     delete mypDestinationDataset;
00571   }
00572   return true;
00573 
00574 }
00575 
00576 const bool OmgGdal::gdal2Tiff(const QString theFileName, 
00577     const QString theOutputFileName)
00578 {
00579    return gdal2gdal(theFileName, 
00580     theOutputFileName,
00581     "GTiff");
00582 }
00583 const bool OmgGdal::gdal2Ascii(const QString theFileName, 
00584     const QString theOutputFileName)
00585 {
00586    return gdal2gdal(theFileName, 
00587     theOutputFileName,
00588     "AAIGrid");
00589 }
00590 
00591 
00592 
00593 
00594 
00595 void OmgGdal::showProgress (int theProgress,int theMaximum)
00596 {
00597   emit updateProgress (theProgress,theMaximum);
00598 }
00599 
00600 
00601 
00602 bool OmgGdal::isValidGdalFile(const QString theFilename)
00603 {
00604   //test for some common known not valid formats
00605   QStringList myList;
00606   myList << "prj" << "so" << "dylib" << "txt" << "xml" << "mea" << "exe" ;
00607   QFileInfo myFileInfo(theFilename);
00608   QString myExtension = myFileInfo.suffix();
00609   QStringListIterator myIterator(myList);
00610   while (myIterator.hasNext())
00611   {
00612     if (myIterator.next()==myExtension)
00613     {
00614       return false;
00615     }
00616   }
00617   if (theFilename.endsWith("~"))
00618   {
00619     return false;
00620   }
00621   //now lets try to load the file and see if gdal recognises
00622   
00623   GDALAllRegister();
00624   OGRRegisterAll();
00625   GDALDataset * myTestFile = (GDALDataset *)GDALOpen( theFilename.toLocal8Bit(), GA_ReadOnly );
00626 
00627   if( myTestFile == NULL )
00628   {
00629     //not GDAL compatible
00630     GDALClose(myTestFile);
00631     return false;
00632   }
00633   else
00634   {
00635     //is GDAL compatible
00636     GDALClose(myTestFile);
00637     return true;
00638   }
00639 }
00640 
00641 bool OmgGdal::isValidGdalProj(const QString theFilename)
00642 {
00643   GDALAllRegister();
00644   OGRRegisterAll();
00645   //test whether the file has GDAL projection info
00646   GDALDataset * myTestFile = (GDALDataset *)GDALOpen( theFilename.toLocal8Bit(), GA_ReadOnly );
00647 
00648   QString myProjectionString = myTestFile->GetProjectionRef();
00649 
00650   if(myProjectionString.isEmpty())
00651   {
00652     //does not have projection info
00653     GDALClose(myTestFile);
00654     return false;
00655   }
00656   else
00657   {
00658     //does have projection info
00659     GDALClose(myTestFile);
00660     return true;
00661   }
00662 }
00664 void OmgGdal::calculateStats(BandStats * theBandStats,GDALDataset * gdalDataset)
00665 {
00666   //std::cout << "Calculating statistics..." << std::endl;
00667   GDALRasterBand  *myGdalBand = gdalDataset->GetRasterBand( 1 );
00668   QString myColorInterpretation = GDALGetColorInterpretationName(myGdalBand->GetColorInterpretation());
00669   theBandStats->bandName=myColorInterpretation;
00670   theBandStats->bandNo=1;
00671   // get the dimensions of the raster
00672   int myColsInt = myGdalBand->GetXSize();
00673   int myRowsInt = myGdalBand->GetYSize();
00674 
00675   theBandStats->elementCountInt=myColsInt*myRowsInt;
00676   theBandStats->noDataDouble=myGdalBand->GetNoDataValue();
00677   //allocate a buffer to hold one row of ints
00678   int myAllocationSizeInt = sizeof(float)*myColsInt;
00679   float * myScanlineAllocInt = (float*) CPLMalloc(myAllocationSizeInt);
00680   bool myFirstIterationFlag = true;
00681   //unfortunately we need to make two passes through the data to calculate stddev
00682   for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++)
00683   {
00684     CPLErr myResult = myGdalBand->RasterIO(
00685         GF_Read, 0, myCurrentRowInt, myColsInt, 1, 
00686         myScanlineAllocInt, myColsInt, 1, GDT_Float32, 0, 0 );
00687     if (myResult != CE_None)
00688     {
00689       emit error ("Unable to raster band");
00690       return;
00691     }
00692     for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++)
00693     {
00694       //get the nth element from the current row
00695       double myDouble=myScanlineAllocInt[myCurrentColInt];
00696       //only use this element if we have a non null element
00697       if (myDouble != theBandStats->noDataDouble )
00698       {
00699         if (myFirstIterationFlag)
00700         {
00701           //this is the first iteration so initialise vars
00702           myFirstIterationFlag=false;
00703           theBandStats->minValDouble=myDouble;
00704           theBandStats->maxValDouble=myDouble;
00705         } //end of true part for first iteration check
00706         else
00707         {
00708           //this is done for all subsequent iterations
00709           if (myDouble < theBandStats->minValDouble)
00710           {
00711             theBandStats->minValDouble=myDouble;
00712           }
00713           if (myDouble > theBandStats->maxValDouble)
00714           {
00715             //  printf ("Maxval updated to %f\n",myDouble);
00716             theBandStats->maxValDouble=myDouble;
00717           }
00718           //only increment the running total if it is not a nodata value
00719           if (myDouble != theBandStats->noDataDouble)
00720           {
00721             theBandStats->sumDouble += myDouble;
00722             ++theBandStats->elementCountInt;
00723           }
00724         } //end of false part for first iteration check
00725       } //end of nodata chec
00726     } //end of column wise loop
00727   } //end of row wise loop
00728   //
00729   //end of first pass through data now calculate the range
00730   theBandStats->rangeDouble = theBandStats->maxValDouble-theBandStats->minValDouble;
00731   //calculate the mean
00732   theBandStats->meanDouble = theBandStats->sumDouble / theBandStats->elementCountInt;
00733   //for the second pass we will get the sum of the squares / mean
00734   for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++)
00735   {
00736     CPLErr myResult = myGdalBand->RasterIO(
00737         GF_Read, 0, myCurrentRowInt, myColsInt, 1, myScanlineAllocInt, myColsInt, 1, GDT_Float32, 0, 0 );
00738     if (myResult != CE_None)
00739     {
00740       emit error ("Unable to raster band");
00741       return;
00742     }
00743     for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++)
00744     {
00745       //get the nth element from the current row
00746       double myDouble=myScanlineAllocInt[myCurrentColInt];
00747       theBandStats->sumSqrDevDouble += static_cast<double>(pow(myDouble - theBandStats->meanDouble,2));
00748     } //end of column wise loop
00749   } //end of row wise loop
00750   //divide result by sample size - 1 and get square root to get stdev
00751   theBandStats->stdDevDouble = static_cast<double>(sqrt(theBandStats->sumSqrDevDouble /
00752         (theBandStats->elementCountInt - 1)));
00753   CPLFree(myScanlineAllocInt);
00754   //printf("CalculateStats::\n");
00755   //std::cout << "Band Name   : " << theBandStats->bandName << std::endl;
00756   //printf("Band No   : %i\n",theBandStats->bandNo);
00757   //printf("Band min  : %f\n",theBandStats->minValDouble);
00758   //printf("Band max  : %f\n",theBandStats->maxValDouble);
00759   //printf("Band range: %f\n",theBandStats->rangeDouble);
00760   //printf("Band mean : %f\n",theBandStats->meanDouble);
00761   //printf("Band sum : %f\n",theBandStats->sumDouble);
00762   return ;
00763 }
00764 
00765 void OmgGdal::writeImage(QString theInputFileString, 
00766     QString theOutputFileString,
00767     int theWidth,
00768     int theHeight)
00769 {
00770   qDebug("Started with input :  " + theInputFileString.toLocal8Bit());
00771   qDebug("Started with output : " + theOutputFileString.toLocal8Bit());
00772   QFileInfo myRasterFileInfo ( theInputFileString );
00773   QgsRasterLayer *  mpRasterLayer = new QgsRasterLayer ( myRasterFileInfo.filePath(),
00774             myRasterFileInfo.completeBaseName() );
00775   // Register the layer with the registry
00776   QgsMapLayerRegistry::instance()->removeAllMapLayers(); //will delete raster too
00777   QgsMapLayerRegistry::instance()->addMapLayer(mpRasterLayer);
00778   // add the test layer to the maprender
00779   QgsMapRender * mpMapRenderer = new QgsMapRender();
00780   QStringList myLayers;
00781   myLayers << mpRasterLayer->getLayerID();
00782   mpMapRenderer->setLayerSet(myLayers);
00783   mpRasterLayer->setDrawingStyle(QgsRasterLayer::SINGLE_BAND_PSEUDO_COLOR);
00784   mpRasterLayer->setColorShadingAlgorithm(QgsRasterLayer::PSEUDO_COLOR);  
00785   mpRasterLayer->setContrastEnhancementAlgorithm(
00786       QgsContrastEnhancement::STRETCH_TO_MINMAX, false);
00787   mpRasterLayer->setMinimumValue(mpRasterLayer->getGrayBandName(),0.0, false);
00788   mpRasterLayer->setMaximumValue(mpRasterLayer->getGrayBandName(),10.0);
00789   mpMapRenderer->setExtent(mpRasterLayer->extent());
00790   //
00791   // Now render our layers onto a pixmap 
00792   //
00793   QImage myImage( theWidth , theHeight , QImage::Format_RGB32 );
00794   myImage.fill ( qRgba( 255,255,255,255  ) );
00795   QPainter myPainter( &myImage );
00796   mpMapRenderer->setOutputSize( QSize ( theWidth,theHeight ),72 /* dpi */ ); 
00797   mpMapRenderer->render( &myPainter );
00798   myPainter.end();
00799   myImage.save (theOutputFileString);
00800   delete mpMapRenderer;
00801   QgsMapLayerRegistry::instance()->removeAllMapLayers(); //will delete raster too
00802 
00803   return ;
00804 }
00805 
00806 const bool OmgGdal::makeLegend(const QString theOutputFileName, int theWidth)
00807 {
00808   int myFinalWidth = theWidth;
00809   int myLegendWidth = 100;
00810   int myLegendHeight =  10 ;
00811   QImage myLegendImage(myLegendWidth, 1, QImage::Format_ARGB32);
00812   QPainter myQPainter; 
00813 
00814   //set up the three class breaks for pseudocolour mapping
00815   double myRangeSizeDouble = 90;  //hard coded for now
00816   double myBreakSizeDouble = myRangeSizeDouble / 3;
00817   double myClassBreakMin1 = 0;
00818   double myClassBreakMax1 = myClassBreakMin1 + myBreakSizeDouble;
00819   double myClassBreakMin2 = myClassBreakMax1;
00820   double myClassBreakMax2 = myClassBreakMin2 + myBreakSizeDouble;
00821   double myClassBreakMin3 = myClassBreakMax2;
00822 
00823   //
00824   // Create the legend 
00825   //
00826   myQPainter.begin(&myLegendImage);
00827   int myPosInt = 0;
00828   for (double myDouble = 0; myDouble < myRangeSizeDouble; myDouble += myRangeSizeDouble / 100.0)
00829   {
00830     //draw pseudocolor legend
00831     //check if we are in the first class break
00832     if ((myDouble >= myClassBreakMin1) && (myDouble < myClassBreakMax1))
00833     {
00834       int myRedInt = 0;
00835       int myBlueInt = 255;
00836       int myGreenInt = static_cast < int >(((255 / myRangeSizeDouble) * (myDouble - myClassBreakMin1)) * 3);
00837       myQPainter.setPen(QPen(QColor(myRedInt, myGreenInt, myBlueInt, QColor::Rgb), 0));
00838     }
00839     //check if we are in the second class break
00840     else if ((myDouble >= myClassBreakMin2) && (myDouble < myClassBreakMax2))
00841     {
00842       int myRedInt = static_cast < int >(((255 / myRangeSizeDouble) * ((myDouble - myClassBreakMin2) / 1)) * 3);
00843       int myBlueInt = static_cast < int >(255 - (((255 / myRangeSizeDouble) * ((myDouble - myClassBreakMin2) / 1)) * 3));
00844       int myGreenInt = 255;
00845       myQPainter.setPen(QPen(QColor(myRedInt, myGreenInt, myBlueInt, QColor::Rgb), 0));
00846     }
00847     //otherwise we must be in the third classbreak
00848     else
00849     {
00850       int myRedInt = 255;
00851       int myBlueInt = 0;
00852       int myGreenInt = static_cast < int >(255 - (((255 / myRangeSizeDouble) * ((myDouble - myClassBreakMin3) / 1) * 3)));
00853       myQPainter.setPen(QPen(QColor(myRedInt, myGreenInt, myBlueInt, QColor::Rgb), 0));
00854     }
00855     myQPainter.drawPoint(myPosInt++, 0);
00856   }
00857 
00858 
00859   myQPainter.end();
00860 
00861 
00862 
00863 
00864   //create a matrix to
00865   QMatrix myQWMatrix;
00866   //scale the raster legend up a bit 
00867   //note that scaling parameters are factors, not absolute values,
00868   // so scale (0.25,1) scales the painter to a quarter of its size in the x direction
00869   //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix
00870   //hard coding thes values for now.
00871   //assume 100px so scale by factor of 1.5 (=150px wide)
00872   //also we add font width to allow space for lettering overlap 
00873   float myScaleFactor = myFinalWidth / myLegendWidth ;
00874   myQWMatrix.scale(myScaleFactor, myLegendHeight);
00875 
00876 #if WIN32  
00877   QFont myQFont("Verdana", 10, QFont::Normal);
00878 #else
00879   QFont myQFont("Arial", 10, QFont::Normal);
00880 #endif
00881 
00882   QFontMetrics myQFontMetrics(myQFont);
00883   //an amount in pixels to leave small amounts of whitespace between image and text parts
00884   int  myVerticalSpace = 5;
00885   int  myHorizontalSpace = 3;
00886   QImage myImage2( myFinalWidth  , 
00887                   myLegendHeight + myQFontMetrics.height() + (myVerticalSpace *2), 
00888                   QImage::Format_ARGB32);
00889   myImage2.fill(Qt::white);
00890   QPainter myPainter2(&myImage2);
00891   //draw the pseudocolors with the matrix appleid
00892   //in the process
00893   myPainter2.drawImage(0,0, myLegendImage.transformed(myQWMatrix));
00894   //
00895   // Overlay the layername
00896   //
00897   myPainter2.setPen(Qt::black);
00898   myPainter2.setFont(myQFont);
00899   myPainter2.setRenderHint(QPainter::TextAntialiasing,true);
00900   myPainter2.drawText(myHorizontalSpace, myLegendHeight + (myQFontMetrics.height() /2) + myVerticalSpace , tr("Low"));
00901   myPainter2.drawText(myFinalWidth - (myQFontMetrics.width("255")+myHorizontalSpace ), 
00902       myLegendHeight + (myQFontMetrics.height() /2)+ myVerticalSpace ,
00903       tr("High"));
00904   QString myString = tr("Medium Probability");
00905   myPainter2.drawText((myFinalWidth / 2) -( myQFontMetrics.width(myString) /2 ) , 
00906         myLegendHeight + (myQFontMetrics.height() /2) + myVerticalSpace , 
00907         myString);
00908   //
00909   // finish up
00910   //
00911   myPainter2.end();
00912   myImage2.save(theOutputFileName);
00913   return true;
00914 
00915 }//end of makeLegend function
00916 

Generated on Mon Apr 28 15:08:32 2008 for openModellerDesktop by  doxygen 1.4.1-20050210