osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/worldwind/ReaderWriterWorldWind.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth worldwind plugin - for the osgEarth toolkit
00003 * based on the yahoo plugin provided as part of the osgearth distribution
00004 * Produced by Matt Franklin
00005 * Contact: MattFranklin1 at gmail.com
00006 *
00007 * Please note that the use of this plugin requires the user to be accept
00008 * the license agreements provided by NASA
00009 *
00010 * This plugin is free software; you can redistribute it and/or modify
00011 * it under the terms of the GNU Lesser General Public License as published by
00012 * the Free Software Foundation; either version 2 of the License, or
00013 * (at your option) any later version.
00014 *
00015 * This program is distributed in the hope that it will be useful,
00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 * GNU Lesser General Public License for more details.
00019 *
00020 */
00021 #include "WorldWindOptions"
00022 
00023 #include <iostream>
00024 #include <fstream>
00025 #include <stdio.h>
00026 
00027 #include <osgEarth/TileSource>
00028 #include <osgEarth/ImageToHeightFieldConverter>
00029 #include <osgEarth/Registry>
00030 
00031 #include <osgDB/FileNameUtils>
00032 #include <osgDB/FileUtils>
00033 #include <osgDB/Registry>
00034 #include <osgDB/ReadFile>
00035 #include <osgDB/WriteFile>
00036 #include <osgDB/Archive>
00037 
00038 #include "zip.h"
00039 
00040 #include <sstream>
00041 #include <iomanip>
00042 #include <iostream>
00043 #include <fstream>
00044 
00045 #ifdef remove
00046 #undef remove
00047 #endif
00048 
00049 #define LC "[WorldWind BIL] "
00050 
00051 using namespace osgEarth;
00052 using namespace osgEarth::Drivers;
00053 
00054 class WorldWindSource : public TileSource
00055 {
00056 public:
00057     WorldWindSource( const TileSourceOptions& options ) : TileSource( options )
00058     {
00059         _options = options;
00060     }
00061 
00062 public:
00063     void initialize( const std::string& referenceURI, const Profile* overrideProfile)
00064     {
00065         setProfile( Profile::create(
00066             "epsg:4326",
00067             -180.0, -90.0, 180.0, 90.0,
00068             "",
00069             18, 9 ) );
00070 
00071         if ( !_options.elevationCachePath().isSet() )
00072         {
00073             OE_WARN << LC << "Elevation cache path is not set, but is required. No data will be available" << std::endl;
00074         }
00075     }
00076 
00077     osg::HeightField* createHeightFieldFromBil(char* buf,int buflength)
00078     {
00079         osg::HeightField* hf = new osg::HeightField;
00080         //osg::notify(osg::NOTICE) << "Read heightfield image" << std::endl;
00081         hf->allocate(150, 150);
00082 
00083         for( unsigned int row=0; row < 150; row++ )
00084         {
00085             for( unsigned int col=0; col < 150; col++ )
00086             {
00087                 short* ptr = (short*)buf;
00088                 short val = ptr[col + ((150-row -1)*150)];
00089 
00090                 hf->setHeight( col, row, (float)val * 0.3048 );
00091             }
00092         }
00093         return hf;
00094     }
00095 
00096 public:
00097     osg::Image* createImage( const TileKey& key, ProgressCallback* progress)
00098     {
00099         // NYI - eventually, consolidate the "tileservice" plugin into this one //GW
00100         return NULL;
00101     }
00102 
00103 
00104     osg::HeightField* createHeightField( const TileKey& key, ProgressCallback* progress)
00105     {
00106         if ( *_options.maxLOD() <= key.getLevelOfDetail()) return NULL;
00107         if ( !_options.elevationCachePath().isSet() ) return NULL;
00108 
00109         osg::HeightField *hf = NULL;
00110         std::string cachefilepath = *_options.elevationCachePath() + "/" + createCachePath(key);
00111         std::string cachefilename = createCacheName(key) + ".bil";
00112         std::string fullcachefilename = cachefilepath + "/" + cachefilename;
00113         OE_DEBUG << LC << "Cached name " << fullcachefilename << std::endl;
00114         if (osgDB::fileExists(fullcachefilename))
00115         {
00116             // read file
00117             std::ifstream fin;
00118             fin.open(fullcachefilename.c_str(), std::ios::in | std::ios::binary);
00119             if (!fin)
00120             {
00121                 OE_WARN << LC << "Coud not open elevation cache " << fullcachefilename << ", maybe a permissions problem" << std::endl;
00122                 _options.elevationCachePath().unset();
00123                 return NULL;
00124             }
00125             int fullsize = 150*150*2;
00126             char *buf = new char[fullsize];
00127             OE_DEBUG << LC << "Loading from cache " << fullcachefilename << std::endl;
00128             if ( !fin.read(buf, fullsize))
00129             {
00130                 OE_WARN << LC << "Coud not read from elevation cache " << fullcachefilename << ", file may be corrupt" << std::endl;
00131                 delete[] buf;
00132                 fin.close();
00133                 _options.elevationCachePath().unset();
00134                 return NULL;
00135             }
00136             hf = createHeightFieldFromBil((char*)buf,fullsize);
00137             delete[] buf;
00138             fin.close();
00139         }
00140         else // cached BIL file doesn't exist, try to download and cache it.
00141         {
00142             // download file
00143             HTTPResponse out_response;
00144             std::string URI = createURI(key);
00145 
00146             OE_DEBUG << "Requesting " << URI << std::endl;
00147             out_response = HTTPClient::get( URI, 0L, progress );
00148 
00149             if ( !out_response.isOK() )
00150             {
00151                 OE_NOTICE << "No Response received for " << URI << std::endl;
00152                 return NULL;
00153             }
00154 
00155             // store downloaded part as a zip file
00156             // Useful to store a local copy as the same file is requested many times
00157             unsigned int part_num = out_response.getNumParts() > 1? 1 : 0;
00158             std::string zipfilename;
00159             out_response.getPartHeader(part_num, zipfilename);
00160             std::istream& input_stream = out_response.getPartStream( part_num );
00161 
00162             if ( !osgDB::fileExists(cachefilepath) )
00163             {
00164                 osgDB::makeDirectory(cachefilepath);
00165             }
00166             std::ofstream fout;
00167             std::string tempname = fullcachefilename + ".zip";
00168             fout.open(tempname.c_str(), std::ios::out | std::ios::binary);
00169 
00170             if ( !fout )
00171             {
00172                 OE_WARN << LC << "Could not write zip file to " << tempname << std::endl;
00173                 _options.elevationCachePath().unset();
00174                 return NULL;
00175             }
00176             input_stream.seekg (0, std::ios::end);
00177             int length = input_stream.tellg();
00178             input_stream.seekg (0, std::ios::beg);
00179 
00180             char *buffer = new char[length];
00181             input_stream.read(buffer, length);
00182             fout.write(buffer, length);
00183             delete[] buffer;
00184             fout.close();
00185 
00186 
00187             //Unzip the file
00188             int err;
00189 
00190             //Open the zip file
00191             struct zip* pZip = zip_open(tempname.c_str(), ZIP_CHECKCONS, &err);
00192             if (pZip)
00193             {
00194                 //List the files
00195                 int numFiles = zip_get_num_files(pZip);
00196                 //OE_DEBUG <<  tempname << " has " << numFiles << " files " << std::endl;
00197                 /*for (int i = 0; i < numFiles; ++i)
00198                 {
00199                     OE_NOTICE << i << ": " << zip_get_name(pZip, i, 0) << std::endl;
00200                 }*/
00201 
00202                 //Find the index within the zip file for the given zip entry
00203                 int zipIndex = 0;
00204 
00205                 //Open the first file for reading
00206                 zip_file* pZipFile = zip_fopen_index(pZip, 0, 0);
00207 
00208                 if (pZipFile) 
00209                 {
00210                     //Read the data from the entry into a std::string
00211                     int dataSize = 0;
00212                     std::string data;
00213                     do{
00214                         char* buf = new char[1024];
00215                         dataSize = zip_fread(pZipFile, buf, 1024);
00216                         if (dataSize == 0)
00217                         {
00218                             delete [](buf);
00219                             buf = NULL;
00220                         }
00221                         if (buf)
00222                         {
00223                             data.append((char*)buf, dataSize);
00224                         }
00225                     }while (dataSize > 0);
00226 
00227                     //Close the zip entry and the actual zip file itself
00228                     zip_fclose(pZipFile);
00229                     zip_close(pZip);
00230 
00231                     //Write the BIL file to the cache
00232                     fout.open(fullcachefilename.c_str(), std::ios::out | std::ios::binary);
00233                     if ( !fout )
00234                     {
00235                         std::cout << "Cannot write bil file"<< std::endl;
00236                         return NULL;
00237                     }
00238 
00239                     fout.write((char*)data.c_str(), data.size());
00240                     fout.close(); 
00241 
00242                     hf = createHeightFieldFromBil((char*)data.c_str(),data.size());                    
00243                     // delete zip file as it has now been processed
00244                     remove(tempname.c_str());
00245                 }               
00246             }
00247         }
00248         return hf;
00249     }
00250 
00251     std::string createCachePath( const TileKey& key ) const
00252     {
00253         unsigned int x, y;
00254         key.getTileXY(x, y);
00255 
00256         unsigned int lod = key.getLevelOfDetail();
00257 
00258         std::stringstream buf;
00259         buf << "" << lod
00260             << "/" << std::setw(4) << std::setfill('0') << x;
00261         std::string bufStr;
00262         bufStr = buf.str();
00263         return bufStr;
00264     }
00265 
00266     std::string createCacheName( const TileKey& key ) const
00267     {
00268         unsigned int x, y;
00269         key.getTileXY(x, y);
00270 
00271         unsigned int lod = key.getLevelOfDetail();
00272 
00273         // flip the y based on level
00274         int flippedy = ((9 * powf((int)2,(int)lod)) - 1) - y;
00275         //printf("Key %i, %i, %i\n", lod,x,flippedy);
00276 
00277         std::stringstream buf;
00278         buf << "" << std::setw(4) << std::setfill('0') << x
00279             << "_" << std::setw(4) << std::setfill('0') << flippedy;
00280         std::string bufStr;
00281         bufStr = buf.str();
00282         return bufStr;
00283     }
00284 
00285     std::string createURI( const TileKey& key ) const
00286     {
00287         unsigned int x, y;
00288         key.getTileXY(x, y);
00289 
00290         unsigned int lod = key.getLevelOfDetail();
00291 
00292         // flip the y based on level
00293         int flippedy = ((9 * powf((int)2,(int)lod)) - 1) - y;
00294 
00295         std::stringstream buf;
00296         buf << *_options.elevationURL() // "http://worldwind25.arc.nasa.gov/wwelevation/wwelevation.aspx?T=srtm30pluszip"
00297             << "&L=" << lod
00298             << "&X=" << x
00299             << "&Y=" << flippedy;
00300         std::string bufStr;
00301         bufStr = buf.str();
00302         return bufStr;
00303     }
00304 
00305     virtual int getPixelsPerTile() const
00306     {
00307         return 150;
00308     }
00309 
00310     virtual std::string getExtension()  const
00311     {
00312         return "bil";
00313     }
00314 
00315 private:
00316     WorldWindOptions _options;
00317 };
00318 
00319 
00320 class ReaderWriterWorldWind : public TileSourceDriver
00321 {
00322 public:
00323     ReaderWriterWorldWind() {}
00324 
00325     virtual const char* className()
00326     {
00327         return "WorldWind Reader";
00328     }
00329 
00330     virtual bool acceptsExtension(const std::string& extension) const
00331     {
00332         return osgDB::equalCaseInsensitive( extension, "osgearth_WorldWind" );
00333     }
00334 
00335     virtual ReadResult readObject(const std::string& file_name, const Options* opt) const
00336     {
00337         std::string ext = osgDB::getFileExtension( file_name );
00338         if ( !acceptsExtension( ext ) )
00339         {
00340             return ReadResult::FILE_NOT_HANDLED;
00341         }
00342 
00343         return new WorldWindSource( getTileSourceOptions(opt) );
00344     }
00345 };
00346 
00347 REGISTER_OSGPLUGIN(osgearth_WorldWind, ReaderWriterWorldWind) 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines