00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <vector>
00011 #include <sstream>
00012 #include <stdexcept>
00013 #include <iomanip>
00014 #include <cerrno>
00015 #include "GeographicLib/GeoCoords.hpp"
00016 #include "GeographicLib/MGRS.hpp"
00017 #include "GeographicLib/DMS.hpp"
00018
00019 namespace {
00020 char RCSID[] = "$Id: GeoCoords.cpp 6555 2009-02-25 16:04:25Z ckarney $";
00021 char RCSID_H[] = GEOCOORDS_HPP;
00022 }
00023
00024 namespace GeographicLib {
00025
00026 using namespace std;
00027
00028 void GeoCoords::Reset(const std::string& s) {
00029 vector<string> sa;
00030 bool in = false;
00031 for (unsigned i = 0; i < s.size(); ++i) {
00032 if (isspace(s[i]) || s[i] == ',') {
00033 in = false;
00034 continue;
00035 }
00036 if (!in)
00037 sa.push_back("");
00038 in = true;
00039 sa.back().push_back(s[i]);
00040 }
00041 if (sa.size() == 1) {
00042 int prec;
00043 MGRS::Reverse(sa[0], _zone, _northp, _easting, _northing, prec);
00044 UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00045 _lat, _long, _gamma, _k);
00046 } else if (sa.size() == 2) {
00047 DMS::DecodeLatLon(sa[0], sa[1], _lat, _long);
00048 UTMUPS::Forward( _lat, _long,
00049 _zone, _northp, _easting, _northing, _gamma, _k);
00050 } else if (sa.size() == 3) {
00051 unsigned zoneind, coordind;
00052 if (sa[0].size() > 0 && isalpha(sa[0][sa[0].size() - 1])) {
00053 zoneind = 0;
00054 coordind = 1;
00055 } else if (sa[2].size() > 0 && isalpha(sa[2][sa[2].size() - 1])) {
00056 zoneind = 2;
00057 coordind = 0;
00058 } else
00059 throw out_of_range("Neither " + sa[0] + " nor " + sa[2] +
00060 " of the form UTM/UPS Zone + Hemisphere" +
00061 " (ex: 38N, 09S, N)");
00062 char hemi = toupper(sa[zoneind][sa[zoneind].size() - 1]);
00063 _northp = hemi == 'N';
00064 if (! (_northp || hemi == 'S'))
00065 throw out_of_range(string("Illegal hemisphere letter ") + hemi
00066 + " in " + sa[zoneind]);
00067 const char* c = sa[zoneind].c_str();
00068 char* q;
00069 _zone = strtol(c, &q, 10);
00070 if (q - c != int(sa[zoneind].size()) - 1)
00071 throw out_of_range("Extra text in UTM/UPS zone " + sa[zoneind]);
00072 if (q > c && _zone == 0)
00073
00074 throw out_of_range("Illegal zone 0 in " + sa[zoneind]);
00075 if (q == c)
00076 _zone = 0;
00077 for (unsigned i = 0; i < 2; ++i) {
00078 const char* c = sa[coordind + i].c_str();
00079 errno = 0;
00080 double x = strtod(c, &q);
00081 if (errno == ERANGE || !isfinite(x))
00082 throw out_of_range("Number " + sa[coordind + i] + " out of range");
00083 if (q - c != int(sa[coordind + i].size()))
00084 throw out_of_range(string("Extra text in UTM/UPS ") +
00085 (i == 0 ? "easting " : "northing ") +
00086 sa[coordind + i]);
00087 if (i == 0)
00088 _easting = x;
00089 else
00090 _northing = x;
00091 }
00092 UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00093 _lat, _long, _gamma, _k);
00094 FixHemisphere();
00095 } else
00096 throw out_of_range("Coordinate requires 1, 2, or 3 elements");
00097 CopyToAlt();
00098 }
00099
00100
00101 string GeoCoords::GeoRepresentation(int prec) const {
00102 prec = max(0, min(9, prec) + 5);
00103 ostringstream os;
00104 os << fixed << setprecision(prec)
00105 << _lat << " " << _long;
00106 return os.str();
00107 }
00108
00109 string GeoCoords::DMSRepresentation(int prec) const {
00110 prec = max(0, min(10, prec) + 5);
00111 return DMS::Encode(_lat, unsigned(prec), DMS::LATITUDE) +
00112 " " + DMS::Encode(_long, unsigned(prec), DMS::LONGITUDE);
00113 }
00114
00115 string GeoCoords::MGRSRepresentation(int prec) const {
00116
00117 prec = max(0, min(6, prec) + 5);
00118 string mgrs;
00119 MGRS::Forward(_zone, _northp, _easting, _northing, _lat, prec, mgrs);
00120 return mgrs;
00121 }
00122
00123 string GeoCoords::AltMGRSRepresentation(int prec) const {
00124
00125 prec = max(0, min(6, prec) + 5);
00126 string mgrs;
00127 MGRS::Forward(_alt_zone, _northp, _alt_easting, _alt_northing, _lat, prec,
00128 mgrs);
00129 return mgrs;
00130 }
00131
00132 void GeoCoords::UTMUPSString(int zone, double easting, double northing,
00133 int prec, std::string& utm) const {
00134 ostringstream os;
00135 os << fixed << setfill('0');
00136 if (zone)
00137 os << setw(2) << zone;
00138 prec = max(-5, min(9, prec));
00139 double scale = prec < 0 ? pow(10.0, -prec) : 1.0;
00140 os << (_northp ? 'N' : 'S') << " "
00141 << setprecision(max(0, prec))
00142 << easting / scale;
00143 if (prec < 0 && abs(easting / scale) > 0.5)
00144 os << setw(-prec) << 0;
00145 os << " "
00146 << setprecision(max(0, prec))
00147 << northing / scale;
00148 if (prec < 0 && abs(northing / scale) > 0.5)
00149 os << setw(-prec) << 0;
00150 utm = os.str();
00151 }
00152
00153 string GeoCoords::UTMUPSRepresentation(int prec) const {
00154 string utm;
00155 UTMUPSString(_zone, _easting, _northing, prec, utm);
00156 return utm;
00157 }
00158
00159 string GeoCoords::AltUTMUPSRepresentation(int prec) const {
00160 string utm;
00161 UTMUPSString(_alt_zone, _alt_easting, _alt_northing, prec, utm);
00162 return utm;
00163 }
00164
00165 void GeoCoords::FixHemisphere() {
00166 if (_lat == 0 || (_northp && _lat > 0) || (!_northp && _lat < 0))
00167
00168 return;
00169 if (_zone > 0) {
00170 _northing += (_northp ? 1 : -1) * MGRS::utmNshift;
00171 _northp = !_northp;
00172 } else
00173 throw out_of_range("Hemisphere mixup");
00174 }
00175
00176 }