GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
UTMUPS.hpp
Go to the documentation of this file.
1
/**
2
* \file UTMUPS.hpp
3
* \brief Header 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
#if !defined(GEOGRAPHICLIB_UTMUPS_HPP)
11
#define GEOGRAPHICLIB_UTMUPS_HPP 1
12
13
#include <
GeographicLib/Constants.hpp
>
14
15
namespace
GeographicLib
{
16
17
/**
18
* \brief Convert between geographic coordinates and UTM/UPS
19
*
20
* UTM and UPS are defined
21
* - J. W. Hager, J. F. Behensky, and B. W. Drew,
22
* <a href="https://web.archive.org/web/20161214054445/http://earth-info.nga.mil/GandG/publications/tm8358.2/TM8358_2.pdf">
23
* The Universal Grids: Universal Transverse Mercator (UTM) and Universal
24
* Polar Stereographic (UPS)</a>, Defense Mapping Agency, Technical Manual
25
* TM8358.2 (1989).
26
* .
27
* Section 2-3 defines UTM and section 3-2.4 defines UPS. This document also
28
* includes approximate algorithms for the computation of the underlying
29
* transverse Mercator and polar stereographic projections. Here we
30
* substitute much more accurate algorithms given by
31
* GeographicLib:TransverseMercator and GeographicLib:PolarStereographic.
32
* These are the algorithms recommended by the NGA document
33
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-utmups">
34
* The Universal Grids and the Transverse Mercator and Polar Stereographic
35
* Map Projections</a>, NGA.SIG.0012 (2014).
36
*
37
* In this implementation, the conversions are closed, i.e., output from
38
* Forward is legal input for Reverse and vice versa. The error is about 5nm
39
* in each direction. However, the conversion from legal UTM/UPS coordinates
40
* to geographic coordinates and back might throw an error if the initial
41
* point is within 5nm of the edge of the allowed range for the UTM/UPS
42
* coordinates.
43
*
44
* The simplest way to guarantee the closed property is to define allowed
45
* ranges for the eastings and northings for UTM and UPS coordinates. The
46
* UTM boundaries are the same for all zones. (The only place the
47
* exceptional nature of the zone boundaries is evident is when converting to
48
* UTM/UPS coordinates requesting the standard zone.) The MGRS lettering
49
* scheme imposes natural limits on UTM/UPS coordinates which may be
50
* converted into MGRS coordinates. For the conversion to/from geographic
51
* coordinates these ranges have been extended by 100km in order to provide a
52
* generous overlap between UTM and UPS and between UTM zones.
53
*
54
* The <a href="http://www.nga.mil">NGA</a> software package
55
* <a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_geotrans">geotrans</a>
56
* also provides conversions to and from UTM and UPS. Version 2.4.2 (and
57
* earlier) suffers from some drawbacks:
58
* - Inconsistent rules are used to determine the whether a particular UTM or
59
* UPS coordinate is legal. A more systematic approach is taken here.
60
* - The underlying projections are not very accurately implemented.
61
*
62
* The GeographicLib::UTMUPS::EncodeZone encodes the UTM zone and hemisphere
63
* to allow UTM/UPS coordinated to be displayed as, for example, "38N 444500
64
* 3688500". According to NGA.SIG.0012_2.0.0_UTMUPS the use of "N" to denote
65
* "north" in the context is not allowed (since a upper case letter in this
66
* context denotes the MGRS latitude band). Consequently, as of version
67
* 1.36, EncodeZone uses the lower case letters "n" and "s" to denote the
68
* hemisphere. In addition EncodeZone accepts an optional final argument \e
69
* abbrev, which, if false, results in the hemisphere being spelled out as in
70
* "38north".
71
*
72
* Example of use:
73
* \include example-UTMUPS.cpp
74
**********************************************************************/
75
class
GEOGRAPHICLIB_EXPORT
UTMUPS {
76
private
:
77
typedef
Math::real
real;
78
static
const
int
falseeasting_[4];
79
static
const
int
falsenorthing_[4];
80
static
const
int
mineasting_[4];
81
static
const
int
maxeasting_[4];
82
static
const
int
minnorthing_[4];
83
static
const
int
maxnorthing_[4];
84
static
const
int
epsg01N = 32601;
// EPSG code for UTM 01N
85
static
const
int
epsg60N = 32660;
// EPSG code for UTM 60N
86
static
const
int
epsgN = 32661;
// EPSG code for UPS N
87
static
const
int
epsg01S = 32701;
// EPSG code for UTM 01S
88
static
const
int
epsg60S = 32760;
// EPSG code for UTM 60S
89
static
const
int
epsgS = 32761;
// EPSG code for UPS S
90
static
real CentralMeridian(
int
zone)
91
{
return
real
(6 * zone - 183); }
92
// Throw an error if easting or northing are outside standard ranges. If
93
// throwp = false, return bool instead.
94
static
bool
CheckCoords(
bool
utmp,
bool
northp, real x, real y,
95
bool
msgrlimits =
false
,
bool
throwp =
true
);
96
UTMUPS() =
delete
;
// Disable constructor
97
98
public
:
99
100
/**
101
* In this class we bring together the UTM and UPS coordinates systems.
102
* The UTM divides the earth between latitudes −80° and 84°
103
* into 60 zones numbered 1 thru 60. Zone assign zone number 0 to the UPS
104
* regions, covering the two poles. Within UTMUPS, nonnegative zone
105
* numbers refer to one of the "physical" zones, 0 for UPS and [1, 60] for
106
* UTM. Negative "pseudo-zone" numbers are used to select one of the
107
* physical zones.
108
**********************************************************************/
109
enum
zonespec
{
110
/**
111
* The smallest pseudo-zone number.
112
**********************************************************************/
113
MINPSEUDOZONE
= -4,
114
/**
115
* A marker for an undefined or invalid zone. Equivalent to NaN.
116
**********************************************************************/
117
INVALID
= -4,
118
/**
119
* If a coordinate already include zone information (e.g., it is an MGRS
120
* coordinate), use that, otherwise apply the UTMUPS::STANDARD rules.
121
**********************************************************************/
122
MATCH
= -3,
123
/**
124
* Apply the standard rules for UTM zone assigment extending the UTM zone
125
* to each pole to give a zone number in [1, 60]. For example, use UTM
126
* zone 38 for longitude in [42°, 48°). The rules include the
127
* Norway and Svalbard exceptions.
128
**********************************************************************/
129
UTM
= -2,
130
/**
131
* Apply the standard rules for zone assignment to give a zone number in
132
* [0, 60]. If the latitude is not in [−80°, 84°), then
133
* use UTMUPS::UPS = 0, otherwise apply the rules for UTMUPS::UTM. The
134
* tests on latitudes and longitudes are all closed on the lower end open
135
* on the upper. Thus for UTM zone 38, latitude is in [−80°,
136
* 84°) and longitude is in [42°, 48°).
137
**********************************************************************/
138
STANDARD
= -1,
139
/**
140
* The largest pseudo-zone number.
141
**********************************************************************/
142
MAXPSEUDOZONE
= -1,
143
/**
144
* The smallest physical zone number.
145
**********************************************************************/
146
MINZONE
= 0,
147
/**
148
* The zone number used for UPS
149
**********************************************************************/
150
UPS
= 0,
151
/**
152
* The smallest UTM zone number.
153
**********************************************************************/
154
MINUTMZONE
= 1,
155
/**
156
* The largest UTM zone number.
157
**********************************************************************/
158
MAXUTMZONE
= 60,
159
/**
160
* The largest physical zone number.
161
**********************************************************************/
162
MAXZONE
= 60,
163
};
164
165
/**
166
* The standard zone.
167
*
168
* @param[in] lat latitude (degrees).
169
* @param[in] lon longitude (degrees).
170
* @param[in] setzone zone override (optional). If omitted, use the
171
* standard rules for picking the zone. If \e setzone is given then use
172
* that zone if it is nonnegative, otherwise apply the rules given in
173
* UTMUPS::zonespec.
174
* @exception GeographicErr if \e setzone is outside the range
175
* [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE] = [−4, 60].
176
*
177
* This is exact.
178
**********************************************************************/
179
static
int
StandardZone(
real
lat,
real
lon,
int
setzone = STANDARD);
180
181
/**
182
* Forward projection, from geographic to UTM/UPS.
183
*
184
* @param[in] lat latitude of point (degrees).
185
* @param[in] lon longitude of point (degrees).
186
* @param[out] zone the UTM zone (zero means UPS).
187
* @param[out] northp hemisphere (true means north, false means south).
188
* @param[out] x easting of point (meters).
189
* @param[out] y northing of point (meters).
190
* @param[out] gamma meridian convergence at point (degrees).
191
* @param[out] k scale of projection at point.
192
* @param[in] setzone zone override (optional).
193
* @param[in] mgrslimits if true enforce the stricter MGRS limits on the
194
* coordinates (default = false).
195
* @exception GeographicErr if \e lat is not in [−90°,
196
* 90°].
197
* @exception GeographicErr if the resulting \e x or \e y is out of allowed
198
* range (see Reverse); in this case, these arguments are unchanged.
199
*
200
* If \e setzone is omitted, use the standard rules for picking the zone.
201
* If \e setzone is given then use that zone if it is nonnegative,
202
* otherwise apply the rules given in UTMUPS::zonespec. The accuracy of
203
* the conversion is about 5nm.
204
*
205
* The northing \e y jumps by UTMUPS::UTMShift() when crossing the equator
206
* in the southerly direction. Sometimes it is useful to remove this
207
* discontinuity in \e y by extending the "northern" hemisphere using
208
* UTMUPS::Transfer:
209
* \code
210
double lat = -1, lon = 123;
211
int zone;
212
bool northp;
213
double x, y, gamma, k;
214
GeographicLib::UTMUPS::Forward(lat, lon, zone, northp, x, y, gamma, k);
215
GeographicLib::UTMUPS::Transfer(zone, northp, x, y,
216
zone, true, x, y, zone);
217
northp = true;
218
\endcode
219
**********************************************************************/
220
static
void
Forward(
real
lat,
real
lon,
221
int
& zone,
bool
& northp,
real
& x,
real
& y,
222
real
& gamma,
real
& k,
223
int
setzone = STANDARD,
bool
mgrslimits =
false
);
224
225
/**
226
* Reverse projection, from UTM/UPS to geographic.
227
*
228
* @param[in] zone the UTM zone (zero means UPS).
229
* @param[in] northp hemisphere (true means north, false means south).
230
* @param[in] x easting of point (meters).
231
* @param[in] y northing of point (meters).
232
* @param[out] lat latitude of point (degrees).
233
* @param[out] lon longitude of point (degrees).
234
* @param[out] gamma meridian convergence at point (degrees).
235
* @param[out] k scale of projection at point.
236
* @param[in] mgrslimits if true enforce the stricter MGRS limits on the
237
* coordinates (default = false).
238
* @exception GeographicErr if \e zone, \e x, or \e y is out of allowed
239
* range; this this case the arguments are unchanged.
240
*
241
* The accuracy of the conversion is about 5nm.
242
*
243
* UTM eastings are allowed to be in the range [0km, 1000km], northings are
244
* allowed to be in in [0km, 9600km] for the northern hemisphere and in
245
* [900km, 10000km] for the southern hemisphere. However UTM northings
246
* can be continued across the equator. So the actual limits on the
247
* northings are [-9100km, 9600km] for the "northern" hemisphere and
248
* [900km, 19600km] for the "southern" hemisphere.
249
*
250
* UPS eastings and northings are allowed to be in the range [1200km,
251
* 2800km] in the northern hemisphere and in [700km, 3300km] in the
252
* southern hemisphere.
253
*
254
* These ranges are 100km larger than allowed for the conversions to MGRS.
255
* (100km is the maximum extra padding consistent with eastings remaining
256
* nonnegative.) This allows generous overlaps between zones and UTM and
257
* UPS. If \e mgrslimits = true, then all the ranges are shrunk by 100km
258
* so that they agree with the stricter MGRS ranges. No checks are
259
* performed besides these (e.g., to limit the distance outside the
260
* standard zone boundaries).
261
**********************************************************************/
262
static
void
Reverse(
int
zone,
bool
northp,
real
x,
real
y,
263
real
& lat,
real
& lon,
real
& gamma,
real
& k,
264
bool
mgrslimits =
false
);
265
266
/**
267
* UTMUPS::Forward without returning convergence and scale.
268
**********************************************************************/
269
static
void
Forward
(real lat, real lon,
270
int
& zone,
bool
& northp, real& x, real& y,
271
int
setzone =
STANDARD
,
bool
mgrslimits =
false
) {
272
real gamma, k;
273
Forward
(lat, lon, zone, northp, x, y, gamma, k, setzone, mgrslimits);
274
}
275
276
/**
277
* UTMUPS::Reverse without returning convergence and scale.
278
**********************************************************************/
279
static
void
Reverse
(
int
zone,
bool
northp, real x, real y,
280
real& lat, real& lon,
bool
mgrslimits =
false
) {
281
real gamma, k;
282
Reverse
(zone, northp, x, y, lat, lon, gamma, k, mgrslimits);
283
}
284
285
/**
286
* Transfer UTM/UPS coordinated from one zone to another.
287
*
288
* @param[in] zonein the UTM zone for \e xin and \e yin (or zero for UPS).
289
* @param[in] northpin hemisphere for \e xin and \e yin (true means north,
290
* false means south).
291
* @param[in] xin easting of point (meters) in \e zonein.
292
* @param[in] yin northing of point (meters) in \e zonein.
293
* @param[in] zoneout the requested UTM zone for \e xout and \e yout (or
294
* zero for UPS).
295
* @param[in] northpout hemisphere for \e xout output and \e yout.
296
* @param[out] xout easting of point (meters) in \e zoneout.
297
* @param[out] yout northing of point (meters) in \e zoneout.
298
* @param[out] zone the actual UTM zone for \e xout and \e yout (or zero
299
* for UPS); this equals \e zoneout if \e zoneout ≥ 0.
300
* @exception GeographicErr if \e zonein is out of range (see below).
301
* @exception GeographicErr if \e zoneout is out of range (see below).
302
* @exception GeographicErr if \e xin or \e yin fall outside their allowed
303
* ranges (see UTMUPS::Reverse).
304
* @exception GeographicErr if \e xout or \e yout fall outside their
305
* allowed ranges (see UTMUPS::Reverse).
306
*
307
* \e zonein must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
308
* 60] with \e zonein = UTMUPS::UPS, 0, indicating UPS. \e zonein may
309
* also be UTMUPS::INVALID.
310
*
311
* \e zoneout must be in the range [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE]
312
* = [-4, 60]. If \e zoneout < UTMUPS::MINZONE then the rules give in
313
* the documentation of UTMUPS::zonespec are applied, and \e zone is set to
314
* the actual zone used for output.
315
*
316
* (\e xout, \e yout) can overlap with (\e xin, \e yin).
317
**********************************************************************/
318
static
void
Transfer(
int
zonein,
bool
northpin,
real
xin,
real
yin,
319
int
zoneout,
bool
northpout,
real
& xout,
real
& yout,
320
int
& zone);
321
322
/**
323
* Decode a UTM/UPS zone string.
324
*
325
* @param[in] zonestr string representation of zone and hemisphere.
326
* @param[out] zone the UTM zone (zero means UPS).
327
* @param[out] northp hemisphere (true means north, false means south).
328
* @exception GeographicErr if \e zonestr is malformed.
329
*
330
* For UTM, \e zonestr has the form of a zone number in the range
331
* [UTMUPS::MINUTMZONE, UTMUPS::MAXUTMZONE] = [1, 60] followed by a
332
* hemisphere letter, n or s (or "north" or "south" spelled out). For UPS,
333
* it consists just of the hemisphere letter (or the spelled out
334
* hemisphere). The returned value of \e zone is UTMUPS::UPS = 0 for UPS.
335
* Note well that "38s" indicates the southern hemisphere of zone 38 and
336
* not latitude band S, 32° ≤ \e lat < 40°. n, 01s, 2n, 38s,
337
* south, 3north are legal. 0n, 001s, +3n, 61n, 38P are illegal. INV is a
338
* special value for which the returned value of \e is UTMUPS::INVALID.
339
**********************************************************************/
340
static
void
DecodeZone(
const
std::string& zonestr,
341
int
& zone,
bool
& northp);
342
343
/**
344
* Encode a UTM/UPS zone string.
345
*
346
* @param[in] zone the UTM zone (zero means UPS).
347
* @param[in] northp hemisphere (true means north, false means south).
348
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
349
* for hemisphere; otherwise spell out the hemisphere (north/south)
350
* @exception GeographicErr if \e zone is out of range (see below).
351
* @exception std::bad_alloc if memoy for the string can't be allocated.
352
* @return string representation of zone and hemisphere.
353
*
354
* \e zone must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
355
* 60] with \e zone = UTMUPS::UPS, 0, indicating UPS (but the resulting
356
* string does not contain "0"). \e zone may also be UTMUPS::INVALID, in
357
* which case the returned string is "inv". This reverses
358
* UTMUPS::DecodeZone.
359
**********************************************************************/
360
static
std::string EncodeZone(
int
zone,
bool
northp,
bool
abbrev =
true
);
361
362
/**
363
* Decode EPSG.
364
*
365
* @param[in] epsg the EPSG code.
366
* @param[out] zone the UTM zone (zero means UPS).
367
* @param[out] northp hemisphere (true means north, false means south).
368
*
369
* EPSG (European Petroleum Survery Group) codes are a way to refer to many
370
* different projections. DecodeEPSG decodes those referring to UTM or UPS
371
* projections for the WGS84 ellipsoid. If the code does not refer to one
372
* of these projections, \e zone is set to UTMUPS::INVALID. See
373
* https://www.spatialreference.org/ref/epsg/
374
**********************************************************************/
375
static
void
DecodeEPSG(
int
epsg,
int
& zone,
bool
& northp);
376
377
/**
378
* Encode zone as EPSG.
379
*
380
* @param[in] zone the UTM zone (zero means UPS).
381
* @param[in] northp hemisphere (true means north, false means south).
382
* @return EPSG code (or -1 if \e zone is not in the range
383
* [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0, 60])
384
*
385
* Convert \e zone and \e northp to the corresponding EPSG (European
386
* Petroleum Survery Group) codes
387
**********************************************************************/
388
static
int
EncodeEPSG(
int
zone,
bool
northp);
389
390
/**
391
* @return shift (meters) necessary to align north and south halves of a
392
* UTM zone (10<sup>7</sup>).
393
**********************************************************************/
394
static
Math::real
UTMShift();
395
396
/** \name Inspector functions
397
**********************************************************************/
398
///@{
399
/**
400
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
401
*
402
* (The WGS84 value is returned because the UTM and UPS projections are
403
* based on this ellipsoid.)
404
**********************************************************************/
405
static
Math::real
EquatorialRadius
()
406
{
return
Constants::WGS84_a
(); }
407
408
/**
409
* @return \e f the flattening of the WGS84 ellipsoid.
410
*
411
* (The WGS84 value is returned because the UTM and UPS projections are
412
* based on this ellipsoid.)
413
**********************************************************************/
414
static
Math::real
Flattening
()
415
{
return
Constants::WGS84_f
(); }
416
///@}
417
418
};
419
420
}
// namespace GeographicLib
421
422
#endif
// GEOGRAPHICLIB_UTMUPS_HPP
Constants.hpp
Header for GeographicLib::Constants class.
GEOGRAPHICLIB_EXPORT
#define GEOGRAPHICLIB_EXPORT
Definition
Constants.hpp:59
real
GeographicLib::Math::real real
Definition
Geod3Solve.cpp:25
GeographicLib::Constants::WGS84_f
static T WGS84_f()
Definition
Constants.hpp:118
GeographicLib::Constants::WGS84_a
static T WGS84_a()
Definition
Constants.hpp:112
GeographicLib::Math::real
double real
Definition
Math.hpp:115
GeographicLib::UTMUPS::zonespec
zonespec
Definition
UTMUPS.hpp:109
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::MAXPSEUDOZONE
@ MAXPSEUDOZONE
Definition
UTMUPS.hpp:142
GeographicLib::UTMUPS::STANDARD
@ STANDARD
Definition
UTMUPS.hpp:138
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::Flattening
static Math::real Flattening()
Definition
UTMUPS.hpp:414
GeographicLib::UTMUPS::EquatorialRadius
static Math::real EquatorialRadius()
Definition
UTMUPS.hpp:405
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:64
GeographicLib::UTMUPS::Forward
static void Forward(real lat, real lon, int &zone, bool &northp, real &x, real &y, int setzone=STANDARD, bool mgrslimits=false)
Definition
UTMUPS.hpp: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:118
GeographicLib::UTMUPS::Reverse
static void Reverse(int zone, bool northp, real x, real y, real &lat, real &lon, bool mgrslimits=false)
Definition
UTMUPS.hpp:279
GeographicLib
Namespace for GeographicLib.
Definition
Accumulator.cpp:12
include
GeographicLib
UTMUPS.hpp
Generated by
1.17.0