UTMUPS.hpp
Go to the documentation of this file.
00001 /**
00002  * \file UTMUPS.hpp
00003  * \brief Header for GeographicLib::UTMUPS class
00004  *
00005  * Copyright (c) Charles Karney (2008) <charles@karney.com>
00006  * and licensed under the LGPL.
00007  **********************************************************************/
00008 
00009 
00010 #if !defined(UTMUPS_HPP)
00011 #define UTMUPS_HPP "$Id: UTMUPS.hpp 6535 2009-02-10 22:37:07Z ckarney $"
00012 
00013 #include <string>
00014 #include <sstream>
00015 
00016 namespace GeographicLib {
00017 
00018   /**
00019    * \brief Convert between Geographic coordinates and UTM/UPS
00020    *
00021    * UTM and UPS are defined
00022    * - <a href="http://earth-info.nga.mil/GandG/publications/tm8358.2/TM8358_2.pdf">
00023    *   The Universal Grids: Universal Transverse Mercator (UTM) and Universal
00024    *   Polar Stereographic (UPS)</a>, Defense Mapping Agency, Technical Manual
00025    *   TM8358.2 (1989).
00026    * .
00027    * Section 2-3 defines UTM and section 3-2.4 defines UPS.  This document also
00028    * includes approximate algorithms for the computation of the underlying
00029    * transverse Mercator and polar stereographic projections.  Here we
00030    * substitute much more accurate algorithms given by
00031    * GeographicLib:TransverseMercator and GeographicLib:PolarStereographic.
00032    *
00033    * In this implementation, the conversions are closed, i.e., output from
00034    * Forward is legal input for Reverse and vice versa.  The error is about 5nm
00035    * in each direction.  However, the conversion from legal UTM/UPS coordinates
00036    * to geographic coordinates and back might throw an error if the initial
00037    * point is within 5nm of the edge of the allowed range for the UTM/UPS
00038    * coordinates.
00039    *
00040    * The simplest way to guarantee the closed property is to define allowed
00041    * ranges for the eastings and northings for UTM and UPS coordinates.  The
00042    * UTM boundaries are the same for all zones.  (The only place the
00043    * exceptional nature of the zone boundaries is evident is when converting to
00044    * UTM/UPS coordinates requesting the standard zone.)  The MGRS lettering
00045    * scheme imposes natural limits on UTM/UPS coordinates which may be
00046    * converted into MGRS coordinates.  For the conversion to/from geographic
00047    * coordinates these ranges have been extended by 100km in order to provide a
00048    * generous overlap between UTM and UPS and between UTM zones.
00049    *
00050    * The <a href="http://www.nga.mil">NGA</a> software package
00051    * <a href="http://earth-info.nga.mil/GandG/geotrans/index.html">geotrans</a>
00052    * also provides conversions to and from UTM and UPS.  Version 2.4.2 (and
00053    * earlier) suffers from some drawbacks:
00054    * - Inconsistent rules are used to determine the whether a particular UTM or
00055    *   UPS coordinate is legal.  A more systematic approach is taken here.
00056    * - The underlying projections are not very accurately implemented.
00057    **********************************************************************/
00058   class UTMUPS {
00059   private:
00060     static const double falseeasting[4];
00061     static const double falsenorthing[4];
00062     static const double mineasting[4];
00063     static const double maxeasting[4];
00064     static const double minnorthing[4];
00065     static const double maxnorthing[4];
00066     static double CentralMeridian(int zone) throw() { return 6 * zone - 183.0; }
00067     template<typename T> static std::string str(T x) {
00068       std::ostringstream s; s << x; return s.str();
00069     }
00070     static void CheckLatLon(double lat, double lon);
00071     // Throw an error if easting or northing are outside standard ranges.  If
00072     // throwp = false, return bool instead.
00073     static bool CheckCoords(bool utmp, bool northp, double x, double y,
00074                             bool throwp = true);
00075   public:
00076 
00077     /**
00078      * Return the standard zone for latitude \e lat (degrees) and longitude \e
00079      * lon (degrees).  Return 0 if in the standard regions for UPS otherwise
00080      * return the UTM zone.  This includes the Norway and Svalbard exceptions.
00081      * The tests on latitudes and longitudes are all closed on the lower end
00082      * open on the upper.  Thus for UTM zone 38, latitude is in [-80, 84) and
00083      * longitude is in [42, 48).  This is exact.
00084      **********************************************************************/
00085     static int StandardZone(double lat, double lon) throw();
00086 
00087     /**
00088      * Convert geographic coordinates to UTM or UPS coordinate.  Given latitude
00089      * \e lat (degrees), and longitude \e lon (degrees), return \e zone (zero
00090      * indicates UPS), hemisphere \e northp (false means south, true means
00091      * north), easting \e x (meters), and northing \e y (meters).  The prefered
00092      * zone for the result can be specified with \e setzone (negative means
00093      * result of UTMUPS::StandardZone, zero means UPS, positive means a
00094      * particular UTM zone), Throw error if the resulting easting or northing
00095      * is outside the allowed range (see Reverse). This also returns meridian
00096      * convergence \e gamma (degrees) and scale \e k.  The accuracy of the
00097      * conversion is about 5nm.
00098      *
00099      * To extent the standard UTM zones into the UPS regions use \e setzone =
00100      * UTMUPS::StandardZone(max(-80.0, min(80.0, \e lat))).
00101      **********************************************************************/
00102     static void Forward(double lat, double lon,
00103                         int& zone, bool& northp, double& x, double& y,
00104                         double& gamma, double& k,
00105                         int setzone = -1);
00106 
00107     /**
00108      * Convert UTM or UPS coordinate to geographic coordinates .  Given zone \e
00109      * zone (\e zone == 0 indicates UPS), hemisphere \e northp (false means
00110      * south, true means north), easting \e x (meters), and northing \e y
00111      * (meters), return latitude \e lat (degrees) and longitude \e lon
00112      * (degrees).  Throw error if easting or northing is outside the allowed
00113      * range (see below).  This also returns meridian convergence \e gamma
00114      * (degrees) and scale \e k.  The accuracy of the conversion is about 5nm.
00115      *
00116      * UTM eastings are allowed to be in the range [0km, 1000km], northings are
00117      * allowed to be in in [0km, 9600km] for the northern hemisphere and in
00118      * [900km, 10000km] for the southern hemisphere.  (However UTM northings
00119      * can be continued across the equator.  So the actual limits on the
00120      * northings are [-9100km, 9600km] for the "northern" hemisphere and
00121      * [900km, 19600km] for the "southern" hemisphere.)
00122      *
00123      * UPS eastings and northings are allowed to be in the range [1200km,
00124      * 2800km] in the northern hemisphere and in [700km, 3100km] in the
00125      * southern hemisphere.
00126      *
00127      * These ranges are 100km larger than allowed for the conversions to MGRS.
00128      * (100km is the maximum extra padding consistent with eastings remaining
00129      * non-negative.)  This allows generous overlaps between zones and UTM and
00130      * UPS.  No checks are performed beyond these (e.g., to limit the distance
00131      * outside the standard zone boundaries).
00132      **********************************************************************/
00133     static void Reverse(int zone, bool northp, double x, double y,
00134                         double& lat, double& lon, double& gamma, double& k);
00135 
00136     /**
00137      * Forward without returning convergence and scale.
00138      **********************************************************************/
00139     static void Forward(double lat, double lon,
00140                         int& zone, bool& northp, double& x, double& y,
00141                         int setzone = -1) {
00142       double gamma, k;
00143       Forward(lat, lon, zone, northp, x, y, gamma, k, setzone);
00144     }
00145 
00146     /**
00147      * Reverse without returning convergence and scale.
00148      **********************************************************************/
00149     static void Reverse(int zone, bool northp, double x, double y,
00150                         double& lat, double& lon) {
00151       double gamma, k;
00152       Reverse(zone, northp, x, y, lat, lon, gamma, k);
00153     }
00154   };
00155 
00156 } // namespace GeographicLib
00157 #endif