NETGeographicLib 1.52
Loading...
Searching...
No Matches
UTMUPS.h
Go to the documentation of this file.
1#pragma once
2/**
3 * \file NETGeographicLib/UTMUPS.h
4 * \brief Header for NETGeographicLib::UTMUPS class
5 *
6 * NETGeographicLib is copyright (c) Scott Heiman (2013)
7 * GeographicLib is Copyright (c) Charles Karney (2010-2012)
8 * <charles@karney.com> and licensed under the MIT/X11 License.
9 * For more information, see
10 * https://geographiclib.sourceforge.io/
11 **********************************************************************/
12
13namespace NETGeographicLib
14{
15 /**
16 * \brief .NET wrapper for GeographicLib::UTMUPS.
17 *
18 * This class allows .NET applications to access GeographicLib::UTMUPS.
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 *
33 * In this implementation, the conversions are closed, i.e., output from
34 * Forward is legal input for Reverse and vice versa. The error is about 5nm
35 * in each direction. However, the conversion from legal UTM/UPS coordinates
36 * to geographic coordinates and back might throw an error if the initial
37 * point is within 5nm of the edge of the allowed range for the UTM/UPS
38 * coordinates.
39 *
40 * The simplest way to guarantee the closed property is to define allowed
41 * ranges for the eastings and northings for UTM and UPS coordinates. The
42 * UTM boundaries are the same for all zones. (The only place the
43 * exceptional nature of the zone boundaries is evident is when converting to
44 * UTM/UPS coordinates requesting the standard zone.) The MGRS lettering
45 * scheme imposes natural limits on UTM/UPS coordinates which may be
46 * converted into MGRS coordinates. For the conversion to/from geographic
47 * coordinates these ranges have been extended by 100km in order to provide a
48 * generous overlap between UTM and UPS and between UTM zones.
49 *
50 * The <a href="http://www.nga.mil">NGA</a> software package
51 * <a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_geotrans">geotrans</a>
52 * also provides conversions to and from UTM and UPS. Version 2.4.2 (and
53 * earlier) suffers from some drawbacks:
54 * - Inconsistent rules are used to determine the whether a particular UTM or
55 * UPS coordinate is legal. A more systematic approach is taken here.
56 * - The underlying projections are not very accurately implemented.
57 *
58 * C# Example:
59 * \include example-UTMUPS.cs
60 * Managed C++ Example:
61 * \include example-UTMUPS.cpp
62 * Visual Basic Example:
63 * \include example-UTMUPS.vb
64 *
65 **********************************************************************/
66 public ref class UTMUPS
67 {
68 private:
69 // hide the constructor since all members of the class are static.
70 UTMUPS() {}
71 public:
72 /**
73 * In this class we bring together the UTM and UPS coordinates systems.
74 * The UTM divides the earth between latitudes &minus;80&deg; and 84&deg;
75 * into 60 zones numbered 1 thru 60. Zone assign zone number 0 to the UPS
76 * regions, covering the two poles. Within UTMUPS, non-negative zone
77 * numbers refer to one of the "physical" zones, 0 for UPS and [1, 60] for
78 * UTM. Negative "pseudo-zone" numbers are used to select one of the
79 * physical zones.
80 **********************************************************************/
81 enum class ZoneSpec {
82 /**
83 * The smallest pseudo-zone number.
84 **********************************************************************/
85 MINPSEUDOZONE = -4,
86 /**
87 * A marker for an undefined or invalid zone. Equivalent to NaN.
88 **********************************************************************/
89 INVALID = -4,
90 /**
91 * If a coordinate already include zone information (e.g., it is an MGRS
92 * coordinate), use that, otherwise apply the UTMUPS::STANDARD rules.
93 **********************************************************************/
94 MATCH = -3,
95 /**
96 * Apply the standard rules for UTM zone assigment extending the UTM zone
97 * to each pole to give a zone number in [1, 60]. For example, use UTM
98 * zone 38 for longitude in [42&deg;, 48&deg;). The rules include the
99 * Norway and Svalbard exceptions.
100 **********************************************************************/
101 UTM = -2,
102 /**
103 * Apply the standard rules for zone assignment to give a zone number in
104 * [0, 60]. If the latitude is not in [&minus;80&deg;, 84&deg;), then
105 * use UTMUPS::UPS = 0, otherwise apply the rules for UTMUPS::UTM. The
106 * tests on latitudes and longitudes are all closed on the lower end open
107 * on the upper. Thus for UTM zone 38, latitude is in [&minus;80&deg;,
108 * 84&deg;) and longitude is in [42&deg;, 48&deg;).
109 **********************************************************************/
110 STANDARD = -1,
111 /**
112 * The largest pseudo-zone number.
113 **********************************************************************/
114 MAXPSEUDOZONE = -1,
115 /**
116 * The smallest physical zone number.
117 **********************************************************************/
118 MINZONE = 0,
119 /**
120 * The zone number used for UPS
121 **********************************************************************/
122 UPS = 0,
123 /**
124 * The smallest UTM zone number.
125 **********************************************************************/
126 MINUTMZONE = 1,
127 /**
128 * The largest UTM zone number.
129 **********************************************************************/
130 MAXUTMZONE = 60,
131 /**
132 * The largest physical zone number.
133 **********************************************************************/
134 MAXZONE = 60,
135 };
136
137 /**
138 * The standard zone.
139 *
140 * @param[in] lat latitude (degrees).
141 * @param[in] lon longitude (degrees).
142 * @param[in] setzone zone override (use ZoneSpec.STANDARD as default). If
143 * omitted, use the standard rules for picking the zone. If \e setzone
144 * is given then use that zone if it is non-negative, otherwise apply the
145 * rules given in UTMUPS::zonespec.
146 * @exception GeographicErr if \e setzone is outside the range
147 * [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE] = [&minus;4, 60].
148 *
149 * This is exact.
150 **********************************************************************/
151 static int StandardZone(double lat, double lon, int setzone);
152
153 /**
154 * Forward projection, from geographic to UTM/UPS.
155 *
156 * @param[in] lat latitude of point (degrees).
157 * @param[in] lon longitude of point (degrees).
158 * @param[out] zone the UTM zone (zero means UPS).
159 * @param[out] northp hemisphere (true means north, false means south).
160 * @param[out] x easting of point (meters).
161 * @param[out] y northing of point (meters).
162 * @param[out] gamma meridian convergence at point (degrees).
163 * @param[out] k scale of projection at point.
164 * @param[in] setzone zone override (use ZoneSpec.STANDARD as default).
165 * @param[in] mgrslimits if true enforce the stricter MGRS limits on the
166 * coordinates (default = false).
167 * @exception GeographicErr if \e lat is not in [&minus;90&deg;,
168 * 90&deg;].
169 * @exception GeographicErr if the resulting \e x or \e y is out of allowed
170 * range (see Reverse); in this case, these arguments are unchanged.
171 *
172 * If \e setzone is omitted, use the standard rules for picking the zone.
173 * If \e setzone is given then use that zone if it is non-negative,
174 * otherwise apply the rules given in UTMUPS::zonespec. The accuracy of
175 * the conversion is about 5nm.
176 *
177 * The northing \e y jumps by UTMUPS::UTMShift() when crossing the equator
178 * in the southerly direction. Sometimes it is useful to remove this
179 * discontinuity in \e y by extending the "northern" hemisphere using
180 * UTMUPS::Transfer:
181 * \code
182 double lat = -1, lon = 123;
183 int zone;
184 bool northp;
185 double x, y, gamma, k;
186 GeographicLib::UTMUPS::Forward(lat, lon, zone, northp, x, y, gamma, k);
187 GeographicLib::UTMUPS::Transfer(zone, northp, x, y,
188 zone, true, x, y, zone);
189 northp = true;
190 \endcode
191 **********************************************************************/
192 static void Forward(double lat, double lon,
193 [System::Runtime::InteropServices::Out] int% zone,
194 [System::Runtime::InteropServices::Out] bool% northp,
195 [System::Runtime::InteropServices::Out] double% x,
196 [System::Runtime::InteropServices::Out] double% y,
197 [System::Runtime::InteropServices::Out] double% gamma,
198 [System::Runtime::InteropServices::Out] double% k,
199 int setzone, bool mgrslimits);
200
201 /**
202 * Reverse projection, from UTM/UPS to geographic.
203 *
204 * @param[in] zone the UTM zone (zero means UPS).
205 * @param[in] northp hemisphere (true means north, false means south).
206 * @param[in] x easting of point (meters).
207 * @param[in] y northing of point (meters).
208 * @param[out] lat latitude of point (degrees).
209 * @param[out] lon longitude of point (degrees).
210 * @param[out] gamma meridian convergence at point (degrees).
211 * @param[out] k scale of projection at point.
212 * @param[in] mgrslimits if true enforce the stricter MGRS limits on the
213 * coordinates (default = false).
214 * @exception GeographicErr if \e zone, \e x, or \e y is out of allowed
215 * range; this this case the arguments are unchanged.
216 *
217 * The accuracy of the conversion is about 5nm.
218 *
219 * UTM eastings are allowed to be in the range [0km, 1000km], northings are
220 * allowed to be in in [0km, 9600km] for the northern hemisphere and in
221 * [900km, 10000km] for the southern hemisphere. However UTM northings
222 * can be continued across the equator. So the actual limits on the
223 * northings are [-9100km, 9600km] for the "northern" hemisphere and
224 * [900km, 19600km] for the "southern" hemisphere.
225 *
226 * UPS eastings and northings are allowed to be in the range [1200km,
227 * 2800km] in the northern hemisphere and in [700km, 3100km] in the
228 * southern hemisphere.
229 *
230 * These ranges are 100km larger than allowed for the conversions to MGRS.
231 * (100km is the maximum extra padding consistent with eastings remaining
232 * non-negative.) This allows generous overlaps between zones and UTM and
233 * UPS. If \e mgrslimits = true, then all the ranges are shrunk by 100km
234 * so that they agree with the stricter MGRS ranges. No checks are
235 * performed besides these (e.g., to limit the distance outside the
236 * standard zone boundaries).
237 **********************************************************************/
238 static void Reverse(int zone, bool northp, double x, double y,
239 [System::Runtime::InteropServices::Out] double% lat,
240 [System::Runtime::InteropServices::Out] double% lon,
241 [System::Runtime::InteropServices::Out] double% gamma,
242 [System::Runtime::InteropServices::Out] double% k,
243 bool mgrslimits);
244
245 /**
246 * UTMUPS::Forward without returning convergence and scale.
247 **********************************************************************/
248 static void Forward(double lat, double lon,
249 [System::Runtime::InteropServices::Out] int% zone,
250 [System::Runtime::InteropServices::Out] bool% northp,
251 [System::Runtime::InteropServices::Out] double% x,
252 [System::Runtime::InteropServices::Out] double% y,
253 int setzone, bool mgrslimits );
254
255 /**
256 * UTMUPS::Reverse without returning convergence and scale.
257 **********************************************************************/
258 static void Reverse(int zone, bool northp, double x, double y,
259 [System::Runtime::InteropServices::Out] double% lat,
260 [System::Runtime::InteropServices::Out] double% lon,
261 bool mgrslimits);
262
263 /**
264 * Transfer UTM/UPS coordinated from one zone to another.
265 *
266 * @param[in] zonein the UTM zone for \e xin and \e yin (or zero for UPS).
267 * @param[in] northpin hemisphere for \e xin and \e yin (true means north,
268 * false means south).
269 * @param[in] xin easting of point (meters) in \e zonein.
270 * @param[in] yin northing of point (meters) in \e zonein.
271 * @param[in] zoneout the requested UTM zone for \e xout and \e yout (or
272 * zero for UPS).
273 * @param[in] northpout hemisphere for \e xout output and \e yout.
274 * @param[out] xout easting of point (meters) in \e zoneout.
275 * @param[out] yout northing of point (meters) in \e zoneout.
276 * @param[out] zone the actual UTM zone for \e xout and \e yout (or zero
277 * for UPS); this equals \e zoneout if \e zoneout &ge; 0.
278 * @exception GeographicErr if \e zonein is out of range (see below).
279 * @exception GeographicErr if \e zoneout is out of range (see below).
280 * @exception GeographicErr if \e xin or \e yin fall outside their allowed
281 * ranges (see UTMUPS::Reverse).
282 * @exception GeographicErr if \e xout or \e yout fall outside their
283 * allowed ranges (see UTMUPS::Reverse).
284 *
285 * \e zonein must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
286 * 60] with \e zonein = UTMUPS::UPS, 0, indicating UPS. \e zonein may
287 * also be UTMUPS::INVALID.
288 *
289 * \e zoneout must be in the range [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE]
290 * = [-4, 60]. If \e zoneout &lt; UTMUPS::MINZONE then the rules give in
291 * the documentation of UTMUPS::zonespec are applied, and \e zone is set to
292 * the actual zone used for output.
293 *
294 * (\e xout, \e yout) can overlap with (\e xin, \e yin).
295 **********************************************************************/
296 static void Transfer(int zonein, bool northpin, double xin, double yin,
297 int zoneout, bool northpout,
298 [System::Runtime::InteropServices::Out] double% xout,
299 [System::Runtime::InteropServices::Out] double% yout,
300 [System::Runtime::InteropServices::Out] int% zone);
301
302 /**
303 * Decode a UTM/UPS zone string.
304 *
305 * @param[in] zonestr string representation of zone and hemisphere.
306 * @param[out] zone the UTM zone (zero means UPS).
307 * @param[out] northp hemisphere (true means north, false means south).
308 * @exception GeographicErr if \e zonestr is malformed.
309 *
310 * For UTM, \e zonestr has the form of a zone number in the range
311 * [UTMUPS::MINUTMZONE, UTMUPS::MAXUTMZONE] = [1, 60] followed by a
312 * hemisphere letter, n or s (or "north" or "south" spelled out). For UPS,
313 * it consists just of the hemisphere letter (or the spelled out
314 * hemisphere). The returned value of \e zone is UTMUPS::UPS = 0 for UPS.
315 * Note well that "38s" indicates the southern hemisphere of zone 38 and
316 * not latitude band S, 32&deg; &le; \e lat &lt; 40&deg;. n, 01s, 2n, 38s,
317 * south, 3north are legal. 0n, 001s, +3n, 61n, 38P are illegal. INV is a
318 * special value for which the returned value of \e is UTMUPS::INVALID.
319 **********************************************************************/
320 static void DecodeZone(System::String^ zonestr,
321 [System::Runtime::InteropServices::Out] int% zone,
322 [System::Runtime::InteropServices::Out] bool% northp);
323
324 /**
325 * Encode a UTM/UPS zone string.
326 *
327 * @param[in] zone the UTM zone (zero means UPS).
328 * @param[in] northp hemisphere (true means north, false means south).
329 * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
330 * for hemisphere; otherwise spell out the hemisphere (north/south)
331 * @exception GeographicErr if \e zone is out of range (see below).
332 * @exception std::bad_alloc if memoy for the string can't be allocated.
333 * @return string representation of zone and hemisphere.
334 *
335 * \e zone must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
336 * 60] with \e zone = UTMUPS::UPS, 0, indicating UPS (but the resulting
337 * string does not contain "0"). \e zone may also be UTMUPS::INVALID, in
338 * which case the returned string is "inv". This reverses
339 * UTMUPS::DecodeZone.
340 **********************************************************************/
341 static System::String^ EncodeZone(int zone, bool northp, bool abbrev);
342
343 /**
344 * Decode EPSG.
345 *
346 * @param[in] epsg the EPSG code.
347 * @param[out] zone the UTM zone (zero means UPS).
348 * @param[out] northp hemisphere (true means north, false means south).
349 *
350 * EPSG (European Petroleum Survery Group) codes are a way to refer to many
351 * different projections. DecodeEPSG decodes those refering to UTM or UPS
352 * projections for the WGS84 ellipsoid. If the code does not refer to one
353 * of these projections, \e zone is set to UTMUPS::INVALID. See
354 * http://spatialreference.org/ref/epsg/
355 **********************************************************************/
356 static void DecodeEPSG(int epsg,
357 [System::Runtime::InteropServices::Out] int% zone,
358 [System::Runtime::InteropServices::Out] bool% northp);
359
360 /**
361 * Encode zone as EPSG.
362 *
363 * @param[in] zone the UTM zone (zero means UPS).
364 * @param[in] northp hemisphere (true means north, false means south).
365 * @return EPSG code (or -1 if \e zone is not in the range
366 * [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0, 60])
367 *
368 * Convert \e zone and \e northp to the corresponding EPSG (European
369 * Petroleum Survery Group) codes
370 **********************************************************************/
371 static int EncodeEPSG(int zone, bool northp);
372
373 /**
374 * @return shift (meters) necessary to align N and S halves of a UTM zone
375 * (10<sup>7</sup>).
376 **********************************************************************/
377 static double UTMShift();
378
379 /** \name Inspector functions
380 **********************************************************************/
381 ///@{
382 /**
383 * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
384 *
385 * (The WGS84 value is returned because the UTM and UPS projections are
386 * based on this ellipsoid.)
387 **********************************************************************/
388 static double EquatorialRadius();
389
390 /**
391 * @return \e f the flattening of the WGS84 ellipsoid.
392 *
393 * (The WGS84 value is returned because the UTM and UPS projections are
394 * based on this ellipsoid.)
395 **********************************************************************/
396 static double Flattening();
397 ///@}
398 };
399} // namespace NETGeographicLib
.NET wrapper for GeographicLib::UTMUPS.
Definition: UTMUPS.h:67
static void Reverse(int zone, bool northp, double x, double y, [System::Runtime::InteropServices::Out] double% lat, [System::Runtime::InteropServices::Out] double% lon, [System::Runtime::InteropServices::Out] double% gamma, [System::Runtime::InteropServices::Out] double% k, bool mgrslimits)
static int StandardZone(double lat, double lon, int setzone)
static void DecodeZone(System::String^ zonestr, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp)
static double EquatorialRadius()
static void Reverse(int zone, bool northp, double x, double y, [System::Runtime::InteropServices::Out] double% lat, [System::Runtime::InteropServices::Out] double% lon, bool mgrslimits)
static void Forward(double lat, double lon, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp, [System::Runtime::InteropServices::Out] double% x, [System::Runtime::InteropServices::Out] double% y, [System::Runtime::InteropServices::Out] double% gamma, [System::Runtime::InteropServices::Out] double% k, int setzone, bool mgrslimits)
static void Forward(double lat, double lon, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp, [System::Runtime::InteropServices::Out] double% x, [System::Runtime::InteropServices::Out] double% y, int setzone, bool mgrslimits)
static double UTMShift()
static void Transfer(int zonein, bool northpin, double xin, double yin, int zoneout, bool northpout, [System::Runtime::InteropServices::Out] double% xout, [System::Runtime::InteropServices::Out] double% yout, [System::Runtime::InteropServices::Out] int% zone)
static double Flattening()
static int EncodeEPSG(int zone, bool northp)
static System::String ^ EncodeZone(int zone, bool northp, bool abbrev)
static void DecodeEPSG(int epsg, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp)