GeographicLib  1.21
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-2011) <charles@karney.com> and licensed
00006  * under the MIT/X11 License.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  **********************************************************************/
00009 
00010 #include <GeographicLib/GeoCoords.hpp>
00011 #include <vector>
00012 #include <sstream>
00013 #include <iomanip>
00014 #include <GeographicLib/MGRS.hpp>
00015 #include <GeographicLib/DMS.hpp>
00016 
00017 #define GEOGRAPHICLIB_GEOCOORDS_CPP \
00018   "$Id: 084d4ec9163dc9d8989b54b12a04bf0f44a8c23f $"
00019 
00020 RCSID_DECL(GEOGRAPHICLIB_GEOCOORDS_CPP)
00021 RCSID_DECL(GEOGRAPHICLIB_GEOCOORDS_HPP)
00022 
00023 namespace GeographicLib {
00024 
00025   using namespace std;
00026 
00027   void GeoCoords::Reset(const std::string& s, bool centerp, bool swaplatlong) {
00028     vector<string> sa;
00029     const char* spaces = " \t\n\v\f\r,"; // Include comma as a space
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, swaplatlong);
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         (i ? _northing : _easting) = DMS::Decode(sa[coordind + i]);
00061       UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00062                       _lat, _long, _gamma, _k);
00063       FixHemisphere();
00064     } else
00065       throw GeographicErr("Coordinate requires 1, 2, or 3 elements");
00066     CopyToAlt();
00067   }
00068 
00069 
00070   string GeoCoords::GeoRepresentation(int prec, bool swaplatlong) const {
00071     prec = max(0, min(9, prec) + 5);
00072     ostringstream os;
00073     os << fixed << setprecision(prec);
00074     real a = swaplatlong ? _long : _lat;
00075     real b = swaplatlong ? _lat : _long;
00076     if (!Math::isnan(a))
00077       os << a;
00078     else
00079       os << "nan";
00080     os << " ";
00081     if (!Math::isnan(b))
00082       os << b;
00083     else
00084       os << "nan";
00085     return os.str();
00086   }
00087 
00088   string GeoCoords::DMSRepresentation(int prec, bool swaplatlong,
00089                                       char dmssep) const {
00090     prec = max(0, min(10, prec) + 5);
00091     return DMS::Encode(swaplatlong ? _long : _lat, unsigned(prec),
00092                        swaplatlong ? DMS::LONGITUDE : DMS::LATITUDE, dmssep) +
00093       " " + DMS::Encode(swaplatlong ? _lat : _long, unsigned(prec),
00094                         swaplatlong ? DMS::LATITUDE : DMS::LONGITUDE, dmssep);
00095   }
00096 
00097   string GeoCoords::DMSRepresentation(int prec, bool swaplatlong) const
00098   { return DMSRepresentation(prec, swaplatlong, char(0)); }
00099 
00100   string GeoCoords::MGRSRepresentation(int prec) const {
00101     // Max precision is um
00102     prec = max(0, min(6, prec) + 5);
00103     string mgrs;
00104     MGRS::Forward(_zone, _northp, _easting, _northing, _lat, prec, mgrs);
00105     return mgrs;
00106   }
00107 
00108   string GeoCoords::AltMGRSRepresentation(int prec) const {
00109     // Max precision is um
00110     prec = max(0, min(6, prec) + 5);
00111     string mgrs;
00112     MGRS::Forward(_alt_zone, _northp, _alt_easting, _alt_northing, _lat, prec,
00113                   mgrs);
00114     return mgrs;
00115   }
00116 
00117   void GeoCoords::UTMUPSString(int zone, real easting, real northing, int prec,
00118                                std::string& utm) const {
00119     ostringstream os;
00120     prec = max(-5, min(9, prec));
00121     real scale = prec < 0 ? pow(real(10), -prec) : real(1);
00122     os << UTMUPS::EncodeZone(zone, _northp) << fixed << setfill('0');
00123     if (Math::isfinite(easting)) {
00124       os << " " << setprecision(max(0, prec)) << easting / scale;
00125       if (prec < 0 && abs(easting / scale) > real(0.5))
00126         os << setw(-prec) << 0;
00127     } else
00128       os << " nan";
00129     if (Math::isfinite(northing)) {
00130       os << " " << setprecision(max(0, prec)) << northing / scale;
00131       if (prec < 0 && abs(northing / scale) > real(0.5))
00132         os << setw(-prec) << 0;
00133     } else
00134       os << " nan";
00135     utm = os.str();
00136   }
00137 
00138   string GeoCoords::UTMUPSRepresentation(int prec) const {
00139     string utm;
00140     UTMUPSString(_zone, _easting, _northing, prec, utm);
00141     return utm;
00142   }
00143 
00144   string GeoCoords::AltUTMUPSRepresentation(int prec) const {
00145     string utm;
00146     UTMUPSString(_alt_zone, _alt_easting, _alt_northing, prec, utm);
00147     return utm;
00148   }
00149 
00150   void GeoCoords::FixHemisphere() {
00151     if (_lat == 0 || (_northp && _lat >= 0) || (!_northp && _lat < 0) ||
00152         Math::isnan(_lat))
00153       // Allow either hemisphere for equator
00154       return;
00155     if (_zone != UTMUPS::UPS) {
00156       _northing += (_northp ? 1 : -1) * UTMUPS::UTMShift();
00157       _northp = !_northp;
00158     } else
00159       throw GeographicErr("Hemisphere mixup");
00160   }
00161 
00162 } // namespace GeographicLib