00001 /** 00002 * \file DMS.hpp 00003 * \brief Header for GeographicLib::DMS class 00004 * 00005 * Copyright (c) Charles Karney (2008) <charles@karney.com> 00006 * http://charles.karney.info/geographic 00007 * and licensed under the LGPL. 00008 **********************************************************************/ 00009 00010 #if !defined(DMS_HPP) 00011 #define DMS_HPP "$Id: DMS.hpp 6572 2009-03-01 22:41:48Z ckarney $" 00012 00013 #include <string> 00014 #include <sstream> 00015 00016 namespace GeographicLib { 00017 00018 /** 00019 * \brief Convert between degrees to %DMS representation. 00020 * 00021 * Parse a string representing degree, minutes, and seconds and return the 00022 * angle in degrees and format an angle in degrees as degree, minutes, and 00023 * seconds. 00024 **********************************************************************/ 00025 class DMS { 00026 private: 00027 static int lookup(const std::string& s, char c) throw() { 00028 std::string::size_type r = s.find(toupper(c)); 00029 return r == std::string::npos ? -1 : int(r); 00030 } 00031 template<typename T> static std::string str(T x) { 00032 std::ostringstream s; s << x; return s.str(); 00033 } 00034 static const std::string hemispheres; 00035 static const std::string signs; 00036 static const std::string digits; 00037 static const std::string dmsindicators; 00038 static const std::string components[3]; 00039 00040 public: 00041 00042 /** 00043 * Indicator for presence of hemisphere indicator (N/S/E/W) on latitudes 00044 * and longitudes. AZIMUTH is used in Encode to indicate output in [000, 00045 * 360) with no letter indicator. 00046 **********************************************************************/ 00047 enum flag { NONE = 0, LATITUDE = 1, LONGITUDE = 2, AZIMUTH = 3 }; 00048 00049 /** 00050 * Indicator for trailing units on an angle. 00051 **********************************************************************/ 00052 enum component { DEGREE = 0, MINUTE = 1, SECOND = 2 }; 00053 00054 /** 00055 * Read a string \e dms in DMS format and return the resulting angle in 00056 * degrees. Degrees, minutes, and seconds are indicated by the letters d, 00057 * ', ", and these components may only be given in this order. Any (but 00058 * not all) components may be omitted. The last component indicator may be 00059 * omitted and is assumed to be tbe next smallest unit (thus 33d10 is 00060 * interpreted as 33d10'). The final component may be a decimal fraction 00061 * but the non-final components must be integers. The integer parts of the 00062 * minutes and seconds components must be less than 60. A single leading 00063 * sign is permitted. A hemisphere designator (N, E, W, S) may be added to 00064 * tbe beginning or end of the string. The result is mulitplied by the 00065 * implied signed of the hemisphere designator (negative for S and W). In 00066 * addition \e flag is used to indicate whether such a designator was found 00067 * and whether it implies that the angle is a latitude (N or S) or 00068 * longitude (E or W). 00069 **********************************************************************/ 00070 static double Decode(const std::string& dms, flag& ind); 00071 00072 /** 00073 * Convert two strings \e dmsa and \e dmsb to a latitude, \e lat, and 00074 * longitude, \e lon. By default, the \e lat (resp., \e lon) is assigned 00075 * to the results of decoding \e dmsa (resp., \e dmsb). However this is 00076 * overridden if either \e dmsa or \e dmsb contain a latitude or longitude 00077 * hemisphere designator (N, S, E, W). 00078 **********************************************************************/ 00079 static void DecodeLatLon(const std::string& dmsa, const std::string& dmsb, 00080 double& lat, double& lon); 00081 00082 /** 00083 * Convert \e degree into a DMS string. \e trailing indicates the least 00084 * significant component of the string (and this component is given as a 00085 * decimal number if necessary). \e prec indicates the number of digits 00086 * after the decimal point for the trailing component. \e flag indicates 00087 * whether the result should be include a sign (if negative) or a trailing 00088 * latitude or longitude hemisphere indicator. In the latter two cases, 00089 * the integer part of the degrees component is given with 2 (latitude) or 00090 * 3 (longitude) digits (with leading zeros if necessary). The integer 00091 * parts of the minutes and seconds components are always given with 2 00092 * digits. 00093 **********************************************************************/ 00094 static std::string Encode(double degree, 00095 component trailing, 00096 unsigned prec, 00097 flag ind = NONE); 00098 00099 /** 00100 * Convert \e degree into a DMS string selecting the trailing component 00101 * based on \e prec. \e prec indicates the precision relative to 1 degree, 00102 * e.g., \e prec = 3 gives a result accurate to 0.1' and \e prec = 4 gives 00103 * a result accurate to 1". 00104 **********************************************************************/ 00105 static std::string Encode(double degree, 00106 unsigned prec, 00107 flag ind = NONE) { 00108 return Encode(degree, 00109 prec < 2 ? DEGREE : (prec < 4 ? MINUTE : SECOND), 00110 prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4), 00111 ind); 00112 } 00113 }; 00114 00115 } // namespace GeographicLib 00116 00117 #endif