osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/gdal/ReaderWriterGDAL.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #include <osgEarth/TileSource>
00021 #include <osgEarth/FileUtils>
00022 #include <osgEarth/Registry>
00023 #include <osgEarth/ImageUtils>
00024 
00025 #include <osgDB/FileNameUtils>
00026 #include <osgDB/FileUtils>
00027 #include <osgDB/Registry>
00028 #include <osgDB/ReadFile>
00029 #include <osgDB/WriteFile>
00030 #include <osgDB/ImageOptions>
00031 
00032 #include <sstream>
00033 #include <stdlib.h>
00034 #include <memory.h>
00035 
00036 #include <gdal_priv.h>
00037 #include <gdalwarper.h>
00038 #include <ogr_spatialref.h>
00039 
00040 #include "GDALOptions"
00041 
00042 #define LC "[GDAL driver] "
00043 
00044 // From easyrgb.com
00045 float Hue_2_RGB( float v1, float v2, float vH )
00046 {
00047    if ( vH < 0 ) vH += 1;
00048    if ( vH > 1 ) vH -= 1;
00049    if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH );
00050    if ( ( 2 * vH ) < 1 ) return ( v2 );
00051    if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 );
00052    return ( v1 );
00053 }
00054 
00055 #if (GDAL_VERSION_MAJOR > 1 || (GDAL_VERSION_MAJOR >= 1 && GDAL_VERSION_MINOR >= 5))
00056 #  define GDAL_VERSION_1_5_OR_NEWER 1
00057 #endif
00058 
00059 #if (GDAL_VERSION_MAJOR > 1 || (GDAL_VERSION_MAJOR >= 1 && GDAL_VERSION_MINOR >= 6))
00060 #  define GDAL_VERSION_1_6_OR_NEWER 1
00061 #endif
00062 
00063 #ifndef GDAL_VERSION_1_5_OR_NEWER
00064 #  error "**** GDAL 1.5 or newer required ****"
00065 #endif
00066 
00067 //GDAL proxy is only available after GDAL 1.6
00068 #if GDAL_VERSION_1_6_OR_NEWER
00069 #  include <gdal_proxy.h>
00070 #endif
00071 
00072 #include <cpl_string.h>
00073 
00074 //GDAL VRT api is only available after 1.5.0
00075 #include <gdal_vrt.h>
00076 
00077 using namespace std;
00078 using namespace osgEarth;
00079 using namespace osgEarth::Drivers;
00080 
00081 #define GEOTRSFRM_TOPLEFT_X            0
00082 #define GEOTRSFRM_WE_RES               1
00083 #define GEOTRSFRM_ROTATION_PARAM1      2
00084 #define GEOTRSFRM_TOPLEFT_Y            3
00085 #define GEOTRSFRM_ROTATION_PARAM2      4
00086 #define GEOTRSFRM_NS_RES               5
00087 
00088 
00089 
00090 typedef enum
00091 {
00092     LOWEST_RESOLUTION,
00093     HIGHEST_RESOLUTION,
00094     AVERAGE_RESOLUTION
00095 } ResolutionStrategy;
00096 
00097 typedef struct
00098 {
00099     int    isFileOK;
00100     int    nRasterXSize;
00101     int    nRasterYSize;
00102     double adfGeoTransform[6];
00103     int    nBlockXSize;
00104     int    nBlockYSize;
00105 } DatasetProperty;
00106 
00107 typedef struct
00108 {
00109     GDALColorInterp        colorInterpretation;
00110     GDALDataType           dataType;
00111     GDALColorTableH        colorTable;
00112     int                    bHasNoData;
00113     double                 noDataValue;
00114 } BandProperty;
00115 
00116 static void
00117 getFiles(const std::string &file, const std::vector<std::string> &exts, std::vector<std::string> &files)
00118 {
00119     if (osgDB::fileType(file) == osgDB::DIRECTORY)
00120     {
00121         osgDB::DirectoryContents contents = osgDB::getDirectoryContents(file);
00122         for (osgDB::DirectoryContents::iterator itr = contents.begin(); itr != contents.end(); ++itr)
00123         {
00124             if (*itr == "." || *itr == "..") continue;
00125             std::string f = osgDB::concatPaths(file, *itr);
00126             getFiles(f, exts, files);
00127         }
00128     }
00129     else
00130     {
00131         bool fileValid = false;
00132         //If we have no _extensions specified, assume we should try everything
00133         if (exts.size() == 0)
00134         {
00135             fileValid = true;
00136         }
00137         else
00138         {
00139             //Only accept files with the given _extensions
00140             std::string ext = osgDB::getFileExtension(file);
00141             for (unsigned int i = 0; i < exts.size(); ++i)
00142             {
00143                 if (osgDB::equalCaseInsensitive(ext, exts[i]))
00144                 {
00145                     fileValid = true;
00146                     break;
00147                 }
00148             }
00149         }
00150         
00151         if (fileValid)
00152         {
00153           files.push_back(osgDB::convertFileNameToNativeStyle(file));
00154         }
00155     }
00156 }
00157 
00158 // "build_vrt()" is adapted from the gdalbuildvrt application. Following is
00159 // the copyright notice from the source. The original code can be found at
00160 // http://trac.osgeo.org/gdal/browser/trunk/gdal/apps/gdalbuildvrt.cpp
00161 
00162 /******************************************************************************
00163  * Copyright (c) 2007, Even Rouault
00164  *
00165  * Permission is hereby granted, free of charge, to any person obtaining a
00166  * copy of this software and associated documentation files (the "Software"),
00167  * to deal in the Software without restriction, including without limitation
00168  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00169  * and/or sell copies of the Software, and to permit persons to whom the
00170  * Software is furnished to do so, subject to the following conditions:
00171  *
00172  * The above copyright notice and this permission notice shall be included
00173  * in all copies or substantial portions of the Software.
00174  *
00175  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00176  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00177  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00178  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00179  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00180  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00181  * DEALINGS IN THE SOFTWARE.
00182  ****************************************************************************/
00183 static GDALDatasetH
00184 build_vrt(std::vector<std::string> &files, ResolutionStrategy resolutionStrategy)
00185 {
00186     GDAL_SCOPED_LOCK;
00187 
00188     char* projectionRef = NULL;
00189     int nBands = 0;
00190     BandProperty* bandProperties = NULL;
00191     double minX = 0, minY = 0, maxX = 0, maxY = 0;
00192     int i,j;
00193     double we_res = 0;
00194     double ns_res = 0;
00195     int rasterXSize;
00196     int rasterYSize;
00197     int nCount = 0;
00198     int bFirst = TRUE;
00199     VRTDatasetH hVRTDS = NULL;
00200 
00201     int nInputFiles = files.size();
00202 
00203     DatasetProperty* psDatasetProperties =
00204             (DatasetProperty*) CPLMalloc(nInputFiles*sizeof(DatasetProperty));
00205 
00206     for(i=0;i<nInputFiles;i++)
00207     {
00208         const char* dsFileName = files[i].c_str();
00209 
00210         GDALTermProgress( 1.0 * (i+1) / nInputFiles, NULL, NULL);
00211 
00212         GDALDatasetH hDS = GDALOpen(dsFileName, GA_ReadOnly );
00213         psDatasetProperties[i].isFileOK = FALSE;
00214 
00215         if (hDS)
00216         {
00217             const char* proj = GDALGetProjectionRef(hDS);
00218             if (!proj || strlen(proj) == 0)
00219             {                
00220                 std::string prjLocation = osgDB::getNameLessExtension( std::string(dsFileName) ) + std::string(".prj");
00221                 std::string wkt;
00222                 if ( HTTPClient::readString( prjLocation, wkt ) == HTTPClient::RESULT_OK )
00223                 {                    
00224                     proj = CPLStrdup( wkt.c_str() );
00225                 }                
00226             }
00227 
00228             GDALGetGeoTransform(hDS, psDatasetProperties[i].adfGeoTransform);
00229             if (psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] != 0 ||
00230                 psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] != 0)
00231             {
00232                 fprintf( stderr, "GDAL Driver does not support rotated geo transforms. Skipping %s\n",
00233                              dsFileName);
00234                 GDALClose(hDS);
00235                 continue;
00236             }
00237             if (psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES] >= 0)
00238             {
00239                 fprintf( stderr, "GDAL Driver does not support positive NS resolution. Skipping %s\n",
00240                              dsFileName);
00241                 GDALClose(hDS);
00242                 continue;
00243             }
00244             psDatasetProperties[i].nRasterXSize = GDALGetRasterXSize(hDS);
00245             psDatasetProperties[i].nRasterYSize = GDALGetRasterYSize(hDS);
00246             double product_minX = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
00247             double product_maxY = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
00248             double product_maxX = product_minX +
00249                         GDALGetRasterXSize(hDS) * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES];
00250             double product_minY = product_maxY +
00251                         GDALGetRasterYSize(hDS) * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES];
00252 
00253             GDALGetBlockSize(GDALGetRasterBand( hDS, 1 ),
00254                              &psDatasetProperties[i].nBlockXSize,
00255                              &psDatasetProperties[i].nBlockYSize);
00256 
00257             if (bFirst)
00258             {
00259                 if (proj)
00260                     projectionRef = CPLStrdup(proj);
00261                 minX = product_minX;
00262                 minY = product_minY;
00263                 maxX = product_maxX;
00264                 maxY = product_maxY;
00265                 nBands = GDALGetRasterCount(hDS);
00266                 bandProperties = (BandProperty*)CPLMalloc(nBands*sizeof(BandProperty));
00267                 for(j=0;j<nBands;j++)
00268                 {
00269                     GDALRasterBandH hRasterBand = GDALGetRasterBand( hDS, j+1 );
00270                     bandProperties[j].colorInterpretation = GDALGetRasterColorInterpretation(hRasterBand);
00271                     bandProperties[j].dataType = GDALGetRasterDataType(hRasterBand);
00272                     if (bandProperties[j].colorInterpretation == GCI_PaletteIndex)
00273                     {
00274                         bandProperties[j].colorTable = GDALGetRasterColorTable( hRasterBand );
00275                         if (bandProperties[j].colorTable)
00276                         {
00277                             bandProperties[j].colorTable = GDALCloneColorTable(bandProperties[j].colorTable);
00278                         }
00279                     }
00280                     else
00281                         bandProperties[j].colorTable = 0;
00282                     bandProperties[j].noDataValue = GDALGetRasterNoDataValue(hRasterBand, &bandProperties[j].bHasNoData);
00283                 }
00284             }
00285             else
00286             {
00287                 if ((proj != NULL && projectionRef == NULL) ||
00288                     (proj == NULL && projectionRef != NULL) ||
00289                     (proj != NULL && projectionRef != NULL && EQUAL(proj, projectionRef) == FALSE))
00290                 {
00291                     fprintf( stderr, "gdalbuildvrt does not support heterogenous projection. Skipping %s\n",dsFileName);
00292                     GDALClose(hDS);
00293                     continue;
00294                 }
00295                 int _nBands = GDALGetRasterCount(hDS);
00296                 if (nBands != _nBands)
00297                 {
00298                     fprintf( stderr, "gdalbuildvrt does not support heterogenous band numbers. Skipping %s\n",
00299                              dsFileName);
00300                     GDALClose(hDS);
00301                     continue;
00302                 }
00303                 for(j=0;j<nBands;j++)
00304                 {
00305                     GDALRasterBandH hRasterBand = GDALGetRasterBand( hDS, j+1 );
00306                     if (bandProperties[j].colorInterpretation != GDALGetRasterColorInterpretation(hRasterBand) ||
00307                         bandProperties[j].dataType != GDALGetRasterDataType(hRasterBand))
00308                     {
00309                         fprintf( stderr, "gdalbuildvrt does not support heterogenous band characteristics. Skipping %s\n",
00310                              dsFileName);
00311                         GDALClose(hDS);
00312                     }
00313                     if (bandProperties[j].colorTable)
00314                     {
00315                         GDALColorTableH colorTable = GDALGetRasterColorTable( hRasterBand );
00316                         if (colorTable == NULL ||
00317                             GDALGetColorEntryCount(colorTable) != GDALGetColorEntryCount(bandProperties[j].colorTable))
00318                         {
00319                             fprintf( stderr, "gdalbuildvrt does not support heterogenous band characteristics. Skipping %s\n",
00320                              dsFileName);
00321                             GDALClose(hDS);
00322                             break;
00323                         }
00324                         /* We should check that the palette are the same too ! */
00325                     }
00326                 }
00327                 if (j != nBands)
00328                     continue;
00329                 if (product_minX < minX) minX = product_minX;
00330                 if (product_minY < minY) minY = product_minY;
00331                 if (product_maxX > maxX) maxX = product_maxX;
00332                 if (product_maxY > maxY) maxY = product_maxY;
00333             }
00334             if (resolutionStrategy == AVERAGE_RESOLUTION)
00335             {
00336                 we_res += psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES];
00337                 ns_res += psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES];
00338             }
00339             else
00340             {
00341                 if (bFirst)
00342                 {
00343                     we_res = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES];
00344                     ns_res = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES];
00345                 }
00346                 else if (resolutionStrategy == HIGHEST_RESOLUTION)
00347                 {
00348                     we_res = MIN(we_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]);
00349                     /* Yes : as ns_res is negative, the highest resolution is the max value */
00350                     ns_res = MAX(ns_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]);
00351                 }
00352                 else
00353                 {
00354                     we_res = MAX(we_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]);
00355                     /* Yes : as ns_res is negative, the lowest resolution is the min value */
00356                     ns_res = MIN(ns_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]);
00357                 }
00358             }
00359 
00360             psDatasetProperties[i].isFileOK = 1;
00361             nCount ++;
00362             bFirst = FALSE;
00363             GDALClose(hDS);
00364         }
00365         else
00366         {
00367             fprintf( stderr, "Warning : can't open %s. Skipping it\n", dsFileName);
00368         }
00369     }
00370     
00371     if (nCount == 0)
00372         goto end;
00373     
00374     if (resolutionStrategy == AVERAGE_RESOLUTION)
00375     {
00376         we_res /= nCount;
00377         ns_res /= nCount;
00378     }
00379     
00380     rasterXSize = (int)(0.5 + (maxX - minX) / we_res);
00381     rasterYSize = (int)(0.5 + (maxY - minY) / -ns_res);
00382     
00383     hVRTDS = VRTCreate(rasterXSize, rasterYSize);
00384     
00385     if (projectionRef)
00386     {
00387         //OE_NOTICE << "Setting projection to " << projectionRef << std::endl;
00388         GDALSetProjection(hVRTDS, projectionRef);
00389     }
00390     
00391     double adfGeoTransform[6];
00392     adfGeoTransform[GEOTRSFRM_TOPLEFT_X] = minX;
00393     adfGeoTransform[GEOTRSFRM_WE_RES] = we_res;
00394     adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] = 0;
00395     adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] = maxY;
00396     adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] = 0;
00397     adfGeoTransform[GEOTRSFRM_NS_RES] = ns_res;
00398     GDALSetGeoTransform(hVRTDS, adfGeoTransform);
00399     
00400     for(j=0;j<nBands;j++)
00401     {
00402         GDALRasterBandH hBand;
00403         GDALAddBand(hVRTDS, bandProperties[j].dataType, NULL);
00404         hBand = GDALGetRasterBand(hVRTDS, j+1);
00405         GDALSetRasterColorInterpretation(hBand, bandProperties[j].colorInterpretation);
00406         if (bandProperties[j].colorInterpretation == GCI_PaletteIndex)
00407         {
00408             GDALSetRasterColorTable(hBand, bandProperties[j].colorTable);
00409         }
00410         if (bandProperties[j].bHasNoData)
00411             GDALSetRasterNoDataValue(hBand, bandProperties[j].noDataValue);
00412     }
00413 
00414     for(i=0;i<nInputFiles;i++)
00415     {
00416         if (psDatasetProperties[i].isFileOK == 0)
00417             continue;
00418         const char* dsFileName = files[i].c_str();
00419 
00420         bool isProxy = true;
00421 
00422 #if GDAL_VERSION_1_6_OR_NEWER
00423 
00424         //Use a proxy dataset if possible.  This helps with huge amount of files to keep the # of handles down
00425         GDALProxyPoolDatasetH hDS =
00426                GDALProxyPoolDatasetCreate(dsFileName,
00427                                          psDatasetProperties[i].nRasterXSize,
00428                                          psDatasetProperties[i].nRasterYSize,
00429                                          GA_ReadOnly, TRUE, projectionRef,
00430                                          psDatasetProperties[i].adfGeoTransform);
00431 
00432         for(j=0;j<nBands;j++)
00433         {
00434             GDALProxyPoolDatasetAddSrcBandDescription(hDS,
00435                                             bandProperties[j].dataType,
00436                                             psDatasetProperties[i].nBlockXSize,
00437                                             psDatasetProperties[i].nBlockYSize);
00438         }
00439         isProxy = true;
00440         OE_DEBUG << LC << "Using GDALProxyPoolDatasetH" << std::endl;
00441 
00442 #else // !GDAL_VERSION_1_6_OR_NEWER
00443 
00444         OE_DEBUG << LC << "Using GDALDataset, no proxy support enabled" << std::endl;
00445         //Just open the dataset
00446         GDALDatasetH hDS = (GDALDatasetH)GDALOpen(dsFileName, GA_ReadOnly);
00447         isProxy = false;
00448 
00449 #endif
00450 
00451         int xoffset = (int)
00452                 (0.5 + (psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_X] - minX) / we_res);
00453         int yoffset = (int)
00454                 (0.5 + (maxY - psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_Y]) / -ns_res);
00455         int dest_width = (int)
00456                 (0.5 + psDatasetProperties[i].nRasterXSize * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES] / we_res);
00457         int dest_height = (int)
00458                 (0.5 + psDatasetProperties[i].nRasterYSize * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES] / ns_res);
00459 
00460         for(j=0;j<nBands;j++)
00461         {
00462             VRTSourcedRasterBandH hVRTBand = (VRTSourcedRasterBandH)GDALGetRasterBand(hVRTDS, j + 1);
00463 
00464             /* Place the raster band at the right position in the VRT */
00465             VRTAddSimpleSource(hVRTBand, GDALGetRasterBand((GDALDatasetH)hDS, j + 1),
00466                                0, 0,
00467                                psDatasetProperties[i].nRasterXSize,
00468                                psDatasetProperties[i].nRasterYSize,
00469                                xoffset, yoffset,
00470                                dest_width, dest_height, "near",
00471                                VRT_NODATA_UNSET);
00472         }
00473         //Only dereference if it is a proxy dataset
00474         if (isProxy)
00475         {
00476           GDALDereferenceDataset(hDS);
00477         }
00478     }
00479 end:
00480     CPLFree(psDatasetProperties);
00481     for(j=0;j<nBands;j++)
00482     {
00483         GDALDestroyColorTable(bandProperties[j].colorTable);
00484     }
00485     CPLFree(bandProperties);
00486     CPLFree(projectionRef);
00487     return hVRTDS;
00488 }
00489 
00490 
00491 // This is simply the method GDALAutoCreateWarpedVRT() with the GDALSuggestedWarpOutput
00492 // logic replaced with something that will work properly for polar projections.
00493 // see: http://www.mail-archive.com/gdal-dev@lists.osgeo.org/msg01491.html
00494 static
00495 GDALDatasetH GDALAutoCreateWarpedVRTforPolarStereographic(
00496     GDALDatasetH hSrcDS,
00497     const char *pszSrcWKT,
00498     const char *pszDstWKT,
00499     GDALResampleAlg eResampleAlg,
00500     double dfMaxError,
00501     const GDALWarpOptions *psOptionsIn )
00502 {
00503     GDALWarpOptions *psWO;
00504     int i;
00505 
00506     VALIDATE_POINTER1( hSrcDS, "GDALAutoCreateWarpedVRTForPolarStereographic", NULL );
00507 
00508     /* -------------------------------------------------------------------- */
00509     /*      Populate the warp options.                                      */
00510     /* -------------------------------------------------------------------- */
00511     if( psOptionsIn != NULL )
00512         psWO = GDALCloneWarpOptions( psOptionsIn );
00513     else
00514         psWO = GDALCreateWarpOptions();
00515 
00516     psWO->eResampleAlg = eResampleAlg;
00517 
00518     psWO->hSrcDS = hSrcDS;
00519 
00520     psWO->nBandCount = GDALGetRasterCount( hSrcDS );
00521     psWO->panSrcBands = (int *) CPLMalloc(sizeof(int) * psWO->nBandCount);
00522     psWO->panDstBands = (int *) CPLMalloc(sizeof(int) * psWO->nBandCount);
00523 
00524     for( i = 0; i < psWO->nBandCount; i++ )
00525     {
00526         psWO->panSrcBands[i] = i+1;
00527         psWO->panDstBands[i] = i+1;
00528     }
00529 
00530     /* TODO: should fill in no data where available */
00531 
00532     /* -------------------------------------------------------------------- */
00533     /*      Create the transformer.                                         */
00534     /* -------------------------------------------------------------------- */
00535     psWO->pfnTransformer = GDALGenImgProjTransform;
00536     psWO->pTransformerArg =
00537         GDALCreateGenImgProjTransformer( psWO->hSrcDS, pszSrcWKT,
00538         NULL, pszDstWKT,
00539         TRUE, 1.0, 0 );
00540 
00541     if( psWO->pTransformerArg == NULL )
00542     {
00543         GDALDestroyWarpOptions( psWO );
00544         return NULL;
00545     }
00546 
00547     /* -------------------------------------------------------------------- */
00548     /*      Figure out the desired output bounds and resolution.            */
00549     /* -------------------------------------------------------------------- */
00550     double adfDstGeoTransform[6];
00551     int    nDstPixels, nDstLines;
00552     CPLErr eErr;
00553 
00554     eErr =
00555         GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
00556             psWO->pTransformerArg,
00557             adfDstGeoTransform, &nDstPixels, &nDstLines );
00558 
00559     // override the suggestions:
00560     nDstPixels = GDALGetRasterXSize( hSrcDS ) * 4;
00561     nDstLines  = GDALGetRasterYSize( hSrcDS ) / 2;
00562     adfDstGeoTransform[0] = -180.0;
00563     adfDstGeoTransform[1] = 360.0/(double)nDstPixels;
00564     //adfDstGeoTransform[2] = 0.0;
00565     //adfDstGeoTransform[4] = 0.0;
00566     //adfDstGeoTransform[5] = (-90 -adfDstGeoTransform[3])/(double)nDstLines;
00567 
00568     /* -------------------------------------------------------------------- */
00569     /*      Update the transformer to include an output geotransform        */
00570     /*      back to pixel/line coordinates.                                 */
00571     /*                                                                      */
00572     /* -------------------------------------------------------------------- */
00573     GDALSetGenImgProjTransformerDstGeoTransform(
00574         psWO->pTransformerArg, adfDstGeoTransform );
00575 
00576     /* -------------------------------------------------------------------- */
00577     /*      Do we want to apply an approximating transformation?            */
00578     /* -------------------------------------------------------------------- */
00579     if( dfMaxError > 0.0 )
00580     {
00581         psWO->pTransformerArg =
00582             GDALCreateApproxTransformer( psWO->pfnTransformer,
00583             psWO->pTransformerArg,
00584             dfMaxError );
00585         psWO->pfnTransformer = GDALApproxTransform;
00586     }
00587 
00588     /* -------------------------------------------------------------------- */
00589     /*      Create the VRT file.                                            */
00590     /* -------------------------------------------------------------------- */
00591     GDALDatasetH hDstDS;
00592 
00593     hDstDS = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
00594         adfDstGeoTransform, psWO );
00595 
00596     GDALDestroyWarpOptions( psWO );
00597 
00598     if( pszDstWKT != NULL )
00599         GDALSetProjection( hDstDS, pszDstWKT );
00600     else if( pszSrcWKT != NULL )
00601         GDALSetProjection( hDstDS, pszDstWKT );
00602     else if( GDALGetGCPCount( hSrcDS ) > 0 )
00603         GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
00604     else
00605         GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
00606 
00607     return hDstDS;
00608 }
00609 
00610 
00611 class GDALTileSource : public TileSource
00612 {
00613 public:
00614     GDALTileSource( const TileSourceOptions& options ) :
00615       TileSource( options ),
00616       _srcDS(NULL),
00617       _warpedDS(NULL),
00618       _options(options),
00619       _maxDataLevel(30)
00620     {    
00621     }
00622 
00623     virtual ~GDALTileSource()
00624     {             
00625         GDAL_SCOPED_LOCK;
00626 
00627         if (_warpedDS != _srcDS)
00628         {
00629             GDALClose( _warpedDS );
00630         }
00631 
00632         //Close the datasets if it exists
00633         if (_srcDS)
00634         {     
00635             GDALClose(_srcDS);
00636         }
00637     }
00638 
00639 
00640     void initialize( const std::string& referenceURI, const Profile* overrideProfile)
00641     {   
00642         GDAL_SCOPED_LOCK;
00643 
00644         if ( !_options.url().isSet() || _options.url()->empty() )
00645         {
00646             OE_WARN << LC << "No URL or directory specified " << std::endl;
00647             return;
00648         }
00649 
00650         URI uri = _options.url().value();
00651 
00652         //Find the full path to the URL
00653         //If we have a relative path and the map file contains a server address, just concat the server path and the _url together
00654 
00655         if (osgEarth::isRelativePath(uri.full()) && osgDB::containsServerAddress(referenceURI))
00656         {
00657             uri = URI(osgDB::getFilePath(referenceURI) + std::string("/") + uri.full());
00658         }
00659 
00660         //If the path doesn't contain a server address, get the full path to the file.
00661         if (!osgDB::containsServerAddress(uri.full()))
00662         {
00663             uri = URI(uri.full(), referenceURI);
00664         }
00665 
00666         StringTokenizer izer( ";" );
00667         StringVector exts;
00668         izer.tokenize( *_options.extensions(), exts );
00669 
00670         //std::vector<std::string> exts;
00671 
00672         //tokenize( _options.extensions().value(), exts, ";");
00673         for (unsigned int i = 0; i < exts.size(); ++i)
00674         {
00675             OE_DEBUG << LC << "Using Extension: " << exts[i] << std::endl;
00676         }
00677         std::vector<std::string> files;
00678         getFiles(uri.full(), exts, files);
00679 
00680         OE_INFO << LC << "Driver found " << files.size() << " files:" << std::endl;
00681         for (unsigned int i = 0; i < files.size(); ++i)
00682         {
00683             OE_INFO << LC << "" << files[i] << std::endl;
00684         }
00685 
00686         if (files.empty())
00687         {
00688             OE_WARN << LC << "Could not find any valid files " << std::endl;
00689             return;
00690         }
00691 
00692         //If we found more than one file, try to combine them into a single logical dataset
00693         if (files.size() > 1)
00694         {
00695             _srcDS = (GDALDataset*)build_vrt(files, HIGHEST_RESOLUTION);
00696             if (!_srcDS)
00697             {
00698                 OE_WARN << "[osgEarth::GDAL] Failed to build VRT from input datasets" << std::endl;
00699                 return;
00700             }
00701         }
00702         else
00703         {
00704             //If we couldn't build a VRT, just try opening the file directly
00705             //Open the dataset
00706             _srcDS = (GDALDataset*)GDALOpen( files[0].c_str(), GA_ReadOnly );
00707             if ( !_srcDS )
00708             {
00709                 OE_WARN << LC << "Failed to open dataset " << files[0] << std::endl;
00710                 return;
00711             }
00712         }
00713 
00714         //Create a spatial reference for the source.
00715         const char* srcProj = _srcDS->GetProjectionRef();
00716         if ( srcProj != 0L && overrideProfile != 0L )
00717         {
00718             OE_WARN << LC << "WARNING, overriding profile of a source that already defines its own SRS (" 
00719                 << this->getName() << ")" << std::endl;
00720         }
00721 
00722         osg::ref_ptr<const SpatialReference> src_srs;
00723         if ( overrideProfile )
00724         {
00725             src_srs = overrideProfile->getSRS();
00726         }
00727         else if ( srcProj )
00728         {
00729             src_srs = SpatialReference::create( srcProj );
00730         }
00731         
00732         // assert SRS is present
00733         if ( !src_srs.valid() )
00734         {
00735             // not found in the dataset; try loading a .prj file
00736             std::string prjLocation = osgDB::getNameLessExtension( uri.full() ) + std::string(".prj");
00737             std::string wkt;
00738             if ( HTTPClient::readString( prjLocation, wkt ) == HTTPClient::RESULT_OK )
00739             {
00740                 src_srs = SpatialReference::create( wkt );
00741             }
00742 
00743             if ( !src_srs.valid() )
00744             {
00745                 OE_WARN << LC << "Dataset has no spatial reference information: " << uri.full() << std::endl;
00746                 return;
00747             }
00748         }
00749 
00750         const Profile* profile = NULL;
00751 
00752         if ( overrideProfile )
00753         {
00754             profile = overrideProfile;
00755         }
00756 
00757         if ( !profile && src_srs->isGeographic() )
00758         {
00759             profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile();
00760         }
00761 
00762         //Note:  Can cause odd rendering artifacts if we have a dataset that is mercator that doesn't encompass the whole globe
00763         //       if we take on the global profile.
00764         /*
00765         if ( !profile && src_srs->isMercator() )
00766         {
00767             profile = osgEarth::Registry::instance()->getGlobalMercatorProfile();
00768         }*/
00769 
00770         std::string warpedSRSWKT;
00771 
00772         if ( profile && !profile->getSRS()->isEquivalentTo( src_srs.get() ) )
00773         {
00774             if ( profile->getSRS()->isGeographic() && (src_srs->isNorthPolar() || src_srs->isSouthPolar()) )
00775             {
00776                 _warpedDS = (GDALDataset*)GDALAutoCreateWarpedVRTforPolarStereographic(
00777                     _srcDS,
00778                     src_srs->getWKT().c_str(),
00779                     profile->getSRS()->getWKT().c_str(),
00780                     GRA_NearestNeighbour,
00781                     5.0,
00782                     NULL);
00783             }
00784             else
00785             {
00786                 _warpedDS = (GDALDataset*)GDALAutoCreateWarpedVRT(
00787                     _srcDS,
00788                     src_srs->getWKT().c_str(),
00789                     profile->getSRS()->getWKT().c_str(),
00790                     GRA_NearestNeighbour,
00791                     5.0,
00792                     NULL);
00793             }
00794 
00795             if ( _warpedDS )
00796             {
00797                 warpedSRSWKT = _warpedDS->GetProjectionRef();
00798             }
00799 
00800             //GDALAutoCreateWarpedVRT(srcDS, src_wkt.c_str(), t_srs.c_str(), GRA_NearestNeighbour, 5.0, NULL);
00801         }
00802         else
00803         {
00804             _warpedDS = _srcDS;            
00805             warpedSRSWKT = src_srs->getWKT();
00806         }
00807 
00808         //Get the _geotransform
00809         if (overrideProfile)
00810         {        
00811             _geotransform[0] = overrideProfile->getExtent().xMin(); //Top left x
00812             _geotransform[1] = overrideProfile->getExtent().width() / (double)_warpedDS->GetRasterXSize();//pixel width
00813             _geotransform[2] = 0;
00814 
00815             _geotransform[3] = overrideProfile->getExtent().yMax(); //Top left y
00816             _geotransform[4] = 0;
00817             _geotransform[5] = -overrideProfile->getExtent().height() / (double)_warpedDS->GetRasterYSize();//pixel height
00818 
00819         }
00820         else
00821         {
00822             _warpedDS->GetGeoTransform(_geotransform);
00823         }
00824 
00825         GDALInvGeoTransform(_geotransform, _invtransform);
00826 
00827 
00828         //Compute the extents
00829         // polar needs a special case when combined with geographic
00830         if ( profile && profile->getSRS()->isGeographic() && (src_srs->isNorthPolar() || src_srs->isSouthPolar()) )
00831         {
00832             double ll_lon, ll_lat, ul_lon, ul_lat, ur_lon, ur_lat, lr_lon, lr_lat;
00833 
00834             pixelToGeo(0.0, 0.0, ul_lon, ul_lat );
00835             pixelToGeo(0.0, _warpedDS->GetRasterYSize(), ll_lon, ll_lat);
00836             pixelToGeo(_warpedDS->GetRasterXSize(), _warpedDS->GetRasterYSize(), lr_lon, lr_lat);
00837             pixelToGeo(_warpedDS->GetRasterXSize(), 0.0, ur_lon, ur_lat);
00838 
00839             _extentsMin.x() = osg::minimum( ll_lon, osg::minimum( ul_lon, osg::minimum( ur_lon, lr_lon ) ) );
00840             _extentsMax.x() = osg::maximum( ll_lon, osg::maximum( ul_lon, osg::maximum( ur_lon, lr_lon ) ) );
00841             
00842             if ( src_srs->isNorthPolar() )
00843             {
00844                 _extentsMin.y() = osg::minimum( ll_lat, osg::minimum( ul_lat, osg::minimum( ur_lat, lr_lat ) ) );
00845                 _extentsMax.y() = 90.0;
00846             }
00847             else
00848             {
00849                 _extentsMin.y() = -90.0;
00850                 _extentsMax.y() = osg::maximum( ll_lat, osg::maximum( ul_lat, osg::maximum( ur_lat, lr_lat ) ) );
00851             }
00852         }
00853         else
00854         {
00855             pixelToGeo(0.0, _warpedDS->GetRasterYSize(), _extentsMin.x(), _extentsMin.y());
00856             pixelToGeo(_warpedDS->GetRasterXSize(), 0.0, _extentsMax.x(), _extentsMax.y());
00857         }
00858 
00859         OE_INFO << LC << "Geo extents: " << _extentsMin.x() << ", " << _extentsMin.y() << " => " << _extentsMax.x() << ", " << _extentsMax.y() << std::endl;
00860 
00861         if ( !profile )
00862         {
00863             profile = Profile::create( 
00864                 warpedSRSWKT,
00865                 //_warpedDS->GetProjectionRef(),
00866                 _extentsMin.x(), _extentsMin.y(), _extentsMax.x(), _extentsMax.y() );
00867 
00868             OE_INFO << LC << "" << uri.full() << " is projected, SRS = " 
00869                 << warpedSRSWKT << std::endl;
00870                 //<< _warpedDS->GetProjectionRef() << std::endl;
00871         }
00872 
00873         //Compute the min and max data levels
00874         double resolutionX = (_extentsMax.x() - _extentsMin.x()) / (double)_warpedDS->GetRasterXSize();
00875         double resolutionY = (_extentsMax.y() - _extentsMin.y()) / (double)_warpedDS->GetRasterYSize();
00876 
00877                 double maxResolution = osg::minimum(resolutionX, resolutionY);
00878 
00879         OE_INFO << LC << "Resolution= " << resolutionX << "x" << resolutionY << " max=" << maxResolution << std::endl;
00880 
00881         if (_options.maxDataLevel().isSet())
00882         {
00883             _maxDataLevel = _options.maxDataLevel().value();
00884             OE_INFO << "Using override max data level " << _maxDataLevel << std::endl;
00885         }
00886         else
00887         {
00888             unsigned int max_level = 30;
00889             for (unsigned int i = 0; i < max_level; ++i)
00890             {
00891                 _maxDataLevel = i;
00892                 double w, h;
00893                 profile->getTileDimensions(i, w, h);
00894                 double resX = (w / (double)_options.tileSize().value() );
00895                 double resY = (h / (double)_options.tileSize().value() );
00896 
00897                 if (resX < maxResolution || resY < maxResolution)
00898                 {
00899                     break;
00900                 }
00901             }
00902 
00903             OE_INFO << LC << "Max Data Level: " << _maxDataLevel << std::endl;
00904         }
00905 
00906         // record the data extent in profile space:
00907         GeoExtent local_extent(
00908             SpatialReference::create( warpedSRSWKT ), //_warpedDS->GetProjectionRef() ),
00909             _extentsMin.x(), _extentsMin.y(), _extentsMax.x(), _extentsMax.y() );
00910         GeoExtent profile_extent = local_extent.transform( profile->getSRS() );
00911 
00912         getDataExtents().push_back( DataExtent(profile_extent, 0, _maxDataLevel) );
00913         
00914         OE_INFO << LC << "Data Extents: " << profile_extent.toString() << std::endl;
00915 
00916                 //Set the profile
00917                 setProfile( profile );
00918     }
00919 
00920 
00924     static GDALRasterBand* findBand(GDALDataset *ds, GDALColorInterp colorInterp)
00925     {
00926         GDAL_SCOPED_LOCK;
00927 
00928         for (int i = 1; i <= ds->GetRasterCount(); ++i)
00929         {
00930             if (ds->GetRasterBand(i)->GetColorInterpretation() == colorInterp) return ds->GetRasterBand(i);
00931         }
00932         return 0;
00933     }
00934 
00935     static void getPalleteIndexColor(GDALRasterBand* band, int index, osg::Vec4ub& color)
00936     {
00937         const GDALColorEntry *colorEntry = band->GetColorTable()->GetColorEntry( index );
00938         GDALPaletteInterp interp = band->GetColorTable()->GetPaletteInterpretation();
00939         if (!colorEntry)
00940         {
00941             //FIXME: What to do here?
00942 
00943             //OE_INFO << "NO COLOR ENTRY FOR COLOR " << rawImageData[i] << std::endl;
00944             color.r() = 255;
00945             color.g() = 0;
00946             color.b() = 0;
00947             color.a() = 1;
00948 
00949         }
00950         else
00951         {
00952             if (interp == GPI_RGB)
00953             {
00954                 color.r() = colorEntry->c1;
00955                 color.g() = colorEntry->c2;
00956                 color.b() = colorEntry->c3;
00957                 color.a() = colorEntry->c4;
00958             }
00959             else if (interp == GPI_CMYK)
00960             {
00961                 // from wikipedia.org
00962                 short C = colorEntry->c1;
00963                 short M = colorEntry->c2;
00964                 short Y = colorEntry->c3;
00965                 short K = colorEntry->c4;
00966                 color.r() = 255 - C*(255 - K) - K;
00967                 color.g() = 255 - M*(255 - K) - K;
00968                 color.b() = 255 - Y*(255 - K) - K;
00969                 color.a() = 255;
00970             }
00971             else if (interp == GPI_HLS)
00972             {
00973                 // from easyrgb.com
00974                 float H = colorEntry->c1;
00975                 float S = colorEntry->c3;
00976                 float L = colorEntry->c2;
00977                 float R, G, B;
00978                 if ( S == 0 )                       //HSL values = 0 - 1
00979                 {
00980                     R = L;                      //RGB results = 0 - 1 
00981                     G = L;
00982                     B = L;
00983                 }
00984                 else
00985                 {
00986                     float var_2, var_1;
00987                     if ( L < 0.5 )
00988                         var_2 = L * ( 1 + S );
00989                     else
00990                         var_2 = ( L + S ) - ( S * L );
00991 
00992                     var_1 = 2 * L - var_2;
00993 
00994                     R = Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) );
00995                     G = Hue_2_RGB( var_1, var_2, H );
00996                     B = Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) );                                
00997                 } 
00998                 color.r() = static_cast<unsigned char>(R*255.0f);
00999                 color.g() = static_cast<unsigned char>(G*255.0f);
01000                 color.b() = static_cast<unsigned char>(B*255.0f);
01001                 color.a() = static_cast<unsigned char>(255.0f);
01002             }
01003             else if (interp == GPI_Gray)
01004             {
01005                 color.r() = static_cast<unsigned char>(colorEntry->c1*255.0f);
01006                 color.g() = static_cast<unsigned char>(colorEntry->c1*255.0f);
01007                 color.b() = static_cast<unsigned char>(colorEntry->c1*255.0f);
01008                 color.a() = static_cast<unsigned char>(255.0f);
01009             }
01010         }
01011     }
01012 
01013     void pixelToGeo(double x, double y, double &geoX, double &geoY)
01014     {
01015         geoX = _geotransform[0] + _geotransform[1] * x + _geotransform[2] * y;
01016         geoY = _geotransform[3] + _geotransform[4] * x + _geotransform[5] * y;
01017     }
01018 
01019     osg::Image* createImage( const TileKey& key,
01020                              ProgressCallback* progress)
01021     {
01022         if (key.getLevelOfDetail() > _maxDataLevel)
01023         {
01024             OE_DEBUG << LC << "" << getName() << ": Reached maximum data resolution key=" 
01025                 << key.getLevelOfDetail() << " max=" << _maxDataLevel <<  std::endl;
01026             return NULL;
01027         }
01028 
01029         GDAL_SCOPED_LOCK;
01030 
01031         int tileSize = _options.tileSize().value();
01032 
01033         osg::ref_ptr<osg::Image> image;
01034         if (intersects(key)) //TODO: I think this test is OBE -gw
01035         {
01036             //Get the extents of the tile
01037             double xmin, ymin, xmax, ymax;
01038             key.getExtent().getBounds(xmin, ymin, xmax, ymax);
01039 
01040             double dx       = (xmax - xmin) / (tileSize-1); 
01041             double dy       = (ymax - ymin) / (tileSize-1); 
01042 
01043 
01044             int target_width = tileSize;
01045             int target_height = tileSize;
01046             int tile_offset_left = 0;
01047             int tile_offset_top = 0;
01048 
01049             int off_x = int((xmin - _geotransform[0]) / _geotransform[1]);
01050             int off_y = int((ymax - _geotransform[3]) / _geotransform[5]);
01051             int width = int(((xmax - _geotransform[0]) / _geotransform[1]) - off_x);
01052             int height = int(((ymin - _geotransform[3]) / _geotransform[5]) - off_y);
01053 
01054             if (off_x + width > _warpedDS->GetRasterXSize())
01055             {
01056                 int oversize_right = off_x + width - _warpedDS->GetRasterXSize();
01057                 target_width = target_width - int(float(oversize_right) / width * target_width);
01058                 width = _warpedDS->GetRasterXSize() - off_x;
01059             }
01060 
01061             if (off_x < 0)
01062             {
01063                 int oversize_left = -off_x;
01064                 tile_offset_left = int(float(oversize_left) / width * target_width);
01065                 target_width = target_width - int(float(oversize_left) / width * target_width);
01066                 width = width + off_x;
01067                 off_x = 0;
01068             }
01069 
01070             if (off_y + height > _warpedDS->GetRasterYSize())
01071             {
01072                 int oversize_bottom = off_y + height - _warpedDS->GetRasterYSize();
01073                 target_height = target_height - (int)osg::round(float(oversize_bottom) / height * target_height);
01074                 height = _warpedDS->GetRasterYSize() - off_y;
01075             }
01076 
01077 
01078             if (off_y < 0)
01079             {
01080                 int oversize_top = -off_y;
01081                 tile_offset_top = int(float(oversize_top) / height * target_height);
01082                 target_height = target_height - int(float(oversize_top) / height * target_height);
01083                 height = height + off_y;
01084                 off_y = 0;
01085             }
01086 
01087             OE_DEBUG << LC << "ReadWindow " << width << "x" << height << " DestWindow " << target_width << "x" << target_height << std::endl;
01088 
01089             //Return if parameters are out of range.
01090             if (width <= 0 || height <= 0 || target_width <= 0 || target_height <= 0)
01091             {
01092                 return 0;
01093             }
01094 
01095 
01096 
01097             GDALRasterBand* bandRed = findBand(_warpedDS, GCI_RedBand);
01098             GDALRasterBand* bandGreen = findBand(_warpedDS, GCI_GreenBand);
01099             GDALRasterBand* bandBlue = findBand(_warpedDS, GCI_BlueBand);
01100             GDALRasterBand* bandAlpha = findBand(_warpedDS, GCI_AlphaBand);
01101 
01102             GDALRasterBand* bandGray = findBand(_warpedDS, GCI_GrayIndex);
01103 
01104                         GDALRasterBand* bandPalette = findBand(_warpedDS, GCI_PaletteIndex);
01105 
01106             //The pixel format is always RGBA to support transparency
01107             GLenum pixelFormat = GL_RGBA;
01108 
01109 
01110             if (bandRed && bandGreen && bandBlue)
01111             {
01112                 unsigned char *red = new unsigned char[target_width * target_height];
01113                 unsigned char *green = new unsigned char[target_width * target_height];
01114                 unsigned char *blue = new unsigned char[target_width * target_height];
01115                 unsigned char *alpha = new unsigned char[target_width * target_height];
01116 
01117                 //Initialize the alpha values to 255.
01118                 memset(alpha, 255, target_width * target_height);
01119 
01120                 image = new osg::Image;
01121                 image->allocateImage(tileSize, tileSize, 1, pixelFormat, GL_UNSIGNED_BYTE);
01122                 memset(image->data(), 0, image->getImageSizeInBytes());
01123 
01124                 //Nearest interpolation just uses RasterIO to sample the imagery and should be very fast.
01125                 if (!*_options.interpolateImagery() || _options.interpolation() == INTERP_NEAREST)
01126                 {
01127                     bandRed->RasterIO(GF_Read, off_x, off_y, width, height, red, target_width, target_height, GDT_Byte, 0, 0);
01128                     bandGreen->RasterIO(GF_Read, off_x, off_y, width, height, green, target_width, target_height, GDT_Byte, 0, 0);
01129                     bandBlue->RasterIO(GF_Read, off_x, off_y, width, height, blue, target_width, target_height, GDT_Byte, 0, 0);
01130 
01131                     if (bandAlpha)
01132                     {
01133                         bandAlpha->RasterIO(GF_Read, off_x, off_y, width, height, alpha, target_width, target_height, GDT_Byte, 0, 0);
01134                     }
01135 
01136                     for (int src_row = 0, dst_row = tile_offset_top;
01137                         src_row < target_height;
01138                         src_row++, dst_row++)
01139                     {
01140                         for (int src_col = 0, dst_col = tile_offset_left;
01141                             src_col < target_width;
01142                             ++src_col, ++dst_col)
01143                         {
01144                             *(image->data(dst_col, dst_row) + 0) = red[src_col + src_row * target_width];
01145                             *(image->data(dst_col, dst_row) + 1) = green[src_col + src_row * target_width];
01146                             *(image->data(dst_col, dst_row) + 2) = blue[src_col + src_row * target_width];
01147                             *(image->data(dst_col, dst_row) + 3) = alpha[src_col + src_row * target_width];
01148                         }
01149                     }
01150 
01151                     image->flipVertical();
01152                 }
01153                 else
01154                 {
01155                     //Sample each point exactly
01156                     for (unsigned int c = 0; c < tileSize; ++c)
01157                     {
01158                         double geoX = xmin + (dx * (double)c); 
01159                         for (unsigned int r = 0; r < tileSize; ++r)
01160                         {
01161                             double geoY = ymin + (dy * (double)r); 
01162                             *(image->data(c,r) + 0) = getInterpolatedValue(bandRed,  geoX,geoY,false); 
01163                             *(image->data(c,r) + 1) = getInterpolatedValue(bandGreen,geoX,geoY,false); 
01164                             *(image->data(c,r) + 2) = getInterpolatedValue(bandBlue, geoX,geoY,false); 
01165                             if (bandAlpha != NULL) 
01166                                 *(image->data(c,r) + 3) = getInterpolatedValue(bandAlpha,geoX, geoY, false); 
01167                             else 
01168                                 *(image->data(c,r) + 3) = 255; 
01169                         }
01170                     }
01171                 }
01172 
01173                 delete []red;
01174                 delete []green;
01175                 delete []blue;
01176                 delete []alpha;
01177             }
01178             else if (bandGray)
01179             {
01180                 unsigned char *gray = new unsigned char[target_width * target_height];
01181                 unsigned char *alpha = new unsigned char[target_width * target_height];
01182 
01183                 //Initialize the alpha values to 255.
01184                 memset(alpha, 255, target_width * target_height);
01185 
01186                 image = new osg::Image;
01187                 image->allocateImage(tileSize, tileSize, 1, pixelFormat, GL_UNSIGNED_BYTE);
01188                 memset(image->data(), 0, image->getImageSizeInBytes());
01189 
01190 
01191                 if (!*_options.interpolateImagery() || _options.interpolation() == INTERP_NEAREST)
01192                 {
01193                     bandGray->RasterIO(GF_Read, off_x, off_y, width, height, gray, target_width, target_height, GDT_Byte, 0, 0);
01194 
01195                     if (bandAlpha)
01196                     {
01197                         bandAlpha->RasterIO(GF_Read, off_x, off_y, width, height, alpha, target_width, target_height, GDT_Byte, 0, 0);
01198                     }
01199 
01200                     for (int src_row = 0, dst_row = tile_offset_top;
01201                         src_row < target_height;
01202                         src_row++, dst_row++)
01203                     {
01204                         for (int src_col = 0, dst_col = tile_offset_left;
01205                             src_col < target_width;
01206                             ++src_col, ++dst_col)
01207                         {
01208                             *(image->data(dst_col, dst_row) + 0) = gray[src_col + src_row * target_width];
01209                             *(image->data(dst_col, dst_row) + 1) = gray[src_col + src_row * target_width];
01210                             *(image->data(dst_col, dst_row) + 2) = gray[src_col + src_row * target_width];
01211                             *(image->data(dst_col, dst_row) + 3) = alpha[src_col + src_row * target_width];
01212                         }
01213                     }
01214 
01215                     image->flipVertical();
01216                 }
01217                 else
01218                 {
01219                     for (int c = 0; c < tileSize; ++c) 
01220                     { 
01221                         double geoX = xmin + (dx * (double)c); 
01222 
01223                         for (int r = 0; r < tileSize; ++r) 
01224                         { 
01225                             double geoY   = ymin + (dy * (double)r); 
01226                             float  color = getInterpolatedValue(bandGray,geoX,geoY,false); 
01227 
01228                             *(image->data(c,r) + 0) = color; 
01229                             *(image->data(c,r) + 1) = color; 
01230                             *(image->data(c,r) + 2) = color; 
01231                             if (bandAlpha != NULL) 
01232                                 *(image->data(c,r) + 3) = getInterpolatedValue(bandAlpha,geoX,geoY,false); 
01233                             else 
01234                                 *(image->data(c,r) + 3) = 255; 
01235                         }
01236                     }
01237                 }
01238 
01239                 delete []gray;
01240                 delete []alpha;
01241 
01242             }
01243                         else if (bandPalette)
01244             {
01245                 //Pallete indexed imagery doesn't support interpolation currently and only uses nearest
01246                 //b/c interpolating pallete indexes doesn't make sense.
01247                                 unsigned char *palette = new unsigned char[target_width * target_height];
01248 
01249                 image = new osg::Image;
01250                 image->allocateImage(tileSize, tileSize, 1, pixelFormat, GL_UNSIGNED_BYTE);
01251                 memset(image->data(), 0, image->getImageSizeInBytes());
01252 
01253                                 bandPalette->RasterIO(GF_Read, off_x, off_y, width, height, palette, target_width, target_height, GDT_Byte, 0, 0);
01254 
01255                                 for (int src_row = 0, dst_row = tile_offset_top;
01256                                         src_row < target_height;
01257                                         src_row++, dst_row++)
01258                                 {
01259                                         for (int src_col = 0, dst_col = tile_offset_left;
01260                                                 src_col < target_width;
01261                                                 ++src_col, ++dst_col)
01262                                         {
01263                         osg::Vec4ub color;
01264                         getPalleteIndexColor( bandPalette, palette[src_col + src_row * target_width], color );                                          
01265 
01266                         *(image->data(dst_col, dst_row) + 0) = color.r();
01267                         *(image->data(dst_col, dst_row) + 1) = color.g();
01268                         *(image->data(dst_col, dst_row) + 2) = color.b();
01269                         *(image->data(dst_col, dst_row) + 3) = color.a();
01270                                         }
01271                                 }
01272 
01273                                 image->flipVertical();
01274 
01275                                 delete [] palette;
01276 
01277             }
01278             else
01279             {
01280                 OE_WARN 
01281                     << LC << "Could not find red, green and blue bands or gray bands in "
01282                     << _options.url()->full()
01283                     << ".  Cannot create image. " << std::endl;
01284 
01285                 return NULL;
01286             }
01287         }
01288 
01289         // Moved this logic up into ImageLayer::createImageWrapper.
01291         //if (!image.valid())
01292         //{
01293         //    //OE_WARN << LC << "Illegal state-- should not get here" << std::endl;
01294         //    return ImageUtils::createEmptyImage();
01295         //}
01296         return image.release();
01297     }
01298 
01299     bool isValidValue(float v, GDALRasterBand* band)
01300     {
01301         GDAL_SCOPED_LOCK;
01302 
01303         float bandNoData = -32767.0f;
01304         int success;
01305         float value = band->GetNoDataValue(&success);
01306         if (success)
01307         {
01308             bandNoData = value;
01309         }
01310 
01311         //Check to see if the value is equal to the bands specified no data
01312         if (bandNoData == v) return false;
01313         //Check to see if the value is equal to the user specified nodata value
01314         if (getNoDataValue() == v) return false;        
01315 
01316         //Check to see if the user specified a custom min/max
01317         if (v < getNoDataMinValue()) return false;
01318         if (v > getNoDataMaxValue()) return false;
01319 
01320         //Check within a sensible range
01321         if (v < -32000) return false;
01322         if (v > 32000) return false;
01323 
01324         return true;
01325     }
01326 
01327 
01328     float getInterpolatedValue(GDALRasterBand *band, double x, double y, bool applyOffset=true)
01329     {
01330         double r, c;
01331         GDALApplyGeoTransform(_invtransform, x, y, &c, &r);
01332 
01333         //Account for slight rounding errors.  If we are right on the edge of the dataset, clamp to the edge
01334         double eps = 0.0001;
01335         if (osg::equivalent(c, 0, eps)) c = 0;
01336         if (osg::equivalent(r, 0, eps)) r = 0;
01337         if (osg::equivalent(c, (double)_warpedDS->GetRasterXSize(), eps)) c = _warpedDS->GetRasterXSize();
01338         if (osg::equivalent(r, (double)_warpedDS->GetRasterYSize(), eps)) r = _warpedDS->GetRasterYSize();
01339 
01340         if (applyOffset)
01341         {
01342             //Apply half pixel offset
01343             r-= 0.5;
01344             c-= 0.5;
01345 
01346             //Account for the half pixel offset in the geotransform.  If the pixel value is -0.5 we are still technically in the dataset
01347             //since 0,0 is now the center of the pixel.  So, if are within a half pixel above or a half pixel below the dataset just use
01348             //the edge values
01349             if (c < 0 && c >= -0.5)
01350             {
01351                 c = 0;
01352             }
01353             else if (c > _warpedDS->GetRasterXSize()-1 && c <= _warpedDS->GetRasterXSize()-0.5)
01354             {
01355                 c = _warpedDS->GetRasterXSize()-1;
01356             }
01357 
01358             if (r < 0 && r >= -0.5)
01359             {
01360                 r = 0;
01361             }
01362             else if (r > _warpedDS->GetRasterYSize()-1 && r <= _warpedDS->GetRasterYSize()-0.5)
01363             {
01364                 r = _warpedDS->GetRasterYSize()-1;
01365             }
01366         }
01367 
01368         float result = 0.0f;
01369 
01370         //If the location is outside of the pixel values of the dataset, just return 0
01371         if (c < 0 || r < 0 || c > _warpedDS->GetRasterXSize()-1 || r > _warpedDS->GetRasterYSize()-1)
01372             return NO_DATA_VALUE;
01373 
01374         if ( _options.interpolation() == INTERP_NEAREST )
01375         {
01376             band->RasterIO(GF_Read, (int)osg::round(c), (int)osg::round(r), 1, 1, &result, 1, 1, GDT_Float32, 0, 0);
01377             if (!isValidValue( result, band))
01378             {
01379                 return NO_DATA_VALUE;
01380             }
01381         }
01382         else
01383         {
01384             int rowMin = osg::maximum((int)floor(r), 0);
01385             int rowMax = osg::maximum(osg::minimum((int)ceil(r), (int)(_warpedDS->GetRasterYSize()-1)), 0);
01386             int colMin = osg::maximum((int)floor(c), 0);
01387             int colMax = osg::maximum(osg::minimum((int)ceil(c), (int)(_warpedDS->GetRasterXSize()-1)), 0);
01388 
01389             if (rowMin > rowMax) rowMin = rowMax;
01390             if (colMin > colMax) colMin = colMax;
01391 
01392             float urHeight, llHeight, ulHeight, lrHeight;
01393 
01394             band->RasterIO(GF_Read, colMin, rowMin, 1, 1, &llHeight, 1, 1, GDT_Float32, 0, 0);
01395             band->RasterIO(GF_Read, colMin, rowMax, 1, 1, &ulHeight, 1, 1, GDT_Float32, 0, 0);
01396             band->RasterIO(GF_Read, colMax, rowMin, 1, 1, &lrHeight, 1, 1, GDT_Float32, 0, 0);
01397             band->RasterIO(GF_Read, colMax, rowMax, 1, 1, &urHeight, 1, 1, GDT_Float32, 0, 0);
01398 
01399             /*
01400             if (!isValidValue(urHeight, band)) urHeight = 0.0f;
01401             if (!isValidValue(llHeight, band)) llHeight = 0.0f;
01402             if (!isValidValue(ulHeight, band)) ulHeight = 0.0f;
01403             if (!isValidValue(lrHeight, band)) lrHeight = 0.0f;
01404             */
01405             if (!isValidValue(urHeight, band) || (!isValidValue(llHeight, band)) ||(!isValidValue(ulHeight, band)) || (!isValidValue(lrHeight, band)))
01406             {
01407                 return NO_DATA_VALUE;
01408             }
01409 
01410             if ( _options.interpolation() == INTERP_AVERAGE )
01411             {
01412                 double x_rem = c - (int)c;
01413                 double y_rem = r - (int)r;
01414 
01415                 double w00 = (1.0 - y_rem) * (1.0 - x_rem) * (double)llHeight;
01416                 double w01 = (1.0 - y_rem) * x_rem * (double)lrHeight;
01417                 double w10 = y_rem * (1.0 - x_rem) * (double)ulHeight;
01418                 double w11 = y_rem * x_rem * (double)urHeight;
01419 
01420                 result = (float)(w00 + w01 + w10 + w11);
01421             }
01422             else if ( _options.interpolation() == INTERP_BILINEAR )
01423             {
01424                 //Check for exact value
01425                 if ((colMax == colMin) && (rowMax == rowMin))
01426                 {
01427                     //OE_NOTICE << "Exact value" << std::endl;
01428                     result = llHeight;
01429                 }
01430                 else if (colMax == colMin)
01431                 {
01432                     //OE_NOTICE << "Vertically" << std::endl;
01433                     //Linear interpolate vertically
01434                     result = ((float)rowMax - r) * llHeight + (r - (float)rowMin) * ulHeight;
01435                 }
01436                 else if (rowMax == rowMin)
01437                 {
01438                     //OE_NOTICE << "Horizontally" << std::endl;
01439                     //Linear interpolate horizontally
01440                     result = ((float)colMax - c) * llHeight + (c - (float)colMin) * lrHeight;
01441                 }
01442                 else
01443                 {
01444                     //OE_NOTICE << "Bilinear" << std::endl;
01445                     //Bilinear interpolate
01446                     float r1 = ((float)colMax - c) * llHeight + (c - (float)colMin) * lrHeight;
01447                     float r2 = ((float)colMax - c) * ulHeight + (c - (float)colMin) * urHeight;
01448 
01449                     //OE_INFO << "r1, r2 = " << r1 << " , " << r2 << std::endl;
01450                     result = ((float)rowMax - r) * r1 + (r - (float)rowMin) * r2;
01451                 }
01452             }
01453         }
01454 
01455         return result;
01456     }
01457 
01458 
01459     osg::HeightField* createHeightField( const TileKey& key,
01460                                          ProgressCallback* progress)
01461     {
01462         if (key.getLevelOfDetail() > _maxDataLevel)
01463         {
01464             //OE_NOTICE << "Reached maximum data resolution key=" << key.getLevelOfDetail() << " max=" << _maxDataLevel <<  std::endl;
01465             return NULL;
01466         }
01467 
01468         GDAL_SCOPED_LOCK;
01469 
01470         int tileSize = _options.tileSize().value();
01471 
01472         //Allocate the heightfield
01473         osg::ref_ptr<osg::HeightField> hf = new osg::HeightField;
01474         hf->allocate(tileSize, tileSize);
01475 
01476         if (intersects(key))
01477         {
01478             //Get the meter extents of the tile
01479             double xmin, ymin, xmax, ymax;
01480             key.getExtent().getBounds(xmin, ymin, xmax, ymax);
01481 
01482             //Just read from the first band
01483             GDALRasterBand* band = _warpedDS->GetRasterBand(1);
01484 
01485             double dx = (xmax - xmin) / (tileSize-1);
01486             double dy = (ymax - ymin) / (tileSize-1);
01487 
01488             for (int c = 0; c < tileSize; ++c)
01489             {
01490                 double geoX = xmin + (dx * (double)c);
01491                 for (int r = 0; r < tileSize; ++r)
01492                 {
01493                     double geoY = ymin + (dy * (double)r);
01494                     float h = getInterpolatedValue(band, geoX, geoY);
01495                     hf->setHeight(c, r, h);
01496                 }
01497             }
01498         }
01499         else
01500         {
01501             for (unsigned int i = 0; i < hf->getHeightList().size(); ++i) hf->getHeightList()[i] = NO_DATA_VALUE;
01502         }
01503         return hf.release();
01504     }
01505 
01506     bool intersects(const TileKey& key)
01507     {
01508         //Get the native extents of the tile
01509         double xmin, ymin, xmax, ymax;
01510         key.getExtent().getBounds(xmin, ymin, xmax, ymax);
01511 
01512         return ! ( xmin >= _extentsMax.x() || xmax <= _extentsMin.x() || ymin >= _extentsMax.y() || ymax <= _extentsMin.y() );        
01513     }
01514 
01515 
01516 private:
01517 
01518     GDALDataset* _srcDS;
01519     GDALDataset* _warpedDS;
01520     double       _geotransform[6];
01521     double       _invtransform[6];
01522 
01523     osg::Vec2d _extentsMin;
01524     osg::Vec2d _extentsMax;
01525 
01526     //std::string     _url;
01527     //int             _tile_size;
01528     //std::string     _extensions;
01529     //ElevationInterpolation   _interpolation;
01530 
01531     const GDALOptions _options;
01532     //osg::ref_ptr<const GDALOptions> _settings;
01533 
01534     unsigned int _maxDataLevel;
01535 };
01536 
01537 
01538 class ReaderWriterGDALTile : public TileSourceDriver
01539 {
01540 public:
01541     ReaderWriterGDALTile() {}
01542 
01543     virtual const char* className()
01544     {
01545         return "GDAL Tile Reader";
01546     }
01547 
01548     virtual bool acceptsExtension(const std::string& extension) const
01549     {
01550         return osgDB::equalCaseInsensitive( extension, "osgearth_gdal" );
01551     }
01552 
01553     virtual ReadResult readObject(const std::string& file_name, const Options* opt) const
01554     {
01555         if ( !acceptsExtension( osgDB::getFileExtension( file_name ) ) )
01556         {
01557             return ReadResult::FILE_NOT_HANDLED;
01558         }
01559         return new GDALTileSource( getTileSourceOptions(opt) );
01560     }
01561 };
01562 
01563 REGISTER_OSGPLUGIN(osgearth_gdal, ReaderWriterGDALTile)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines