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