NETGeographicLib  1.50.1
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 
13 namespace 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="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="http://earth-info.nga.mil/GandG/geotrans/index.html">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
NETGeographicLib::UTMUPS::ZoneSpec::INVALID
NETGeographicLib::UTMUPS
.NET wrapper for GeographicLib::UTMUPS.
Definition: UTMUPS.h:66
NETGeographicLib::UTMUPS::EncodeEPSG
static int EncodeEPSG(int zone, bool northp)
NETGeographicLib::UTMUPS::Transfer
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)
NETGeographicLib::UTMUPS::EncodeZone
static System::String ^ EncodeZone(int zone, bool northp, bool abbrev)
NETGeographicLib::UTMUPS::ZoneSpec::MINZONE
NETGeographicLib::UTMUPS::ZoneSpec::MAXUTMZONE
NETGeographicLib::UTMUPS::DecodeZone
static void DecodeZone(System::String^ zonestr, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp)
NETGeographicLib::UTMUPS::UTMShift
static double UTMShift()
NETGeographicLib::UTMUPS::ZoneSpec::MINPSEUDOZONE
NETGeographicLib::UTMUPS::DecodeEPSG
static void DecodeEPSG(int epsg, [System::Runtime::InteropServices::Out] int% zone, [System::Runtime::InteropServices::Out] bool% northp)
NETGeographicLib::UTMUPS::ZoneSpec::UPS
NETGeographicLib::UTMUPS::Flattening
static double Flattening()
NETGeographicLib::UTMUPS::ZoneSpec::MINUTMZONE
NETGeographicLib::UTMUPS::ZoneSpec::STANDARD
NETGeographicLib::UTMUPS::EquatorialRadius
static double EquatorialRadius()
NETGeographicLib::UTMUPS::StandardZone
static int StandardZone(double lat, double lon, int setzone)
NETGeographicLib::UTMUPS::ZoneSpec::MAXZONE
NETGeographicLib::UTMUPS::Reverse
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)
NETGeographicLib::UTMUPS::ZoneSpec::MATCH
NETGeographicLib
Definition: Accumulator.h:13
NETGeographicLib::UTMUPS::ZoneSpec
ZoneSpec
Definition: UTMUPS.h:81
NETGeographicLib::UTMUPS::ZoneSpec::UTM
NETGeographicLib::UTMUPS::ZoneSpec::MAXPSEUDOZONE
NETGeographicLib::UTMUPS::Forward
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)