osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/Locators.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 #include <osgEarth/Locators>
00020 #include <osgEarth/TileKey>
00021 #include <osgEarth/Registry>
00022 #include <osgEarth/Map>
00023 #include <osg/Notify>
00024 
00025 using namespace osgEarth;
00026 
00027 GeoLocator::GeoLocator() :
00028 _inverseCalculated(false),
00029 _x0(0.0), _x1(1.0),
00030 _y0(0.0), _y1(1.0)
00031 {
00032     this->setThreadSafeRefUnref(true);
00033 }
00034 
00035 GeoLocator::GeoLocator( const GeoExtent& dataExtent ) :
00036 _inverseCalculated(false),
00037 _dataExtent( dataExtent ),
00038 _x0(0.0), _x1(1.0),
00039 _y0(0.0), _y1(1.0)
00040 {
00041     this->setThreadSafeRefUnref(true);
00042 }
00043 
00044 GeoLocator::GeoLocator( const osgTerrain::Locator& prototype, const GeoExtent& dataExtent ) :
00045 osgTerrain::Locator( prototype ),
00046 _inverseCalculated(false),
00047 _dataExtent( dataExtent ),
00048 _x0(0.0), _x1(1.0),
00049 _y0(0.0), _y1(1.0)
00050 {
00051     //nop
00052 }
00053 
00054 GeoLocator::GeoLocator( const osgTerrain::Locator& prototype, const GeoExtent& dataExtent, const GeoExtent& displayExtent ) :
00055 osgTerrain::Locator( prototype ),
00056 _dataExtent( dataExtent ),
00057 _inverseCalculated(false)
00058 {
00059     // assume they are the same SRS
00060     _x0 = osg::clampBetween( (displayExtent.xMin()-dataExtent.xMin())/dataExtent.width(), 0.0, 1.0 );
00061     _x1 = osg::clampBetween( (displayExtent.xMax()-dataExtent.xMin())/dataExtent.width(), 0.0, 1.0 );
00062     _y0 = osg::clampBetween( (displayExtent.yMin()-dataExtent.yMin())/dataExtent.height(), 0.0, 1.0 );
00063     _y1 = osg::clampBetween( (displayExtent.yMax()-dataExtent.yMin())/dataExtent.height(), 0.0, 1.0 );
00064 }
00065 
00066 bool
00067 GeoLocator::isEquivalentTo( const GeoLocator& rhs ) const
00068 {
00069     return
00070         _transform == rhs._transform &&
00071         _coordinateSystemType == rhs._coordinateSystemType &&
00072         _cs == rhs._cs;
00073 }
00074 
00075 GeoLocator*
00076 GeoLocator::createForKey( const TileKey& key, const MapInfo& map )
00077 {    
00078     const GeoExtent& ex = key.getExtent();
00079     return createForExtent( ex, map );    
00080 }
00081 
00082 GeoLocator* 
00083 GeoLocator::createForExtent( const GeoExtent& extent, const class MapInfo& map)
00084 {
00085     double xmin, ymin, xmax, ymax;
00086     extent.getBounds( xmin, ymin, xmax, ymax );
00087 
00088     // A locator will place the tile on the globe:
00089     GeoLocator* locator = extent.getSRS()->createLocator(
00090         extent.xMin(), extent.yMin(), extent.xMax(), extent.yMax(),
00091         map.isPlateCarre() );
00092 
00093     if ( map.isGeocentric() )
00094         locator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC );
00095 
00096     return locator;
00097 }
00098 
00099 void
00100 GeoLocator::setDataExtent( const GeoExtent& value ) {
00101     _dataExtent = value;
00102 }
00103 
00104 const GeoExtent&
00105 GeoLocator::getDataExtent() const {
00106     return _dataExtent;
00107 }
00108 
00109 GeoLocator*
00110 GeoLocator::cloneAndCrop( const osgTerrain::Locator& prototype, const GeoExtent& displayExtent ) const
00111 {
00112     return new GeoLocator( prototype, _dataExtent, displayExtent );
00113 }
00114 
00115 
00116 bool
00117 GeoLocator::convertModelToLocal(const osg::Vec3d& world, osg::Vec3d& local) const
00118 {
00119     // required becasue of an OSG bug
00120     if ( !_inverseCalculated )
00121     {
00122         const_cast<GeoLocator*>(this)->_inverse.invert( _transform );
00123         const_cast<GeoLocator*>(this)->_inverseCalculated = true;
00124     }
00125 
00126     bool ok = Locator::convertModelToLocal( world, local );
00127 
00128     //cropLocal( local );
00129 
00130     return ok;
00131 }
00132 
00133 void
00134 GeoLocator::cropLocal( osg::Vec3d& local ) const
00135 {
00136     // crop if necessary:
00137     local.x() = osg::clampBetween( _x0 + local.x()*(_x1 - _x0), 0.0, 1.0 );
00138     local.y() = osg::clampBetween( _y0 + local.y()*(_y1 - _y0), 0.0, 1.0 );
00139 }
00140 
00141 GeoLocator* 
00142 GeoLocator::getGeographicFromGeocentric( ) const
00143 {
00144     if (getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC)
00145     {
00146         double xmin, ymin, xmax, ymax;
00147         getDataExtent().getBounds( xmin, ymin,  xmax, ymax );
00148         GeoLocator* geographic = new GeoLocator( getDataExtent() );
00149         geographic->setCoordinateSystemType( Locator::GEOGRAPHIC );
00150         geographic->setTransformAsExtents( xmin, ymin, xmax, ymax);
00151         return geographic;
00152     }
00153     return NULL;
00154 }
00155 
00156 /****************************************************************************/
00157 
00158 
00159 #define MERC_MAX_LAT  85.084059050110383
00160 #define MERC_MIN_LAT -85.084059050110383
00161 
00162 static double
00163 lonToU(double lon) {
00164     return (lon + 180.0) / 360.0;
00165 }
00166 
00167 static double
00168 latToV(double lat) {
00169     double sin_lat = sin( osg::DegreesToRadians( lat ) );
00170     return 0.5 - log( (1+sin_lat) / (1-sin_lat) ) / (4*osg::PI);
00171 }
00172 
00173 static void
00174 getUV(const GeoExtent& ext,
00175       double lon, double lat,
00176       double& out_u, double& out_v)
00177 {
00178     out_u = (lon-ext.xMin())/ext.width();
00179 
00180     double vmin = latToV( osg::clampBetween( ext.yMax(), MERC_MIN_LAT, MERC_MAX_LAT ) );
00181     double vmax = latToV( osg::clampBetween( ext.yMin(), MERC_MIN_LAT, MERC_MAX_LAT ) );
00182     double vlat = latToV( osg::clampBetween( lat, MERC_MIN_LAT, MERC_MAX_LAT ) );
00183 
00184     out_v = (vlat-vmin)/(vmax-vmin);
00185 }
00186 
00187 //static void
00188 //mercatorToLatLon( double x, double y, double& out_lat, double& out_lon )
00189 //{
00190 //    const GeoExtent& m = osgEarth::Registry::instance()->getGlobalMercatorProfile()->getExtent();
00191 //    double xr = -osg::PI + ((x-m.xMin())/m.width())*2.0*osg::PI;
00192 //    double yr = -osg::PI + ((y-m.yMin())/m.height())*2.0*osg::PI;
00193 //    out_lat = osg::RadiansToDegrees( 2.0 * atan( exp(yr) ) - osg::PI_2 );
00194 //    out_lon = osg::RadiansToDegrees( xr );
00195 //}
00196 
00197 MercatorLocator::MercatorLocator( const osgTerrain::Locator& prototype, const GeoExtent& dataExtent ) :
00198 GeoLocator( prototype, dataExtent )
00199 {
00200     // assumption: incoming extent is Mercator SRS; transform it to LAT/LONG
00201 
00202     _geoDataExtent = dataExtent.transform( dataExtent.getSRS()->getGeographicSRS() );
00203 
00205     //double latmin, lonmin, latmax, lonmax;
00206     //mercatorToLatLon( dataExtent.xMin(), dataExtent.yMin(), latmin, lonmin );
00207     //mercatorToLatLon( dataExtent.xMax(), dataExtent.yMax(), latmax, lonmax );
00208 
00209     //_geoDataExtent = GeoExtent(
00210     //    dataExtent.getSRS()->getGeographicSRS(),
00211     //    lonmin, latmin, lonmax, latmax );
00212 }
00213 
00214 GeoLocator*
00215 MercatorLocator::cloneAndCrop( const osgTerrain::Locator& prototype, const GeoExtent& displayExtent )
00216 {
00217     return new MercatorLocator( prototype, getDataExtent() );
00218 }
00219 
00220 bool
00221 MercatorLocator::convertModelToLocal(const osg::Vec3d& world, osg::Vec3d& local) const
00222 {
00223     bool result = false;
00224 
00225     // required becasue of an OSG bug
00226     if ( !_inverseCalculated )
00227     {
00228         const_cast<MercatorLocator*>(this)->_inverse.invert( _transform );
00229         const_cast<MercatorLocator*>(this)->_inverseCalculated = true;
00230     }
00231 
00232     switch(_coordinateSystemType)
00233     {
00234     case(GEOCENTRIC):
00235         {
00236             double longitude, latitude, height;
00237 
00238             _ellipsoidModel->convertXYZToLatLongHeight(world.x(), world.y(), world.z(),
00239                 latitude, longitude, height );
00240 
00241             local = osg::Vec3d(longitude, latitude, height) * _inverse;
00242 
00243             double lon_deg = osg::RadiansToDegrees(longitude);
00244             double lat_deg = osg::RadiansToDegrees(latitude);
00245             double xr, yr;
00246 
00247             getUV( _geoDataExtent, lon_deg, lat_deg, xr, yr );
00248 
00249             local.x() = xr;
00250             local.y() = 1.0-yr;
00251             result = true;
00252         }
00253         break;
00254 
00255 
00256     case(GEOGRAPHIC):
00257         {        
00258             local = world * _inverse;
00259 
00260             osg::Vec3d w = world;
00261             double lon_deg = w.x();
00262             double lat_deg = w.y();
00263 
00264             double xr, yr;
00265             getUV( _geoDataExtent, lon_deg, lat_deg, xr, yr );
00266 
00267             local.x() = xr;
00268             local.y() = 1.0-yr;
00269             result = true;
00270         }
00271         break;
00272 
00273     case(PROJECTED):
00274         {        
00275             local = world * _inverse;
00276             result = true;      
00277         }
00278         break;
00279     }
00280 
00281     return result;
00282 }
00283 
00284 GeoLocator* 
00285 MercatorLocator::getGeographicFromGeocentric( )
00286 {
00287     if (getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC)
00288     {
00289         double xmin, ymin, xmax, ymax;
00290         getDataExtent().getBounds( xmin, ymin, xmax, ymax );
00291         MercatorLocator* geographic = new MercatorLocator( *this, getDataExtent() );
00292         geographic->setCoordinateSystemType( Locator::GEOGRAPHIC );
00293         geographic->setTransformAsExtents( xmin, ymin, xmax, ymax);
00294         return geographic;
00295     }
00296     return NULL;
00297 }
00298 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines