-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmgrs.h
417 lines (378 loc) · 15.5 KB
/
mgrs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#include "utm.h"
#include "pi.h"
#include <stdio.h>
#include <string.h>
#define PI180 0.01745329251
#define DEG_TO_RAD 0.017453292519943295 /* PI/180 */
#define RAD_TO_DEG 57.29577951308232087 /* 180/PI */
#define LETTER_A 0 /* ARRAY INDEX FOR LETTER A */
#define LETTER_B 1 /* ARRAY INDEX FOR LETTER B */
#define LETTER_C 2 /* ARRAY INDEX FOR LETTER C */
#define LETTER_D 3 /* ARRAY INDEX FOR LETTER D */
#define LETTER_E 4 /* ARRAY INDEX FOR LETTER E */
#define LETTER_F 5 /* ARRAY INDEX FOR LETTER F */
#define LETTER_G 6 /* ARRAY INDEX FOR LETTER G */
#define LETTER_H 7 /* ARRAY INDEX FOR LETTER H */
#define LETTER_I 8 /* ARRAY INDEX FOR LETTER I */
#define LETTER_J 9 /* ARRAY INDEX FOR LETTER J */
#define LETTER_K 10 /* ARRAY INDEX FOR LETTER K */
#define LETTER_L 11 /* ARRAY INDEX FOR LETTER L */
#define LETTER_M 12 /* ARRAY INDEX FOR LETTER M */
#define LETTER_N 13 /* ARRAY INDEX FOR LETTER N */
#define LETTER_O 14 /* ARRAY INDEX FOR LETTER O */
#define LETTER_P 15 /* ARRAY INDEX FOR LETTER P */
#define LETTER_Q 16 /* ARRAY INDEX FOR LETTER Q */
#define LETTER_R 17 /* ARRAY INDEX FOR LETTER R */
#define LETTER_S 18 /* ARRAY INDEX FOR LETTER S */
#define LETTER_T 19 /* ARRAY INDEX FOR LETTER T */
#define LETTER_U 20 /* ARRAY INDEX FOR LETTER U */
#define LETTER_V 21 /* ARRAY INDEX FOR LETTER V */
#define LETTER_W 22 /* ARRAY INDEX FOR LETTER W */
#define LETTER_X 23 /* ARRAY INDEX FOR LETTER X */
#define LETTER_Y 24 /* ARRAY INDEX FOR LETTER Y */
#define LETTER_Z 25 /* ARRAY INDEX FOR LETTER Z */
#define MGRS_LETTERS 3 /* NUMBER OF LETTERS IN MGRS */
#define ONEHT 100000.e0 /* ONE HUNDRED THOUSAND */
#define TWOMIL 2000000.e0 /* TWO MILLION */
#define TRUE 1 /* CONSTANT VALUE FOR TRUE VALUE */
#define FALSE 0 /* CONSTANT VALUE FOR FALSE VALUE */
#define MIN_EASTING 100000
#define MAX_EASTING 900000
#define MIN_NORTHING 0
#define MAX_NORTHING 10000000
#define MAX_PRECISION 5 /* Maximum precision of easting & northing */
#define MIN_UTM_LAT ( (-80 * PI) / 180.0 ) /* -80 degrees in radians */
#define MAX_UTM_LAT ( (84 * PI) / 180.0 ) /* 84 degrees in radians */
#define MIN_EAST_NORTH 0
#define MAX_EAST_NORTH 4000000
/* Ellipsoid parameters, default to WGS 84 */
const double MGRS_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */
const double MGRS_f = 1 / 298.257223563; /* Flattening of ellipsoid */
const char MGRS_Ellipsoid_Code[3] = {'W','E',0};
/*
* CLARKE_1866 : Ellipsoid code for CLARKE_1866
* CLARKE_1880 : Ellipsoid code for CLARKE_1880
* BESSEL_1841 : Ellipsoid code for BESSEL_1841
* BESSEL_1841_NAMIBIA : Ellipsoid code for BESSEL 1841 (NAMIBIA)
*/
const char* CLARKE_1866 = "CC";
const char* CLARKE_1880 = "CD";
const char* BESSEL_1841 = "BR";
const char* BESSEL_1841_NAMIBIA = "BN";
#define MGRS_NO_ERROR 0x0000
#define MGRS_LAT_ERROR 0x0001
#define MGRS_LON_ERROR 0x0002
#define MGRS_STRING_ERROR 0x0004
#define MGRS_PRECISION_ERROR 0x0008
#define MGRS_A_ERROR 0x0010
#define MGRS_INV_F_ERROR 0x0020
#define MGRS_EASTING_ERROR 0x0040
#define MGRS_NORTHING_ERROR 0x0080
#define MGRS_ZONE_ERROR 0x0100
#define MGRS_HEMISPHERE_ERROR 0x0200
#define MGRS_LAT_WARNING 0x0400
typedef struct Latitude_Band_Value
{
long letter; /* letter representing latitude band */
double min_northing; /* minimum northing for latitude band */
double north; /* upper latitude for latitude band */
double south; /* lower latitude for latitude band */
double northing_offset; /* latitude band northing offset */
} Latitude_Band;
static const Latitude_Band Latitude_Band_Table[20] =
{{LETTER_C, 1100000.0, -72.0, -80.5, 0.0},
{LETTER_D, 2000000.0, -64.0, -72.0, 2000000.0},
{LETTER_E, 2800000.0, -56.0, -64.0, 2000000.0},
{LETTER_F, 3700000.0, -48.0, -56.0, 2000000.0},
{LETTER_G, 4600000.0, -40.0, -48.0, 4000000.0},
{LETTER_H, 5500000.0, -32.0, -40.0, 4000000.0},
{LETTER_J, 6400000.0, -24.0, -32.0, 6000000.0},
{LETTER_K, 7300000.0, -16.0, -24.0, 6000000.0},
{LETTER_L, 8200000.0, -8.0, -16.0, 8000000.0},
{LETTER_M, 9100000.0, 0.0, -8.0, 8000000.0},
{LETTER_N, 0.0, 8.0, 0.0, 0.0},
{LETTER_P, 800000.0, 16.0, 8.0, 0.0},
{LETTER_Q, 1700000.0, 24.0, 16.0, 0.0},
{LETTER_R, 2600000.0, 32.0, 24.0, 2000000.0},
{LETTER_S, 3500000.0, 40.0, 32.0, 2000000.0},
{LETTER_T, 4400000.0, 48.0, 40.0, 4000000.0},
{LETTER_U, 5300000.0, 56.0, 48.0, 4000000.0},
{LETTER_V, 6200000.0, 64.0, 56.0, 6000000.0},
{LETTER_W, 7000000.0, 72.0, 64.0, 6000000.0},
{LETTER_X, 7900000.0, 84.5, 72.0, 6000000.0}};
long Make_MGRS_String (char* MGRS,
long Zone,
int Letters[MGRS_LETTERS],
double Easting,
double Northing,
long Precision)
/*
* The function Make_MGRS_String constructs an MGRS string
* from its component parts.
*
* MGRS : MGRS coordinate string (output)
* Zone : UTM Zone (input)
* Letters : MGRS coordinate string letters (input)
* Easting : Easting value (input)
* Northing : Northing value (input)
* Precision : Precision level of MGRS string (input)
*/
{ /* Make_MGRS_String */
long i;
long j;
double divisor;
long east;
long north;
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
long error_code = MGRS_NO_ERROR;
i = 0;
if (Zone)
i = sprintf (MGRS+i,"%2.2ld",Zone);
else
strncpy(MGRS, " ", 2); // 2 spaces
for (j=0;j<3;j++)
MGRS[i++] = alphabet[Letters[j]];
divisor = pow (10.0, (5 - Precision));
Easting = fmod (Easting, 100000.0);
if (Easting >= 99999.5)
Easting = 99999.0;
east = (long)(Easting/divisor);
i += sprintf (MGRS+i, "%*.*ld", (int)Precision, (int)Precision, east);
Northing = fmod (Northing, 100000.0);
if (Northing >= 99999.5)
Northing = 99999.0;
north = (long)(Northing/divisor);
i += sprintf (MGRS+i, "%*.*ld", (int)Precision, (int)Precision, north);
return (error_code);
} /* Make_MGRS_String */
void Get_Grid_Values (long zone,
long* ltr2_low_value,
long* ltr2_high_value,
double *pattern_offset)
/*
* The function getGridValues sets the letter range used for
* the 2nd letter in the MGRS coordinate string, based on the set
* number of the utm zone. It also sets the pattern offset using a
* value of A for the second letter of the grid square, based on
* the grid pattern and set number of the utm zone.
*
* zone : Zone number (input)
* ltr2_low_value : 2nd letter low number (output)
* ltr2_high_value : 2nd letter high number (output)
* pattern_offset : Pattern offset (output)
*/
{ /* BEGIN Get_Grid_Values */
long set_number; /* Set number (1-6) based on UTM zone number */
long aa_pattern; /* Pattern based on ellipsoid code */
set_number = zone % 6;
if (!set_number)
set_number = 6;
if (!strcmp(MGRS_Ellipsoid_Code,CLARKE_1866) || !strcmp(MGRS_Ellipsoid_Code, CLARKE_1880) ||
!strcmp(MGRS_Ellipsoid_Code,BESSEL_1841) || !strcmp(MGRS_Ellipsoid_Code,BESSEL_1841_NAMIBIA))
aa_pattern = FALSE;
else
aa_pattern = TRUE;
if ((set_number == 1) || (set_number == 4))
{
*ltr2_low_value = LETTER_A;
*ltr2_high_value = LETTER_H;
}
else if ((set_number == 2) || (set_number == 5))
{
*ltr2_low_value = LETTER_J;
*ltr2_high_value = LETTER_R;
}
else if ((set_number == 3) || (set_number == 6))
{
*ltr2_low_value = LETTER_S;
*ltr2_high_value = LETTER_Z;
}
/* False northing at A for second letter of grid square */
if (aa_pattern)
{
if ((set_number % 2) == 0)
*pattern_offset = 500000.0;
else
*pattern_offset = 0.0;
}
else
{
if ((set_number % 2) == 0)
*pattern_offset = 1500000.0;
else
*pattern_offset = 1000000.00;
}
} /* END OF Get_Grid_Values */
long Get_Latitude_Letter(double latitude, int* letter)
/*
* The function Get_Latitude_Letter receives a latitude value
* and uses the Latitude_Band_Table to determine the latitude band
* letter for that latitude.
*
* latitude : Latitude (input)
* letter : Latitude band letter (output)
*/
{ /* Get_Latitude_Letter */
double temp = 0.0;
long error_code = MGRS_NO_ERROR;
double lat_deg = latitude * RAD_TO_DEG;
if (lat_deg >= 72 && lat_deg < 84.5)
*letter = LETTER_X;
else if (lat_deg > -80.5 && lat_deg < 72)
{
temp = ((latitude + (80.0 * DEG_TO_RAD)) / (8.0 * DEG_TO_RAD)) + 1.0e-12;
*letter = Latitude_Band_Table[(int)temp].letter;
}
else
error_code |= MGRS_LAT_ERROR;
return error_code;
} /* Get_Latitude_Letter */
long UTM_To_MGRS (long Zone,
char Hemisphere,
double Longitude,
double Latitude,
double Easting,
double Northing,
long Precision,
char *MGRS)
/*
* The function UTM_To_MGRS calculates an MGRS coordinate string
* based on the zone, latitude, easting and northing.
*
* Zone : Zone number (input)
* Hemisphere: Hemisphere (input)
* Longitude : Longitude in radians (input)
* Latitude : Latitude in radians (input)
* Easting : Easting (input)
* Northing : Northing (input)
* Precision : Precision (input)
* MGRS : MGRS coordinate string (output)
*/
{ /* BEGIN UTM_To_MGRS */
double pattern_offset; /* Northing offset for 3rd letter */
double grid_easting; /* Easting used to derive 2nd letter of MGRS */
double grid_northing; /* Northing used to derive 3rd letter of MGRS */
long ltr2_low_value; /* 2nd letter range - low number */
long ltr2_high_value; /* 2nd letter range - high number */
int letters[MGRS_LETTERS]; /* Number location of 3 letters in alphabet */
long temp_error_code = MGRS_NO_ERROR;
long error_code = MGRS_NO_ERROR;
/* Special check for rounding to (truncated) eastern edge of zone 31V */
if ((Zone == 31) && (((Latitude >= 56.0 * DEG_TO_RAD) && (Latitude < 64.0 * DEG_TO_RAD)) && ((Longitude >= 3.0 * DEG_TO_RAD) || (Easting >= 500000.0))))
{ /* Reconvert to UTM zone 32 */
Set_UTM_Parameters (MGRS_a, MGRS_f, 32);
temp_error_code = Convert_Geodetic_To_UTM (Latitude, Longitude, &Zone, &Hemisphere, &Easting, &Northing);
if(temp_error_code)
{
if(temp_error_code & UTM_LAT_ERROR)
error_code |= MGRS_LAT_ERROR;
if(temp_error_code & UTM_LON_ERROR)
error_code |= MGRS_LON_ERROR;
if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
error_code |= MGRS_ZONE_ERROR;
if(temp_error_code & UTM_EASTING_ERROR)
error_code |= MGRS_EASTING_ERROR;
if(temp_error_code & UTM_NORTHING_ERROR)
error_code |= MGRS_NORTHING_ERROR;
return error_code;
}
}
if( Latitude <= 0.0 && Northing == 1.0e7)
{
Latitude = 0.0;
Northing = 0.0;
}
Get_Grid_Values(Zone, <r2_low_value, <r2_high_value, &pattern_offset);
error_code = Get_Latitude_Letter(Latitude, &letters[0]);
if (!error_code)
{
grid_northing = Northing;
while (grid_northing >= TWOMIL)
{
grid_northing = grid_northing - TWOMIL;
}
grid_northing = grid_northing + pattern_offset;
if(grid_northing >= TWOMIL)
grid_northing = grid_northing - TWOMIL;
letters[2] = (long)(grid_northing / ONEHT);
if (letters[2] > LETTER_H)
letters[2] = letters[2] + 1;
if (letters[2] > LETTER_N)
letters[2] = letters[2] + 1;
grid_easting = Easting;
if (((letters[0] == LETTER_V) && (Zone == 31)) && (grid_easting == 500000.0))
grid_easting = grid_easting - 1.0; /* SUBTRACT 1 METER */
letters[1] = ltr2_low_value + ((long)(grid_easting / ONEHT) -1);
if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_N))
letters[1] = letters[1] + 1;
Make_MGRS_String (MGRS, Zone, letters, grid_easting, Northing, Precision);
}
return error_code;
} /* END UTM_To_MGRS */
long Convert_Geodetic_To_MGRS (double Latitude,
double Longitude,
long Precision,
char* MGRS)
/*
* The function Convert_Geodetic_To_MGRS converts Geodetic (latitude and
* longitude) coordinates to an MGRS coordinate string, according to the
* current ellipsoid parameters. If any errors occur, the error code(s)
* are returned by the function, otherwise MGRS_NO_ERROR is returned.
*
* Latitude : Latitude in radians (input)
* Longitude : Longitude in radians (input)
* Precision : Precision level of MGRS string (input)
* MGRS : MGRS coordinate string (output)
*
*/
{ /* Convert_Geodetic_To_MGRS */
long zone;
char hemisphere;
double easting;
double northing;
long temp_error_code = MGRS_NO_ERROR;
long error_code = MGRS_NO_ERROR;
if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
{ /* Latitude out of range */
error_code |= MGRS_LAT_ERROR;
}
if ((Longitude < -PI) || (Longitude > (2*PI)))
{ /* Longitude out of range */
error_code |= MGRS_LON_ERROR;
}
if ((Precision < 0) || (Precision > MAX_PRECISION))
error_code |= MGRS_PRECISION_ERROR;
if (!error_code)
{
temp_error_code = Set_UTM_Parameters (MGRS_a, MGRS_f, 0);
if(!temp_error_code)
{
temp_error_code = Convert_Geodetic_To_UTM (Latitude, Longitude, &zone, &hemisphere, &easting, &northing);
if(!temp_error_code)
error_code |= UTM_To_MGRS (zone, hemisphere, Longitude, Latitude, easting, northing, Precision, MGRS);
else
{
if(temp_error_code & UTM_LAT_ERROR)
error_code |= MGRS_LAT_ERROR;
if(temp_error_code & UTM_LON_ERROR)
error_code |= MGRS_LON_ERROR;
if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
error_code |= MGRS_ZONE_ERROR;
if(temp_error_code & UTM_EASTING_ERROR)
error_code |= MGRS_EASTING_ERROR;
if(temp_error_code & UTM_NORTHING_ERROR)
error_code |= MGRS_NORTHING_ERROR;
}
}
else
{
if(temp_error_code & UTM_A_ERROR)
error_code |= MGRS_A_ERROR;
if(temp_error_code & UTM_INV_F_ERROR)
error_code |= MGRS_INV_F_ERROR;
if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
error_code |= MGRS_ZONE_ERROR;
}
}
return (error_code);
} /* Convert_Geodetic_To_MGRS */