16 namespace GeographicLib {
21 { MGRS::upseasting_ * MGRS::tile_, MGRS::upseasting_ * MGRS::tile_,
22 MGRS::utmeasting_ * MGRS::tile_, MGRS::utmeasting_ * MGRS::tile_ };
24 { MGRS::upseasting_ * MGRS::tile_, MGRS::upseasting_ * MGRS::tile_,
25 MGRS::maxutmSrow_ * MGRS::tile_, MGRS::minutmNrow_ * MGRS::tile_ };
27 { MGRS::minupsSind_ * MGRS::tile_, MGRS::minupsNind_ * MGRS::tile_,
28 MGRS::minutmcol_ * MGRS::tile_, MGRS::minutmcol_ * MGRS::tile_ };
30 { MGRS::maxupsSind_ * MGRS::tile_, MGRS::maxupsNind_ * MGRS::tile_,
31 MGRS::maxutmcol_ * MGRS::tile_, MGRS::maxutmcol_ * MGRS::tile_ };
33 { MGRS::minupsSind_ * MGRS::tile_, MGRS::minupsNind_ * MGRS::tile_,
34 MGRS::minutmSrow_ * MGRS::tile_,
35 (MGRS::minutmNrow_ + MGRS::minutmSrow_ - MGRS::maxutmSrow_)
38 { MGRS::maxupsSind_ * MGRS::tile_, MGRS::maxupsNind_ * MGRS::tile_,
39 (MGRS::maxutmSrow_ + MGRS::maxutmNrow_ - MGRS::minutmNrow_) * MGRS::tile_,
40 MGRS::maxutmNrow_ * MGRS::tile_ };
43 if (!(setzone >= MINPSEUDOZONE && setzone <= MAXZONE))
45 if (setzone >= MINZONE || setzone == INVALID)
49 if (setzone == UTM || (lat >= -80 && lat < 84)) {
51 int ilon = int(floor(lon));
56 int zone = (ilon + 186)/6;
57 int band = MGRS::LatitudeBand(lat);
58 if (band == 7 && zone == 31 && ilon >= 3)
60 else if (band == 9 && ilon >= 0 && ilon < 42)
61 zone = 2 * ((ilon + 183)/12) + 1;
68 int& zone,
bool& northp, real& x, real& y,
70 int setzone,
bool mgrslimits) {
71 CheckLatLon(lat, lon);
72 bool northp1 = lat >= 0;
73 int zone1 = StandardZone(lat, lon, setzone);
74 if (zone1 == INVALID) {
77 x = y = gamma = k = Math::NaN<real>();
80 real x1, y1, gamma1, k1;
81 bool utmp = zone1 != UPS;
84 lon0 = CentralMeridian(zone1),
86 dlon = abs(dlon - 360 * floor((dlon + 180)/360));
91 +
"d more than 60d from center of UTM zone "
98 +
"d more than 20d from "
99 + (northp1 ?
"N" :
"S") +
" pole");
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) )
108 +
" out of legal range for "
119 real& lat, real& lon, real& gamma, real& k,
122 lat = lon = gamma = k = Math::NaN<real>();
125 if (!(zone >= MINZONE && zone <= MAXZONE))
127 +
" not in range [0, 60]");
128 bool utmp = zone != UPS;
129 CheckCoords(utmp, northp, x, y, mgrslimits);
130 int ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
131 x -= falseeasting_[ind];
132 y -= falsenorthing_[ind];
135 x, y, lat, lon, gamma, k);
140 void UTMUPS::CheckLatLon(
real lat,
real lon) {
143 +
"d not in [-90d, 90d]");
144 if (lon < -540 || lon >= 540)
146 +
"d not in [-540d, 540d)");
149 bool UTMUPS::CheckCoords(
bool utmp,
bool northp,
real x,
real y,
150 bool mgrslimits,
bool throwp) {
153 real slop = mgrslimits ? 0 : MGRS::tile_;
154 int ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
155 if (x < mineasting_[ind] - slop || x > maxeasting_[ind] + slop) {
156 if (!throwp)
return false;
157 throw GeographicErr(
"Easting " +
Utility::str(x/1000) +
"km not in "
158 + (mgrslimits ?
"MGRS/" :
"")
159 + (utmp ?
"UTM" :
"UPS") +
" range for "
160 + (northp ?
"N" :
"S" ) +
" hemisphere ["
166 if (y < minnorthing_[ind] - slop || y > maxnorthing_[ind] + slop) {
167 if (!throwp)
return false;
168 throw GeographicErr(
"Northing " +
Utility::str(y/1000) +
"km not in "
169 + (mgrslimits ?
"MGRS/" :
"")
170 + (utmp ?
"UTM" :
"UPS") +
" range for "
171 + (northp ?
"N" :
"S" ) +
" hemisphere ["
181 int zoneout,
bool northpout, real& xout, real& yout,
183 bool northp = northpin;
184 if (zonein != zoneout) {
194 if (zone1 == 0 && northp != northpout)
196 (
"Attempt to transfer UPS coordinates between hemispheres");
201 if (zoneout == 0 && northp != northpout)
203 (
"Attempt to transfer UPS coordinates between hemispheres");
208 if (northp != northpout)
210 yout += (northpout ? -1 : 1) * MGRS::utmNshift_;
215 unsigned zlen = unsigned(zonestr.size());
219 throw GeographicErr(
"More than 3 characters in zone specification "
222 toupper(zonestr[0]) ==
'I' &&
223 toupper(zonestr[1]) ==
'N' &&
224 toupper(zonestr[2]) ==
'V') {
229 char hemi = char(toupper(zonestr[zlen - 1]));
230 bool northp1 = hemi ==
'N';
231 if (! (northp1 || hemi ==
'S'))
232 throw GeographicErr(
string(
"Illegal hemisphere letter ") + hemi +
" in "
233 + zonestr +
", specify N or S");
237 const char* c = zonestr.c_str();
239 int zone1 = strtol(c, &q, 10);
242 if (q - c !=
int(zlen) - 1)
244 zonestr.substr(q - c,
int(zlen) - 1 - (q - c)) +
245 " in UTM/UPS zone " + zonestr);
249 ", use just " + hemi +
" for UPS");
250 if (!(zone1 >= MINUTMZONE && zone1 <= MAXUTMZONE))
252 +
" not in range [1, 60]");
260 return string(
"INV");
261 if (!(zone >= MINZONE && zone <= MAXZONE))
263 +
" not in range [0, 60]");
266 os << setfill(
'0') << setw(2) << zone;
267 os << (northp ?
'N' :
'S');
272 if (epsg >= epsg01N && epsg <= epsg60N) {
273 zone = epsg - epsg01N + 1;
275 }
else if (epsg == epsgN) {
278 }
else if (epsg >= epsg01S && epsg <= epsg60S) {
279 zone = epsg - epsg01S + 1;
281 }
else if (epsg == epsgS) {
294 else if (zone >= MINUTMZONE && zone <= MAXUTMZONE)
295 epsg = epsg + (zone - MINUTMZONE) + epsg01S;
296 if (epsg >= 0 && northp)
297 epsg += epsgN - epsgS;