UNPKG

mgrs-pole-test

Version:

Get MGRS coordinate for North Pole/South Pole

1,213 lines (1,071 loc) 99.1 kB
const MGRS_NO_ERROR = 0x0000 const MGRS_LAT_ERROR = 0x0001 const MGRS_LON_ERROR = 0x0002 const MGRS_STRING_ERROR = 0x0004 const MGRS_PRECISION_ERROR = 0x0008 const MGRS_A_ERROR = 0x0010 const MGRS_INV_F_ERROR = 0x0020 const MGRS_EASTING_ERROR = 0x0040 const MGRS_NORTHING_ERROR = 0x0080 const MGRS_ZONE_ERROR = 0x0100 const MGRS_HEMISPHERE_ERROR = 0x0200 const MGRS_LAT_WARNING = 0x0400 const UPS_NO_ERROR = 0x0000 const UPS_LAT_ERROR = 0x0001 const UPS_LON_ERROR = 0x0002 const UPS_HEMISPHERE_ERROR = 0x0004 const UPS_EASTING_ERROR = 0x0008 const UPS_NORTHING_ERROR = 0x0010 const UPS_A_ERROR = 0x0020 const UPS_INV_F_ERROR = 0x0040 const POLAR_NO_ERROR = 0x0000 const POLAR_LAT_ERROR = 0x0001 const POLAR_LON_ERROR = 0x0002 const POLAR_ORIGIN_LAT_ERROR = 0x0004 const POLAR_ORIGIN_LON_ERROR = 0x0008 const POLAR_EASTING_ERROR = 0x0010 const POLAR_NORTHING_ERROR = 0x0020 const POLAR_A_ERROR = 0x0040 const POLAR_INV_F_ERROR = 0x0080 const POLAR_RADIUS_ERROR = 0x0100 const TRANMERC_NO_ERROR = 0x0000 const TRANMERC_LAT_ERROR = 0x0001 const TRANMERC_LON_ERROR = 0x0002 const TRANMERC_EASTING_ERROR = 0x0004 const TRANMERC_NORTHING_ERROR = 0x0008 const TRANMERC_ORIGIN_LAT_ERROR = 0x0010 const TRANMERC_CENT_MER_ERROR = 0x0020 const TRANMERC_A_ERROR = 0x0040 const TRANMERC_INV_F_ERROR = 0x0080 const TRANMERC_SCALE_FACTOR_ERROR = 0x0100 const TRANMERC_LON_WARNING = 0x0200 const UTM_NO_ERROR = 0x0000 const UTM_LAT_ERROR = 0x0001 const UTM_LON_ERROR = 0x0002 const UTM_EASTING_ERROR = 0x0004 const UTM_NORTHING_ERROR = 0x0008 const UTM_ZONE_ERROR = 0x0010 const UTM_HEMISPHERE_ERROR = 0x0020 const UTM_ZONE_OVERRIDE_ERROR = 0x0040 const UTM_A_ERROR = 0x0080 const UTM_INV_F_ERROR = 0x0100 const DEG_TO_RAD = 0.017453292519943295 /* PI/180 */ const RAD_TO_DEG = 57.29577951308232087 /* 180/PI */ const LETTER_A = 0 /* ARRAY INDEX FOR LETTER A */ const LETTER_B = 1 /* ARRAY INDEX FOR LETTER B */ const LETTER_C = 2 /* ARRAY INDEX FOR LETTER C */ const LETTER_D = 3 /* ARRAY INDEX FOR LETTER D */ const LETTER_E = 4 /* ARRAY INDEX FOR LETTER E */ const LETTER_F = 5 /* ARRAY INDEX FOR LETTER F */ const LETTER_G = 6 /* ARRAY INDEX FOR LETTER G */ const LETTER_H = 7 /* ARRAY INDEX FOR LETTER H */ const LETTER_I = 8 /* ARRAY INDEX FOR LETTER I */ const LETTER_J = 9 /* ARRAY INDEX FOR LETTER J */ const LETTER_K = 10 /* ARRAY INDEX FOR LETTER K */ const LETTER_L = 11 /* ARRAY INDEX FOR LETTER L */ const LETTER_M = 12 /* ARRAY INDEX FOR LETTER M */ const LETTER_N = 13 /* ARRAY INDEX FOR LETTER N */ const LETTER_O = 14 /* ARRAY INDEX FOR LETTER O */ const LETTER_P = 15 /* ARRAY INDEX FOR LETTER P */ const LETTER_Q = 16 /* ARRAY INDEX FOR LETTER Q */ const LETTER_R = 17 /* ARRAY INDEX FOR LETTER R */ const LETTER_S = 18 /* ARRAY INDEX FOR LETTER S */ const LETTER_T = 19 /* ARRAY INDEX FOR LETTER T */ const LETTER_U = 20 /* ARRAY INDEX FOR LETTER U */ const LETTER_V = 21 /* ARRAY INDEX FOR LETTER V */ const LETTER_W = 22 /* ARRAY INDEX FOR LETTER W */ const LETTER_X = 23 /* ARRAY INDEX FOR LETTER X */ const LETTER_Y = 24 /* ARRAY INDEX FOR LETTER Y */ const LETTER_Z = 25 /* ARRAY INDEX FOR LETTER Z */ const MGRS_LETTERS = 3 /* NUMBER OF LETTERS IN MGRS */ const ONEHT = 100000.e0 /* ONE HUNDRED THOUSAND */ const TWOMIL = 2000000.e0 /* TWO MILLION */ const TRUE = 1 /* CONSTANT VALUE FOR TRUE VALUE */ const FALSE = 0 /* CONSTANT VALUE FOR FALSE VALUE */ const PI = 3.14159265358979323e0 /* PI */ const PI_OVER_2 = (PI / 2.0e0) const MIN_EASTING = 100000 const MAX_EASTING = 900000 const MIN_NORTHING = 0 const MAX_NORTHING = 10000000 const MAX_PRECISION = 5 /* Maximum precision of easting & northing */ const MIN_UTM_LAT = ((-80 * PI) / 180.0 ) /* -80 degrees in radians */ const MAX_UTM_LAT = ((84 * PI) / 180.0 ) /* 84 degrees in radians */ const MIN_EAST_NORTH = 0 const MAX_EAST_NORTH = 4000000 const PI_OVER = (PI/2.0e0) /* PI over 2 */ const MIN_LAT = ((-80.5 * PI) / 180.0) /* -80.5 degrees in radians */ const MAX_LAT = ((PI * 90)/180.0) /* 90 degrees in radians */ const MAX_ORIGIN_LAT = ((81.114528 * PI) / 180.0) const MIN_NORTH_LAT = (83.5*PI/180.0) const MIN_SOUTH_LAT = (-79.5*PI/180.0) const TWO_PI = (2.0 * PI) const MAX_DELTA_LONG = ((PI * 90)/180.0) /* 90 degrees in radians */ const MIN_SCALE_FACTOR = 0.3 const MAX_SCALE_FACTOR = 3.0 const NORTH_POLE_RADIUS = 666727; const SOUTH_POLE_RADIUS = 1112950.7; let MGRS_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */ let MGRS_f = 1 / 298.257223563; /* Flattening of ellipsoid */ let UPS_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */ let UPS_f = 1 / 298.257223563; /* Flattening of ellipsoid */ /* Ellipsoid Parameters, default to WGS 84 */ let UPS_False_Easting = 2000000; let UPS_False_Northing = 2000000; let UPS_Origin_Latitude = MAX_ORIGIN_LAT; /*set default = North Hemisphere */ let UPS_Origin_Longitude = 0.0; const PI_Over_4 = (PI / 4.0); /* Ellipsoid Parameters, default to WGS 84 */ let Polar_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */ let Polar_f = 1 / 298.257223563; /* Flattening of ellipsoid */ let es = 0.08181919084262188000; /* Eccentricity of ellipsoid */ let es_OVER_2 = .040909595421311; /* es / 2.0 */ let Southern_Hemisphere = 0; /* Flag variable */ let tc = 1.0; let e4 = 1.0033565552493; let Polar_a_mc = 6378137.0; /* Polar_a * mc */ let two_Polar_a = 12756274.0; /* 2.0 * Polar_a */ /* Polar Stereographic projection Parameters */ let Polar_Origin_Lat = ((PI * 90) / 180); /* Latitude of origin in radians */ let Polar_Origin_Long = 0.0; /* Longitude of origin in radians */ let Polar_False_Easting = 0.0; /* False easting in meters */ let Polar_False_Northing = 0.0; /* False northing in meters */ /* Maximum variance for easting and northing values for WGS 84. */ let Polar_Delta_Easting = 12713601.0; let Polar_Delta_Northing = 12713601.0; /* Ellipsoid Parameters, default to WGS 84 */ let TranMerc_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */ let TranMerc_f = 1 / 298.257223563; /* Flattening of ellipsoid */ let TranMerc_es = 0.0066943799901413800; /* Eccentricity (0.08181919084262188000) squared */ let TranMerc_ebs = 0.0067394967565869; /* Second Eccentricity squared */ /* Transverse_Mercator projection Parameters */ let TranMerc_Origin_Lat = 0.0; /* Latitude of origin in radians */ let TranMerc_Origin_Long = 0.0; /* Longitude of origin in radians */ let TranMerc_False_Northing = 0.0; /* False northing in meters */ let TranMerc_False_Easting = 0.0; /* False easting in meters */ let TranMerc_Scale_Factor = 1.0; /* Scale factor */ /* Isometeric to geodetic latitude parameters, default to WGS 84 */ let TranMerc_ap = 6367449.1458008; let TranMerc_bp = 16038.508696861; let TranMerc_cp = 16.832613334334; let TranMerc_dp = 0.021984404273757; let TranMerc_ep = 3.1148371319283e-005; /* Maximum variance for easting and northing values for WGS 84. */ let TranMerc_Delta_Easting = 40000000.0; let TranMerc_Delta_Northing = 40000000.0; let UTM_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */ let UTM_f = 1 / 298.257223563; /* Flattening of ellipsoid */ let UTM_Override = 0; /* Zone override flag */ const UPS_Constant_Table = [ { letter: LETTER_A, ltr2_low_value: LETTER_J, ltr2_high_value: LETTER_Z, ltr3_high_value: LETTER_Z, false_easting: 800000.0, false_northing: 800000.0 }, { letter: LETTER_B, ltr2_low_value: LETTER_A, ltr2_high_value: LETTER_R, ltr3_high_value: LETTER_Z, false_easting: 2000000.0, false_northing: 800000.0 }, { letter: LETTER_Y, ltr2_low_value: LETTER_J, ltr2_high_value: LETTER_Z, ltr3_high_value: LETTER_P, false_easting: 800000.0, false_northing: 1300000.0 }, { letter: LETTER_Z, ltr2_low_value: LETTER_A, ltr2_high_value: LETTER_J, ltr3_high_value: LETTER_P, false_easting: 2000000.0, false_northing: 1300000.0 } ]; const Latitude_Band_Table = [ {letter: LETTER_C, min_northing: 1100000.0, north: -72.0, south: -80.5, northing_offset: 0.0 }, {letter: LETTER_D, min_northing: 2000000.0, north: -64.0, south: -72.0, northing_offset: 2000000.0}, {letter: LETTER_E, min_northing: 2800000.0, north: -56.0, south: -64.0, northing_offset: 2000000.0}, {letter: LETTER_F, min_northing: 3700000.0, north: -48.0, south: -56.0, northing_offset: 2000000.0}, {letter: LETTER_G, min_northing: 4600000.0, north: -40.0, south: -48.0, northing_offset: 4000000.0}, {letter: LETTER_H, min_northing: 5500000.0, north: -32.0, south: -40.0, northing_offset: 4000000.0}, {letter: LETTER_J, min_northing: 6400000.0, north: -24.0, south: -32.0, northing_offset: 6000000.0}, {letter: LETTER_K, min_northing: 7300000.0, north: -16.0, south: -24.0, northing_offset: 6000000.0}, {letter: LETTER_L, min_northing: 8200000.0, north: -8.0, south: -16.0, northing_offset: 8000000.0}, {letter: LETTER_M, min_northing: 9100000.0, north: 0.0, south: -8.0, northing_offset: 8000000.0}, {letter: LETTER_N, min_northing: 0.0, north: 8.0, south: 0.0, northing_offset: 0.0 }, {letter: LETTER_P, min_northing: 800000.0, north: 16.0, south: 8.0, northing_offset: 0.0}, {letter: LETTER_Q, min_northing: 1700000.0, north: 24.0, south: 16.0, northing_offset: 0.0}, {letter: LETTER_R, min_northing: 2600000.0, north: 32.0, south: 24.0, northing_offset: 2000000.0}, {letter: LETTER_S, min_northing: 3500000.0, north: 40.0, south: 32.0, northing_offset: 2000000.0}, {letter: LETTER_T, min_northing: 4400000.0, north: 48.0, south: 40.0, northing_offset: 4000000.0}, {letter: LETTER_U, min_northing: 5300000.0, north: 56.0, south: 48.0, northing_offset: 4000000.0}, {letter: LETTER_V, min_northing: 6200000.0, north: 64.0, south: 56.0, northing_offset: 6000000.0}, {letter: LETTER_W, min_northing: 7000000.0, north: 72.0, south: 64.0, northing_offset: 6000000.0}, {letter: LETTER_X, min_northing: 7900000.0, north: 84.5, south: 72.0, northing_offset: 6000000.0} ]; class MgrsError { constructor(message) { this.message = message; } } class MgrsPole { fmod(a,b) { return Number((a - (Math.floor(a / b) * b)).toPrecision(8)); }; zfill(num, len) {return (Array(len).join("0") + num).slice(-len);} POLAR_POW(EsSin) { return Math.pow((1.0 - EsSin) / (1.0 + EsSin), es_OVER_2); } SPHTMD(Latitude) { return (TranMerc_ap * Latitude - TranMerc_bp * Math.sin(2.e0 * Latitude) + TranMerc_cp * Math.sin(4.e0 * Latitude) - TranMerc_dp * Math.sin(6.e0 * Latitude) + TranMerc_ep * Math.sin(8.e0 * Latitude)); } SPHSN(Latitude) { return (TranMerc_a / Math.sqrt( 1.e0 - TranMerc_es * Math.pow(Math.sin(Latitude), 2))); } SPHSR(Latitude) { return (TranMerc_a * (1.e0 - TranMerc_es) / Math.pow(this.DENOM(Latitude), 3)); } DENOM(Latitude) { return (Math.sqrt(1.e0 - TranMerc_es * Math.pow(Math.sin(Latitude), 2))); } Set_UPS_Parameters(a, f) { /* * The function SET_UPS_PARAMETERS receives the ellipsoid parameters and sets * the corresponding state variables. If any errors occur, the error code(s) * are returned by the function, otherwise UPS_NO_ERROR is returned. * * a : Semi-major axis of ellipsoid in meters (input) * f : Flattening of ellipsoid (input) */ const inv_f = 1 / f; let Error_Code = UPS_NO_ERROR; if (a <= 0.0) { /* Semi-major axis must be greater than zero */ Error_Code |= UPS_A_ERROR; throw new MgrsError(`Semi-major axis = ‘${a}’ must be greater than zero`); } if ((inv_f < 250) || (inv_f > 350)) { /* Inverse flattening must be between 250 and 350 */ Error_Code |= UPS_INV_F_ERROR; throw new MgrsError(`Inverse flattening ${inv_f} must be between 250 and 350`); } if (!Error_Code){ /* no errors */ UPS_a = a; UPS_f = f; } return (Error_Code); } /* END of Set_UPS_Parameters */ Convert_Geodetic_To_Polar_Stereographic (Latitude, Longitude) { /* BEGIN Convert_Geodetic_To_Polar_Stereographic */ /* * The function Convert_Geodetic_To_Polar_Stereographic converts geodetic * coordinates (latitude and longitude) to Polar Stereographic coordinates * (easting and northing), according to the current ellipsoid * and Polar Stereographic projection parameters. If any errors occur, error * code(s) are returned by the function, otherwise POLAR_NO_ERROR is returned. * * Latitude : Latitude, in radians (input) * Longitude : Longitude, in radians (input) * Easting : Easting (X), in meters (output) * Northing : Northing (Y), in meters (output) */ let Easting = ''; let Northing = ''; let dlam; let slat; let essin; let t; let rho; let pow_es; let Error_Code = POLAR_NO_ERROR; if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2)) { /* Latitude out of range */ Error_Code |= POLAR_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Latitude < 0) && (Southern_Hemisphere == 0)) { /* Latitude and Origin Latitude in different hemispheres */ Error_Code |= POLAR_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Latitude > 0) && (Southern_Hemisphere == 1)) { /* Latitude and Origin Latitude in different hemispheres */ Error_Code |= POLAR_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Longitude < -PI) || (Longitude > TWO_PI)) { /* Longitude out of range */ Error_Code |= POLAR_LON_ERROR; throw new MgrsError(`Longitude ‘${Longitude * RAD_TO_DEG}’ out of range`); } if (!Error_Code) { /* no errors */ if (Math.abs(Math.abs(Latitude) - PI_OVER_2) < 1.0e-10) { Easting = Polar_False_Easting; Northing = Polar_False_Northing; } else { if (Southern_Hemisphere != 0) { Longitude *= -1.0; Latitude *= -1.0; } dlam = Longitude - Polar_Origin_Long; if (dlam > PI) { dlam -= TWO_PI; } if (dlam < -PI) { dlam += TWO_PI; } slat = Math.sin(Latitude); essin = es * slat; pow_es = this.POLAR_POW(essin); t = Math.tan(PI_Over_4 - Latitude / 2.0) / pow_es; if (Math.abs(Math.abs(Polar_Origin_Lat) - PI_OVER_2) > 1.0e-10) rho = Polar_a_mc * t / tc; else rho = two_Polar_a * t / e4; if (Southern_Hemisphere != 0) { Easting = -(rho * Math.sin(dlam) - Polar_False_Easting); // *Easting *= -1.0; Northing = rho * Math.cos(dlam) + Polar_False_Northing; } else { Easting = rho * Math.sin(dlam) + Polar_False_Easting; Northing = -rho * Math.cos(dlam) + Polar_False_Northing; } } } return [Error_Code, Easting, Northing]; } /* END OF Convert_Geodetic_To_Polar_Stereographic */ Set_Polar_Stereographic_Parameters (a, f, Latitude_of_True_Scale, Longitude_Down_from_Pole, False_Easting, False_Northing) { /* BEGIN Set_Polar_Stereographic_Parameters */ /* * The function Set_Polar_Stereographic_Parameters receives the ellipsoid * parameters and Polar Stereograpic projection parameters as inputs, and * sets the corresponding state variables. If any errors occur, error * code(s) are returned by the function, otherwise POLAR_NO_ERROR is returned. * * a : Semi-major axis of ellipsoid, in meters (input) * f : Flattening of ellipsoid (input) * Latitude_of_True_Scale : Latitude of true scale, in radians (input) * Longitude_Down_from_Pole : Longitude down from pole, in radians (input) * False_Easting : Easting (X) at center of projection, in meters (input) * False_Northing : Northing (Y) at center of projection, in meters (input) */ let es2; let slat, clat; let essin; let one_PLUS_es, one_MINUS_es; let pow_es; let temp, temp_northing; let inv_f = 1 / f; let mc; // const double epsilon = 1.0e-2; let Error_Code = POLAR_NO_ERROR; if (a <= 0.0) { /* Semi-major axis must be greater than zero */ Error_Code |= POLAR_A_ERROR; throw new MgrsError(`Semi-major axis = ‘${a}’ must be greater than zero`); } if ((inv_f < 250) || (inv_f > 350)) { /* Inverse flattening must be between 250 and 350 */ Error_Code |= POLAR_INV_F_ERROR; throw new MgrsError(`Inverse flattening ${inv_f} must be between 250 and 350`); } if ((Latitude_of_True_Scale < -PI_OVER_2) || (Latitude_of_True_Scale > PI_OVER_2)) { /* Origin Latitude out of range */ Error_Code |= POLAR_ORIGIN_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude_of_True_Scale * RAD_TO_DEG}’ out of range`); } if ((Longitude_Down_from_Pole < -PI) || (Longitude_Down_from_Pole > TWO_PI)) { /* Origin Longitude out of range */ Error_Code |= POLAR_ORIGIN_LON_ERROR; throw new MgrsError(`Longitude ‘${Longitude_Down_from_Pole * RAD_TO_DEG}’ out of range`); } if (!Error_Code) { /* no errors */ Polar_a = a; two_Polar_a = 2.0 * Polar_a; Polar_f = f; if (Longitude_Down_from_Pole > PI) Longitude_Down_from_Pole -= TWO_PI; if (Latitude_of_True_Scale < 0) { Southern_Hemisphere = 1; Polar_Origin_Lat = -Latitude_of_True_Scale; Polar_Origin_Long = -Longitude_Down_from_Pole; } else { Southern_Hemisphere = 0; Polar_Origin_Lat = Latitude_of_True_Scale; Polar_Origin_Long = Longitude_Down_from_Pole; } Polar_False_Easting = False_Easting; Polar_False_Northing = False_Northing; es2 = 2 * Polar_f - Polar_f * Polar_f; es = Math.sqrt(es2); es_OVER_2 = es / 2.0; if (Math.abs(Math.abs(Polar_Origin_Lat) - PI_OVER_2) > 1.0e-10) { slat = Math.sin(Polar_Origin_Lat); essin = es * slat; pow_es = this.POLAR_POW(essin); clat = Math.cos(Polar_Origin_Lat); mc = clat / Math.sqrt(1.0 - essin * essin); Polar_a_mc = Polar_a * mc; tc = Math.tan(PI_Over_4 - Polar_Origin_Lat / 2.0) / pow_es; } else { one_PLUS_es = 1.0 + es; one_MINUS_es = 1.0 - es; e4 = Math.sqrt(Math.pow(one_PLUS_es, one_PLUS_es) * Math.pow(one_MINUS_es, one_MINUS_es)); } /* Calculate Radius */ const [local_Error_Code, temp, temp_northing] = this.Convert_Geodetic_To_Polar_Stereographic(0, Longitude_Down_from_Pole); Polar_Delta_Northing = temp_northing; if(Polar_False_Northing) Polar_Delta_Northing -= Polar_False_Northing; if (Polar_Delta_Northing < 0) Polar_Delta_Northing = -Polar_Delta_Northing; Polar_Delta_Northing *= 1.01; Polar_Delta_Easting = Polar_Delta_Northing; /* Polar_Delta_Easting = temp_northing; if(Polar_False_Easting) Polar_Delta_Easting -= Polar_False_Easting; if (Polar_Delta_Easting < 0) Polar_Delta_Easting = -Polar_Delta_Easting; Polar_Delta_Easting *= 1.01;*/ } return (Error_Code); } /* END OF Set_Polar_Stereographic_Parameters */ Convert_Geodetic_To_UPS (Latitude, Longitude) { /* * The function Convert_Geodetic_To_UPS converts geodetic (latitude and * longitude) coordinates to UPS (hemisphere, easting, and northing) * coordinates, according to the current ellipsoid parameters. If any * errors occur, the error code(s) are returned by the function, * otherwide UPS_NO_ERROR is returned. * * Latitude : Latitude in radians (input) * Longitude : Longitude in radians (input) * Hemisphere : Hemisphere either 'N' or 'S' (output) * Easting : Easting/X in meters (output) * Northing : Northing/Y in meters (output) */ let Easting; let Northing; let tempEasting, tempNorthing; let Error_Code = UPS_NO_ERROR; let Hemisphere =''; if ((Latitude < -MAX_LAT) || (Latitude > MAX_LAT)) { /* latitude out of range */ Error_Code |= UPS_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Latitude < 0) && (Latitude > MIN_SOUTH_LAT)) { Error_Code |= UPS_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Latitude >= 0) && (Latitude < MIN_NORTH_LAT)) { Error_Code |= UPS_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Longitude < -PI) || (Longitude > (2 * PI))) { /* slam out of range */ Error_Code |= UPS_LON_ERROR; throw new MgrsError(`Longitude ‘${Longitude * RAD_TO_DEG}’ out of range`); } if (!Error_Code) { /* no errors */ if (Latitude < 0) { UPS_Origin_Latitude = -MAX_ORIGIN_LAT; Hemisphere = 'S'; } else { UPS_Origin_Latitude = MAX_ORIGIN_LAT; Hemisphere = 'N'; } this.Set_Polar_Stereographic_Parameters( UPS_a, UPS_f, UPS_Origin_Latitude, UPS_Origin_Longitude, UPS_False_Easting, UPS_False_Northing); const [localError, tempEasting, tempNorthing] = this.Convert_Geodetic_To_Polar_Stereographic(Latitude, Longitude); // &tempEasting, // &tempNorthing); Easting = tempEasting; Northing = tempNorthing; } /* END of if(!Error_Code) */ return [Error_Code, Hemisphere, Easting, Northing]; } /* END OF Convert_Geodetic_To_UPS */ Convert_UPS_To_MGRS (Hemisphere, Easting, Northing, Precision) /* * The function Convert_UPS_To_MGRS converts UPS (hemisphere, easting, * and northing) 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 UPS_NO_ERROR is * returned. * * Hemisphere : Hemisphere either 'N' or 'S' (input) * Easting : Easting/X in meters (input) * Northing : Northing/Y in meters (input) * Precision : Precision level of MGRS string (input) * MGRS : MGRS coordinate string (output) */ { /* Convert_UPS_To_MGRS */ let MGRS =''; let false_easting; /* False easting for 2nd letter */ let false_northing; /* False northing for 3rd letter */ let grid_easting; /* Easting used to derive 2nd letter of MGRS */ let grid_northing; /* Northing used to derive 3rd letter of MGRS */ let ltr2_low_value; /* 2nd letter range - low number */ let letters = [0, 0, 0]; /* Number location of 3 letters in alphabet */ let index = 0; let error_code = MGRS_NO_ERROR; if ((Hemisphere != 'N') && (Hemisphere != 'S')) { error_code |= MGRS_HEMISPHERE_ERROR; throw new MgrsError(`MGRS Hemisphre Error at ${Hemisphere}`); } if ((Easting < MIN_EAST_NORTH) || (Easting > MAX_EAST_NORTH)) { error_code |= MGRS_EASTING_ERROR; throw new MgrsError(`MGRS Easting Error at ${Easting}`); } if ((Northing < MIN_EAST_NORTH) || (Northing > MAX_EAST_NORTH)) { error_code |= MGRS_NORTHING_ERROR; throw new MgrsError(`MGRS Northing Error at ${Northing}`); } if ((Precision < 0) || (Precision > MAX_PRECISION)) { error_code |= MGRS_PRECISION_ERROR; throw new MgrsError(`MGRS Precision Error at ${Precision}`); } if (!error_code) { let start = 0 if (Hemisphere == 'N') { if (Easting >= TWOMIL) { letters[0] = LETTER_Z; } else { letters[0] = LETTER_Y; } index = letters[0] - 22; ltr2_low_value = UPS_Constant_Table[index].ltr2_low_value; false_easting = UPS_Constant_Table[index].false_easting; false_northing = UPS_Constant_Table[index].false_northing; } else { if (Easting >= TWOMIL) letters[0] = LETTER_B; else letters[0] = LETTER_A; ltr2_low_value = UPS_Constant_Table[letters[0]].ltr2_low_value; false_easting = UPS_Constant_Table[letters[0]].false_easting; false_northing = UPS_Constant_Table[letters[0]].false_northing; } grid_northing = Northing; grid_northing = grid_northing - false_northing; letters[2] = Math.floor(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; grid_easting = grid_easting - false_easting; letters[1] = ltr2_low_value + (Math.floor(grid_easting / ONEHT)); if (Easting < TWOMIL) { if (letters[1] > LETTER_L) letters[1] = letters[1] + 3; if (letters[1] > LETTER_U) letters[1] = letters[1] + 2; } else { if (letters[1] > LETTER_C) letters[1] = letters[1] + 2; if (letters[1] > LETTER_H) letters[1] = letters[1] + 1; if (letters[1] > LETTER_L) letters[1] = letters[1] + 3; } const [ localError, mgrs ] = this.Make_MGRS_String (0, letters, Easting, Northing, Precision); error_code |= localError; MGRS = mgrs; } return [error_code, MGRS]; } /* Convert_UPS_To_MGRS */ Make_MGRS_String (Zone, Letters, Easting, Northing, 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 */ let MGRS = ''; let i; let j; let divisor; let east; let north; let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let error_code = MGRS_NO_ERROR; i = 0; if (Zone) MGRS = `${Zone}`; // i = sprintf (MGRS+i,"%2.2ld",Zone); // else // strncpy(MGRS, " ", 2); // 2 spaces for (j = 0; j < 3; j++) { MGRS = MGRS.concat(alphabet[Letters[j]]); } divisor = Math.pow (10.0, (5 - Precision)); Easting = this.fmod(Easting, 100000.0); if (Easting >= 99999.5) Easting = 99999.0; east = Math.floor(Easting/divisor); // i += sprintf (MGRS+i, "%*.*ld", (int)Precision, (int)Precision, east); MGRS = MGRS.concat(this.zfill(east,5)); Northing = this.fmod (Northing, 100000.0); if (Northing >= 99999.5) Northing = 99999.0; north = Math.floor(Northing/divisor); // i += sprintf (MGRS+i, "%*.*ld", (int)Precision, (int)Precision, north); MGRS = MGRS.concat(this.zfill(north,5)); return [error_code, MGRS]; } /* Make_MGRS_String */ isdigit(c) { return c >= '0' && c <= '9'; } isalpha(c) { return c >= 'A' && c <= 'Z'; } Check_Zone(MGRS) /* * The function Check_Zone receives an MGRS coordinate string. * If a zone is given, TRUE is returned. Otherwise, FALSE * is returned. * * MGRS : MGRS coordinate string (input) * zone_exists : TRUE if a zone is given, * FALSE if a zone is not given (output) */ { /* Check_Zone */ let zone_exists = false; let i = 0; let j = 0; let num_digits = 0; let error_code = MGRS_NO_ERROR; /* skip any leading blanks */ while (MGRS[i] == ' ') i++; j = i; while (this.isdigit(MGRS[i])) i++; num_digits = i - j; if (num_digits <= 2) { if (num_digits > 0) zone_exists = true; else zone_exists = false; } else { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } return [error_code, zone_exists]; } /* Check_Zone */ Convert_Geodetic_To_MGRS (Latitude, Longitude, Precision) { let MGRS; let zone; let hemisphere; let easting; let northing; let temp_error_code = MGRS_NO_ERROR; let error_code = MGRS_NO_ERROR; if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2)) { /* Latitude out of range */ error_code |= MGRS_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if ((Longitude < -PI) || (Longitude > (2*PI))) { /* Longitude out of range */ error_code |= MGRS_LON_ERROR; throw new MgrsError(`Longitude ‘${Longitude * RAD_TO_DEG}’ out of range`); } if ((Precision < 0) || (Precision > MAX_PRECISION)) { error_code |= MGRS_PRECISION_ERROR; throw new MgrsError(`MGRS Precision Error at ${Precision}`); } if (!error_code) { if ((Latitude < MIN_UTM_LAT) || (Latitude > MAX_UTM_LAT)) { temp_error_code = this.Set_UPS_Parameters (MGRS_a, MGRS_f); if(!temp_error_code) { const [temp_error_code, hemisphere, easting, northing] = this.Convert_Geodetic_To_UPS (Latitude, Longitude); //, &hemisphere, &easting, &northing); if(!temp_error_code) { const [local_error_code, mgrs] = this.Convert_UPS_To_MGRS (hemisphere, easting, northing, Precision); error_code = error_code | local_error_code; MGRS = mgrs; } else { if (temp_error_code & UPS_LAT_ERROR) { error_code |= MGRS_LAT_ERROR; throw new MgrsError(`Latitude ‘${Latitude * RAD_TO_DEG}’ out of range`); } if (temp_error_code & UPS_LON_ERROR) { error_code |= MGRS_LON_ERROR; throw new MgrsError(`Longitude ‘${Longitude * RAD_TO_DEG}’ out of range`); } } } } } return [error_code, MGRS]; } Break_MGRS_String (MGRS) /* * The function Break_MGRS_String breaks down an MGRS * coordinate string into its component parts. * * MGRS : MGRS coordinate string (input) * Zone : UTM Zone (output) * Letters : MGRS coordinate string letters (output) * Easting : Easting value (output) * Northing : Northing value (output) * Precision : Precision level of MGRS string (output) */ { /* Break_MGRS_String */ let Zone; let Letters =[0,0,0]; let Easting; let Northing; let Precision; let num_digits; let num_letters; let i = 0; let j = 0; let error_code = MGRS_NO_ERROR; while (MGRS[i] == ' ') i++; /* skip any leading blanks */ j = i; while (this.isdigit(MGRS[i])) i++; num_digits = i - j; if (num_digits <= 2) { if (num_digits > 0) { let zone_string = MGRS.substring(j, j+num_digits); Zone = Number(zone_string); if ((Zone < 1) || (Zone > 60)) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } } else Zone = 0; } else { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } j = i; while (this.isalpha(MGRS[i])) i++; num_letters = i - j; if (num_letters == 3) { /* get letters */ Letters[0] = MGRS[j].toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0); if ((Letters[0] == LETTER_I) || (Letters[0] == LETTER_O)) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } Letters[1] = MGRS[j+1].toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0); if ((Letters[1] == LETTER_I) || (Letters[1] == LETTER_O)) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } Letters[2] = MGRS[j+2].toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0); if ((Letters[2] == LETTER_I) || (Letters[2] == LETTER_O)) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } } else { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } j = i; while (this.isdigit(MGRS[i])) i++; num_digits = i - j; if ((num_digits <= 10) && (num_digits%2 == 0)) { let n; let east_string = []; // east_string[6]; let north_string = []; // north_string[6]; let east; let north; let multiplier; /* get easting & northing */ n = num_digits/2; Precision = n; if (n > 0) { east_string[n] = 0; east_string = MGRS.substring(j, j+n); east = Number(east_string); north_string[n] = 0; north_string = MGRS.substring(j+n); north = Number(north_string); multiplier = Math.pow (10.0, 5 - n); Easting = east * multiplier; Northing = north * multiplier; } else { Easting = 0.0; Northing = 0.0; } } else { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } return [error_code, Zone, Letters, Easting, Northing, Precision]; } /* Break_MGRS_String */ Get_Grid_Values (zone) /* * 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 */ let set_number; /* Set number (1-6) based on UTM zone number */ let aa_pattern; /* Pattern based on ellipsoid code */ let ltr2_low_value; let ltr2_high_value; let pattern_offset; set_number = zone % 6; if (!set_number) { set_number = 6; } 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; } return [ltr2_low_value, ltr2_high_value, pattern_offset]; } /* END OF Get_Grid_Values */ Set_UTM_Parameters(a, f, override) { /* * The function Set_UTM_Parameters receives the ellipsoid parameters and * UTM zone override parameter as inputs, and sets the corresponding state * variables. If any errors occur, the error code(s) are returned by the * function, otherwise UTM_NO_ERROR is returned. * * a : Semi-major axis of ellipsoid, in meters (input) * f : Flattening of ellipsoid (input) * override : UTM override zone, zero indicates no override (input) */ let inv_f = 1 / f; let Error_Code = UTM_NO_ERROR; if (a <= 0.0) { /* Semi-major axis must be greater than zero */ Error_Code |= UTM_A_ERROR; } if ((inv_f < 250) || (inv_f > 350)) { /* Inverse flattening must be between 250 and 350 */ Error_Code |= UTM_INV_F_ERROR; } if ((override < 0) || (override > 60)) { Error_Code |= UTM_ZONE_OVERRIDE_ERROR; } if (!Error_Code) { /* no errors */ UTM_a = a; UTM_f = f; UTM_Override = override; } return (Error_Code); } /* END OF Set_UTM_Parameters */ Convert_MGRS_To_UTM (MGRS) /* * The function Convert_MGRS_To_UTM converts an MGRS coordinate string * to UTM projection (zone, hemisphere, easting and northing) coordinates * according to the current ellipsoid parameters. If any errors occur, * the error code(s) are returned by the function, otherwise UTM_NO_ERROR * is returned. * * MGRS : MGRS coordinate string (input) * Zone : UTM zone (output) * Hemisphere : North or South hemisphere (output) * Easting : Easting (X) in meters (output) * Northing : Northing (Y) in meters (output) */ { /* Convert_MGRS_To_UTM */ let Zone; let Hemisphere; let Easting; let Northing; let min_northing; let northing_offset; let ltr2_low_value; let ltr2_high_value; let pattern_offset; let upper_lat_limit; /* North latitude limits based on 1st letter */ let lower_lat_limit; /* South latitude limits based on 1st letter */ let grid_easting; /* Easting for 100,000 meter grid square */ let grid_northing; /* Northing for 100,000 meter grid square */ let letters; let in_precision; let latitude = 0.0; let longitude = 0.0; let divisor = 1.0; let utm_error_code = MGRS_NO_ERROR; let error_code = MGRS_NO_ERROR; // error_code = Break_MGRS_String (MGRS, Zone, letters, Easting, Northing, &in_precision); const [local_error_code, local_zone, local_letters, local_Easting, local_Northing, local_in_precision ] = this.Break_MGRS_String (MGRS); error_code |= local_error_code; Zone = local_zone; letters = local_letters; Easting = local_Easting; Northing = local_Northing; in_precision = local_in_precision; if (!Zone) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } else { if (!error_code) { if ((letters[0] == LETTER_X) && ((Zone == 32) || (Zone == 34) || (Zone == 36))) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } else { if (letters[0] < LETTER_N) { Hemisphere = 'S'; } else { Hemisphere = 'N'; } // Get_Grid_Values(*Zone, &ltr2_low_value, &ltr2_high_value, &pattern_offset); const [local_ltr2_low_value, local_ltr2_high_value, local_pattern_offset] = this.Get_Grid_Values(Zone); ltr2_low_value = local_ltr2_low_value; ltr2_high_value = local_ltr2_high_value; pattern_offset = local_pattern_offset; /* Check that the second letter of the MGRS string is within * the range of valid second letter values * Also check that the third letter is valid */ if ((letters[1] < ltr2_low_value) || (letters[1] > ltr2_high_value) || (letters[2] > LETTER_V)) { error_code |= MGRS_STRING_ERROR; throw new MgrsError(`MGRS Zone String error at ${MGRS}`); } if (!error_code) { let row_letter_northing = Number((letters[2]) * ONEHT); grid_easting = ((letters[1]) - ltr2_low_value + 1) * ONEHT; if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_O)) grid_easting = grid_easting - ONEHT; if (letters[2] > LETTER_O) row_letter_northing = row_letter_northing - ONEHT; if (letters[2] > LETTER_I) row_letter_northing = row_letter_northing - ONEHT; if (row_letter_northing >= TWOMIL) row_letter_northing = row_letter_northing - TWOMIL; const [local_error_code, local_min_northing, local_northing_offset] = this.Get_Latitude_Band_Min_Northing(letters[0]); min_northing = local_min_northing; northing_offset = local_northing_offset; error_code |= local_error_code; if (!error_code) { grid_northing = row_letter_northing - pattern_offset; if(grid_northing < 0) grid_northing += TWOMIL; grid_northing += northing_offset; if(grid_northing < min_northing) grid_northing += TWOMIL; Easting = grid_easting + Easting; Northing = grid_northing + Northing; /* check that point is within Zone Letter bounds */ utm_error_code = this.Set_UTM_Parameters(MGRS_a,MGRS_f,0); if (!utm_error_code) { // utm_error_code = Convert_UTM_To_Geodetic(*Zone,*Hemisphere,*Easting,*Northing,&latitude,&longitude); const [local_temp_error_code, local_Latitude, local_Longitude] = this.Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing); utm_error_code = local_temp_error_code; latitude = local_Latitude; longitude = local_Longitude; if (!utm_error_code) { divisor = Math.pow(10.0, in_precision); // error_code = Get_Latitude_Range(letters[0], &upper_lat_limit, &lower_lat_limit); if (!error_code) { if (!(((lower_lat_limit - DEG_TO_RAD/divisor) <= latitude) && (latitude <= (upper_lat_limit + DEG_TO_RAD/divisor)))) { error_code |= MGRS_LAT_WARNING; }