GeoCoords.cpp

Go to the documentation of this file.
00001 /**
00002  * \file GeoCoords.cpp
00003  * \brief Implementation for GeographicLib::GeoCoords class
00004  *
00005  * Copyright (c) Charles Karney (2008, 2009, 2010) <charles@karney.com>
00006  * and licensed under the LGPL.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  **********************************************************************/
00009 
00010 #include "GeographicLib/GeoCoords.hpp"
00011 #include "GeographicLib/MGRS.hpp"
00012 #include "GeographicLib/DMS.hpp"
00013 #include <vector>
00014 #include <sstream>
00015 #include <iomanip>
00016 
00017 #define GEOGRAPHICLIB_GEOCOORDS_CPP "$Id: GeoCoords.cpp 6785 2010-01-05 22:15:42Z karney $"
00018 
00019 RCSID_DECL(GEOGRAPHICLIB_GEOCOORDS_CPP)
00020 RCSID_DECL(GEOGRAPHICLIB_GEOCOORDS_HPP)
00021 
00022 namespace GeographicLib {
00023 
00024   using namespace std;
00025 
00026   void GeoCoords::Reset(const std::string& s, bool centerp) {
00027     vector<string> sa;
00028     const char* spaces = " \t\n\v\f\r,"; // Include comma as a space
00029     const char* digits = "0123456789.";  // Include period as a digit
00030     for (string::size_type pos0 = 0, pos1; pos0 != string::npos;) {
00031       pos1 = s.find_first_not_of(spaces, pos0);
00032       if (pos1 == string::npos)
00033         break;
00034       pos0 = s.find_first_of(spaces, pos1);
00035       sa.push_back(s.substr(pos1, pos0 == string::npos ? pos0 : pos0 - pos1));
00036     }
00037     if (sa.size() == 1) {
00038       int prec;
00039       MGRS::Reverse(sa[0], _zone, _northp, _easting, _northing, prec, centerp);
00040       UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00041                       _lat, _long, _gamma, _k);
00042     } else if (sa.size() == 2) {
00043       DMS::DecodeLatLon(sa[0], sa[1], _lat, _long);
00044       UTMUPS::Forward( _lat, _long,
00045                        _zone, _northp, _easting, _northing, _gamma, _k);
00046     } else if (sa.size() == 3) {
00047       unsigned zoneind, coordind;
00048       if (sa[0].size() > 0 && isalpha(sa[0][sa[0].size() - 1])) {
00049         zoneind = 0;
00050         coordind = 1;
00051       } else if (sa[2].size() > 0 && isalpha(sa[2][sa[2].size() - 1])) {
00052         zoneind = 2;
00053         coordind = 0;
00054       } else
00055         throw GeographicErr("Neither " + sa[0] + " nor " + sa[2]
00056                             + " of the form UTM/UPS Zone + Hemisphere"
00057                             + " (ex: 38N, 09S, N)");
00058       UTMUPS::DecodeZone(sa[zoneind], _zone, _northp);
00059       for (unsigned i = 0; i < 2; ++i) {
00060         istringstream str(sa[coordind + i]);
00061         real x;
00062         if (!(str >> x))
00063           throw GeographicErr("Bad number " + sa[coordind + i]
00064                               + " for UTM/UPS "
00065                               + (i == 0 ? "easting " : "northing "));
00066         // Both g++ and VS handle "str >> x" incorrectly when the string is
00067         // 1234E.  (The "right" result would be to handle it the same way as
00068         // 1234X; x is set to 1234 with tellg() is 4.)  VS fails to read any
00069         // number (which is incorrect but which is OK here).  Linux reads past
00070         // the "E" and a following sign if there is one; we need to detect this
00071         // and report it as an error.  So look for last character which is
00072         // legal as the final character in a number (digit or period).
00073         int pos = min(int(str.tellg()),
00074                       int(sa[coordind + i].find_last_of(digits)) + 1);
00075         if (pos != int(sa[coordind + i].size()))
00076           throw GeographicErr("Extra text "
00077                               + sa[coordind + i].substr(pos) + " in UTM/UPS "
00078                               + (i == 0 ? "easting " : "northing ")
00079                               + sa[coordind + i]);
00080         (i ? _northing : _easting) = x;
00081       }
00082       UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00083                       _lat, _long, _gamma, _k);
00084       FixHemisphere();
00085     } else
00086       throw GeographicErr("Coordinate requires 1, 2, or 3 elements");
00087     CopyToAlt();
00088   }
00089 
00090 
00091   string GeoCoords::GeoRepresentation(int prec) const {
00092     prec = max(0, min(9, prec) + 5);
00093     ostringstream os;
00094     os << fixed << setprecision(prec) << _lat << " " << _long;
00095     return os.str();
00096   }
00097 
00098   string GeoCoords::DMSRepresentation(int prec) const {
00099     prec = max(0, min(10, prec) + 5);
00100     return DMS::Encode(_lat, unsigned(prec), DMS::LATITUDE) +
00101       " " + DMS::Encode(_long, unsigned(prec), DMS::LONGITUDE);
00102   }
00103 
00104   string GeoCoords::MGRSRepresentation(int prec) const {
00105     // Max precision is um
00106     prec = max(0, min(6, prec) + 5);
00107     string mgrs;
00108     MGRS::Forward(_zone, _northp, _easting, _northing, _lat, prec, mgrs);
00109     return mgrs;
00110   }
00111 
00112   string GeoCoords::AltMGRSRepresentation(int prec) const {
00113     // Max precision is um
00114     prec = max(0, min(6, prec) + 5);
00115     string mgrs;
00116     MGRS::Forward(_alt_zone, _northp, _alt_easting, _alt_northing, _lat, prec,
00117                   mgrs);
00118     return mgrs;
00119   }
00120 
00121   void GeoCoords::UTMUPSString(int zone, real easting, real northing, int prec,
00122                                std::string& utm) const {
00123     ostringstream os;
00124     prec = max(-5, min(9, prec));
00125     real scale = prec < 0 ? pow(real(10), -prec) : real(1);
00126     os << UTMUPS::EncodeZone(zone, _northp) << fixed << setfill('0');
00127     os << " " << setprecision(max(0, prec)) << easting / scale;
00128     if (prec < 0 && abs(easting / scale) > real(0.5))
00129       os << setw(-prec) << 0;
00130     os << " " << setprecision(max(0, prec)) << northing / scale;
00131     if (prec < 0 && abs(northing / scale) > real(0.5))
00132       os << setw(-prec) << 0;
00133     utm = os.str();
00134   }
00135 
00136   string GeoCoords::UTMUPSRepresentation(int prec) const {
00137     string utm;
00138     UTMUPSString(_zone, _easting, _northing, prec, utm);
00139     return utm;
00140   }
00141 
00142   string GeoCoords::AltUTMUPSRepresentation(int prec) const {
00143     string utm;
00144     UTMUPSString(_alt_zone, _alt_easting, _alt_northing, prec, utm);
00145     return utm;
00146   }
00147 
00148   void GeoCoords::FixHemisphere() {
00149     if (_lat == 0 || (_northp && _lat >= 0) || (!_northp && _lat < 0))
00150       // Allow either hemisphere for equator
00151       return;
00152     if (_zone != UTMUPS::UPS) {
00153       _northing += (_northp ? 1 : -1) * UTMUPS::UTMShift();
00154       _northp = !_northp;
00155     } else
00156       throw GeographicErr("Hemisphere mixup");
00157   }
00158 
00159 } // namespace GeographicLib

Generated on 21 May 2010 for GeographicLib by  doxygen 1.6.1