GeographicLib
1.21
|
00001 /** 00002 * \file MGRS.hpp 00003 * \brief Header for GeographicLib::MGRS 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 #if !defined(GEOGRAPHICLIB_MGRS_HPP) 00011 #define GEOGRAPHICLIB_MGRS_HPP "$Id: 80e08da6eca9d9cf92c5adad148c64302df2573d $" 00012 00013 #include <sstream> 00014 #include <GeographicLib/Constants.hpp> 00015 #include <GeographicLib/UTMUPS.hpp> 00016 00017 #if defined(_MSC_VER) 00018 // Squelch warnings about dll vs string 00019 #pragma warning (push) 00020 #pragma warning (disable: 4251) 00021 #endif 00022 00023 namespace GeographicLib { 00024 00025 /** 00026 * \brief Convert between UTM/UPS and %MGRS 00027 * 00028 * MGRS is defined in Chapter 3 of 00029 * - J. W. Hager, L. L. Fry, S. S. Jacks, D. R. Hill, 00030 * <a href="http://earth-info.nga.mil/GandG/publications/tm8358.1/pdf/TM8358_1.pdf"> 00031 00032 * Datums, Ellipsoids, Grids, and Grid Reference Systems</a>, 00033 * Defense Mapping Agency, Technical Manual TM8358.1 (1990). 00034 * 00035 * This implementation has the following properties: 00036 * - The conversions are closed, i.e., output from Forward is legal input for 00037 * Reverse and vice versa. Conversion in both directions preserve the 00038 * UTM/UPS selection and the UTM zone. 00039 * - Forward followed by Reverse and vice versa is approximately the 00040 * identity. (This is affected in predictable ways by errors in 00041 * determining the latitude band and by loss of precision in the MGRS 00042 * coordinates.) 00043 * - All MGRS coordinates truncate to legal 100 km blocks. All MGRS 00044 * coordinates with a legal 100 km block prefix are legal (even though the 00045 * latitude band letter may now belong to a neighboring band). 00046 * - The range of UTM/UPS coordinates allowed for conversion to MGRS 00047 * coordinates is the maximum consistent with staying within the letter 00048 * ranges of the MGRS scheme. 00049 * - All the transformations are implemented as static methods in the MGRS 00050 * class. 00051 * 00052 * The <a href="http://www.nga.mil">NGA</a> software package 00053 * <a href="http://earth-info.nga.mil/GandG/geotrans/index.html">geotrans</a> 00054 * also provides conversions to and from MGRS. Version 3.0 (and earlier) 00055 * suffers from some drawbacks: 00056 * - Inconsistent rules are used to determine the whether a particular MGRS 00057 * coordinate is legal. A more systematic approach is taken here. 00058 * - The underlying projections are not very accurately implemented. 00059 * 00060 * Example of use: 00061 * \include example-MGRS.cpp 00062 **********************************************************************/ 00063 class GEOGRAPHIC_EXPORT MGRS { 00064 private: 00065 typedef Math::real real; 00066 // The smallest length s.t., 1.0e7 - eps_ < 1.0e7 (approx 1.9 nm) 00067 static const real eps_; 00068 // The smallest angle s.t., 90 - eps_ < 90 (approx 50e-12 arcsec) 00069 static const real angeps_; 00070 static const std::string hemispheres_; 00071 static const std::string utmcols_[3]; 00072 static const std::string utmrow_; 00073 static const std::string upscols_[4]; 00074 static const std::string upsrows_[2]; 00075 static const std::string latband_; 00076 static const std::string upsband_; 00077 static const std::string digits_; 00078 00079 static const int mineasting_[4]; 00080 static const int maxeasting_[4]; 00081 static const int minnorthing_[4]; 00082 static const int maxnorthing_[4]; 00083 enum { 00084 base_ = 10, 00085 // Top-level tiles are 10^5 m = 100 km on a side 00086 tilelevel_ = 5, 00087 // Period of UTM row letters 00088 utmrowperiod_ = 20, 00089 // Row letters are shifted by 5 for even zones 00090 utmevenrowshift_ = 5, 00091 // Maximum precision is um 00092 maxprec_ = 5 + 6, 00093 }; 00094 static void CheckCoords(bool utmp, bool& northp, real& x, real& y); 00095 static int UTMRow(int iband, int icol, int irow) throw(); 00096 00097 friend class UTMUPS; // UTMUPS::StandardZone calls LatitudeBand 00098 // Return latitude band number [-10, 10) for the give latitude (degrees). 00099 // The bands are reckoned in include their southern edges. 00100 static int LatitudeBand(real lat) throw() { 00101 int ilat = int(std::floor(lat)); 00102 return (std::max)(-10, (std::min)(9, (ilat + 80)/8 - 10)); 00103 } 00104 // UTMUPS access these enums 00105 enum { 00106 tile_ = 100000, // Size MGRS blocks 00107 minutmcol_ = 1, 00108 maxutmcol_ = 9, 00109 minutmSrow_ = 10, 00110 maxutmSrow_ = 100, // Also used for UTM S false northing 00111 minutmNrow_ = 0, // Also used for UTM N false northing 00112 maxutmNrow_ = 95, 00113 minupsSind_ = 8, // These 4 ind's apply to easting and northing 00114 maxupsSind_ = 32, 00115 minupsNind_ = 13, 00116 maxupsNind_ = 27, 00117 upseasting_ = 20, // Also used for UPS false northing 00118 utmeasting_ = 5, // UTM false easting 00119 // Difference between S hemisphere northing and N hemisphere northing 00120 utmNshift_ = (maxutmSrow_ - minutmNrow_) * tile_ 00121 }; 00122 MGRS(); // Disable constructor 00123 00124 public: 00125 00126 /** 00127 * Convert UTM or UPS coordinate to an MGRS coordinate. 00128 * 00129 * @param[in] zone UTM zone (zero means UPS). 00130 * @param[in] northp hemisphere (true means north, false means south). 00131 * @param[in] x easting of point (meters). 00132 * @param[in] y northing of point (meters). 00133 * @param[in] prec precision relative to 100 km. 00134 * @param[out] mgrs MGRS string. 00135 * 00136 * \e prec specifies the precision of the MGRS string as follows: 00137 * - prec = 0 (min), 100 km 00138 * - prec = 1, 10 km 00139 * - prec = 2, 1 km 00140 * - prec = 3, 100 m 00141 * - prec = 4, 10 m 00142 * - prec = 5, 1 m 00143 * - prec = 6, 0.1 m 00144 * - prec = 11 (max), 1 um 00145 * 00146 * UTM eastings are allowed to be in the range [100 km, 900 km], northings 00147 * are allowed to be in in [0 km, 9500 km] for the northern hemisphere and 00148 * in [1000 km, 10000 km] for the southern hemisphere. (However UTM 00149 * northings can be continued across the equator. So the actual limits on 00150 * the northings are [-9000 km, 9500 km] for the "northern" hemisphere and 00151 * [1000 km, 19500 km] for the "southern" hemisphere.) 00152 * 00153 * UPS eastings/northings are allowed to be in the range [1300 km, 2700 km] 00154 * in the northern hemisphere and in [800 km, 3200 km] in the southern 00155 * hemisphere. 00156 * 00157 * The ranges are 100 km more restrictive that for the conversion between 00158 * geographic coordinates and UTM and UPS given by UTMUPS. These 00159 * restrictions are dictated by the allowed letters in MGRS coordinates. 00160 * The choice of 9500 km for the maximum northing for northern hemisphere 00161 * and of 1000 km as the minimum northing for southern hemisphere provide 00162 * at least 0.5 degree extension into standard UPS zones. The upper ends 00163 * of the ranges for the UPS coordinates is dictated by requiring symmetry 00164 * about the meridians 0E and 90E. 00165 * 00166 * All allowed UTM and UPS coordinates may now be converted to legal MGRS 00167 * coordinates with the proviso that eastings and northings on the upper 00168 * boundaries are silently reduced by about 4 nm (4 nanometers) to place 00169 * them \e within the allowed range. (This includes reducing a southern 00170 * hemisphere northing of 10000 km by 4 nm so that it is placed in latitude 00171 * band M.) The UTM or UPS coordinates are truncated to requested 00172 * precision to determine the MGRS coordinate. Thus in UTM zone 38N, the 00173 * square area with easting in [444 km, 445 km) and northing in [3688 km, 00174 * 3689 km) maps to MGRS coordinate 38SMB4488 (at \e prec = 2, 1 km), 00175 * Khulani Sq., Baghdad. 00176 * 00177 * The UTM/UPS selection and the UTM zone is preserved in the conversion to 00178 * MGRS coordinate. Thus for \e zone > 0, the MGRS coordinate begins with 00179 * the zone number followed by one of [C–M] for the southern 00180 * hemisphere and [N–X] for the northern hemisphere. For \e zone = 00181 * 0, the MGRS coordinates begins with one of [AB] for the southern 00182 * hemisphere and [XY] for the northern hemisphere. 00183 * 00184 * The conversion to the MGRS is exact for prec in [0, 5] except that a 00185 * neighboring latitude band letter may be given if the point is within 5nm 00186 * of a band boundary. For prec in [6, 11], the conversion is accurate to 00187 * roundoff. 00188 * 00189 * If \e x or \e y is NaN or if \e zone is UTMUPS::INVALID, the returned 00190 * MGRS string is "INVALID". 00191 * 00192 * Return the result via a reference argument to avoid the overhead of 00193 * allocating a potentially large number of small strings. If an error is 00194 * thrown, then \e mgrs is unchanged. 00195 **********************************************************************/ 00196 static void Forward(int zone, bool northp, real x, real y, 00197 int prec, std::string& mgrs); 00198 00199 /** 00200 * Convert UTM or UPS coordinate to an MGRS coordinate when the latitude is 00201 * known. 00202 * 00203 * @param[in] zone UTM zone (zero means UPS). 00204 * @param[in] northp hemisphere (true means north, false means south). 00205 * @param[in] x easting of point (meters). 00206 * @param[in] y northing of point (meters). 00207 * @param[in] lat latitude (degrees). 00208 * @param[in] prec precision relative to 100 km. 00209 * @param[out] mgrs MGRS string. 00210 * 00211 * The latitude is ignored for \e zone = 0 (UPS); otherwise the latitude is 00212 * used to determine the latitude band and this is checked for consistency 00213 * using the same tests as Reverse. 00214 **********************************************************************/ 00215 static void Forward(int zone, bool northp, real x, real y, real lat, 00216 int prec, std::string& mgrs); 00217 00218 /** 00219 * Convert a MGRS coordinate to UTM or UPS coordinates. 00220 * 00221 * @param[in] mgrs MGRS string. 00222 * @param[out] zone UTM zone (zero means UPS). 00223 * @param[out] northp hemisphere (true means north, false means south). 00224 * @param[out] x easting of point (meters). 00225 * @param[out] y northing of point (meters). 00226 * @param[out] prec precision relative to 100 km. 00227 * @param[in] centerp if true (default), return center of the MGRS square, 00228 * else return SW (lower left) corner. 00229 * 00230 * All conversions from MGRS to UTM/UPS are permitted provided the MGRS 00231 * coordinate is a possible result of a conversion in the other direction. 00232 * (The leading 0 may be dropped from an input MGRS coordinate for UTM 00233 * zones 1–9.) In addition, MGRS coordinates with a neighboring 00234 * latitude band letter are permitted provided that some portion of the 00235 * 100 km block is within the given latitude band. Thus 00236 * - 38VLS and 38WLS are allowed (latitude 64N intersects the square 00237 * 38[VW]LS); but 38VMS is not permitted (all of 38VMS is north of 64N) 00238 * - 38MPE and 38NPF are permitted (they straddle the equator); but 38NPE 00239 * and 38MPF are not permitted (the equator does not intersect either 00240 * block). 00241 * - Similarly ZAB and YZB are permitted (they straddle the prime 00242 * meridian); but YAB and ZZB are not (the prime meridian does not 00243 * intersect either block). 00244 * 00245 * The UTM/UPS selection and the UTM zone is preserved in the conversion 00246 * from MGRS coordinate. The conversion is exact for prec in [0, 5]. With 00247 * centerp = true the conversion from MGRS to geographic and back is 00248 * stable. This is not assured if \e centerp = false. 00249 * 00250 * If an error is thrown, then the arguments are unchanged. 00251 **********************************************************************/ 00252 static void Reverse(const std::string& mgrs, 00253 int& zone, bool& northp, real& x, real& y, 00254 int& prec, bool centerp = true); 00255 00256 /** \name Inspector functions 00257 **********************************************************************/ 00258 ///@{ 00259 /** 00260 * @return \e a the equatorial radius of the WGS84 ellipsoid (meters). 00261 * 00262 * (The WGS84 value is returned because the UTM and UPS projections are 00263 * based on this ellipsoid.) 00264 **********************************************************************/ 00265 static Math::real MajorRadius() throw() { return UTMUPS::MajorRadius(); } 00266 00267 /** 00268 * @return \e f the flattening of the WGS84 ellipsoid. 00269 * 00270 * (The WGS84 value is returned because the UTM and UPS projections are 00271 * based on this ellipsoid.) 00272 **********************************************************************/ 00273 static Math::real Flattening() throw() { return UTMUPS::Flattening(); } 00274 ///@} 00275 00276 /// \cond SKIP 00277 /** 00278 * <b>DEPRECATED</b> 00279 * @return \e r the inverse flattening of the WGS84 ellipsoid. 00280 **********************************************************************/ 00281 static Math::real InverseFlattening() throw() 00282 { return UTMUPS::InverseFlattening(); } 00283 /// \endcond 00284 }; 00285 00286 } // namespace GeographicLib 00287 00288 #if defined(_MSC_VER) 00289 #pragma warning (pop) 00290 #endif 00291 00292 #endif // GEOGRAPHICLIB_MGRS_HPP