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, 2009, 2010) <charles@karney.com>
00006  * and licensed under the LGPL.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  **********************************************************************/
00009 
00010 #ifndef GEOGRAPHICLIB_GEOCOORDS_HPP
00011 #define GEOGRAPHICLIB_GEOCOORDS_HPP "$Id: GeoCoords.hpp 6876 2010-10-18 13:47:55Z karney $"
00012 
00013 #include "GeographicLib/UTMUPS.hpp"
00014 #include "GeographicLib/Constants.hpp"
00015 
00016 namespace GeographicLib {
00017 
00018   /**
00019    * \brief Conversion between geographic coordinates
00020    *
00021    * This class stores a geographic position which may be set via the
00022    * constructors or Reset via
00023    * - latitude and longitude
00024    * - UTM or UPS coordinates
00025    * - a string represention of these or an MGRS coordinate string
00026    *
00027    * The state consists of the latitude and longitude and the supplied UTM or
00028    * UPS coordinates (possibly derived from the MGRS coordinates).  If latitude
00029    * and longitude were given then the UTM/UPS coordinates follows the standard
00030    * conventions.
00031    *
00032    * The mutable state consists of the UTM or UPS coordinates for a alternate
00033    * zone.  A method SetAltZone is provided to set the alternate UPS/UTM zone.
00034    *
00035    * Methods are provided to return the geographic coordinates, the input UTM
00036    * or UPS coordinates (and associated meridian convergence and scale), or
00037    * alternate UTM or UPS coordinates (and their associated meridian
00038    * convergence and scale).
00039    *
00040    * Once the input string has been parsed, you can print the result out in any
00041    * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS.
00042    **********************************************************************/
00043   class GeoCoords {
00044   private:
00045     typedef Math::real real;
00046     real _lat, _long, _easting, _northing, _gamma, _k;
00047     bool _northp;
00048     int _zone;                  // See UTMUPS::zonespec
00049     mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k;
00050     mutable int _alt_zone;
00051 
00052     void CopyToAlt() const throw() {
00053       _alt_easting = _easting;
00054       _alt_northing = _northing;
00055       _alt_gamma = _gamma;
00056       _alt_k = _k;
00057       _alt_zone = _zone;
00058     }
00059     void UTMUPSString(int zone, real easting, real northing,
00060                       int prec, std::string& utm) const;
00061     void FixHemisphere();
00062   public:
00063 
00064     /** \name Initializing the GeoCoords object
00065      **********************************************************************/
00066     ///@{
00067     /**
00068      * The default contructor is equivalent to \e latitude = 90<sup>o</sup>, \e
00069      * longitude = 0<sup>o</sup>.
00070      **********************************************************************/
00071     GeoCoords() throw()
00072       // This is the N pole
00073       : _lat(90)
00074       , _long(0)
00075       , _easting(2000000)
00076       , _northing(2000000)
00077       , _northp(true)
00078       , _zone(0)
00079     { CopyToAlt(); }
00080 
00081     /**
00082      * Construct from a string.
00083      *
00084      * @param[in] s 1-element, 2-element, or 3-element string representation of
00085      *   the position.
00086      * @param[in] centerp governs the interpretation of MGRS coordinates (see
00087      *   below).
00088      *
00089      * Parse as a string and interpret it as a geographic position.  The input
00090      * string is broken into space (or comma) separated pieces and Basic
00091      * decision on which format is based on number of components
00092      * -# MGRS
00093      * -# "Lat Long" or "Long Lat"
00094      * -# "Zone Easting Northing" or "Easting Northing Zone"
00095      *
00096      * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq)
00097      * - Latitude and Longitude
00098      *   -  33.44      43.27
00099      *   -  N33d26.4'  E43d16.2'
00100      *   -  43d16'12"E 33d26'24"N
00101      * - MGRS
00102      *   -  38SLC301
00103      *   -  38SLC391014
00104      *   -  38SLC3918701405
00105      *   -  37SHT9708
00106      * - UTM
00107      *   -  38N 339188 3701405
00108      *   -  897039 3708229 37N
00109      *
00110      * Latitude and Longitude parsing.  Latitude precedes longitude, unless a
00111      * N, S, E, W hemisphere designator is used on one or both coordinates.
00112      * Thus
00113      * - 40 -75
00114      * - N40 W75
00115      * - -75 N40
00116      * - 75W 40N
00117      * - E-75 -40S
00118      * .
00119      * are all the same position.  The coodinates may be given in decimal
00120      * degrees, degrees and decimal minutes, degrees, minutes, seconds, etc.
00121      * Use d, ', and " to make off the degrees, minutes and seconds.  Thus
00122      * - 40d30'30"
00123      * - 40d30'30
00124      * - 40d30.5'
00125      * - 40d30.5
00126      * - 40.508333333
00127      * .
00128      * all specify the same angle.  The leading sign applies to all components
00129      * so -1d30 is -(1+30/60) = -1.5.  Latitudes must be in the range [-90, 90]
00130      * and longitudes in the range [-180, 360].  Internally longitudes are
00131      * reduced to the range [-180, 180).
00132      *
00133      * UTM/UPS parsing.  For UTM zones (-80 <= Lat <= 84), the zone designator
00134      * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or
00135      * S), e.g., 38N.  The latitude zone designer ([C&ndash;M] in the southern
00136      * hemisphere and [N&ndash;X] in the northern) should NOT be used.  (This
00137      * is part of the MGRS coordinate.)  The zone designator for the poles
00138      * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S.
00139      *
00140      * MGRS parsing interprets the grid references as square area at the
00141      * specified precision (1m, 10m, 100m, etc.).  If \e centerp = true (the
00142      * default), the center of this square is then taken to be the precise
00143      * position; thus:
00144      * - 38SMB           = 38N 450000 3650000
00145      * - 38SMB4484       = 38N 444500 3684500
00146      * - 38SMB44148470   = 38N 444145 3684705
00147      * .
00148      * Otherwise, the "south-west" corner of the square is used, i.e.,
00149      * - 38SMB           = 38N 400000 3600000
00150      * - 38SMB4484       = 38N 444000 3684000
00151      * - 38SMB44148470   = 38N 444140 3684700
00152      **********************************************************************/
00153     explicit GeoCoords(const std::string& s, bool centerp = true)
00154     { Reset(s, centerp); }
00155 
00156     /**
00157      * Construct from geographic coordinates.
00158      *
00159      * @param[in] latitude (degrees).
00160      * @param[in] longitude (degrees).
00161      * @param[in] zone if specified, force the UTM/UPS representation to use a
00162      *   specified zone using the rules given in UTMUPS::zonespec.
00163      **********************************************************************/
00164     GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
00165       Reset(latitude, longitude, zone);
00166     }
00167 
00168     /**
00169      * Construct from UTM/UPS coordinates.
00170      *
00171      * @param[in] zone UTM zone (zero means UPS).
00172      * @param[in] northp hemisphere (true means north, false means south).
00173      * @param[in] easting (meters).
00174      * @param[in] northing (meters).
00175      **********************************************************************/
00176     GeoCoords(int zone, bool northp, real easting, real northing) {
00177       Reset(zone, northp, easting, northing);
00178     }
00179 
00180     /**
00181      * Reset the location from a string.  See
00182      * GeoCoords(const std::string& s, bool centerp).
00183      **********************************************************************/
00184     void Reset(const std::string& s, bool centerp = true);
00185 
00186     /**
00187      * Reset the location in terms of geographic coordinates.  See
00188      * GeoCoords(real latitude, real longitude, int zone).
00189      **********************************************************************/
00190     void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
00191       UTMUPS::Forward(latitude, longitude,
00192                       _zone, _northp, _easting, _northing, _gamma, _k,
00193                       zone);
00194       _lat = latitude;
00195       _long = longitude;
00196       if (_long >= 180)
00197         _long -= 360;
00198       CopyToAlt();
00199     }
00200 
00201     /**
00202      * Reset the location in terms of UPS/UPS coordinates.  See
00203      * GeoCoords(int zone, bool northp, real easting, real northing).
00204      **********************************************************************/
00205     void Reset(int zone, bool northp, real easting, real northing) {
00206       UTMUPS::Reverse(zone, northp, easting, northing,
00207                       _lat, _long, _gamma, _k);
00208       _zone = zone;
00209       _northp = northp;
00210       _easting = easting;
00211       _northing = northing;
00212       FixHemisphere();
00213       CopyToAlt();
00214     }
00215     ///@}
00216 
00217     /** \name Querying the GeoCoords object
00218      **********************************************************************/
00219     ///@{
00220     /**
00221      * @return latitude (degrees)
00222      **********************************************************************/
00223     Math::real Latitude() const throw() { return _lat; }
00224 
00225     /**
00226      * @return longitude (degrees)
00227      **********************************************************************/
00228     Math::real Longitude() const throw() { return _long; }
00229 
00230     /**
00231      * @return easting (meters)
00232      **********************************************************************/
00233     Math::real Easting() const throw() { return _easting; }
00234 
00235     /**
00236      * @return northing (meters)
00237      **********************************************************************/
00238     Math::real Northing() const throw() { return _northing; }
00239 
00240     /**
00241      * @return meridian convergence (degrees) for the UTM/UPS projection.
00242      **********************************************************************/
00243     Math::real Convergence() const throw() { return _gamma; }
00244 
00245     /**
00246      * @return scale for the UTM/UPS projection.
00247      **********************************************************************/
00248     Math::real Scale() const throw() { return _k; }
00249 
00250     /**
00251      * @return hemisphere (false means south, true means north).
00252      **********************************************************************/
00253     bool Northp() const throw() { return _northp; }
00254 
00255     /**
00256      * @return hemisphere letter N or S.
00257      **********************************************************************/
00258     char Hemisphere() const throw() { return _northp ? 'N' : 'S'; }
00259 
00260     /**
00261      * @return the zone corresponding to the input (return 0 for UPS).
00262      **********************************************************************/
00263     int Zone() const throw() { return _zone; }
00264 
00265     ///@}
00266 
00267     /** \name Setting and querying the alternate zone
00268      **********************************************************************/
00269     ///@{
00270     /**
00271      * Specify alternate zone number.
00272      *
00273      * @param[in] zone zone number for the alternate representation.
00274      *
00275      * See UTMUPS::zonespec for more information on the interpretation of \e
00276      * zone.  Note that \e zone == UTMUPS::STANDARD (the default) use the
00277      * standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the
00278      * existing alternate representation.  Before this is called the alternate
00279      * zone is the input zone.
00280      **********************************************************************/
00281     void SetAltZone(int zone = UTMUPS::STANDARD) const {
00282       if (zone == UTMUPS::MATCH)
00283         return;
00284       zone = UTMUPS::StandardZone(_lat, _long, zone);
00285       if (zone == _zone)
00286         CopyToAlt();
00287       else {
00288         bool northp;
00289         UTMUPS::Forward(_lat, _long,
00290                         _alt_zone, northp,
00291                         _alt_easting, _alt_northing, _alt_gamma, _alt_k,
00292                         zone);
00293       }
00294     }
00295 
00296     /**
00297      * @return current alternate zone (return 0 for UPS).
00298      **********************************************************************/
00299     int AltZone() const throw() { return _alt_zone; }
00300 
00301     /**
00302      * @return easting (meters) for alternate zone.
00303      **********************************************************************/
00304     Math::real AltEasting() const throw() { return _alt_easting; }
00305 
00306     /**
00307      * @return northing (meters) for alternate zone.
00308      **********************************************************************/
00309     Math::real AltNorthing() const throw() { return _alt_northing; }
00310 
00311     /**
00312      * @return meridian convergence (degrees) for altermate zone.
00313      **********************************************************************/
00314     Math::real AltConvergence() const throw() { return _alt_gamma; }
00315 
00316     /**
00317      * @return scale for altermate zone.
00318      **********************************************************************/
00319     Math::real AltScale() const throw() { return _alt_k; }
00320     ///@}
00321 
00322     /** \name String representations of the GeoCoords object
00323      **********************************************************************/
00324     ///@{
00325     /**
00326      * String representation with latitude and longitude as signed decimal
00327      * degrees.
00328      *
00329      * @param[in] prec precision (relative to about 1m).
00330      * @return decimal latitude/longitude string representation.
00331      *
00332      * Precision specifies accuracy of representation as follows:
00333      * - prec = -5 (min), 1d
00334      * - prec = 0, 10<sup>-5</sup>d (about 1m)
00335      * - prec = 3, 10<sup>-8</sup>d
00336      * - prec = 9 (max), 10<sup>-14</sup>d
00337      **********************************************************************/
00338     std::string GeoRepresentation(int prec = 0) const;
00339 
00340     /**
00341      * String representation with latitude and longitude as degrees, minutes,
00342      * seconds, and hemisphere.
00343      *
00344      * @param[in] prec precision (relative to about 1m)
00345      * @return DMS latitude/longitude string representation.
00346      *
00347      * Precision specifies accuracy of representation as follows:
00348      * - prec = -5 (min), 1d
00349      * - prec = -4, 0.1d
00350      * - prec = -3, 1'
00351      * - prec = -2, 0.1'
00352      * - prec = -1, 1"
00353      * - prec = 0, 0.1" (about 3m)
00354      * - prec = 1, 0.01"
00355      * - prec = 10 (max), 10<sup>-11</sup>"
00356      **********************************************************************/
00357     std::string DMSRepresentation(int prec = 0) const;
00358 
00359     /**
00360      * MGRS string.
00361      *
00362      * @param[in] prec precision (relative to about 1m).
00363      * @return MGRS string.
00364      *
00365      * This gives the coordinates of the enclosing grid square with size given
00366      * by the precision.  Thus 38N 444180 3684790 converted to a MGRS
00367      * coordinate at precision -2 (100m) is 38SMB441847 and not 38SMB442848.
00368      * \e prec specifies the precision of the MSGRS string as follows:
00369      * - prec = -5 (min), 100km
00370      * - prec = -4, 10km
00371      * - prec = -3, 1km
00372      * - prec = -2, 100m
00373      * - prec = -1, 10m
00374      * - prec = 0, 1m
00375      * - prec = 1, 0.1m
00376      * - prec = 6 (max), 1um
00377      **********************************************************************/
00378     std::string MGRSRepresentation(int prec = 0) const;
00379 
00380     /**
00381      * UTM/UPS string.
00382      *
00383      * @param[in] prec precision (relative to about 1m)
00384      * @return UTM/UPS string representation: zone designator, easting, and
00385      *   northing.
00386      *
00387      * Precision specifies accuracy of representation as follows:
00388      * - prec = -5 (min), 100km
00389      * - prec = -3, 1km
00390      * - prec = 0, 1m
00391      * - prec = 3, 1mm
00392      * - prec = 6, 1um
00393      * - prec = 9 (max), 1nm
00394      **********************************************************************/
00395     std::string UTMUPSRepresentation(int prec = 0) const;
00396 
00397     /**
00398      * MGRS string for the alternate zone.  See GeoCoords::MGRSRepresentation.
00399      **********************************************************************/
00400     std::string AltMGRSRepresentation(int prec = 0) const;
00401 
00402     /**
00403      * UTM/UPS string for the alternate zone.  See
00404      * GeoCoords::UTMUPSRepresentation.
00405      **********************************************************************/
00406     std::string AltUTMUPSRepresentation(int prec = 0) const;
00407     ///@}
00408 
00409     /** \name Inspector functions
00410      **********************************************************************/
00411     ///@{
00412     /**
00413      * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
00414      *
00415      * (The WGS84 value is returned because the UTM and UPS projections are
00416      * based on this ellipsoid.)
00417      **********************************************************************/
00418     Math::real MajorRadius() const throw() { return UTMUPS::MajorRadius(); }
00419 
00420     /**
00421      * @return \e r the inverse flattening of the WGS84 ellipsoid.
00422      *
00423      * (The WGS84 value is returned because the UTM and UPS projections are
00424      * based on this ellipsoid.)
00425      **********************************************************************/
00426     Math::real InverseFlattening() const throw()
00427     { return UTMUPS::InverseFlattening(); }
00428     ///@}
00429   };
00430 
00431 } // namespace GeographicLib
00432 #endif  // GEOGRAPHICLIB_GEOCOORDS_HPP