osgEarth 2.1.1
|
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