Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsninecellfilter.h - description 00003 ------------------- 00004 begin : August 6th, 2009 00005 copyright : (C) 2009 by Marco Hugentobler 00006 email : marco dot hugentobler at karto dot baug dot ethz dot ch 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgsninecellfilter.h" 00019 #include "cpl_string.h" 00020 #include <QProgressDialog> 00021 00022 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 00023 #define TO8(x) (x).toUtf8().constData() 00024 #else 00025 #define TO8(x) (x).toLocal8Bit().constData() 00026 #endif 00027 00028 QgsNineCellFilter::QgsNineCellFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat ) 00029 : mInputFile( inputFile ), mOutputFile( outputFile ), mOutputFormat( outputFormat ), mCellSizeX( -1 ), mCellSizeY( -1 ), 00030 mInputNodataValue( -1 ), mOutputNodataValue( -1 ), mZFactor( 1.0 ) 00031 { 00032 00033 } 00034 00035 QgsNineCellFilter::QgsNineCellFilter() 00036 { 00037 00038 } 00039 00040 QgsNineCellFilter::~QgsNineCellFilter() 00041 { 00042 00043 } 00044 00045 int QgsNineCellFilter::processRaster( QProgressDialog* p ) 00046 { 00047 GDALAllRegister(); 00048 00049 //open input file 00050 int xSize, ySize; 00051 GDALDatasetH inputDataset = openInputFile( xSize, ySize ); 00052 if ( inputDataset == NULL ) 00053 { 00054 return 1; //opening of input file failed 00055 } 00056 00057 //output driver 00058 GDALDriverH outputDriver = openOutputDriver(); 00059 if ( outputDriver == 0 ) 00060 { 00061 return 2; 00062 } 00063 00064 GDALDatasetH outputDataset = openOutputFile( inputDataset, outputDriver ); 00065 if ( outputDataset == NULL ) 00066 { 00067 return 3; //create operation on output file failed 00068 } 00069 00070 //open first raster band for reading (operation is only for single band raster) 00071 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, 1 ); 00072 if ( rasterBand == NULL ) 00073 { 00074 GDALClose( inputDataset ); 00075 GDALClose( outputDataset ); 00076 return 4; 00077 } 00078 mInputNodataValue = GDALGetRasterNoDataValue( rasterBand, NULL ); 00079 00080 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 ); 00081 if ( outputRasterBand == NULL ) 00082 { 00083 GDALClose( inputDataset ); 00084 GDALClose( outputDataset ); 00085 return 5; 00086 } 00087 //try to set -9999 as nodata value 00088 GDALSetRasterNoDataValue( outputRasterBand, -9999 ); 00089 mOutputNodataValue = GDALGetRasterNoDataValue( outputRasterBand, NULL ); 00090 00091 if ( ySize < 3 ) //we require at least three rows (should be true for most datasets) 00092 { 00093 GDALClose( inputDataset ); 00094 GDALClose( outputDataset ); 00095 return 6; 00096 } 00097 00098 //keep only three scanlines in memory at a time 00099 float* scanLine1 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); 00100 float* scanLine2 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); 00101 float* scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); 00102 00103 float* resultLine = ( float * ) CPLMalloc( sizeof( float ) * xSize ); 00104 00105 if ( p ) 00106 { 00107 p->setMaximum( ySize ); 00108 } 00109 00110 //values outside the layer extent (if the 3x3 window is on the border) are sent to the processing method as (input) nodata values 00111 for ( int i = 0; i < ySize; ++i ) 00112 { 00113 if ( p ) 00114 { 00115 p->setValue( i ); 00116 } 00117 00118 if ( p && p->wasCanceled() ) 00119 { 00120 break; 00121 } 00122 00123 if ( i == 0 ) 00124 { 00125 //fill scanline 1 with (input) nodata for the values above the first row and feed scanline2 with the first row 00126 for ( int a = 0; a < xSize; ++a ) 00127 { 00128 scanLine1[a] = mInputNodataValue; 00129 } 00130 GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, scanLine2, xSize, 1, GDT_Float32, 0, 0 ); 00131 } 00132 else 00133 { 00134 //normally fetch only scanLine3 and release scanline 1 if we move forward one row 00135 CPLFree( scanLine1 ); 00136 scanLine1 = scanLine2; 00137 scanLine2 = scanLine3; 00138 scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); 00139 } 00140 00141 if ( i == ySize - 1 ) //fill the row below the bottom with nodata values 00142 { 00143 for ( int a = 0; a < xSize; ++a ) 00144 { 00145 scanLine3[a] = mInputNodataValue; 00146 } 00147 } 00148 else 00149 { 00150 GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, scanLine3, xSize, 1, GDT_Float32, 0, 0 ); 00151 } 00152 00153 for ( int j = 0; j < xSize; ++j ) 00154 { 00155 if ( j == 0 ) 00156 { 00157 resultLine[j] = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j], 00158 &scanLine2[j+1], &mInputNodataValue, &scanLine3[j], &scanLine3[j+1] ); 00159 } 00160 else if ( j == xSize - 1 ) 00161 { 00162 resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j], 00163 &mInputNodataValue, &scanLine3[j-1], &scanLine3[j], &mInputNodataValue ); 00164 } 00165 else 00166 { 00167 resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j], 00168 &scanLine2[j+1], &scanLine3[j-1], &scanLine3[j], &scanLine3[j+1] ); 00169 } 00170 } 00171 00172 GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine, xSize, 1, GDT_Float32, 0, 0 ); 00173 } 00174 00175 if ( p ) 00176 { 00177 p->setValue( ySize ); 00178 } 00179 00180 CPLFree( resultLine ); 00181 CPLFree( scanLine1 ); 00182 CPLFree( scanLine2 ); 00183 CPLFree( scanLine3 ); 00184 00185 GDALClose( inputDataset ); 00186 00187 if ( p && p->wasCanceled() ) 00188 { 00189 //delete the dataset without closing (because it is faster) 00190 GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() ); 00191 return 7; 00192 } 00193 GDALClose( outputDataset ); 00194 00195 return 0; 00196 } 00197 00198 GDALDatasetH QgsNineCellFilter::openInputFile( int& nCellsX, int& nCellsY ) 00199 { 00200 GDALDatasetH inputDataset = GDALOpen( TO8( mInputFile ), GA_ReadOnly ); 00201 if ( inputDataset != NULL ) 00202 { 00203 nCellsX = GDALGetRasterXSize( inputDataset ); 00204 nCellsY = GDALGetRasterYSize( inputDataset ); 00205 00206 //we need at least one band 00207 if ( GDALGetRasterCount( inputDataset ) < 1 ) 00208 { 00209 GDALClose( inputDataset ); 00210 return NULL; 00211 } 00212 } 00213 return inputDataset; 00214 } 00215 00216 GDALDriverH QgsNineCellFilter::openOutputDriver() 00217 { 00218 char **driverMetadata; 00219 00220 //open driver 00221 GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() ); 00222 00223 if ( outputDriver == NULL ) 00224 { 00225 return outputDriver; //return NULL, driver does not exist 00226 } 00227 00228 driverMetadata = GDALGetMetadata( outputDriver, NULL ); 00229 if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) ) 00230 { 00231 return NULL; //driver exist, but it does not support the create operation 00232 } 00233 00234 return outputDriver; 00235 } 00236 00237 GDALDatasetH QgsNineCellFilter::openOutputFile( GDALDatasetH inputDataset, GDALDriverH outputDriver ) 00238 { 00239 if ( inputDataset == NULL ) 00240 { 00241 return NULL; 00242 } 00243 00244 int xSize = GDALGetRasterXSize( inputDataset ); 00245 int ySize = GDALGetRasterYSize( inputDataset );; 00246 00247 //open output file 00248 char **papszOptions = NULL; 00249 GDALDatasetH outputDataset = GDALCreate( outputDriver, mOutputFile.toLocal8Bit().data(), xSize, ySize, 1, GDT_Float32, papszOptions ); 00250 if ( outputDataset == NULL ) 00251 { 00252 return outputDataset; 00253 } 00254 00255 //get geotransform from inputDataset 00256 double geotransform[6]; 00257 if ( GDALGetGeoTransform( inputDataset, geotransform ) != CE_None ) 00258 { 00259 GDALClose( outputDataset ); 00260 return NULL; 00261 } 00262 GDALSetGeoTransform( outputDataset, geotransform ); 00263 00264 //make sure mCellSizeX and mCellSizeY are always > 0 00265 mCellSizeX = geotransform[1]; 00266 if ( mCellSizeX < 0 ) 00267 { 00268 mCellSizeX = -mCellSizeX; 00269 } 00270 mCellSizeY = geotransform[5]; 00271 if ( mCellSizeY < 0 ) 00272 { 00273 mCellSizeY = -mCellSizeY; 00274 } 00275 00276 const char* projection = GDALGetProjectionRef( inputDataset ); 00277 GDALSetProjection( outputDataset, projection ); 00278 00279 return outputDataset; 00280 } 00281