osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/Formatters.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 <osgEarthUtil/Formatters>
00020 #include <iomanip>
00021 #include <sstream>
00022 #include <cstdio>
00023 #include <algorithm>
00024 
00025 using namespace osgEarth;
00026 using namespace osgEarth::Util;
00027 
00028 #define LC "[LatLongFormatter] "
00029 
00030 LatLongFormatter::LatLongFormatter(const AngularFormat& defaultFormat,
00031                                    unsigned             options ) :
00032 _defaultFormat( defaultFormat ),
00033 _options      ( options ),
00034 _prec         ( 5 )
00035 {
00036     if ( _defaultFormat == FORMAT_DEFAULT )
00037     {
00038         _defaultFormat = FORMAT_DEGREES_MINUTES_SECONDS;
00039     }
00040 }
00041 
00042 std::string
00043 LatLongFormatter::format( const Angular& angle, int precision, const AngularFormat& format )
00044 {
00045     std::stringstream buf;
00046     std::string result;
00047     std::string space = _options & USE_SPACES ? " " : "";
00048 
00049     AngularFormat f =
00050         format == FORMAT_DEFAULT ? _defaultFormat :
00051         format;
00052 
00053     if ( precision < 0 )
00054         precision = _prec;
00055 
00056     if ( precision > 0 )
00057         buf << std::setprecision(precision);
00058 
00059     switch( f )
00060     {
00061     case FORMAT_DECIMAL_DEGREES:
00062         {
00063             if ( _options & USE_SYMBOLS )
00064                 buf << angle.as(Units::DEGREES) << "\xb0";
00065             else
00066                 buf << angle.as(Units::DEGREES);
00067         }
00068         break;
00069 
00070     case FORMAT_DEGREES_DECIMAL_MINUTES:
00071         {
00072             double df = angle.as(Units::DEGREES);
00073             int    d  = (int)floor(df);
00074             double mf = 60.0*(df-(double)d);
00075             if ( mf == 60.0 ) {
00076                 d += 1;
00077                 mf = 0.0;
00078             }
00079             if ( _options & USE_SYMBOLS )
00080                 buf << d << "\xb0" << space << mf << "'";
00081             else if ( _options & USE_COLONS )
00082                 buf << d << ":" << mf;
00083             else
00084                 buf << d << " " << mf;
00085         }
00086         break;
00087 
00088     case FORMAT_DEGREES_MINUTES_SECONDS:
00089         {
00090             double df = angle.as(Units::DEGREES);
00091             int    d  = (int)floor(df);
00092             double mf = 60.0*(df-(double)d);
00093             int    m  = (int)floor(mf);
00094             double sf = 60.0*(mf-(double)m);
00095             if ( sf == 60.0 ) {
00096                 m += 1;
00097                 sf = 0.0;
00098                 if ( m == 60 ) {
00099                     d += 1;
00100                     m = 0;
00101                 }
00102             }
00103             if ( _options & USE_SYMBOLS )
00104                 buf << d << "\xb0" << space << m << "'" << space << sf << "\"";
00105             else if ( _options & USE_COLONS )
00106                 buf << d << ":" << m << ":" << sf;
00107             else
00108                 buf << d << " " << m << " " << sf;
00109         }
00110         break;
00111     }
00112 
00113     result = buf.str();
00114     return result;
00115 }
00116 
00117 bool
00118 LatLongFormatter::parseAngle( const std::string& input, Angular& out_value )
00119 {
00120     const char* c = input.c_str();
00121 
00122     double d=0.0, m=0.0, s=0.0;
00123 
00124     if (sscanf(c, "%lf:%lf:%lf",     &d, &m, &s) == 3 ||
00125         sscanf(c, "%lf\xb0%lf'%lf\"",   &d, &m, &s) == 3 ||
00126         sscanf(c, "%lf\xb0 %lf' %lf\"", &d, &m ,&s) == 3 ||
00127         sscanf(c, "%lfd %lf' %lf\"", &d, &m, &s) == 3 ||
00128         sscanf(c, "%lfd %lfm %lfs",  &d, &m, &s) == 3 ||
00129         sscanf(c, "%lf %lf' %lf\"",  &d, &m, &s) == 3 )
00130     {
00131         out_value.set( d + m/60.0 + s/3600.0, Units::DEGREES );
00132         return true;
00133     }
00134     else if (
00135         sscanf(c, "%lf:%lf",   &d, &m) == 2 ||
00136         sscanf(c, "%lf\xb0 %lf'", &d, &m) == 2 ||
00137         sscanf(c, "%lf\xb0%lf'",  &d, &m) == 2 ||
00138         sscanf(c, "%lfd %lf'", &d, &m) == 2 ||
00139         sscanf(c, "%lfd %lfm", &d, &m) == 2 ||
00140         sscanf(c, "%lfd%lf'",  &d, &m) == 2 ||
00141         sscanf(c, "%lf %lf'",  &d, &m) == 2 )
00142     {
00143         out_value.set( d + m/60.0, Units::DEGREES );
00144         return true;
00145     }
00146     else if (
00147         sscanf(c, "%lf\xb0", &d) == 1 ||
00148         sscanf(c, "%lfd", &d) == 1 ||
00149         sscanf(c, "%lf",  &d) == 1 )
00150     {
00151         out_value.set( d, Units::DEGREES );
00152         return true;
00153     }
00154 
00155     return false;
00156 }
00157 
00158 //------------------------------------------------------------------------
00159 
00160 #undef LC
00161 #define LC "[MGRSFormatter] "
00162 
00163 namespace
00164 {
00165     static char*    GZD_ALPHABET     = "CDEFGHJKLMNPQRSTUVWXX";    // 2 X's because X is a 12 degree high grid zone
00166     static char*    UTM_COL_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ";
00167     static char*    UTM_ROW_ALPHABET = "ABCDEFGHJKLMNPQRSTUV";
00168     static unsigned UTM_ROW_ALPHABET_SIZE = 20;
00169 
00170     static char*    UPS_COL_ALPHABET = "ABCFGHJKLPQRSTUXYZ";        // omit I, O, D, E, M, N, V, W
00171     static unsigned UPS_COL_ALPHABET_SIZE = 18;
00172     static char*    UPS_ROW_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ";  // omit I, O
00173     static unsigned UPS_ROW_ALPHABET_SIZE = 24;
00174 }
00175 
00176 MGRSFormatter::MGRSFormatter(Precision               precision,
00177                              const SpatialReference* referenceSRS,
00178                              unsigned                options ) :
00179 _precision( precision ),
00180 _options  ( options )
00181 {
00182     if ( referenceSRS )
00183     {
00184         _refSRS = referenceSRS->getGeographicSRS();
00185     }
00186     else
00187     {
00188         _refSRS = SpatialReference::create( "wgs84" );
00189     }
00190 
00191     if ( options & FORCE_AA_SCHEME )
00192     {
00193         _useAL = false;
00194     }
00195     else if ( options & FORCE_AL_SCHEME )
00196     {
00197         _useAL = true;
00198     }
00199     else
00200     {
00201         // use the "AL" lettering scheme for these older datum ellipsoids.
00202         std::string eName = _refSRS->getEllipsoid()->getName();
00203         _useAL = 
00204             eName.find("bessel") != std::string::npos ||
00205             eName.find("clark")  != std::string::npos ||
00206             eName.find("clrk")   != std::string::npos;
00207     }
00208 }
00209 
00210 std::string
00211 MGRSFormatter::format( double latDeg, double lonDeg ) const
00212 {
00213     unsigned    zone;
00214     char        gzd;
00215     unsigned    x=0, y=0;
00216     char        sqid[3];
00217     std::string space;
00218 
00219     if ( _options & USE_SPACES )
00220         space = " ";
00221 
00222     sqid[0] = '?';
00223     sqid[1] = '?';
00224     sqid[2] = 0;
00225 
00226     if ( latDeg >= 84.0 || latDeg <= -80.0 ) // polar projection
00227     {
00228         bool isNorth = latDeg > 0.0;
00229         zone = 0;
00230         gzd = isNorth ? (lonDeg < 0.0 ? 'Y' : 'Z') : (lonDeg < 0.0? 'A' : 'B');
00231 
00232         osg::ref_ptr<const SpatialReference> ups = isNorth?
00233             SpatialReference::create( "+proj=stere +lat_ts=90 +lat_0=90 +lon_0=0 +k_0=1 +x_0=0 +y_0=0" ) :
00234             SpatialReference::create( "+proj=stere +lat_ts=-90 +lat_0=-90 +lon_0=0 +k_0=1 +x_0=0 +y_0=0" );
00235 
00236         if ( !ups.valid() )
00237         {
00238             OE_WARN << LC << "Failed to create UPS SRS" << std::endl;
00239             return "";
00240         }
00241 
00242         double upsX, upsY;
00243         if ( _refSRS->transform2D( lonDeg, latDeg, ups.get(), upsX, upsY ) == false )
00244         {
00245             OE_WARN << LC << "Failed to transform lat/long to UPS" << std::endl;
00246             return "";
00247         }
00248 
00249         int sqXOffset = upsX >= 0.0 ? (int)floor(upsX/100000.0) : -(int)floor(1.0-(upsX/100000.0));
00250         int sqYOffset = upsY >= 0.0 ? (int)floor(upsY/100000.0) : -(int)floor(1.0-(upsY/100000.0));
00251 
00252         int alphaOffset = isNorth ? 7 : 12;
00253 
00254         sqid[0] = UPS_COL_ALPHABET[ (UPS_COL_ALPHABET_SIZE+sqXOffset) % UPS_COL_ALPHABET_SIZE ];
00255         sqid[1] = UPS_ROW_ALPHABET[alphaOffset + sqYOffset];
00256 
00257         x = upsX - (100000.0*(double)sqXOffset);
00258         y = upsY - (100000.0*(double)sqYOffset);
00259     }
00260 
00261     else // UTM
00262     {
00263         // figure out the grid zone designator
00264         unsigned gzdIndex = ((unsigned)(latDeg+80.0))/8;
00265         gzd = GZD_ALPHABET[gzdIndex];
00266 
00267         // figure out the UTM zone:
00268         zone = (unsigned)floor((lonDeg+180.0)/6.0);   // [0..59]
00269         bool north = latDeg >= 0.0;
00270 
00271         // convert the input coordinates to UTM:
00272         // yes, always use +north so we get Y relative to equator
00273         std::stringstream buf;
00274         buf << "+proj=utm +zone=" << (zone+1) << " +north +units=m";
00275         osg::ref_ptr<SpatialReference> utm = SpatialReference::create( buf.str() );
00276 
00277         double utmX, utmY;
00278         if ( _refSRS->transform2D( lonDeg, latDeg, utm.get(), utmX, utmY ) == false )
00279         {
00280             OE_WARN << LC << "Error transforming lat/long into UTM" << std::endl;
00281             return "";
00282         }
00283 
00284         // the alphabet set:
00285         unsigned set = zone % 6; // [0..5]
00286 
00287         // find the horizontal SQID offset (100KM increments) from the central meridian:
00288         unsigned xSetOffset = 8 * (set % 3);
00289         double xMeridianOffset = utmX - 500000.0;
00290         int sqMeridianOffset = xMeridianOffset >= 0.0 ? (int)floor(xMeridianOffset/100000.0) : -(int)floor(1.0-(xMeridianOffset/100000.0));
00291         unsigned indexOffset = (4 + sqMeridianOffset);
00292         sqid[0] = UTM_COL_ALPHABET[xSetOffset + indexOffset];
00293         double xWest = 500000.0 + (100000.0*(double)sqMeridianOffset);
00294         x = utmX - xWest;
00295 
00296         // find the vertical SQID offset (100KM increments) from the equator:
00297         unsigned ySetOffset = 5 * (zone % 2); //(set % 2);
00298         int sqEquatorOffset = (int)floor(utmY/100000.0);
00299         int absOffset = ySetOffset + sqEquatorOffset + (10 * UTM_ROW_ALPHABET_SIZE);
00300         if ( _useAL )
00301             absOffset += 10;
00302         sqid[1] = UTM_ROW_ALPHABET[absOffset % UTM_ROW_ALPHABET_SIZE];
00303         y = utmY - (100000.0*(double)sqEquatorOffset);
00304     }
00305 
00306     std::stringstream buf;
00307 
00308     if ( (unsigned)_precision > PRECISION_1M )
00309     {
00310         x /= (unsigned)_precision;
00311         y /= (unsigned)_precision;
00312     }
00313 
00314     buf << (zone+1) << gzd << space << sqid;
00315 
00316     if ( (unsigned)_precision < PRECISION_100000M )
00317     {
00318         int sigdigs =
00319             _precision == PRECISION_10000M ? 1 :
00320             _precision == PRECISION_1000M  ? 2 :
00321             _precision == PRECISION_100M   ? 3 :
00322             _precision == PRECISION_10M    ? 4 :
00323             5;
00324 
00325         buf << space
00326             << std::setfill('0')
00327             << std::setw(sigdigs) << x
00328             << space
00329             << std::setw(sigdigs) << y;
00330     }
00331 
00332     std::string result;
00333     result = buf.str();
00334     return result;
00335 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines