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 00020 #include <osgEarth/SpatialReference> 00021 #include <osgEarth/Registry> 00022 #include <osgEarth/Cube> 00023 #include <osgEarth/LocalTangentPlane> 00024 #include <OpenThreads/ScopedLock> 00025 #include <osg/Notify> 00026 #include <ogr_api.h> 00027 #include <ogr_spatialref.h> 00028 #include <algorithm> 00029 00030 #define LC "[SpatialReference] " 00031 00032 using namespace osgEarth; 00033 00034 #define USE_CUSTOM_MERCATOR_TRANSFORM 1 00035 //#undef USE_CUSTOM_MERCATOR_TRANSFORM 00036 00037 //------------------------------------------------------------------------ 00038 00039 namespace 00040 { 00041 std::string 00042 getOGRAttrValue( void* _handle, const std::string& name, int child_num, bool lowercase =false) 00043 { 00044 GDAL_SCOPED_LOCK; 00045 const char* val = OSRGetAttrValue( _handle, name.c_str(), child_num ); 00046 if ( val ) 00047 { 00048 std::string t = val; 00049 if ( lowercase ) 00050 { 00051 std::transform( t.begin(), t.end(), t.begin(), ::tolower ); 00052 } 00053 return t; 00054 } 00055 return ""; 00056 } 00057 00058 std::string& 00059 replaceIn( std::string& s, const std::string& sub, const std::string& other) 00060 { 00061 if ( sub.empty() ) return s; 00062 size_t b=0; 00063 for( ; ; ) 00064 { 00065 b = s.find( sub, b ); 00066 if ( b == s.npos ) break; 00067 s.replace( b, sub.size(), other ); 00068 b += other.size(); 00069 } 00070 return s; 00071 } 00072 } 00073 00074 //------------------------------------------------------------------------ 00075 00076 SpatialReference::SpatialReferenceCache& SpatialReference::getSpatialReferenceCache() 00077 { 00078 //Make sure the registry is created before the cache 00079 osgEarth::Registry::instance(); 00080 static SpatialReferenceCache s_cache; 00081 return s_cache; 00082 } 00083 00084 00085 SpatialReference* 00086 SpatialReference::createFromPROJ4( const std::string& init, const std::string& init_alias, const std::string& name ) 00087 { 00088 SpatialReference* result = NULL; 00089 GDAL_SCOPED_LOCK; 00090 void* handle = OSRNewSpatialReference( NULL ); 00091 if ( OSRImportFromProj4( handle, init.c_str() ) == OGRERR_NONE ) 00092 { 00093 result = new SpatialReference( handle, "PROJ4", init_alias, name ); 00094 } 00095 else 00096 { 00097 OE_WARN << LC << "Unable to create spatial reference from PROJ4: " << init << std::endl; 00098 OSRDestroySpatialReference( handle ); 00099 } 00100 return result; 00101 } 00102 00103 SpatialReference* 00104 SpatialReference::createCube() 00105 { 00106 // root the cube srs with a WGS84 intermediate ellipsoid. 00107 std::string init = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; 00108 00109 SpatialReference* result = NULL; 00110 GDAL_SCOPED_LOCK; 00111 void* handle = OSRNewSpatialReference( NULL ); 00112 if ( OSRImportFromProj4( handle, init.c_str() ) == OGRERR_NONE ) 00113 { 00114 result = new CubeSpatialReference( handle ); 00115 } 00116 else 00117 { 00118 OE_WARN << LC << "Unable to create SRS: " << init << std::endl; 00119 OSRDestroySpatialReference( handle ); 00120 } 00121 return result; 00122 } 00123 00124 #if 0 00125 SpatialReference* 00126 SpatialReference::createLTP( const osg::Vec3d& refPointLLA, const SpatialReference* geoSRS ) 00127 { 00128 GDAL_SCOPED_LOCK; 00129 00130 void* handle = OSRNewSpatialReference( NULL ); 00131 bool ok = false; 00132 SpatialReference* result = 0L; 00133 00134 if ( geoSRS ) 00135 { 00136 std::string init = geoSRS->getGeographicSRS()->getWKT(); 00137 char buf[4096]; 00138 char* buf_ptr = &buf[0]; 00139 strcpy( buf, init.c_str() ); 00140 ok = ( OSRImportFromWkt( handle, &buf_ptr ) == OGRERR_NONE ); 00141 } 00142 else 00143 { 00144 std::string init = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; 00145 ok = ( OSRImportFromProj4( handle, init.c_str() ) == OGRERR_NONE ); 00146 } 00147 00148 if ( ok ) 00149 { 00150 result = new LTPSpatialReference( handle, refPointLLA ); 00151 } 00152 else 00153 { 00154 OE_WARN << LC << "Unable to create LTP SRS" << std::endl; 00155 if ( handle ) 00156 OSRDestroySpatialReference( handle ); 00157 } 00158 00159 return result; 00160 } 00161 #endif 00162 00163 SpatialReference* 00164 SpatialReference::createFromWKT( const std::string& init, const std::string& init_alias, const std::string& name ) 00165 { 00166 osg::ref_ptr<SpatialReference> result; 00167 GDAL_SCOPED_LOCK; 00168 void* handle = OSRNewSpatialReference( NULL ); 00169 char buf[4096]; 00170 char* buf_ptr = &buf[0]; 00171 strcpy( buf, init.c_str() ); 00172 if ( OSRImportFromWkt( handle, &buf_ptr ) == OGRERR_NONE ) 00173 { 00174 result = new SpatialReference( handle, "WKT", init_alias, name ); 00175 result = result->validate(); 00176 } 00177 else 00178 { 00179 OE_WARN << LC << "Unable to create spatial reference from WKT: " << init << std::endl; 00180 OSRDestroySpatialReference( handle ); 00181 } 00182 return result.release(); 00183 } 00184 00185 SpatialReference* 00186 SpatialReference::create( const std::string& init ) 00187 { 00188 static OpenThreads::Mutex s_mutex; 00189 OpenThreads::ScopedLock<OpenThreads::Mutex> exclusiveLock(s_mutex); 00190 00191 std::string low = init; 00192 std::transform( low.begin(), low.end(), low.begin(), ::tolower ); 00193 00194 SpatialReferenceCache::iterator itr = getSpatialReferenceCache().find(init); 00195 if (itr != getSpatialReferenceCache().end()) 00196 { 00197 //OE_NOTICE << "Returning cached SRS" << std::endl; 00198 return itr->second.get(); 00199 } 00200 00201 osg::ref_ptr<SpatialReference> srs; 00202 00203 // shortcut for spherical-mercator: 00204 if (low == "spherical-mercator" || low == "epsg:900913" || low == "epsg:3785" || 00205 low == "epsg:41001" || low == "epsg:102113" || low == "epsg:102100") 00206 { 00207 // note the use of nadgrids=@null (see http://proj.maptools.org/faq.html) 00208 // adjusted +a by ONE to work around osg manipulator error until we can figure out why.. GW 00209 srs = createFromPROJ4( 00210 "+proj=merc +a=6378137 +b=6378137 +lon_0=0 +k=1 +x_0=0 +y_0=0 +nadgrids=@null +units=m +no_defs", 00211 init, 00212 "Spherical Mercator" ); 00213 } 00214 00215 // ellipsoidal ("world") mercator: 00216 else if (low == "epsg:54004" || low == "epsg:9804" || low == "epsg:3832") 00217 { 00218 srs = createFromPROJ4( 00219 "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", 00220 init, 00221 "World Mercator" ); 00222 } 00223 00224 // common WGS84: 00225 else if (low == "epsg:4326" || low == "wgs84") 00226 { 00227 srs = createFromPROJ4( 00228 "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs", 00229 init, 00230 "WGS84" ); 00231 } 00232 00233 // custom srs for the unified cube 00234 else if ( low == "unified-cube" ) 00235 { 00236 srs = createCube(); 00237 } 00238 00239 else if ( low.find( "+" ) == 0 ) 00240 { 00241 srs = createFromPROJ4( low, init ); 00242 } 00243 else if ( low.find( "epsg:" ) == 0 || low.find( "osgeo:" ) == 0 ) 00244 { 00245 srs = createFromPROJ4( std::string("+init=") + low, init ); 00246 } 00247 else if ( low.find( "projcs" ) == 0 || low.find( "geogcs" ) == 0 ) 00248 { 00249 srs = createFromWKT( init, init ); 00250 } 00251 else 00252 { 00253 return NULL; 00254 } 00255 00256 getSpatialReferenceCache()[init] = srs; 00257 return srs.get(); 00258 } 00259 00260 00261 SpatialReference* 00262 SpatialReference::create( osg::CoordinateSystemNode* csn ) 00263 { 00264 SpatialReference* result = NULL; 00265 if ( csn && !csn->getCoordinateSystem().empty() ) 00266 { 00267 result = create( csn->getCoordinateSystem() ); 00268 } 00269 return result; 00270 } 00271 00272 00273 SpatialReference* 00274 SpatialReference::createFromHandle( void* ogrHandle, bool xferOwnership ) 00275 { 00276 SpatialReference* srs = new SpatialReference( ogrHandle, xferOwnership ); 00277 return srs; 00278 } 00279 00280 SpatialReference* 00281 SpatialReference::validate() 00282 { 00283 std::string proj = getOGRAttrValue( _handle, "PROJECTION", 0 ); 00284 00285 // fix invalid ESRI LCC projections: 00286 if ( proj == "Lambert_Conformal_Conic" ) 00287 { 00288 bool has_2_sps = 00289 !getOGRAttrValue( _handle, "Standard_Parallel_2", 0 ).empty() || 00290 !getOGRAttrValue( _handle, "standard_parallel_2", 0 ).empty(); 00291 00292 std::string new_wkt = getWKT(); 00293 if ( has_2_sps ) 00294 replaceIn( new_wkt, "Lambert_Conformal_Conic", "Lambert_Conformal_Conic_2SP" ); 00295 else 00296 replaceIn( new_wkt, "Lambert_Conformal_Conic", "Lambert_Conformal_Conic_1SP" ); 00297 00298 OE_INFO << LC << "Morphing Lambert_Conformal_Conic to 1SP/2SP" << std::endl; 00299 00300 return createFromWKT( new_wkt, _init_str, _name ); 00301 } 00302 00303 // fixes for ESRI Plate_Carree and Equidistant_Cylindrical projections: 00304 else if ( proj == "Plate_Carree" ) 00305 { 00306 std::string new_wkt = getWKT(); 00307 replaceIn( new_wkt, "Plate_Carree", "Equirectangular" ); 00308 OE_INFO << LC << "Morphing Plate_Carree to Equirectangular" << std::endl; 00309 return createFromWKT( new_wkt, _init_str, _name ); //, input->getReferenceFrame() ); 00310 } 00311 else if ( proj == "Equidistant_Cylindrical" ) 00312 { 00313 std::string new_wkt = getWKT(); 00314 OE_INFO << LC << "Morphing Equidistant_Cylindrical to Equirectangular" << std::endl; 00315 replaceIn( new_wkt, "Equidistant_Cylindrical", "Equirectangular" ); 00316 return createFromWKT( new_wkt, _init_str, _name ); 00317 } 00318 00319 // no changes. 00320 return this; 00321 } 00322 00323 00324 /****************************************************************************/ 00325 00326 00327 SpatialReference::SpatialReference(void* handle, 00328 const std::string& init_type, 00329 const std::string& init_str, 00330 const std::string& name ) : 00331 osg::Referenced( true ), 00332 _initialized( false ), 00333 _handle( handle ), 00334 _owns_handle( true ), 00335 _name( name ), 00336 _init_type( init_type ), 00337 _init_str( init_str ), 00338 _is_geographic( false ), 00339 _is_mercator( false ), 00340 _is_north_polar( false ), 00341 _is_south_polar( false ), 00342 _is_cube( false ), 00343 _is_contiguous( false ), 00344 _is_user_defined( false ), 00345 _is_ltp( false ) 00346 { 00347 _init_str_lc = init_str; 00348 std::transform( _init_str_lc.begin(), _init_str_lc.end(), _init_str_lc.begin(), ::tolower ); 00349 } 00350 00351 SpatialReference::SpatialReference(void* handle, bool ownsHandle) : 00352 osg::Referenced( true ), 00353 _initialized( false ), 00354 _handle( handle ), 00355 _owns_handle( ownsHandle ) 00356 { 00357 //nop 00358 } 00359 00360 SpatialReference::~SpatialReference() 00361 { 00362 if ( _handle ) 00363 { 00364 GDAL_SCOPED_LOCK; 00365 00366 for (TransformHandleCache::iterator itr = _transformHandleCache.begin(); itr != _transformHandleCache.end(); ++itr) 00367 { 00368 OCTDestroyCoordinateTransformation(itr->second); 00369 } 00370 00371 if ( _owns_handle ) 00372 { 00373 OSRDestroySpatialReference( _handle ); 00374 } 00375 00376 _handle = NULL; 00377 } 00378 } 00379 00380 bool 00381 SpatialReference::isGeographic() const 00382 { 00383 if ( !_initialized ) 00384 const_cast<SpatialReference*>(this)->init(); 00385 return _is_geographic; 00386 } 00387 00388 bool 00389 SpatialReference::isProjected() const 00390 { 00391 if ( !_initialized ) 00392 const_cast<SpatialReference*>(this)->init(); 00393 return !_is_geographic; 00394 } 00395 00396 const std::string& 00397 SpatialReference::getName() const 00398 { 00399 if ( !_initialized ) 00400 const_cast<SpatialReference*>(this)->init(); 00401 return _name; 00402 } 00403 00404 const osg::EllipsoidModel* 00405 SpatialReference::getEllipsoid() const 00406 { 00407 if ( !_initialized ) 00408 const_cast<SpatialReference*>(this)->init(); 00409 return _ellipsoid.get(); 00410 } 00411 00412 const std::string& 00413 SpatialReference::getDatumName() const 00414 { 00415 if ( !_initialized ) 00416 const_cast<SpatialReference*>(this)->init(); 00417 return _datum; 00418 } 00419 00420 const std::string& 00421 SpatialReference::getWKT() const 00422 { 00423 if ( !_initialized ) 00424 const_cast<SpatialReference*>(this)->init(); 00425 return _wkt; 00426 } 00427 00428 const std::string& 00429 SpatialReference::getInitString() const 00430 { 00431 if ( !_initialized ) 00432 const_cast<SpatialReference*>(this)->init(); 00433 return _init_str; 00434 } 00435 00436 const std::string& 00437 SpatialReference::getInitType() const 00438 { 00439 if ( !_initialized ) 00440 const_cast<SpatialReference*>(this)->init(); 00441 return _init_type; 00442 } 00443 00444 bool 00445 SpatialReference::isEquivalentTo( const SpatialReference* rhs ) const 00446 { 00447 if ( !_initialized ) 00448 const_cast<SpatialReference*>(this)->init(); 00449 00450 return _isEquivalentTo( rhs ); 00451 } 00452 00453 bool 00454 SpatialReference::_isEquivalentTo( const SpatialReference* rhs ) const 00455 { 00456 if ( !rhs ) 00457 return false; 00458 00459 if ( this == rhs ) 00460 return true; 00461 00462 if (isGeographic() != rhs->isGeographic() || 00463 isMercator() != rhs->isMercator() || 00464 isNorthPolar() != rhs->isNorthPolar() || 00465 isSouthPolar() != rhs->isSouthPolar() || 00466 isContiguous() != rhs->isContiguous() || 00467 isUserDefined() != rhs->isUserDefined() || 00468 isCube() != rhs->isCube() || 00469 isLTP() != rhs->isLTP() ) 00470 { 00471 return false; 00472 } 00473 00474 if ( _init_str_lc == rhs->_init_str_lc ) 00475 return true; 00476 00477 if ( this->getWKT() == rhs->getWKT() ) 00478 return true; 00479 00480 if (this->isGeographic() && rhs->isGeographic() && 00481 this->getEllipsoid()->getRadiusEquator() == rhs->getEllipsoid()->getRadiusEquator() && 00482 this->getEllipsoid()->getRadiusPolar() == rhs->getEllipsoid()->getRadiusPolar()) 00483 { 00484 return true; 00485 } 00486 00487 // last resort, since it requires the lock 00488 GDAL_SCOPED_LOCK; 00489 return TRUE == ::OSRIsSame( _handle, rhs->_handle ); 00490 } 00491 00492 const SpatialReference* 00493 SpatialReference::getGeographicSRS() const 00494 { 00495 if ( !_initialized ) 00496 const_cast<SpatialReference*>(this)->init(); 00497 00498 if ( _is_geographic ) 00499 return this; 00500 00501 if ( !_geo_srs.valid() ) 00502 { 00503 GDAL_SCOPED_LOCK; 00504 00505 if ( !_geo_srs.valid() ) // double-check pattern 00506 { 00507 void* new_handle = OSRNewSpatialReference( NULL ); 00508 int err = OSRCopyGeogCSFrom( new_handle, _handle ); 00509 if ( err == OGRERR_NONE ) 00510 { 00511 const_cast<SpatialReference*>(this)->_geo_srs = new SpatialReference( new_handle ); 00512 } 00513 else 00514 { 00515 OSRDestroySpatialReference( new_handle ); 00516 } 00517 } 00518 } 00519 00520 return _geo_srs.get(); 00521 } 00522 00523 SpatialReference* 00524 SpatialReference::createTangentPlaneSRS( const osg::Vec3d& pos ) const 00525 { 00526 SpatialReference* result = 0L; 00527 osg::Vec3d lla; 00528 if ( this->transform(pos, this->getGeographicSRS(), lla) ) 00529 { 00530 result = new LTPSpatialReference( this->getGeographicSRS()->_handle, lla ); 00531 } 00532 else 00533 { 00534 OE_WARN << LC << "Unable to create LTP SRS" << std::endl; 00535 } 00536 return result; 00537 } 00538 00539 SpatialReference* 00540 SpatialReference::createTransMercFromLongitude( const Angular& lon ) const 00541 { 00542 // note. using tmerc with +lat_0 <> 0 is sloooooow. 00543 std::string datum = getDatumName(); 00544 std::stringstream buf; 00545 buf << "+proj=tmerc +lat_0=0" 00546 << " +lon_0=" << lon.as(Units::DEGREES) 00547 << " +datum=" << (!datum.empty() ? "wgs84" : datum); 00548 std::string projstr; 00549 projstr = buf.str(); 00550 return create( projstr ); 00551 } 00552 00553 SpatialReference* 00554 SpatialReference::createUTMFromLongitude( const Angular& lon ) const 00555 { 00556 // note. UTM is up to 10% faster than TMERC for the same meridian. 00557 unsigned zone = 1 + (unsigned)floor((lon.as(Units::DEGREES)+180.0)/6.0); 00558 std::string datum = getDatumName(); 00559 std::stringstream buf; 00560 buf << "+proj=utm +zone=" << zone 00561 << " +datum=" << (!datum.empty() ? "wgs84" : datum); 00562 std::string projstr; 00563 projstr = buf.str(); 00564 return create( projstr ); 00565 } 00566 00567 bool 00568 SpatialReference::isMercator() const 00569 { 00570 if ( !_initialized ) 00571 const_cast<SpatialReference*>(this)->init(); 00572 return _is_mercator; 00573 } 00574 00575 bool 00576 SpatialReference::isNorthPolar() const 00577 { 00578 if ( !_initialized ) 00579 const_cast<SpatialReference*>(this)->init(); 00580 return _is_north_polar; 00581 } 00582 00583 bool 00584 SpatialReference::isSouthPolar() const 00585 { 00586 if ( !_initialized ) 00587 const_cast<SpatialReference*>(this)->init(); 00588 return _is_south_polar; 00589 } 00590 00591 bool 00592 SpatialReference::isContiguous() const 00593 { 00594 if ( !_initialized ) 00595 const_cast<SpatialReference*>(this)->init(); 00596 return _is_contiguous; 00597 } 00598 00599 bool 00600 SpatialReference::isUserDefined() const 00601 { 00602 if ( !_initialized ) 00603 const_cast<SpatialReference*>(this)->init(); 00604 return _is_user_defined; 00605 } 00606 00607 bool 00608 SpatialReference::isCube() const 00609 { 00610 if ( !_initialized ) 00611 const_cast<SpatialReference*>(this)->init(); 00612 return _is_cube; 00613 } 00614 00615 osg::CoordinateSystemNode* 00616 SpatialReference::createCoordinateSystemNode() const 00617 { 00618 if ( !_initialized ) 00619 const_cast<SpatialReference*>(this)->init(); 00620 00621 osg::CoordinateSystemNode* csn = new osg::CoordinateSystemNode(); 00622 populateCoordinateSystemNode( csn ); 00623 return csn; 00624 } 00625 00626 bool 00627 SpatialReference::populateCoordinateSystemNode( osg::CoordinateSystemNode* csn ) const 00628 { 00629 if ( !csn ) 00630 return false; 00631 00632 if ( !_initialized ) 00633 const_cast<SpatialReference*>(this)->init(); 00634 00635 if ( !_wkt.empty() ) 00636 { 00637 csn->setFormat( "WKT" ); 00638 csn->setCoordinateSystem( _wkt ); 00639 } 00640 else if ( !_proj4.empty() ) 00641 { 00642 csn->setFormat( "PROJ4" ); 00643 csn->setCoordinateSystem( _proj4 ); 00644 } 00645 else 00646 { 00647 csn->setFormat( _init_type ); 00648 csn->setCoordinateSystem( _init_str ); 00649 } 00650 00651 csn->setEllipsoidModel( _ellipsoid.get() ); 00652 00653 return true; 00654 } 00655 00656 // Make a MatrixTransform suitable for use with a Locator object based on the given extents. 00657 // Calling Locator::setTransformAsExtents doesn't work with OSG 2.6 due to the fact that the 00658 // _inverse member isn't updated properly. Calling Locator::setTransform works correctly. 00659 static osg::Matrixd 00660 getTransformFromExtents(double minX, double minY, double maxX, double maxY) 00661 { 00662 osg::Matrixd transform; 00663 transform.set( 00664 maxX-minX, 0.0, 0.0, 0.0, 00665 0.0, maxY-minY, 0.0, 0.0, 00666 0.0, 0.0, 1.0, 0.0, 00667 minX, minY, 0.0, 1.0); 00668 return transform; 00669 } 00670 00671 GeoLocator* 00672 SpatialReference::createLocator(double xmin, double ymin, double xmax, double ymax, 00673 bool plate_carre ) const 00674 { 00675 if ( !_initialized ) 00676 const_cast<SpatialReference*>(this)->init(); 00677 00678 GeoLocator* locator = new GeoLocator( GeoExtent(this, xmin, ymin, xmax, ymax) ); 00679 locator->setEllipsoidModel( (osg::EllipsoidModel*)getEllipsoid() ); 00680 locator->setCoordinateSystemType( isGeographic()? osgTerrain::Locator::GEOGRAPHIC : osgTerrain::Locator::PROJECTED ); 00681 // note: not setting the format/cs on purpose. 00682 00683 if ( isGeographic() && !plate_carre ) 00684 { 00685 locator->setTransform( getTransformFromExtents( 00686 osg::DegreesToRadians( xmin ), 00687 osg::DegreesToRadians( ymin ), 00688 osg::DegreesToRadians( xmax ), 00689 osg::DegreesToRadians( ymax ) ) ); 00690 } 00691 else 00692 { 00693 locator->setTransform( getTransformFromExtents( xmin, ymin, xmax, ymax ) ); 00694 } 00695 return locator; 00696 } 00697 00698 bool 00699 SpatialReference::transform(double x, double y, double z, 00700 const SpatialReference* out_srs, 00701 double& out_x, double& out_y, double& out_z, 00702 void* context ) const 00703 { 00704 if ( !_initialized ) 00705 const_cast<SpatialReference*>(this)->init(); 00706 00707 //Check for equivalence and return if the coordinate systems are the same. 00708 if (isEquivalentTo(out_srs)) 00709 { 00710 out_x = x; 00711 out_y = y; 00712 out_z = z; 00713 return true; 00714 } 00715 00716 out_x = x; 00717 out_y = y; 00718 out_z = z; 00719 bool result = transformPoints(out_srs, &out_x, &out_y, &out_z, 1, context); 00720 00721 return result; 00722 } 00723 00724 // http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_projection 00725 static bool 00726 mercatorToGeographic( double* x, double* y, double* z, int numPoints ) 00727 { 00728 for( int i=0; i<numPoints; i++ ) 00729 { 00730 double xr = -osg::PI + ((x[i]-MERC_MINX)/MERC_WIDTH)*2.0*osg::PI; 00731 double yr = -osg::PI + ((y[i]-MERC_MINY)/MERC_HEIGHT)*2.0*osg::PI; 00732 x[i] = osg::RadiansToDegrees( xr ); 00733 y[i] = osg::RadiansToDegrees( 2.0 * atan( exp(yr) ) - osg::PI_2 ); 00734 // z doesn't change 00735 } 00736 return true; 00737 } 00738 00739 // http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_projection 00740 static bool 00741 geographicToMercator( double* x, double* y, double* z, int numPoints ) 00742 { 00743 for( int i=0; i<numPoints; i++ ) 00744 { 00745 double xr = (osg::DegreesToRadians(x[i]) - (-osg::PI)) / (2.0*osg::PI); 00746 double sinLat = sin(osg::DegreesToRadians(y[i])); 00747 double oneMinusSinLat = 1-sinLat; 00748 if ( oneMinusSinLat != 0.0 ) 00749 { 00750 double yr = ((0.5 * log( (1+sinLat)/oneMinusSinLat )) - (-osg::PI)) / (2.0*osg::PI); 00751 x[i] = MERC_MINX + (xr * MERC_WIDTH); 00752 y[i] = MERC_MINY + (yr * MERC_HEIGHT); 00753 // z doesn't change 00754 } 00755 } 00756 return true; 00757 } 00758 00759 bool 00760 SpatialReference::transformPoints(const SpatialReference* out_srs, 00761 double* x, double* y, double* z, 00762 unsigned int numPoints, 00763 void* context, 00764 bool ignore_errors ) const 00765 { 00766 if ( !_initialized ) 00767 const_cast<SpatialReference*>(this)->init(); 00768 00769 //Check for equivalence and return if the coordinate systems are the same. 00770 if (isEquivalentTo(out_srs)) 00771 return true; 00772 00773 if ( z ) 00774 { 00775 for (unsigned int i = 0; i < numPoints; ++i) 00776 preTransform(x[i], y[i], z[i], context); 00777 } 00778 else 00779 { 00780 double dummyZ = 0.0; 00781 for (unsigned int i = 0; i < numPoints; ++i) 00782 preTransform(x[i], y[i], dummyZ, context); 00783 } 00784 00785 bool success = false; 00786 00787 #ifdef USE_CUSTOM_MERCATOR_TRANSFORM 00788 00789 if ( isGeographic() && out_srs->isMercator() ) 00790 { 00791 success = geographicToMercator( x, y, z, numPoints ); 00792 } 00793 00794 else if ( isMercator() && out_srs->isGeographic() ) 00795 { 00796 success = mercatorToGeographic( x, y, z, numPoints ); 00797 } 00798 00799 else 00800 #endif 00801 00802 { 00803 GDAL_SCOPED_LOCK; 00804 00805 void* xform_handle = NULL; 00806 TransformHandleCache::const_iterator itr = _transformHandleCache.find(out_srs->getWKT()); 00807 if (itr != _transformHandleCache.end()) 00808 { 00809 //OE_DEBUG << "SpatialRefernece: using cached transform handle" << std::endl; 00810 xform_handle = itr->second; 00811 } 00812 else 00813 { 00814 xform_handle = OCTNewCoordinateTransformation( _handle, out_srs->_handle); 00815 const_cast<SpatialReference*>(this)->_transformHandleCache[out_srs->getWKT()] = xform_handle; 00816 } 00817 00818 if ( !xform_handle ) 00819 { 00820 OE_WARN << LC 00821 << "SRS xform not possible" << std::endl 00822 << " From => " << getName() << std::endl 00823 << " To => " << out_srs->getName() << std::endl; 00824 return false; 00825 } 00826 00827 //double* temp_z = new double[numPoints]; 00828 //success = OCTTransform( xform_handle, numPoints, x, y, temp_z ) > 0; 00829 //delete[] temp_z; 00830 00831 success = OCTTransform( xform_handle, numPoints, x, y, z ) > 0; 00832 00833 // END GDAL_SCOPE_LOCK 00834 } 00835 00836 if ( success || ignore_errors ) 00837 { 00838 if ( z ) 00839 { 00840 for (unsigned int i = 0; i < numPoints; ++i) 00841 out_srs->postTransform(x[i], y[i], z[i], context); 00842 } 00843 else 00844 { 00845 double dummyZ = 0.0; 00846 for (unsigned int i = 0; i < numPoints; ++i) 00847 out_srs->postTransform(x[i], y[i], dummyZ, context); 00848 } 00849 } 00850 else 00851 { 00852 OE_WARN << LC << "Failed to xform a point from " 00853 << getName() << " to " << out_srs->getName() 00854 << std::endl; 00855 } 00856 return success; 00857 } 00858 00859 bool 00860 SpatialReference::transformPoints(const SpatialReference* out_srs, 00861 std::vector<osg::Vec3d>& points, 00862 void* context, 00863 bool ignore_errors ) const 00864 { 00865 if ( !_initialized ) 00866 const_cast<SpatialReference*>(this)->init(); 00867 00868 //Check for equivalence and return if the coordinate systems are the same. 00869 if (isEquivalentTo(out_srs)) 00870 return true; 00871 00872 int numPoints = points.size(); 00873 double* x = new double[numPoints]; 00874 double* y = new double[numPoints]; 00875 double* z = new double[numPoints]; 00876 00877 for( int i=0; i<numPoints; i++ ) 00878 { 00879 x[i] = points[i].x(); 00880 y[i] = points[i].y(); 00881 z[i] = points[i].z(); 00882 } 00883 00884 bool success = transformPoints( out_srs, x, y, z, numPoints, context, ignore_errors ); 00885 00886 if ( success ) 00887 { 00888 for( int i=0; i<numPoints; i++ ) 00889 { 00890 points[i].x() = x[i]; 00891 points[i].y() = y[i]; 00892 points[i].z() = z[i]; 00893 } 00894 } 00895 00896 delete[] x; 00897 delete[] y; 00898 delete[] z; 00899 00900 return success; 00901 } 00902 00903 bool 00904 SpatialReference::transformToECEF(const osg::Vec3d& input, 00905 osg::Vec3d& output ) const 00906 { 00907 double lat = input.y(), lon = input.x(), alt = input.z(); 00908 00909 // first convert to lat/long if necessary: 00910 if ( !isGeographic() ) 00911 transform( input.x(), input.y(), input.z(), getGeographicSRS(), lon, lat, alt ); 00912 00913 // then convert to ECEF. 00914 //double z = input.z(); 00915 getGeographicSRS()->getEllipsoid()->convertLatLongHeightToXYZ( 00916 osg::DegreesToRadians( lat ), osg::DegreesToRadians( lon ), alt, 00917 output.x(), output.y(), output.z() ); 00918 00919 return true; 00920 } 00921 00922 bool 00923 SpatialReference::transformToECEF(std::vector<osg::Vec3d>& points, 00924 bool ignoreErrors ) const 00925 { 00926 if ( points.size() == 0 ) 00927 return false; 00928 00929 const SpatialReference* geoSRS = getGeographicSRS(); 00930 const osg::EllipsoidModel* ellipsoid = geoSRS->getEllipsoid(); 00931 00932 for( unsigned i=0; i<points.size(); ++i ) 00933 { 00934 osg::Vec3d& p = points[i]; 00935 00936 if ( !isGeographic() ) 00937 transform( p.x(), p.y(), p.z(), geoSRS, p.x(), p.y(), p.z() ); 00938 00939 ellipsoid->convertLatLongHeightToXYZ( 00940 osg::DegreesToRadians( p.y() ), osg::DegreesToRadians( p.x() ), p.z(), 00941 p.x(), p.y(), p.z() ); 00942 } 00943 00944 return true; 00945 } 00946 00947 bool 00948 SpatialReference::transformFromECEF(const osg::Vec3d& input, 00949 osg::Vec3d& output ) const 00950 { 00951 // transform to lat/long: 00952 osg::Vec3d geo; 00953 00954 getGeographicSRS()->getEllipsoid()->convertXYZToLatLongHeight( 00955 input.x(), input.y(), input.z(), 00956 geo.y(), geo.x(), geo.z() ); 00957 00958 // then convert to the local SRS. 00959 if ( isGeographic() ) 00960 { 00961 output.set( osg::RadiansToDegrees(geo.x()), osg::RadiansToDegrees(geo.y()), geo.z() ); 00962 } 00963 else 00964 { 00965 getGeographicSRS()->transform( 00966 osg::RadiansToDegrees(geo.x()), osg::RadiansToDegrees(geo.y()), geo.z(), 00967 this, 00968 output.x(), output.y(), output.z() ); 00969 //output.z() = geo.z(); 00970 } 00971 00972 return true; 00973 } 00974 00975 bool 00976 SpatialReference::transformFromECEF(std::vector<osg::Vec3d>& points, 00977 bool ignoreErrors ) const 00978 { 00979 bool ok = true; 00980 00981 // first convert all the points to lat/long (in place): 00982 for( unsigned i=0; i<points.size(); ++i ) 00983 { 00984 osg::Vec3d& p = points[i]; 00985 osg::Vec3d geo; 00986 getGeographicSRS()->getEllipsoid()->convertXYZToLatLongHeight( 00987 p.x(), p.y(), p.z(), 00988 geo.y(), geo.x(), geo.z() ); 00989 geo.x() = osg::RadiansToDegrees( geo.x() ); 00990 geo.y() = osg::RadiansToDegrees( geo.y() ); 00991 p = geo; 00992 } 00993 00994 // then convert them all to the local SRS if necessary. 00995 if ( !isGeographic() ) 00996 { 00997 ok = getGeographicSRS()->transformPoints( this, points, 0L, ignoreErrors ); 00998 } 00999 01000 return ok; 01001 } 01002 01003 bool 01004 SpatialReference::transformExtent(const SpatialReference* to_srs, 01005 double& in_out_xmin, 01006 double& in_out_ymin, 01007 double& in_out_xmax, 01008 double& in_out_ymax, 01009 void* context ) const 01010 { 01011 if ( !_initialized ) 01012 const_cast<SpatialReference*>(this)->init(); 01013 01014 int oks = 0; 01015 01016 //Transform all points and take the maximum bounding rectangle the resulting points 01017 double llx, lly; 01018 double ulx, uly; 01019 double urx, ury; 01020 double lrx, lry; 01021 double dummyZ = 0; 01022 01023 //Lower Left 01024 oks += transform( in_out_xmin, in_out_ymin, 0, to_srs, llx, lly, dummyZ, context ) == true; 01025 01026 //Upper Left 01027 oks += transform( in_out_xmin, in_out_ymax, 0, to_srs, ulx, uly, dummyZ, context ) == true; 01028 01029 //Upper Right 01030 oks += transform( in_out_xmax, in_out_ymax, 0, to_srs, urx, ury, dummyZ, context ) == true; 01031 01032 //Lower Right 01033 oks += transform( in_out_xmax, in_out_ymin, 0, to_srs, lrx, lry, dummyZ, context ) == true; 01034 01035 01036 if (oks == 4) 01037 { 01038 in_out_xmin = osg::minimum(llx, ulx); 01039 in_out_xmax = osg::maximum(lrx, urx); 01040 in_out_ymin = osg::minimum(lly, lry); 01041 in_out_ymax = osg::maximum(uly, ury); 01042 return true; 01043 } 01044 return false; 01045 } 01046 01047 bool SpatialReference::transformExtentPoints(const SpatialReference* to_srs, 01048 double in_xmin, double in_ymin, 01049 double in_xmax, double in_ymax, 01050 double* x, double* y, 01051 unsigned int numx, unsigned int numy, 01052 void* context, bool ignore_errors ) const 01053 { 01054 const double dx = (in_xmax - in_xmin) / (numx - 1); 01055 const double dy = (in_ymax - in_ymin) / (numy - 1); 01056 01057 unsigned int pixel = 0; 01058 double fc = 0.0; 01059 for (unsigned int c = 0; c < numx; ++c, ++fc) 01060 { 01061 const double dest_x = in_xmin + fc * dx; 01062 double fr = 0.0; 01063 for (unsigned int r = 0; r < numy; ++r, ++fr) 01064 { 01065 const double dest_y = in_ymin + fr * dy; 01066 01067 x[pixel] = dest_x; 01068 y[pixel] = dest_y; 01069 pixel++; 01070 } 01071 } 01072 return transformPoints(to_srs, x, y, 0L, numx * numy, context, ignore_errors); 01073 } 01074 01075 void 01076 SpatialReference::init() 01077 { 01078 GDAL_SCOPED_LOCK; 01079 01080 // always double-check the _initialized flag after obtaining the lock. 01081 if ( !_initialized ) 01082 { 01083 // calls the internal version, which can be overriden by the developer. 01084 // therefore do not call init() from the constructor! 01085 _init(); 01086 } 01087 } 01088 01089 void 01090 SpatialReference::_init() 01091 { 01092 // set defaults: 01093 _is_user_defined = false; 01094 _is_contiguous = true; 01095 _is_cube = false; 01096 _is_geographic = OSRIsGeographic( _handle ) != 0; 01097 01098 // extract the ellipsoid parameters: 01099 int err; 01100 double semi_major_axis = OSRGetSemiMajor( _handle, &err ); 01101 double semi_minor_axis = OSRGetSemiMinor( _handle, &err ); 01102 _ellipsoid = new osg::EllipsoidModel( semi_major_axis, semi_minor_axis ); 01103 01104 // try to get an ellipsoid name: 01105 _ellipsoid->setName( getOGRAttrValue(_handle, "SPHEROID", 0, true) ); 01106 01107 // extract the projection: 01108 if ( _name.empty() || _name == "unnamed" ) 01109 { 01110 _name = _is_geographic? 01111 getOGRAttrValue( _handle, "GEOGCS", 0 ) : 01112 getOGRAttrValue( _handle, "PROJCS", 0 ); 01113 } 01114 std::string proj = getOGRAttrValue( _handle, "PROJECTION", 0, true ); 01115 01116 // check for the Mercator projection: 01117 _is_mercator = !proj.empty() && proj.find("mercator")==0; 01118 01119 // check for the Polar projection: 01120 if ( !proj.empty() && proj.find("polar_stereographic") != std::string::npos ) 01121 { 01122 double lat = as<double>( getOGRAttrValue( _handle, "latitude_of_origin", 0, true ), -90.0 ); 01123 _is_north_polar = lat > 0.0; 01124 _is_south_polar = lat < 0.0; 01125 } 01126 else 01127 { 01128 _is_north_polar = false; 01129 _is_south_polar = false; 01130 } 01131 01132 // Give the SRS a name if it doesn't have one: 01133 if ( _name == "unnamed" || _name.empty() ) 01134 { 01135 _name = 01136 _is_geographic? "Geographic CS" : 01137 _is_mercator? "Mercator CS" : 01138 ( !proj.empty()? proj : "Projected CS" ); 01139 } 01140 01141 // Try to extract the OGC well-known-text (WKT) string: 01142 char* wktbuf; 01143 if ( OSRExportToWkt( _handle, &wktbuf ) == OGRERR_NONE ) 01144 { 01145 _wkt = wktbuf; 01146 OGRFree( wktbuf ); 01147 } 01148 01149 // If the user did not specify and initialization string, use the WKT. 01150 if ( _init_str.empty() ) 01151 { 01152 _init_str = _wkt; 01153 _init_type = "WKT"; 01154 } 01155 01156 // Try to extract the PROJ4 initialization string: 01157 char* proj4buf; 01158 if ( OSRExportToProj4( _handle, &proj4buf ) == OGRERR_NONE ) 01159 { 01160 _proj4 = proj4buf; 01161 OGRFree( proj4buf ); 01162 } 01163 01164 // Try to extract the datum 01165 _datum = getOGRAttrValue( _handle, "DATUM", 0, true ); 01166 01167 _initialized = true; 01168 }