00001 /** 00002 * \file OSGB.hpp 00003 * \brief Header for GeographicLib::OSGB class 00004 * 00005 * Copyright (c) Charles Karney (2010) <charles@karney.com> and licensed under 00006 * the LGPL. For more information, see http://geographiclib.sourceforge.net/ 00007 **********************************************************************/ 00008 00009 #if !defined(GEOGRAPHICLIB_OSGB_HPP) 00010 #define GEOGRAPHICLIB_OSGB_HPP "$Id: OSGB.hpp 6911 2010-12-09 23:13:55Z karney $" 00011 00012 #include "GeographicLib/Constants.hpp" 00013 #include "GeographicLib/TransverseMercator.hpp" 00014 #include <string> 00015 #include <sstream> 00016 00017 namespace GeographicLib { 00018 00019 /** 00020 * \brief Ordnance Survey grid system for Great Britain 00021 * 00022 * The class implements the coordinate system used by the Ordnance Survey for 00023 * maps of Great Britain and conversions to the grid reference system. 00024 * 00025 * See 00026 * - <a href="http://www.ordnancesurvey.co.uk/oswebsite/gps/docs/A_Guide_to_Coordinate_Systems_in_Great_Britain.pdf"> 00027 * A guide to coordinate systems in Great Britain</a> 00028 * - <a href="http://www.ordnancesurvey.co.uk/oswebsite/gps/information/coordinatesystemsinfo/guidetonationalgrid/page1.html"> 00029 * Guide to National Grid</a> 00030 * 00031 * \b WARNING: the latitudes and longitudes for the Ordnance Survey grid 00032 * system do not use the WGS84 datum. Do not use the values returned by this 00033 * class in the UTMUPS, MGRS, or Geoid classes without first converting the 00034 * datum (and vice versa). 00035 **********************************************************************/ 00036 class OSGB { 00037 private: 00038 typedef Math::real real; 00039 static const std::string letters; 00040 static const std::string digits; 00041 static const TransverseMercator OSGBTM; 00042 static const real northoffset; 00043 enum { 00044 base = 10, 00045 tile = 100000, 00046 tilelevel = 5, 00047 tilegrid = 5, 00048 tileoffx = 2 * tilegrid, 00049 tileoffy = 1 * tilegrid, 00050 minx = - tileoffx * tile, 00051 miny = - tileoffy * tile, 00052 maxx = (tilegrid*tilegrid - tileoffx) * tile, 00053 maxy = (tilegrid*tilegrid - tileoffy) * tile, 00054 // Maximum precision is um 00055 maxprec = 5 + 6, 00056 }; 00057 static real computenorthoffset() throw(); 00058 static void CheckCoords(real x, real y); 00059 static int lookup(const std::string& s, char c) throw() { 00060 std::string::size_type r = s.find(toupper(c)); 00061 return r == std::string::npos ? -1 : int(r); 00062 } 00063 template<typename T> static std::string str(T x) { 00064 std::ostringstream s; s << x; return s.str(); 00065 } 00066 OSGB(); // Disable constructor 00067 00068 public: 00069 00070 /** 00071 * Forward projection, from geographic to OSGB coordinates. 00072 * 00073 * @param[in] lat latitude of point (degrees). 00074 * @param[in] lon longitude of point (degrees). 00075 * @param[out] x easting of point (meters). 00076 * @param[out] y northing of point (meters). 00077 * @param[out] gamma meridian convergence at point (degrees). 00078 * @param[out] k scale of projection at point. 00079 * 00080 * \e lat should be in the range [-90, 90]; \e lon and \e lon0 should be in 00081 * the range [-180, 360]. 00082 **********************************************************************/ 00083 static void Forward(real lat, real lon, 00084 real& x, real& y, real& gamma, real& k) throw() { 00085 OSGBTM.Forward(OriginLongitude(), lat, lon, x, y, gamma, k); 00086 x += FalseEasting(); 00087 y += northoffset; 00088 } 00089 00090 /** 00091 * Reverse projection, from OSGB coordinates to geographic. 00092 * 00093 * @param[in] x easting of point (meters). 00094 * @param[in] y northing of point (meters). 00095 * @param[out] lat latitude of point (degrees). 00096 * @param[out] lon longitude of point (degrees). 00097 * @param[out] gamma meridian convergence at point (degrees). 00098 * @param[out] k scale of projection at point. 00099 * 00100 * The value of \e lon returned is in the range [-180, 180). 00101 **********************************************************************/ 00102 00103 static void Reverse(real x, real y, 00104 real& lat, real& lon, real& gamma, real& k) throw() { 00105 x -= FalseEasting(); 00106 y -= northoffset; 00107 OSGBTM.Reverse(OriginLongitude(), x, y, lat, lon, gamma, k); 00108 } 00109 00110 /** 00111 * OSGB::Forward without returning the convergence and scale. 00112 **********************************************************************/ 00113 static void Forward(real lat, real lon, real& x, real& y) throw() { 00114 real gamma, k; 00115 Forward(lat, lon, x, y, gamma, k); 00116 } 00117 00118 /** 00119 * OSGB::Reverse without returning the convergence and scale. 00120 **********************************************************************/ 00121 static void Reverse(real x, real y, real& lat, real& lon) throw() { 00122 real gamma, k; 00123 Reverse(x, y, lat, lon, gamma, k); 00124 } 00125 00126 /** 00127 * Convert OSGB coordinates to a grid reference. 00128 * 00129 * @param[in] x easting of point (meters). 00130 * @param[in] y northing of point (meters). 00131 * @param[in] prec precision relative to 100 km. 00132 * @param[out] gridref National Grid reference. 00133 * 00134 * \e prec specifies the precision of the grid reference string as follows: 00135 * - prec = 0 (min), 100km 00136 * - prec = 1, 10km 00137 * - prec = 2, 1km 00138 * - prec = 3, 100m 00139 * - prec = 4, 10m 00140 * - prec = 5, 1m 00141 * - prec = 6, 0.1m 00142 * - prec = 11 (max), 1um 00143 * 00144 * The easting must be in the range [-1000 km, 1500 km) and the northing 00145 * must be in the range [-500 km, 2000 km). An exception is thrown if 00146 * either the easting and northing is outside these bounds. These bounds 00147 * are consistent with rules for the letter designations for the grid 00148 * system. 00149 **********************************************************************/ 00150 static void GridReference(real x, real y, int prec, std::string& gridref); 00151 00152 /** 00153 * Convert OSGB coordinates to a grid reference. 00154 * 00155 * @param[in] gridref National Grid reference. 00156 * @param[out] x easting of point (meters). 00157 * @param[out] y northing of point (meters). 00158 * @param[out] prec precision relative to 100 km. 00159 * @param[in] centerp if true (default), return center of the grid square, 00160 * else return SW (lower left) corner. 00161 * 00162 * The grid reference must be of the form: two letters (not including I) 00163 * followed by an even number of digits (up to 22). 00164 **********************************************************************/ 00165 static void GridReference(const std::string& gridref, 00166 real& x, real& y, int& prec, 00167 bool centerp = true); 00168 00169 /** \name Inspector functions 00170 **********************************************************************/ 00171 ///@{ 00172 /** 00173 * @return \e a the equatorial radius of the Airy 1830 ellipsoid (meters). 00174 * 00175 * This is 20923713 ft converted to meters using the rule 1 ft = 00176 * 10^(9.48401603-10) m. (The Airy 1830 value is returned because the OSGB 00177 * projection is based on this ellipsoid.) 00178 **********************************************************************/ 00179 static Math::real MajorRadius() throw() 00180 { return real(6377563.396032066440602120008397385037L); } 00181 00182 /** 00183 * @return \e r the inverse flattening of the Airy 1830 ellipsoid. 00184 * 00185 * For the Airy 1830 ellipsoid, \e a = 20923713 ft and \e b = 20853810 ft; 00186 * thus the inverse flattening = 20923713/(20923713 - 20853810) = 00187 * 2324857/7767 = 299.32496459... (The Airy 1830 value is returned because 00188 * the OSGB projection is based on this ellipsoid.) 00189 **********************************************************************/ 00190 static Math::real InverseFlattening() throw() 00191 { return real(2324857)/real(7767); } 00192 00193 /** 00194 * @return \e k0 central scale for the OSGB projection (0.9996012717). 00195 **********************************************************************/ 00196 static Math::real CentralScale() throw() 00197 { return real(0.9996012717L); } 00198 00199 /** 00200 * @return latitude of the origin for the OSGB projection (49 degrees). 00201 **********************************************************************/ 00202 static Math::real OriginLatitude() throw() { return real(49); } 00203 00204 /** 00205 * @return longitude of the origin for the OSGB projection (-2 degrees). 00206 **********************************************************************/ 00207 static Math::real OriginLongitude() throw() { return real(-2); } 00208 00209 /** 00210 * @return false northing the OSGB projection (-100000 meters). 00211 **********************************************************************/ 00212 static Math::real FalseNorthing() throw() { return real(-100000); } 00213 00214 /** 00215 * @return false easting the OSGB projection (400000 meters). 00216 **********************************************************************/ 00217 static Math::real FalseEasting() throw() { return real(400000); } 00218 ///@} 00219 00220 }; 00221 00222 } // namespace GeographicLib 00223 #endif