GeographicLib 2.4

Loading...
Searching...
No Matches
UTMUPS.cpp
Go to the documentation of this file.
1/**
2 * \file UTMUPS.cpp
3 * \brief Implementation for GeographicLib::UTMUPS class
4 *
5 * Copyright (c) Charles Karney (2008-2022) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 **********************************************************************/
9
10#include <GeographicLib/UTMUPS.hpp>
11#include <GeographicLib/MGRS.hpp>
12#include <GeographicLib/PolarStereographic.hpp>
13#include <GeographicLib/TransverseMercator.hpp>
14#include <GeographicLib/Utility.hpp>
15
16 namespace GeographicLib {
17
18 using namespace std;
19
20 const int UTMUPS::falseeasting_[] =
21 { MGRS::upseasting_ * MGRS::tile_, MGRS::upseasting_ * MGRS::tile_,
22 MGRS::utmeasting_ * MGRS::tile_, MGRS::utmeasting_ * MGRS::tile_ };
23 const int UTMUPS::falsenorthing_[] =
24 { MGRS::upseasting_ * MGRS::tile_, MGRS::upseasting_ * MGRS::tile_,
25 MGRS::maxutmSrow_ * MGRS::tile_, MGRS::minutmNrow_ * MGRS::tile_ };
26 const int UTMUPS::mineasting_[] =
27 { MGRS::minupsSind_ * MGRS::tile_, MGRS::minupsNind_ * MGRS::tile_,
28 MGRS::minutmcol_ * MGRS::tile_, MGRS::minutmcol_ * MGRS::tile_ };
29 const int UTMUPS::maxeasting_[] =
30 { MGRS::maxupsSind_ * MGRS::tile_, MGRS::maxupsNind_ * MGRS::tile_,
31 MGRS::maxutmcol_ * MGRS::tile_, MGRS::maxutmcol_ * MGRS::tile_ };
32 const int UTMUPS::minnorthing_[] =
33 { MGRS::minupsSind_ * MGRS::tile_, MGRS::minupsNind_ * MGRS::tile_,
34 MGRS::minutmSrow_ * MGRS::tile_,
35 (MGRS::minutmNrow_ + MGRS::minutmSrow_ - MGRS::maxutmSrow_)
36 * MGRS::tile_ };
37 const int UTMUPS::maxnorthing_[] =
38 { MGRS::maxupsSind_ * MGRS::tile_, MGRS::maxupsNind_ * MGRS::tile_,
39 (MGRS::maxutmSrow_ + MGRS::maxutmNrow_ - MGRS::minutmNrow_) *
40 MGRS::tile_,
41 MGRS::maxutmNrow_ * MGRS::tile_ };
42
43 int UTMUPS::StandardZone(real lat, real lon, int setzone) {
44 using std::isnan; // Needed for Centos 7, ubuntu 14
45 if (!(setzone >= MINPSEUDOZONE && setzone <= MAXZONE))
46 throw GeographicErr("Illegal zone requested " + Utility::str(setzone));
47 if (setzone >= MINZONE || setzone == INVALID)
48 return setzone;
49 if (isnan(lat) || isnan(lon)) // Check if lat or lon is a NaN
50 return INVALID;
51 if (setzone == UTM || (lat >= -80 && lat < 84)) {
52 int ilon = int(floor(Math::AngNormalize(lon)));
53 if (ilon == Math::hd) ilon = -Math::hd; // ilon now in [-180,180)
54 int zone = (ilon + 186)/6;
55 int band = MGRS::LatitudeBand(lat);
56 if (band == 7 && zone == 31 && ilon >= 3) // The Norway exception
57 zone = 32;
58 else if (band == 9 && ilon >= 0 && ilon < 42) // The Svalbard exception
59 zone = 2 * ((ilon + 183)/12) + 1;
60 return zone;
61 } else
62 return UPS;
63 }
64
65 void UTMUPS::Forward(real lat, real lon,
66 int& zone, bool& northp, real& x, real& y,
67 real& gamma, real& k,
68 int setzone, bool mgrslimits) {
69 if (fabs(lat) > Math::qd)
70 throw GeographicErr("Latitude " + Utility::str(lat)
71 + "d not in [-" + to_string(Math::qd)
72 + "d, " + to_string(Math::qd) + "d]");
73 bool northp1 = !(signbit(lat));
74 int zone1 = StandardZone(lat, lon, setzone);
75 if (zone1 == INVALID) {
76 zone = zone1;
77 northp = northp1;
78 x = y = gamma = k = Math::NaN();
79 return;
80 }
81 real x1, y1, gamma1, k1;
82 bool utmp = zone1 != UPS;
83 if (utmp) {
84 real
85 lon0 = CentralMeridian(zone1),
86 dlon = Math::AngDiff(lon0, lon);
87 if (!(dlon <= 60))
88 // Check isn't really necessary because CheckCoords catches this case.
89 // But this allows a more meaningful error message to be given.
90 throw GeographicErr("Longitude " + Utility::str(lon)
91 + "d more than 60d from center of UTM zone "
92 + Utility::str(zone1));
93 TransverseMercator::UTM().Forward(lon0, lat, lon, x1, y1, gamma1, k1);
94 } else {
95 if (fabs(lat) < 70)
96 // Check isn't really necessary ... (see above).
97 throw GeographicErr("Latitude " + Utility::str(lat)
98 + "d more than 20d from "
99 + (northp1 ? "N" : "S") + " pole");
100 PolarStereographic::UPS().Forward(northp1, lat, lon, x1, y1, gamma1, k1);
101 }
102 int ind = (utmp ? 2 : 0) + (northp1 ? 1 : 0);
103 x1 += falseeasting_[ind];
104 y1 += falsenorthing_[ind];
105 if (! CheckCoords(zone1 != UPS, northp1, x1, y1, mgrslimits, false) )
106 throw GeographicErr("Latitude " + Utility::str(lat)
107 + ", longitude " + Utility::str(lon)
108 + " out of legal range for "
109 + (utmp ? "UTM zone " + Utility::str(zone1) :
110 "UPS"));
111 zone = zone1;
112 northp = northp1;
113 x = x1;
114 y = y1;
115 gamma = gamma1;
116 k = k1;
117 }
118
119 void UTMUPS::Reverse(int zone, bool northp, real x, real y,
120 real& lat, real& lon, real& gamma, real& k,
121 bool mgrslimits) {
122 using std::isnan; // Needed for Centos 7, ubuntu 14
123 if (zone == INVALID || isnan(x) || isnan(y)) {
124 lat = lon = gamma = k = Math::NaN();
125 return;
126 }
127 if (!(zone >= MINZONE && zone <= MAXZONE))
128 throw GeographicErr("Zone " + Utility::str(zone)
129 + " not in range [0, 60]");
130 bool utmp = zone != UPS;
131 CheckCoords(utmp, northp, x, y, mgrslimits);
132 int ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
133 x -= falseeasting_[ind];
134 y -= falsenorthing_[ind];
135 if (utmp)
136 TransverseMercator::UTM().Reverse(CentralMeridian(zone),
137 x, y, lat, lon, gamma, k);
138 else
139 PolarStereographic::UPS().Reverse(northp, x, y, lat, lon, gamma, k);
140 }
141
142 bool UTMUPS::CheckCoords(bool utmp, bool northp, real x, real y,
143 bool mgrslimits, bool throwp) {
144 // Limits are all multiples of 100km and are all closed on the both ends.
145 // Failure tests are such that NaNs succeed.
146 real slop = mgrslimits ? 0 : MGRS::tile_;
147 int ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
148 if (x < mineasting_[ind] - slop || x > maxeasting_[ind] + slop) {
149 if (!throwp) return false;
150 throw GeographicErr("Easting " + Utility::str(x/1000) + "km not in "
151 + (mgrslimits ? "MGRS/" : "")
152 + (utmp ? "UTM" : "UPS") + " range for "
153 + (northp ? "N" : "S" ) + " hemisphere ["
154 + Utility::str((mineasting_[ind] - slop)/1000)
155 + "km, "
156 + Utility::str((maxeasting_[ind] + slop)/1000)
157 + "km]");
158 }
159 if (y < minnorthing_[ind] - slop || y > maxnorthing_[ind] + slop) {
160 if (!throwp) return false;
161 throw GeographicErr("Northing " + Utility::str(y/1000) + "km not in "
162 + (mgrslimits ? "MGRS/" : "")
163 + (utmp ? "UTM" : "UPS") + " range for "
164 + (northp ? "N" : "S" ) + " hemisphere ["
165 + Utility::str((minnorthing_[ind] - slop)/1000)
166 + "km, "
167 + Utility::str((maxnorthing_[ind] + slop)/1000)
168 + "km]");
169 }
170 return true;
171 }
172
173 void UTMUPS::Transfer(int zonein, bool northpin, real xin, real yin,
174 int zoneout, bool northpout, real& xout, real& yout,
175 int& zone) {
176 bool northp = northpin;
177 if (zonein != zoneout) {
178 // Determine lat, lon
179 real lat, lon;
180 GeographicLib::UTMUPS::Reverse(zonein, northpin, xin, yin, lat, lon);
181 // Try converting to zoneout
182 real x, y;
183 int zone1;
184 GeographicLib::UTMUPS::Forward(lat, lon, zone1, northp, x, y,
185 zoneout == UTMUPS::MATCH
186 ? zonein : zoneout);
187 if (zone1 == 0 && northp != northpout)
188 throw GeographicErr
189 ("Attempt to transfer UPS coordinates between hemispheres");
190 zone = zone1;
191 xout = x;
192 yout = y;
193 } else {
194 if (zoneout == 0 && northp != northpout)
195 throw GeographicErr
196 ("Attempt to transfer UPS coordinates between hemispheres");
197 zone = zoneout;
198 xout = xin;
199 yout = yin;
200 }
201 if (northp != northpout)
202 // Can't get here if UPS
203 yout += (northpout ? -1 : 1) * MGRS::utmNshift_;
204 return;
205 }
206
207 void UTMUPS::DecodeZone(const string& zonestr, int& zone, bool& northp)
208 {
209 unsigned zlen = unsigned(zonestr.size());
210 if (zlen == 0)
211 throw GeographicErr("Empty zone specification");
212 // Longest zone spec is 32north, 42south, invalid = 7
213 if (zlen > 7)
214 throw GeographicErr("More than 7 characters in zone specification "
215 + zonestr);
216
217 const char* c = zonestr.c_str();
218 char* q;
219 int zone1 = strtol(c, &q, 10);
220 // if (zone1 == 0) zone1 = UPS; (not necessary)
221
222 if (zone1 == UPS) {
223 if (!(q == c))
224 // Don't allow 0n as an alternative to n for UPS coordinates
225 throw GeographicErr("Illegal zone 0 in " + zonestr +
226 ", use just the hemisphere for UPS");
227 } else if (!(zone1 >= MINUTMZONE && zone1 <= MAXUTMZONE))
228 throw GeographicErr("Zone " + Utility::str(zone1)
229 + " not in range [1, 60]");
230 else if (!isdigit(zonestr[0]))
231 throw GeographicErr("Must use unsigned number for zone "
232 + Utility::str(zone1));
233 else if (q - c > 2)
234 throw GeographicErr("More than 2 digits use to specify zone "
235 + Utility::str(zone1));
236
237 string hemi(zonestr, q - c);
238 for (string::iterator p = hemi.begin(); p != hemi.end(); ++p)
239 *p = char(tolower(*p));
240 if (q == c && (hemi == "inv" || hemi == "invalid")) {
241 zone = INVALID;
242 northp = false;
243 return;
244 }
245 bool northp1 = hemi == "north" || hemi == "n";
246 if (!(northp1 || hemi == "south" || hemi == "s"))
247 throw GeographicErr(string("Illegal hemisphere ") + hemi + " in "
248 + zonestr + ", specify north or south");
249 zone = zone1;
250 northp = northp1;
251 }
252
253 string UTMUPS::EncodeZone(int zone, bool northp, bool abbrev) {
254 if (zone == INVALID)
255 return string(abbrev ? "inv" : "invalid");
256 if (!(zone >= MINZONE && zone <= MAXZONE))
257 throw GeographicErr("Zone " + Utility::str(zone)
258 + " not in range [0, 60]");
259 ostringstream os;
260 if (zone != UPS)
261 os << setfill('0') << setw(2) << zone;
262 if (abbrev)
263 os << (northp ? 'n' : 's');
264 else
265 os << (northp ? "north" : "south");
266 return os.str();
267 }
268
269 void UTMUPS::DecodeEPSG(int epsg, int& zone, bool& northp) {
270 northp = false;
271 if (epsg >= epsg01N && epsg <= epsg60N) {
272 zone = (epsg - epsg01N) + MINUTMZONE;
273 northp = true;
274 } else if (epsg == epsgN) {
275 zone = UPS;
276 northp = true;
277 } else if (epsg >= epsg01S && epsg <= epsg60S) {
278 zone = (epsg - epsg01S) + MINUTMZONE;
279 } else if (epsg == epsgS) {
280 zone = UPS;
281 } else {
282 zone = INVALID;
283 }
284 }
285
286 int UTMUPS::EncodeEPSG(int zone, bool northp) {
287 int epsg = -1;
288 if (zone == UPS)
289 epsg = epsgS;
290 else if (zone >= MINUTMZONE && zone <= MAXUTMZONE)
291 epsg = (zone - MINUTMZONE) + epsg01S;
292 if (epsg >= 0 && northp)
293 epsg += epsgN - epsgS;
294 return epsg;
295 }
296
297 Math::real UTMUPS::UTMShift() { return real(MGRS::utmNshift_); }
298
299} // namespace GeographicLib
real
GeographicLib::Math::real real
Definition GeodSolve.cpp:28
MGRS.hpp
Header for GeographicLib::MGRS class.
PolarStereographic.hpp
Header for GeographicLib::PolarStereographic class.
TransverseMercator.hpp
Header for GeographicLib::TransverseMercator class.
UTMUPS.hpp
Header for GeographicLib::UTMUPS class.
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition Constants.hpp:316
GeographicLib::Math::qd
static constexpr int qd
degrees per quarter turn
Definition Math.hpp:145
GeographicLib::Math::AngNormalize
static T AngNormalize(T x)
Definition Math.cpp:66
GeographicLib::Math::NaN
static T NaN()
Definition Math.cpp:277
GeographicLib::Math::AngDiff
static T AngDiff(T x, T y, T &e)
Definition Math.cpp:77
GeographicLib::Math::hd
static constexpr int hd
degrees per half turn
Definition Math.hpp:148
GeographicLib::Math::real
double real
Definition Math.hpp:110
GeographicLib::PolarStereographic::Reverse
void Reverse(bool northp, real x, real y, real &lat, real &lon, real &gamma, real &k) const
Definition PolarStereographic.cpp:81
GeographicLib::PolarStereographic::UPS
static const PolarStereographic & UPS()
Definition PolarStereographic.cpp:33
GeographicLib::PolarStereographic::Forward
void Forward(bool northp, real lat, real lon, real &x, real &y, real &gamma, real &k) const
Definition PolarStereographic.cpp:61
GeographicLib::TransverseMercator::Reverse
void Reverse(real lon0, real x, real y, real &lat, real &lon, real &gamma, real &k) const
Definition TransverseMercator.cpp:523
GeographicLib::TransverseMercator::UTM
static const TransverseMercator & UTM()
Definition TransverseMercator.cpp:282
GeographicLib::TransverseMercator::Forward
void Forward(real lon0, real lat, real lon, real &x, real &y, real &gamma, real &k) const
Definition TransverseMercator.cpp:355
GeographicLib::UTMUPS::MINPSEUDOZONE
@ MINPSEUDOZONE
Definition UTMUPS.hpp:113
GeographicLib::UTMUPS::MAXZONE
@ MAXZONE
Definition UTMUPS.hpp:162
GeographicLib::UTMUPS::MINUTMZONE
@ MINUTMZONE
Definition UTMUPS.hpp:154
GeographicLib::UTMUPS::UPS
@ UPS
Definition UTMUPS.hpp:150
GeographicLib::UTMUPS::MATCH
@ MATCH
Definition UTMUPS.hpp:122
GeographicLib::UTMUPS::UTM
@ UTM
Definition UTMUPS.hpp:129
GeographicLib::UTMUPS::MAXUTMZONE
@ MAXUTMZONE
Definition UTMUPS.hpp:158
GeographicLib::UTMUPS::INVALID
@ INVALID
Definition UTMUPS.hpp:117
GeographicLib::UTMUPS::MINZONE
@ MINZONE
Definition UTMUPS.hpp:146
GeographicLib::UTMUPS::EncodeEPSG
static int EncodeEPSG(int zone, bool northp)
Definition UTMUPS.cpp:286
GeographicLib::UTMUPS::StandardZone
static int StandardZone(real lat, real lon, int setzone=STANDARD)
Definition UTMUPS.cpp:43
GeographicLib::UTMUPS::EncodeZone
static std::string EncodeZone(int zone, bool northp, bool abbrev=true)
Definition UTMUPS.cpp:253
GeographicLib::UTMUPS::Forward
static void Forward(real lat, real lon, int &zone, bool &northp, real &x, real &y, real &gamma, real &k, int setzone=STANDARD, bool mgrslimits=false)
Definition UTMUPS.cpp:65
GeographicLib::UTMUPS::DecodeEPSG
static void DecodeEPSG(int epsg, int &zone, bool &northp)
Definition UTMUPS.cpp:269
GeographicLib::UTMUPS::Reverse
static void Reverse(int zone, bool northp, real x, real y, real &lat, real &lon, real &gamma, real &k, bool mgrslimits=false)
Definition UTMUPS.cpp:119
GeographicLib::UTMUPS::UTMShift
static Math::real UTMShift()
Definition UTMUPS.cpp:297
GeographicLib::UTMUPS::Transfer
static void Transfer(int zonein, bool northpin, real xin, real yin, int zoneout, bool northpout, real &xout, real &yout, int &zone)
Definition UTMUPS.cpp:173
GeographicLib::UTMUPS::DecodeZone
static void DecodeZone(const std::string &zonestr, int &zone, bool &northp)
Definition UTMUPS.cpp:207
GeographicLib::Utility
Some utility routines for GeographicLib.
Definition Utility.hpp:35
GeographicLib::Utility::str
static std::string str(T x, int p=-1)
Definition Utility.hpp:161
GeographicLib
Namespace for GeographicLib.
Definition Accumulator.cpp:12
std
Definition NearestNeighbor.hpp:806