GeoCoords.hpp
Go to the documentation of this file.
00001 /**
00002  * \file GeoCoords.hpp
00003  * \brief Header for GeographicLib::GeoCoords 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 #ifndef GEOCOORDS_HPP
00011 #define GEOCOORDS_HPP "$Id: GeoCoords.hpp 6543 2009-02-17 11:36:37Z ckarney $"
00012 
00013 #include <cmath>
00014 #include <string>
00015 #include <cstdlib>
00016 #include "GeographicLib/UTMUPS.hpp"
00017 #if defined(_MSC_VER)
00018 #include <float.h>              // For _finite
00019 #endif
00020 
00021 namespace GeographicLib {
00022 
00023   /**
00024    * \brief Conversion between geographic coordinates
00025    *
00026    * This class stores a geographic position which may be set via the
00027    * constructors or Reset via
00028    * - latitude and longitude
00029    * - UTM or UPS coordinates
00030    * - a string represention of these or an MGRS coordinate string
00031    *
00032    * The state consists of the latitude and longitude and the supplied UTM or
00033    * UPS coordinates (possibly derived from the MGRS coordinates).  If latitude
00034    * and longitude were given then the UTM/UPS coordinates follows the standard
00035    * conventions.
00036    *
00037    * The mutable state consists of the UTM or UPS coordinates for a alternate
00038    * zone.  A method SetAltZone is provided to set the alternate UPS/UTM zone.
00039    *
00040    * Methods are provided to return the geographic coordinates, the input UTM
00041    * or UPS coordinates (and associated meridian convergence and scale), or
00042    * alternate UTM or UPS coordinates (and their associated meridian
00043    * convergence and scale).
00044    *
00045    * Once the input string has been parsed, you can print the result out in any
00046    * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS.
00047    **********************************************************************/
00048   class GeoCoords {
00049   private:
00050     double _lat, _long, _easting, _northing, _gamma, _k;
00051     bool _northp;
00052     int _zone;                  // 0 = poles, -1 = undefined
00053     mutable double _alt_easting, _alt_northing, _alt_gamma, _alt_k;
00054     mutable int _alt_zone;
00055 
00056     void CopyToAlt() const throw() {
00057       _alt_easting = _easting;
00058       _alt_northing = _northing;
00059       _alt_gamma = _gamma;
00060       _alt_k = _k;
00061       _alt_zone = _zone;
00062     }
00063     void UTMUPSString(int zone, double easting, double northing,
00064                    int prec, std::string& utm) const;
00065     void FixHemisphere();
00066 #if defined(_MSC_VER)
00067     static inline int isfinite(double x) throw() { return _finite(x); }
00068 #else
00069     static inline int isfinite(double x) throw() { return std::isfinite(x); }
00070     static inline int isnan(double x) throw() { return std::isnan(x); }
00071     static inline int isinf(double x) throw() { return std::isinf(x); }
00072 #endif
00073   public:
00074 
00075     /**
00076      * The default contructor is equivalent to \e latitude = 90<sup>o</sup>, \e
00077      * longitude = 0<sup>o</sup>.
00078      **********************************************************************/
00079     GeoCoords() throw()
00080       // This is the N pole
00081       : _lat(90.0)
00082       , _long(0.0)
00083       , _easting(2000000.0)
00084       , _northing(2000000.0)
00085       , _northp(true)
00086       , _zone(0)
00087     { CopyToAlt();}
00088 
00089     /**
00090      * Parse as a string and interpret it as a geographic position.  The input
00091      * string is broken into space (or comma) separated pieces and Basic
00092      * decision on which format is based on number of components
00093      * -# MGRS
00094      * -# "Lat Long" or "Long Lat"
00095      * -# "Zone Easting Northing" or "Easting Northing Zone"
00096      *
00097      * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq)
00098      * - Latitude and Longitude
00099      *   -  33.44      43.27
00100      *   -  N33d26.4'  E43d16.2'
00101      *   -  43d16'12"E 33d26'24"N
00102      * - MGRS
00103      *   -  38SLC301
00104      *   -  38SLC391014
00105      *   -  38SLC3918701405
00106      *   -  37SHT9708
00107      * - UTM
00108      *   -  38N 339188 3701405
00109      *   -  897039 3708229 37N
00110      *
00111      * Latitude and Longitude parsing.  Latitude precedes longitude, unless a
00112      * N, S, E, W hemisphere designator is used on one or both coordinates.
00113      * Thus
00114      * - 40 -75
00115      * - N40 W75
00116      * - -75 N40
00117      * - 75W 40N
00118      * - E-75 -40S
00119      * .
00120      * are all the same position.  The coodinates may be given in decimal
00121      * degrees, degrees and decimal minutes, degrees, minutes, seconds, etc.
00122      * Use d, ', and " to make off the degrees, minutes and seconds.  Thus
00123      * - 40d30'30"
00124      * - 40d30'30
00125      * - 40d30.5'
00126      * - 40d30.5
00127      * - 40.508333333
00128      * .
00129      * all specify the same angle.  The leading sign applies to all components
00130      * so -1d30 is -(1+30/60) = -1.5.  Latitudes must be in the range [-90, 90]
00131      * and longitudes in the range [-180, 360].  Internally longitudes are
00132      * reduced to the range [-180, 180).
00133      *
00134      * UTM/UPS parsing.  For UTM zones (-80 <= Lat <= 84), the zone designator
00135      * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or
00136      * S), e.g., 38N.  The latitude zone designer ([C&ndash;M] in the southern
00137      * hemisphere and [N&ndash;X] in the northern) should NOT be used.  (This
00138      * is part of the MGRS coordinate.)  The zone designator for the poles
00139      * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S.
00140      *
00141      * MGRS parsing interprets the grid references as square area at the
00142      * specified precision (1m, 10m, 100m, etc.).  The center of this square is
00143      * then taken to be the precise position.  Thus:
00144      * - 38SMB           = 38N 450000 3650000
00145      * - 38SMB4484       = 38N 444500 3684500
00146      * - 38SMB44148470   = 38N 444145 3684705
00147      **********************************************************************/
00148     GeoCoords(const std::string& s) { Reset(s); }
00149 
00150     /**
00151      * Specify the location in terms of \e latitude (degrees) and \e longitude
00152      * (degrees).  Use \e zone to force the UTM/UPS representation to use
00153      * a specified zone (\e zone = 0 means UPS).  Omitting the third argument
00154      * causes the standard zone to be used.
00155      **********************************************************************/
00156     GeoCoords(double latitude, double longitude, int zone = -1) {
00157       Reset(latitude, longitude, zone);
00158     }
00159 
00160     /**
00161      * Specify the location in terms of UPS/UPS \e zone (zero means UPS),
00162      * hemisphere \e northp (false means south, true means north), \e easting
00163      * (meters) and \e northing (meters).
00164      **********************************************************************/
00165     GeoCoords(int zone, bool northp, double easting, double northing) {
00166       Reset(zone, northp, easting, northing);
00167     }
00168 
00169     /**
00170      * Reset the location as a 1-element, 2-element, or 3-element string.  See
00171      * GeoCoords(const string& s).
00172      **********************************************************************/
00173     void Reset(const std::string& s);
00174 
00175     /**
00176      * Reset the location in terms of \e latitude and \e longitude.  See
00177      * GeoCoords(double latitude, double longitude, int zone).
00178      **********************************************************************/
00179     void Reset(double latitude, double longitude, int zone = -1) {
00180       _lat = latitude;
00181       _long = longitude;
00182       UTMUPS::Forward(_lat, _long,
00183                       _zone, _northp, _easting, _northing, _gamma, _k,
00184                       zone);
00185       if (_long >= 180)
00186         _long -= 360;
00187       CopyToAlt();
00188     }
00189 
00190     /**
00191      * Reset the location in terms of UPS/UPS \e zone, hemisphere \e northp, \e
00192      * easting, and \e northing.  See GeoCoords(int zone, bool northp, double
00193      * easting, double northing).
00194      **********************************************************************/
00195     void Reset(int zone, bool northp, double easting, double northing) {
00196       _zone = zone;
00197       _northp = northp;
00198       _easting = easting;
00199       _northing = northing;
00200       UTMUPS::Reverse(_zone, _northp, _easting, _northing,
00201                       _lat, _long, _gamma, _k);
00202       FixHemisphere();
00203       CopyToAlt();
00204     }
00205 
00206     /**
00207      * Return latitude (degrees)
00208      **********************************************************************/
00209     double Latitude() const throw() { return _lat; }
00210 
00211     /**
00212      * Return longitude (degrees)
00213      **********************************************************************/
00214     double Longitude() const throw() { return _long; }
00215 
00216     /**
00217      * Return easting (meters)
00218      **********************************************************************/
00219     double Easting() const throw() { return _easting; }
00220 
00221     /**
00222      * Return northing (meters)
00223      **********************************************************************/
00224     double Northing() const throw() { return _northing; }
00225 
00226     /**
00227      * Return meridian convergence (degrees) for the UTM/UPS projection.
00228      **********************************************************************/
00229     double Convergence() const throw() { return _gamma; }
00230 
00231     /**
00232      * Return scale for the UTM/UPS projection.
00233      **********************************************************************/
00234     double Scale() const throw() { return _k; }
00235 
00236     /**
00237      * Return hemisphere (false means south, true means north).
00238      **********************************************************************/
00239     bool Northp() const throw() { return _northp; }
00240 
00241     /**
00242      * Return hemisphere letter N or S.
00243      **********************************************************************/
00244     char Hemisphere() const throw() { return _northp ? 'N' : 'S'; }
00245 
00246     /**
00247      * Return the zone corresponding to the input (return 0 for UPS).
00248      **********************************************************************/
00249     int Zone() const throw() { return _zone; }
00250 
00251     /**
00252      * Set the zone (default, -1, means use the standard zone) for the
00253      * alternate representation.  Before this is called the alternate zone is
00254      * the input zone.
00255      **********************************************************************/
00256     void SetAltZone(int zone = -1) const {
00257       if (zone == _zone ||
00258           (zone < 0 && _zone == UTMUPS::StandardZone(_lat, _long)))
00259         CopyToAlt();
00260       else {
00261         bool northp;
00262         UTMUPS::Forward(_lat, _long,
00263                         _alt_zone, northp,
00264                         _alt_easting, _alt_northing, _alt_gamma, _alt_k,
00265                         zone);
00266       }
00267     }
00268 
00269     /**
00270      * Returns the current alternate zone (return 0 for UPS).
00271      **********************************************************************/
00272     int AltZone() const throw() { return _alt_zone; }
00273 
00274     /**
00275      * Return easting (meters) for alternate zone.
00276      **********************************************************************/
00277     double AltEasting() const throw() { return _alt_easting; }
00278 
00279     /**
00280      * Return northing (meters) for alternate zone.
00281      **********************************************************************/
00282     double AltNorthing() const throw() { return _alt_northing; }
00283 
00284     /**
00285      * Return meridian convergence (degrees) for altermate zone.
00286      **********************************************************************/
00287     double AltConvergence() const throw() { return _alt_gamma; }
00288 
00289     /**
00290      * Return scale for altermate zone.
00291      **********************************************************************/
00292     double AltScale() const throw() { return _alt_k; }
00293 
00294     /**
00295      * Return string with latitude and longitude as signed decimal degrees.
00296      * Precision \e prec specifies accuracy of representation as follows:
00297      * - prec = -5 (min), 1d
00298      * - prec = 0, 10<sup>-5</sup>d (about 1m)
00299      * - prec = 3, 10<sup>-8</sup>d
00300      * - prec = 9 (max), 10<sup>-14</sup>d
00301      **********************************************************************/
00302     std::string GeoRepresentation(int prec = 0) const;
00303 
00304     /**
00305      * Return string with latitude and longitude as degrees, minutes, seconds,
00306      * and hemisphere.  Precision \e prec specifies accuracy of representation
00307      * as follows:
00308      * - prec = -5 (min), 1d
00309      * - prec = -4, 0.1d
00310      * - prec = -3, 1'
00311      * - prec = -2, 0.1'
00312      * - prec = -1, 1"
00313      * - prec = 0, 0.1" (about 3m)
00314      * - prec = 1, 0.01"
00315      * - prec = 10 (max), 10<sup>-11</sup>"
00316      **********************************************************************/
00317     std::string DMSRepresentation(int prec = 0) const;
00318 
00319     /**
00320      * Return MGRS string.  This gives the coordinates of the enclosing grid
00321      * square with size given by the precision \e prec.  Thus 38N 444180
00322      * 3684790 converted to a MGRS coordinate at precision -2 (100m) is
00323      * 38SMB441847 and not 38SMB442848.  Precision \e prec specifies the
00324      * precision of the MSGRS string as follows:
00325      * - prec = -5 (min), 100km
00326      * - prec = -4, 10km
00327      * - prec = -3, 1km
00328      * - prec = -2, 100m
00329      * - prec = -1, 10m
00330      * - prec = 0, 1m
00331      * - prec = 1, 0.1m
00332      * - prec = 6 (max), 1um
00333      **********************************************************************/
00334     std::string MGRSRepresentation(int prec = 0) const;
00335 
00336     /**
00337      * Return string consisting of UTM/UPS zone designator, easting, and
00338      * northing,  Precision \e prec specifies accuracy of representation
00339      * as follows:
00340      * - prec = -5 (min), 100km
00341      * - prec = -3, 1km
00342      * - prec = 0, 1m
00343      * - prec = 3, 1mm
00344      * - prec = 6, 1um
00345      * - prec = 9 (max), 1nm
00346      **********************************************************************/
00347     std::string UTMUPSRepresentation(int prec = 0) const;
00348 
00349     /**
00350      * Return MGRS string using alternative zone.  See MGRSRepresentation for
00351      * the interpretation of \e prec.
00352      **********************************************************************/
00353     std::string AltMGRSRepresentation(int prec = 0) const;
00354 
00355     /**
00356      * Return string consisting of alternate UTM/UPS zone designator, easting,
00357      * and northing.  See UTMUPSRepresentation for the interpretation of \e
00358      * prec.
00359      **********************************************************************/
00360     std::string AltUTMUPSRepresentation(int prec = 0) const;
00361   };
00362 
00363 } // namespace GeographicLib
00364 #endif  // GEOCOORDS_HPP