osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/wcs/WCS11Source.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 "WCS11Source.h"
00021 #include <osgEarth/HTTPClient>
00022 #include <osgEarth/ImageToHeightFieldConverter>
00023 #include <osgEarth/Registry>
00024 #include <osg/Notify>
00025 #include <osgDB/Registry>
00026 #include <iostream>
00027 #include <stdlib.h>
00028 
00029 using namespace osgEarth;
00030 
00031 
00032 WCS11Source::WCS11Source( const TileSourceOptions& options ) :
00033 TileSource( options ),
00034 _options(options)
00035 {
00036     _covFormat = _options.format().value();
00037     
00038     if ( _covFormat.empty() )
00039         _covFormat = "image/GeoTIFF";
00040 
00041     _osgFormat = "tif";
00042 }
00043 
00044 
00045 void WCS11Source::initialize( const std::string& referenceURI, const Profile* overrideProfile)
00046 {
00047         if (overrideProfile)
00048         {
00049                 setProfile( overrideProfile );
00050         }
00051         else
00052         {
00053                 //TODO: once we read GetCapabilities.. this will change..
00054                 setProfile(osgEarth::Registry::instance()->getGlobalGeodeticProfile());
00055         }
00056 }
00057 
00058 
00059 std::string
00060 WCS11Source::getExtension() const
00061 {
00062     return "tif";
00063 }
00064 
00065 
00066 osg::Image*
00067 WCS11Source::createImage( const TileKey& key,
00068                          ProgressCallback* progress)
00069 {
00070     HTTPRequest request = createRequest( key );
00071 
00072     OE_INFO << "[osgEarth::WCS1.1] Key=" << key.str() << " URL = " << request.getURL() << std::endl;
00073 
00074     double lon0,lat0,lon1,lat1;
00075     key.getExtent().getBounds( lon0, lat0, lon1, lat1 );
00076 
00077     // download the data
00078     HTTPResponse response = HTTPClient::get( request, 0L, progress ); //getOptions(), progress );
00079     if ( !response.isOK() )
00080     {
00081         OE_WARN << "[osgEarth::WCS1.1] WARNING: HTTP request failed" << std::endl;
00082         return NULL;
00083     }
00084 
00085     //TODO:  Make WCS driver use progress callback
00086     unsigned int part_num = response.getNumParts() > 1? 1 : 0;
00087     std::istream& input_stream = response.getPartStream( part_num );
00088 
00089     //TODO: un-hard-code TIFFs
00090     osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension( "tiff" );
00091 
00092     if ( !reader )
00093     {
00094         OE_NOTICE << "[osgEarth::WCS1.1] WARNING: no reader for \"tiff\"" << std::endl;
00095         return NULL;
00096     }
00097 
00098     osgDB::ReaderWriter::ReadResult result = reader->readImage( input_stream ); //, getOptions() );
00099     if ( !result.success() )
00100     {
00101         OE_NOTICE << "[osgEarth::WCS1.1] WARNING: readImage() failed for Reader " << reader->getName() << std::endl;
00102         return NULL;
00103     }
00104 
00105     osg::Image* image = result.getImage();
00106     //OE_NOTICE << "Returned grid is " << image->s() << "x" << image->t() << std::endl;
00107     if ( image ) image->ref();
00108     return image;
00109 }
00110 
00111 
00112 osg::HeightField*
00113 WCS11Source::createHeightField( const TileKey& key,
00114                                 ProgressCallback* progress)
00115 {
00116     osg::HeightField* field = NULL;
00117 
00118     osg::ref_ptr<osg::Image> image = createImage( key, progress );
00119     if ( image.valid() )
00120     {        
00121         ImageToHeightFieldConverter conv;
00122         conv.setRemoveNoDataValues( true );
00123         field = conv.convert( image.get() );
00124     }
00125 
00126     return field;
00127 }
00128 
00129 /*
00130 http://server/ArcGIS/services/WorldElevation/MapServer/WCSServer
00131     ?SERVICE=WCS
00132     &VERSION=1.1.0
00133     &REQUEST=GetCoverage
00134     &IDENTIFIER=1
00135     &FORMAT=image/GeoTIFF
00136     &BOUNDINGBOX=-180,-90,0,90,urn:ogc:def:crs:EPSG::4326  // (sic - coord ordering bug in ESRI)
00137     &RangeSubset=Field_1:bilinear[Band[1]]
00138     &GridBaseCRS=urn:ogc:def:crs:EPSG::4326
00139     &GridCS=urn:ogc:def:crs:EPSG::4326
00140     &GridType=urn:ogc:def:method:WCS:1.1:2dGridIn2dCrs
00141     &GridOrigin=-180,90
00142     &GridOffsets=6,-6
00143 */
00144 
00145 
00146 HTTPRequest
00147 WCS11Source::createRequest( const TileKey& key ) const
00148 {
00149     std::stringstream buf;
00150 
00151     double lon_min, lat_min, lon_max, lat_max;
00152     key.getExtent().getBounds( lon_min, lat_min, lon_max, lat_max );
00153 
00154     int lon_samples = _options.tileSize().value();
00155     int lat_samples = _options.tileSize().value();
00156     double lon_interval = (lon_max-lon_min)/(double)(lon_samples-1);
00157     double lat_interval = (lat_max-lat_min)/(double)(lat_samples-1);
00158 
00159     HTTPRequest req( _options.url()->full() );
00160 
00161     req.addParameter( "SERVICE",    "WCS" );
00162     req.addParameter( "VERSION",    "1.1.0" );
00163     req.addParameter( "REQUEST",    "GetCoverage" );
00164     req.addParameter( "IDENTIFIER", _options.identifier().value() );
00165     req.addParameter( "FORMAT",     _covFormat );
00166 
00167     req.addParameter( "GridBaseCRS", "urn:ogc:def:crs:EPSG::4326" );
00168     req.addParameter( "GridCS",      "urn:ogc:def:crs:EPSG::4326" );
00169     req.addParameter( "GridType",    "urn:ogc:def:method:WCS:1.1:2dGridIn2dCrs" );
00170 
00171     // IMPORTANT NOTE:
00172     //   For WCS1.1+, the BOUNDINGBOX for geographic CRS's (like WGS84) are expressed
00173     //   at minlat,minlon,maxlat,maxlon instead of the usual minx,miny,maxx,maxy.
00174     //   So we will somehow need to figure out whether the CRS is geographic.
00175     //
00176     // MORE IMPORTANT NOTE:
00177     //   ESRI's ArcGIS WCS Server doesn't obey the above rule. Their server expects
00178     //   minx,miny,maxx,maxy no matter what ...
00179 
00180     // Hack to guess whether it's an ArcGIS Server:
00181     buf.str("");
00182 
00183     //bool use_legacy_geog_bbox_encoding = _url.find( "/MapServer/WCSServer" ) != std::string::npos;
00184     //if ( use_legacy_geog_bbox_encoding )
00185     //    buf << lon_min << "," << lat_min << "," << lon_max << "," << lat_max;
00186     //else
00187     //    buf << lat_min << "," << lon_min << "," << lat_max << "," << lon_max;
00188     //buf << ",urn:ogc:def:crs:EPSG::4326";
00189 
00190     double halfLon = lon_interval/2.0;
00191     double halfLat = lat_interval/2.0;
00192 
00193     //We need to shift the bounding box out by half a pixel in all directions so that the center of the edge pixels lie on
00194     //the edge of this TileKey's extents.  Doing this makes neighboring tiles have the same elevation values so there is no need
00195     //to run the tile edge normalization code.
00196     buf << lon_min - halfLon << "," << lat_min - halfLat << "," << lon_max + halfLon << "," << lat_max + halfLat << ",EPSG:4326";
00197         std::string bufStr;
00198         bufStr = buf.str();
00199     req.addParameter( "BOUNDINGBOX", bufStr );
00200 
00201     double originX = lon_min;
00202     double originY = lat_max;
00203 
00204     buf.str("");
00205     buf << originX << "," << originY; 
00206         bufStr = buf.str();
00207     req.addParameter( "GridOrigin", bufStr );
00208     
00209     buf.str("");
00210     buf << lon_interval << "," << lat_interval;   // note: top-down
00211     //buf << lon_interval << "," << lat_interval;
00212         bufStr = buf.str();
00213     req.addParameter( "GridOffsets", bufStr );
00214 
00215     if ( !_options.rangeSubset()->empty() )
00216         req.addParameter( "RangeSubset", _options.rangeSubset().value() );
00217 
00218     return req;
00219 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines