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/VerticalSpatialReference> 00021 #include <osgEarth/EGM> 00022 #include <osgEarth/StringUtils> 00023 #include <osgEarth/GeoData> 00024 00025 using namespace osgEarth; 00026 00027 #define LC "[VSRS] " 00028 00029 // -------------------------------------------------------------------------- 00030 00031 //TODO: replace this with some kind of registry. 00032 VerticalSpatialReference* 00033 VerticalSpatialReference::create( const std::string& initString ) 00034 { 00035 static OpenThreads::Mutex s_mutex; 00036 OpenThreads::ScopedLock<OpenThreads::Mutex> exclusiveLock(s_mutex); 00037 00038 if ( !_geoidRegistry ) 00039 { 00040 // initialize the registry the first time through. 00041 registerGeoid( new EGM96Geoid() ); 00042 } 00043 00044 std::string s = toLower( initString ); 00045 00046 GeoidRegistry::const_iterator i = (*_geoidRegistry).find( s ); 00047 if ( i != (*_geoidRegistry).end() ) 00048 { 00049 const Geoid* geoid = i->second.get(); 00050 return new VerticalSpatialReference( geoid->getName(), initString, geoid ); 00051 } 00052 else if ( s == "meters" || s == "metres" || s == "meter" || s == "metre" ) 00053 return new VerticalSpatialReference( Units::METERS ); 00054 else if ( startsWith( s, "feet" ) || startsWith( s, "foot" ) ) 00055 return new VerticalSpatialReference( Units::FEET ); 00056 00057 return 0L; 00058 } 00059 00060 void 00061 VerticalSpatialReference::registerGeoid( const Geoid* geoid ) 00062 { 00063 if ( !_geoidRegistry ) 00064 _geoidRegistry = new GeoidRegistry(); 00065 00066 if ( geoid ) 00067 (*_geoidRegistry)[geoid->getName()] = geoid; 00068 } 00069 00070 VerticalSpatialReference::GeoidRegistry* 00071 VerticalSpatialReference::_geoidRegistry = 0L; 00072 00073 // -------------------------------------------------------------------------- 00074 00075 VerticalSpatialReference::VerticalSpatialReference(const std::string& name, 00076 const std::string& initString, 00077 const Geoid* geoid ) : 00078 _name( name ), 00079 _initString( initString ), 00080 _geoid( geoid ), 00081 _units( Units::METERS ) 00082 { 00083 if ( _geoid.valid() ) 00084 _units = _geoid->getUnits(); 00085 } 00086 00087 VerticalSpatialReference::VerticalSpatialReference( const Units& units ) : 00088 _name( units.getName() ), 00089 _initString( units.getName() ), 00090 _units( units ) 00091 { 00092 //nop 00093 } 00094 00095 bool 00096 VerticalSpatialReference::canTransform( const VerticalSpatialReference* toVSRS ) const 00097 { 00098 return toVSRS && !isEquivalentTo( toVSRS ); 00099 } 00100 00101 bool 00102 VerticalSpatialReference::canTransform(const VerticalSpatialReference* fromVSRS, 00103 const VerticalSpatialReference* toVSRS ) 00104 { 00105 return fromVSRS && fromVSRS->canTransform( toVSRS ); 00106 } 00107 00108 bool 00109 VerticalSpatialReference::transform(const VerticalSpatialReference* toSRS, 00110 double lat_deg, double lon_deg, double in_z, 00111 double& out_z ) const 00112 { 00113 if ( this->isEquivalentTo( toSRS ) ) 00114 { 00115 out_z = in_z; 00116 } 00117 else 00118 { 00119 double workZ = in_z; 00120 00121 // transform out of the source VSRS (this): 00122 if ( _geoid.valid() ) 00123 { 00124 if ( !_geoid->isValid() ) 00125 return false; 00126 00127 float offset = _geoid->getOffset( lat_deg, lon_deg, INTERP_BILINEAR ); 00128 workZ -= offset; 00129 } 00130 00131 // convert the value to output units: 00132 Units::convert( getUnits(), toSRS->getUnits(), workZ, workZ ); 00133 00134 // transform into the target VSRS: 00135 if ( toSRS->_geoid.valid() ) 00136 { 00137 if ( !toSRS->_geoid->isValid() ) 00138 return false; 00139 00140 float offset = toSRS->_geoid->getOffset( lat_deg, lon_deg, INTERP_BILINEAR ); 00141 workZ += offset; 00142 } 00143 00144 out_z = workZ; 00145 } 00146 00147 return true; 00148 } 00149 00150 osg::HeightField* 00151 VerticalSpatialReference::createReferenceHeightField( const GeoExtent& ex, int numCols, int numRows ) const 00152 { 00153 osg::HeightField* hf = new osg::HeightField(); 00154 hf->allocate( numCols, numRows ); 00155 hf->setOrigin( osg::Vec3d( ex.xMin(), ex.yMin(), 0.0 ) ); 00156 hf->setXInterval( (ex.xMax() - ex.xMin())/(double)(numCols-1) ); 00157 hf->setYInterval( (ex.yMax() - ex.yMin())/(double)(numRows-1) ); 00158 00159 if ( _geoid.valid() && _geoid->isValid() ) 00160 { 00161 // need the lat/long extent for geoid queries: 00162 GeoExtent geodeticExtent = ex.getSRS()->isGeographic() ? ex : ex.transform( ex.getSRS()->getGeographicSRS() ); 00163 double latMin = geodeticExtent.yMin(); 00164 double lonMin = geodeticExtent.xMin(); 00165 double lonInterval = geodeticExtent.width() / (double)(numCols-1); 00166 double latInterval = geodeticExtent.height() / (double)(numRows-1); 00167 00168 for( int r=0; r<numRows; ++r ) 00169 { 00170 double lat = latMin + latInterval*(double)r; 00171 for( int c=0; c<numCols; ++c ) 00172 { 00173 double lon = lonMin + lonInterval*(double)c; 00174 double offset = _geoid->getOffset( lat, lon ); 00175 hf->setHeight( c, r, offset ); 00176 } 00177 } 00178 } 00179 else 00180 { 00181 for(unsigned int i=0; i<hf->getHeightList().size(); i++ ) 00182 hf->getHeightList()[i] = 0.0; 00183 } 00184 00185 hf->setBorderWidth( 0 ); 00186 return hf; 00187 } 00188 00189 bool 00190 VerticalSpatialReference::isEquivalentTo( const VerticalSpatialReference* rhs ) const 00191 { 00192 if ( this == rhs ) 00193 return true; 00194 00195 if ( _units != rhs->_units ) 00196 return false; 00197 00198 if ( _geoid.valid() != rhs->_geoid.valid() ) 00199 return false; 00200 00201 if ( _geoid.valid() && !_geoid->isEquivalentTo( *rhs->_geoid.get() ) ) 00202 return false; 00203 00204 //TODO - add comparisons as necessary 00205 00206 return true; 00207 }