OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
LatLong-UTMconversion.cpp
Go to the documentation of this file.
1 //LatLong- UTM conversion.cpp
2 //Lat Long - UTM, UTM - Lat Long conversions
3 
4 #include <math.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "constants.h"
9 
10 /*Reference ellipsoids derived from Peter H. Dana's website-
11 http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html
12 Department of Geography, University of Texas at Austin
13 Internet: pdana@mail.utexas.edu
14 3/22/95
15 
16 Source
17 Defense Mapping Agency. 1987b. DMA Technical Report: Supplement to Department of Defense World Geodetic System
18 1984 Technical Report. Part I and II. Washington, DC: Defense Mapping Agency
19  */
20 
21 
22 
23 void LLtoUTM(int ReferenceEllipsoid, const double Lat, const double Long,
24  double &UTMNorthing, double &UTMEasting, char* UTMZone) {
25  //converts lat/long to UTM coords. Equations from USGS Bulletin 1532
26  //East Longitudes are positive, West longitudes are negative.
27  //North latitudes are positive, South latitudes are negative
28  //Lat and Long are in decimal degrees
29  //Written by Chuck Gantz- chuck.gantz@globalstar.com
30 
31  double a = ellipsoid[ReferenceEllipsoid].EquatorialRadius;
32  double eccSquared = ellipsoid[ReferenceEllipsoid].eccentricitySquared;
33  double k0 = 0.9996;
34 
35  double LongOrigin;
36  double eccPrimeSquared;
37  double N, T, C, A, M;
38 
39  //Make sure the longitude is between -180.00 .. 179.9
40  double LongTemp = (Long + 180) - int((Long + 180) / 360)*360 - 180; // -180.00 .. 179.9;
41 
42  double LatRad = Lat*deg2rad;
43  double LongRad = LongTemp*deg2rad;
44  double LongOriginRad;
45  int ZoneNumber;
46 
47  ZoneNumber = int((LongTemp + 180) / 6) + 1;
48 
49  if (Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0)
50  ZoneNumber = 32;
51 
52  // Special zones for Svalbard
53  if (Lat >= 72.0 && Lat < 84.0) {
54  if (LongTemp >= 0.0 && LongTemp < 9.0) ZoneNumber = 31;
55  else if (LongTemp >= 9.0 && LongTemp < 21.0) ZoneNumber = 33;
56  else if (LongTemp >= 21.0 && LongTemp < 33.0) ZoneNumber = 35;
57  else if (LongTemp >= 33.0 && LongTemp < 42.0) ZoneNumber = 37;
58  }
59  LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone
60  LongOriginRad = LongOrigin * deg2rad;
61 
62  //compute the UTM Zone from the latitude and longitude
63  sprintf(UTMZone, "%d%c", ZoneNumber, UTMLetterDesignator(Lat));
64 
65  eccPrimeSquared = (eccSquared) / (1 - eccSquared);
66 
67  N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad));
68  T = tan(LatRad) * tan(LatRad);
69  C = eccPrimeSquared * cos(LatRad) * cos(LatRad);
70  A = cos(LatRad)*(LongRad - LongOriginRad);
71 
72  M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad
73  - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(2 * LatRad)
74  + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(4 * LatRad)
75  - (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad));
76 
77  UTMEasting = (double) (k0 * N * (A + (1 - T + C) * A * A * A / 6
78  + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120)
79  + 500000.0);
80 
81  UTMNorthing = (double) (k0 * (M + N * tan(LatRad)*(A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24
82  + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));
83  if (Lat < 0)
84  UTMNorthing += 10000000.0; //10000000 meter offset for southern hemisphere
85 }
86 
87 char UTMLetterDesignator(double Lat) {
88  //This routine determines the correct UTM letter designator for the given latitude
89  //returns 'Z' if latitude is outside the UTM limits of 84N to 80S
90  //Written by Chuck Gantz- chuck.gantz@globalstar.com
91  char LetterDesignator;
92 
93  if ((84 >= Lat) && (Lat >= 72)) LetterDesignator = 'X';
94  else if ((72 > Lat) && (Lat >= 64)) LetterDesignator = 'W';
95  else if ((64 > Lat) && (Lat >= 56)) LetterDesignator = 'V';
96  else if ((56 > Lat) && (Lat >= 48)) LetterDesignator = 'U';
97  else if ((48 > Lat) && (Lat >= 40)) LetterDesignator = 'T';
98  else if ((40 > Lat) && (Lat >= 32)) LetterDesignator = 'S';
99  else if ((32 > Lat) && (Lat >= 24)) LetterDesignator = 'R';
100  else if ((24 > Lat) && (Lat >= 16)) LetterDesignator = 'Q';
101  else if ((16 > Lat) && (Lat >= 8)) LetterDesignator = 'P';
102  else if ((8 > Lat) && (Lat >= 0)) LetterDesignator = 'N';
103  else if ((0 > Lat) && (Lat >= -8)) LetterDesignator = 'M';
104  else if ((-8 > Lat) && (Lat >= -16)) LetterDesignator = 'L';
105  else if ((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
106  else if ((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
107  else if ((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
108  else if ((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
109  else if ((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
110  else if ((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
111  else if ((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
112  else if ((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
113  else LetterDesignator = 'Z'; //This is here as an error flag to show that the Latitude is outside the UTM limits
114 
115  return LetterDesignator;
116 }
117 
118 void UTMtoLL(int ReferenceEllipsoid, const double UTMNorthing, const double UTMEasting, const char* UTMZone,
119  double& Lat, double& Long) {
120  //converts UTM coords to lat/long. Equations from USGS Bulletin 1532
121  //East Longitudes are positive, West longitudes are negative.
122  //North latitudes are positive, South latitudes are negative
123  //Lat and Long are in decimal degrees.
124  //Written by Chuck Gantz- chuck.gantz@globalstar.com
125 
126  double k0 = 0.9996;
127  double a = ellipsoid[ReferenceEllipsoid].EquatorialRadius;
128  double eccSquared = ellipsoid[ReferenceEllipsoid].eccentricitySquared;
129  double eccPrimeSquared;
130  double e1 = (1 - sqrt(1 - eccSquared)) / (1 + sqrt(1 - eccSquared));
131  double N1, T1, C1, R1, D, M;
132  double LongOrigin;
133  double mu, phi1Rad;
134  //double phi1;
135  double x, y;
136  int ZoneNumber;
137  char* ZoneLetter;
138  // int NorthernHemisphere; //1 for northern hemispher, 0 for southern
139 
140  x = UTMEasting - 500000.0; //remove 500,000 meter offset for longitude
141  y = UTMNorthing;
142 
143  ZoneNumber = strtoul(UTMZone, &ZoneLetter, 10);
144  /*
145  if((*ZoneLetter - 'N') >= 0)
146  NorthernHemisphere = 1;//point is in northern hemisphere
147  else
148  {
149  NorthernHemisphere = 0;//point is in southern hemisphere
150  y -= 10000000.0;//remove 10,000,000 meter offset used for southern hemisphere
151  }
152  */
153  if ((*ZoneLetter - 'N') < 0) {
154  y -= 10000000.0; //remove 10,000,000 meter offset used for southern hemisphere
155  }
156 
157  LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone
158 
159  eccPrimeSquared = (eccSquared) / (1 - eccSquared);
160 
161  M = y / k0;
162  mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
163 
164  phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu)
165  + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu)
166  +(151 * e1 * e1 * e1 / 96) * sin(6 * mu);
167  // phi1 = phi1Rad*rad2deg;
168 
169  N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad));
170  T1 = tan(phi1Rad) * tan(phi1Rad);
171  C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
172  R1 = a * (1 - eccSquared) / pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5);
173  D = x / (N1 * k0);
174 
175  Lat = phi1Rad - (N1 * tan(phi1Rad) / R1)*(D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24
176  + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
177  Lat = Lat * rad2deg;
178 
179  Long = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1)
180  * D * D * D * D * D / 120) / cos(phi1Rad);
181  Long = LongOrigin + Long * rad2deg;
182 
183 }
char UTMLetterDesignator(double Lat)
int N
Definition: Usds.c:60
const double C
const double deg2rad
float mu
#define C1
Definition: bbt_2_rad.c:6
integer, parameter double
int M[]
Definition: Usds.c:107
void LLtoUTM(int ReferenceEllipsoid, const double Lat, const double Long, double &UTMNorthing, double &UTMEasting, char *UTMZone)
void UTMtoLL(int ReferenceEllipsoid, const double UTMNorthing, const double UTMEasting, const char *UTMZone, double &Lat, double &Long)
const double rad2deg
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424