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, 2009, 2010) <charles@karney.com>
00006  * and licensed under the LGPL.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  **********************************************************************/
00009 
00010 #if !defined(GEOGRAPHICLIB_DMS_HPP)
00011 #define GEOGRAPHICLIB_DMS_HPP "$Id: DMS.hpp 6827 2010-05-20 19:56:18Z karney $"
00012 
00013 #include "GeographicLib/Constants.hpp"
00014 #include <sstream>
00015 #include <iomanip>
00016 
00017 namespace GeographicLib {
00018 
00019   /**
00020    * \brief Convert between degrees and %DMS representation.
00021    *
00022    * Parse a string representing degree, minutes, and seconds and return the
00023    * angle in degrees and format an angle in degrees as degree, minutes, and
00024    * seconds.
00025    **********************************************************************/
00026   class DMS {
00027   private:
00028     typedef Math::real real;
00029     static int lookup(const std::string& s, char c) throw() {
00030       std::string::size_type r = s.find(toupper(c));
00031       return r == std::string::npos ? -1 : int(r);
00032     }
00033     template<typename T> static std::string str(T x) {
00034       std::ostringstream s; s << x; return s.str();
00035     }
00036     static const std::string hemispheres;
00037     static const std::string signs;
00038     static const std::string digits;
00039     static const std::string dmsindicators;
00040     static const std::string components[3];
00041     DMS();                      // Disable constructor
00042 
00043   public:
00044 
00045     /**
00046      * Indicator for presence of hemisphere indicator (N/S/E/W) on latitudes
00047      * and longitudes.  DMS::AZIMUTH is used in Encode to indicate output in
00048      * [000, 360) with no letter indicator.  DMS::NUMBER is used in Encode to
00049      * indicate the output of a plain number.
00050      **********************************************************************/
00051     enum flag { NONE = 0, LATITUDE = 1, LONGITUDE = 2, AZIMUTH = 3,
00052                 NUMBER = 4, };
00053 
00054     /**
00055      * Indicator for trailing units on an angle.
00056      **********************************************************************/
00057     enum component { DEGREE = 0, MINUTE = 1, SECOND = 2 };
00058 
00059     /**
00060      * Read a string \e dms in DMS format and return the resulting angle in
00061      * degrees.  Degrees, minutes, and seconds are indicated by the letters d,
00062      * ', &quot;, and these components may only be given in this order.  Any
00063      * (but not all) components may be omitted.  The last component indicator
00064      * may be omitted and is assumed to be tbe next smallest unit (thus 33d10
00065      * is interpreted as 33d10').  The final component may be a decimal
00066      * fraction but the non-final components must be integers.  The integer
00067      * parts of the minutes and seconds components must be less than 60.  A
00068      * single leading sign is permitted.  A hemisphere designator (N, E, W, S)
00069      * may be added to tbe beginning or end of the string.  The result is
00070      * multiplied by the implied signed of the hemisphere designator (negative
00071      * for S and W).  In addition \e flag is used to indicate whether such a
00072      * designator was found and whether it implies that the angle is a latitude
00073      * (N or S) or longitude (E or W).  Throws an error on a malformed string.
00074      * No check is performed on the range of the result.
00075      **********************************************************************/
00076     static Math::real Decode(const std::string& dms, flag& ind);
00077 
00078     /**
00079      * Convert real degrees \e d, minutes \e m, and seconds \e s, to degrees.
00080      * This does not propagate the sign on \e d to the other components, so
00081      * -3d20' would need to be represented as - DMS::Decode(3.0, 20.0) or
00082      * DMS::Decode(-3.0, -20.0).
00083      **********************************************************************/
00084     static Math::real Decode(real d, real m = 0, real s = 0) throw()
00085     { return d + (m + s/real(60))/real(60); }
00086 
00087     /**
00088      * Convert a string \e str to a real number.
00089      **********************************************************************/
00090     static Math::real Decode(const std::string& str);
00091 
00092     /**
00093      * Convert two strings \e dmsa and \e dmsb to a latitude, \e lat, and
00094      * longitude, \e lon.  By default, the \e lat (resp., \e lon) is assigned
00095      * to the results of decoding \e dmsa (resp., \e dmsb).  However this is
00096      * overridden if either \e dmsa or \e dmsb contain a latitude or longitude
00097      * hemisphere designator (N, S, E, W).  Throws an error if the decoded
00098      * numbers are out of the ranges [-90<sup>o</sup>, 90<sup>o</sup>] for
00099      * latitude and [-180<sup>o</sup>, 360<sup>o</sup>] for longitude and, in
00100      * which case \e lat and \e lon are unchanged.  Finally the longitude is
00101      * reduced to the range [-180<sup>o</sup>, 180<sup>o</sup>).
00102      **********************************************************************/
00103     static void DecodeLatLon(const std::string& dmsa, const std::string& dmsb,
00104                              real& lat, real& lon);
00105 
00106     /**
00107      * Convert a string \e angstr to an angle in degrees.  No hemisphere
00108      * designator is allowed and no check is done on the range of the result.
00109      **********************************************************************/
00110     static Math::real DecodeAngle(const std::string& angstr);
00111 
00112     /**
00113      * Convert a string \e azistr to an azimuth in degrees.  A hemisphere
00114      * designator E/W can be used; the result is multiplied by -1 if W is
00115      * present.  Throws an error if the result is out of the range
00116      * [-180<sup>o</sup>, 360<sup>o</sup>].  Finally the azimuth is reduced to
00117      * the range [-180<sup>o</sup>, 180<sup>o</sup>).
00118      **********************************************************************/
00119     static Math::real DecodeAzimuth(const std::string& azistr);
00120 
00121     /**
00122      * Convert \e angle (in degrees) into a DMS string.  \e trailing indicates
00123      * the least significant component of the string (and this component is
00124      * given as a decimal number if necessary).  \e prec indicates the number
00125      * of digits after the decimal point for the trailing component.  \e flag
00126      * indicates additional formating as follows
00127      * - flag == DMS::NONE, signed result no leading zeros on degrees except in
00128      *   the units place, e.g., -8d03'.
00129      * - flag == DMS::LATITUDE, trailing N or S hemisphere designator, no sign,
00130      *   pad degress to 2 digits, e.g., 08d03'S.
00131      * - flag == DMS::LONGITUDE, trailing E or W hemisphere designator, no
00132      *   sign, pad degress to 3 digits, e.g., 008d03'W.
00133      * - flag == DMS::AZIMUTH, convert to the range [0, 360<sup>o</sup>), no
00134      *   sign, pad degrees to 3 digits, , e.g., 351d57'.
00135      * .
00136      * The integer parts of the minutes and seconds components are always given
00137      * with 2 digits.
00138      **********************************************************************/
00139     static std::string Encode(real angle, component trailing, unsigned prec,
00140                               flag ind = NONE);
00141 
00142     /**
00143      * Convert \e angle into a DMS string selecting the trailing component
00144      * based on \e prec.  \e prec indicates the precision relative to 1 degree,
00145      * e.g., \e prec = 3 gives a result accurate to 0.1' and \e prec = 4 gives
00146      * a result accurate to 1&quot;.  If \e ind is DMS::NUMBER, then merely
00147      * format \e angle as a number in fixed format with precision \e prec.
00148      **********************************************************************/
00149     static std::string Encode(real angle, unsigned prec, flag ind = NONE) {
00150       if (ind == NUMBER) {
00151         std::ostringstream s;
00152         s << std::fixed << std::setprecision(prec) << angle;
00153         return s.str();
00154       } else
00155         return Encode(angle,
00156                       prec < 2 ? DEGREE : (prec < 4 ? MINUTE : SECOND),
00157                       prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4),
00158                       ind);
00159     }
00160 
00161     /**
00162      * Split angle, \e ang, into degrees, \e d, and minutes \e m.
00163      **********************************************************************/
00164     static void Encode(real ang, real& d, real& m) throw() {
00165       d = int(ang); m = 60 * (ang - d);
00166     }
00167 
00168     /**
00169      * Split angle, \e ang, into degrees, \e d, minutes, \e m, and seconds \e
00170      * s.
00171      **********************************************************************/
00172     static void Encode(real ang, real& d, real& m, real& s) throw() {
00173       d = int(ang); ang = 60 * (ang - d);
00174       m = int(ang); s = 60 * (ang - m);
00175     }
00176 
00177   };
00178 
00179 } // namespace GeographicLib
00180 
00181 #endif

Generated on 21 May 2010 for GeographicLib by  doxygen 1.6.1