DMS.hpp
Go to the documentation of this file.
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