long Convert_UTM_To_OSSIM_MGRS (long Zone, char Hemisphere, double Easting, double Northing, long Precision, char* OSSIM_MGRS) /* * The function Convert_UTM_To_OSSIM_MGRS converts UTM (zone, easting, and * northing) coordinates to an OSSIM_MGRS coordinate string, according to the * current ellipsoid parameters. If any errors occur, the error code(s) * are returned by the function, otherwise OSSIM_MGRS_NO_ERROR is returned. * * Zone : UTM zone (input) * Hemisphere : North or South hemisphere (input) * Easting : Easting (X) in meters (input) * Northing : Northing (Y) in meters (input) * Precision : Precision level of OSSIM_MGRS string (input) * OSSIM_MGRS : OSSIM_MGRS coordinate string (output) */ { /* Convert_UTM_To_OSSIM_MGRS */ long error_code = OSSIM_MGRS_NO_ERROR; long temp_error = OSSIM_MGRS_NO_ERROR; long Letters[OSSIM_MGRS_LETTERS]; /* Number location of 3 letters in alphabet */ double Latitude; /* Latitude of UTM point */ double Longitude; /* Longitude of UTM point */ double divisor; if ((Zone < 1) || (Zone > 60)) error_code |= OSSIM_MGRS_ZONE_ERROR; if ((Hemisphere != 'S') && (Hemisphere != 'N')) error_code |= OSSIM_MGRS_HEMISPHERE_ERROR; if ((Easting < MIN_EASTING) || (Easting > MAX_EASTING)) error_code |= OSSIM_MGRS_EASTING_ERROR; if ((Northing < MIN_NORTHING) || (Northing > MAX_NORTHING)) error_code |= OSSIM_MGRS_NORTHING_ERROR; if ((Precision < 0) || (Precision > MAX_PRECISION)) error_code |= OSSIM_MGRS_PRECISION_ERROR; if (!error_code) { Set_UTM_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f,0); temp_error = Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, &Latitude, &Longitude); if (temp_error & UTM_NORTHING_ERROR) error_code |= OSSIM_MGRS_NORTHING_ERROR; else { /* Round easting and northing values */ divisor = pow (10.0, (5 - Precision)); Easting = Round_OSSIM_MGRS (Easting/divisor) * divisor; Northing = Round_OSSIM_MGRS (Northing/divisor) * divisor; UTMOSSIM_MGRS (Zone, Letters, Latitude, Easting, Northing); /* UTM checks - these should be done in UTMOSSIM_MGRS */ if ((Zone == 31) && (Letters[0] == LETTER_V)) if (Easting > 500000) Easting = 500000; if (Northing > 10000000) Northing = 10000000; Make_OSSIM_MGRS_String (OSSIM_MGRS, Zone, Letters, Easting, Northing, Precision); } } return (error_code); } /* Convert_UTM_To_OSSIM_MGRS */
long Convert_OSSIM_MGRS_To_Geodetic (const char* OSSIM_MGRS, double *Latitude, double *Longitude) /* * OSSIM_MGRS : OSSIM_MGRS coordinate string (output) * Latitude : Latitude in radians (input) * Longitude : Longitude in radians (input) * */ { /* Convert_OSSIM_MGRS_To_Geodetic */ long error_code = OSSIM_MGRS_NO_ERROR; long Zone; long Letters[OSSIM_MGRS_LETTERS]; char Hemisphere; double Easting; double Northing; long In_Precision; error_code = Break_OSSIM_MGRS_String (OSSIM_MGRS, &Zone, Letters, &Easting, &Northing, &In_Precision); if (!error_code) { if (Zone) { error_code |= Convert_OSSIM_MGRS_To_UTM (OSSIM_MGRS, &Zone, &Hemisphere, &Easting, &Northing); Set_UTM_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f, 0); error_code |= Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, Latitude, Longitude); } else { error_code |= Convert_OSSIM_MGRS_To_UPS (OSSIM_MGRS, &Hemisphere, &Easting, &Northing); Set_UPS_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f); error_code |= Convert_UPS_To_Geodetic (Hemisphere, Easting, Northing, Latitude, Longitude); } } return (error_code); } /* END OF Convert_OSSIM_MGRS_To_Geodetic */
long Convert_UTM_To_MGRS (long Zone, char Hemisphere, double Easting, double Northing, long Precision, char* MGRS) /* * The function Convert_UTM_To_MGRS converts UTM (zone, 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 MGRS_NO_ERROR is returned. * * Zone : UTM zone (input) * Hemisphere : North or South hemisphere (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_UTM_To_MGRS */ double latitude; /* Latitude of UTM point */ double longitude; /* Longitude of UTM point */ long utm_error_code = MGRS_NO_ERROR; long error_code = MGRS_NO_ERROR; if ((Zone < 1) || (Zone > 60)) error_code |= MGRS_ZONE_ERROR; if ((Hemisphere != 'S') && (Hemisphere != 'N')) error_code |= MGRS_HEMISPHERE_ERROR; if ((Easting < MIN_EASTING) || (Easting > MAX_EASTING)) error_code |= MGRS_EASTING_ERROR; if ((Northing < MIN_NORTHING) || (Northing > MAX_NORTHING)) error_code |= MGRS_NORTHING_ERROR; if ((Precision < 0) || (Precision > MAX_PRECISION)) error_code |= MGRS_PRECISION_ERROR; if (!error_code) { Set_UTM_Parameters (MGRS_a, MGRS_f, 0); utm_error_code = Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, &latitude, &longitude); if(utm_error_code) { if((utm_error_code & UTM_ZONE_ERROR) || (utm_error_code & UTM_HEMISPHERE_ERROR)) error_code |= MGRS_STRING_ERROR; if(utm_error_code & UTM_EASTING_ERROR) error_code |= MGRS_EASTING_ERROR; if(utm_error_code & UTM_NORTHING_ERROR) error_code |= MGRS_NORTHING_ERROR; } error_code = UTM_To_MGRS (Zone, Hemisphere, longitude, latitude, Easting, Northing, Precision, MGRS); } return (error_code); } /* Convert_UTM_To_MGRS */
static int parse_location (char *e) { int len; int ipat; char xstr[20], ystr[20], zstr[20], bstr[20], dstr[20]; double x, y, dist, bearing; double lat0, lon0; double lat9, lon9; long lerr; double easting, northing; char mh[20]; assert (*e == 'B'); m_dao[2] = e[0]; m_dao[3] = e[1]; /* Type of location. e.g. !TB6! */ /* Will be changed by point types. */ /* If this ever changes, be sure to update corresponding */ /* section in process_comment() in decode_aprs.c */ len = strlen(e); ipat = find_ttloc_match (e, xstr, ystr, zstr, bstr, dstr); if (ipat >= 0) { //dw_printf ("ipat=%d, x=%s, y=%s, b=%s, d=%s\n", ipat, xstr, ystr, bstr, dstr); switch (tt_config.ttloc_ptr[ipat].type) { case TTLOC_POINT: m_latitude = tt_config.ttloc_ptr[ipat].point.lat; m_longitude = tt_config.ttloc_ptr[ipat].point.lon; /* Is it one of ten or a hundred positions? */ /* It's not hardwired to always be B0n or B9nn. */ /* This is a pretty good approximation. */ if (strlen(e) == 3) { /* probably B0n --> !Tn ! */ m_dao[2] = e[2]; m_dao[3] = ' '; } if (strlen(e) == 4) { /* probably B9nn --> !Tnn! */ m_dao[2] = e[2]; m_dao[3] = e[3]; } break; case TTLOC_VECTOR: if (strlen(bstr) != 3) { text_color_set(DW_COLOR_ERROR); dw_printf ("Bearing \"%s\" should be 3 digits.\n", bstr); // return error code? } if (strlen(dstr) < 1) { text_color_set(DW_COLOR_ERROR); dw_printf ("Distance \"%s\" should 1 or more digits.\n", dstr); // return error code? } lat0 = D2R(tt_config.ttloc_ptr[ipat].vector.lat); lon0 = D2R(tt_config.ttloc_ptr[ipat].vector.lon); dist = atof(dstr) * tt_config.ttloc_ptr[ipat].vector.scale; bearing = D2R(atof(bstr)); /* Equations and caluculators found here: */ /* http://movable-type.co.uk/scripts/latlong.html */ /* This should probably be a function in latlong.c in case we have another use for it someday. */ m_latitude = R2D(asin(sin(lat0) * cos(dist/R) + cos(lat0) * sin(dist/R) * cos(bearing))); m_longitude = R2D(lon0 + atan2(sin(bearing) * sin(dist/R) * cos(lat0), cos(dist/R) - sin(lat0) * sin(D2R(m_latitude)))); break; case TTLOC_GRID: if (strlen(xstr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Missing X coordinate.\n"); strcpy (xstr, "0"); } if (strlen(ystr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Missing Y coordinate.\n"); strcpy (ystr, "0"); } lat0 = tt_config.ttloc_ptr[ipat].grid.lat0; lat9 = tt_config.ttloc_ptr[ipat].grid.lat9; y = atof(ystr); m_latitude = lat0 + y * (lat9-lat0) / (pow(10., strlen(ystr)) - 1.); lon0 = tt_config.ttloc_ptr[ipat].grid.lon0; lon9 = tt_config.ttloc_ptr[ipat].grid.lon9; x = atof(xstr); m_longitude = lon0 + x * (lon9-lon0) / (pow(10., strlen(xstr)) - 1.); break; case TTLOC_UTM: if (strlen(xstr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Missing X coordinate.\n"); /* Avoid divide by zero later. Put in middle of range. */ strcpy (xstr, "5"); } if (strlen(ystr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Missing Y coordinate.\n"); /* Avoid divide by zero later. Put in middle of range. */ strcpy (ystr, "5"); } x = atof(xstr); easting = x * tt_config.ttloc_ptr[ipat].utm.scale + tt_config.ttloc_ptr[ipat].utm.x_offset; y = atof(ystr); northing = y * tt_config.ttloc_ptr[ipat].utm.scale + tt_config.ttloc_ptr[ipat].utm.y_offset; lerr = Convert_UTM_To_Geodetic(tt_config.ttloc_ptr[ipat].utm.lzone, tt_config.ttloc_ptr[ipat].utm.hemi, easting, northing, &lat0, &lon0); if (lerr == 0) { m_latitude = R2D(lat0); m_longitude = R2D(lon0); //printf ("DEBUG: from UTM, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude); } else { char message[300]; text_color_set(DW_COLOR_ERROR); utm_error_string (lerr, message); dw_printf ("Conversion from UTM failed:\n%s\n\n", message); } break; case TTLOC_MGRS: case TTLOC_USNG: if (strlen(xstr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("MGRS/USNG: Missing X (easting) coordinate.\n"); /* Should not be possible to get here. Fake it and carry on. */ strcpy (xstr, "5"); } if (strlen(ystr) == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("MGRS/USNG: Missing Y (northing) coordinate.\n"); /* Should not be possible to get here. Fake it and carry on. */ strcpy (ystr, "5"); } char loc[40]; strcpy (loc, tt_config.ttloc_ptr[ipat].mgrs.zone); strcat (loc, xstr); strcat (loc, ystr); //text_color_set(DW_COLOR_DEBUG); //dw_printf ("MGRS/USNG location debug: %s\n", loc); if (tt_config.ttloc_ptr[ipat].type == TTLOC_MGRS) lerr = Convert_MGRS_To_Geodetic(loc, &lat0, &lon0); else lerr = Convert_USNG_To_Geodetic(loc, &lat0, &lon0); if (lerr == 0) { m_latitude = R2D(lat0); m_longitude = R2D(lon0); //printf ("DEBUG: from MGRS/USNG, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude); } else { char message[300]; text_color_set(DW_COLOR_ERROR); mgrs_error_string (lerr, message); dw_printf ("Conversion from MGRS/USNG failed:\n%s\n\n", message); } break; case TTLOC_SATSQ: if (strlen(xstr) != 4) { text_color_set(DW_COLOR_ERROR); dw_printf ("Expected 4 digits for the Satellite Square.\n"); return (TT_ERROR_SATSQ); } /* Convert 4 digits to usual AA99 form, then to location. */ if (tt_gridsquare_to_text (xstr, 0, mh) == 0) { ll_from_grid_square (mh, &m_latitude, &m_longitude); } break; default: assert (0); } return (0); } /* Send reject sound. */ /* Does not match any location specification. */ return (TT_ERROR_INVALID_LOC); } /* end parse_location */
long Convert_MGRS_To_UTM (char *MGRS, long *Zone, char *Hemisphere, double *Easting, double *Northing) /* * 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 */ double min_northing; double northing_offset; long ltr2_low_value; long ltr2_high_value; double pattern_offset; double upper_lat_limit; /* North latitude limits based on 1st letter */ double lower_lat_limit; /* South latitude limits based on 1st letter */ double grid_easting; /* Easting for 100,000 meter grid square */ double grid_northing; /* Northing for 100,000 meter grid square */ long letters[MGRS_LETTERS]; long in_precision; double latitude = 0.0; double longitude = 0.0; double divisor = 1.0; long utm_error_code = MGRS_NO_ERROR; long error_code = MGRS_NO_ERROR; error_code = Break_MGRS_String (MGRS, Zone, letters, Easting, Northing, &in_precision); if (!*Zone) error_code |= MGRS_STRING_ERROR; else { if (!error_code) { if ((letters[0] == LETTER_X) && ((*Zone == 32) || (*Zone == 34) || (*Zone == 36))) error_code |= MGRS_STRING_ERROR; else { if (letters[0] < LETTER_N) *Hemisphere = 'S'; else *Hemisphere = 'N'; Get_Grid_Values(*Zone, <r2_low_value, <r2_high_value, &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; if (!error_code) { double row_letter_northing = (double)(letters[2]) * ONEHT; grid_easting = (double)((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; error_code = Get_Latitude_Band_Min_Northing(letters[0], &min_northing, &northing_offset); 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 = 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); if (!utm_error_code) { divisor = 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; } } else { if((utm_error_code & UTM_ZONE_ERROR) || (utm_error_code & UTM_HEMISPHERE_ERROR)) error_code |= MGRS_STRING_ERROR; if(utm_error_code & UTM_EASTING_ERROR) error_code |= MGRS_EASTING_ERROR; if(utm_error_code & UTM_NORTHING_ERROR) error_code |= MGRS_NORTHING_ERROR; } } else { if(utm_error_code & UTM_A_ERROR) error_code |= MGRS_A_ERROR; if(utm_error_code & UTM_INV_F_ERROR) error_code |= MGRS_INV_F_ERROR; if(utm_error_code & UTM_ZONE_OVERRIDE_ERROR) error_code |= MGRS_ZONE_ERROR; } } } } } } return (error_code); } /* Convert_MGRS_To_UTM */
long Convert_MGRS_To_Geodetic (char* MGRS, double *Latitude, double *Longitude) /* * The function Convert_MGRS_To_Geodetic converts an MGRS coordinate string * to Geodetic (latitude and longitude) 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) * Latitude : Latitude in radians (output) * Longitude : Longitude in radians (output) * */ { /* Convert_MGRS_To_Geodetic */ long zone; char hemisphere; double easting; double northing; long zone_exists; long temp_error_code = MGRS_NO_ERROR; long error_code = MGRS_NO_ERROR; error_code = Check_Zone(MGRS, &zone_exists); if (!error_code) { if (zone_exists) { error_code |= Convert_MGRS_To_UTM (MGRS, &zone, &hemisphere, &easting, &northing); if(!error_code || (error_code & MGRS_LAT_WARNING)) { temp_error_code = Set_UTM_Parameters (MGRS_a, MGRS_f, 0); if(!temp_error_code) { temp_error_code = Convert_UTM_To_Geodetic (zone, hemisphere, easting, northing, Latitude, Longitude); if(temp_error_code) { if((temp_error_code & UTM_ZONE_ERROR) || (temp_error_code & UTM_HEMISPHERE_ERROR)) error_code |= MGRS_STRING_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; } } } else { error_code |= Convert_MGRS_To_UPS (MGRS, &hemisphere, &easting, &northing); if(!error_code) { temp_error_code = Set_UPS_Parameters (MGRS_a, MGRS_f); if(!temp_error_code) { temp_error_code = Convert_UPS_To_Geodetic (hemisphere, easting, northing, Latitude, Longitude); if(temp_error_code) { if(temp_error_code & UPS_HEMISPHERE_ERROR) error_code |= MGRS_STRING_ERROR; if(temp_error_code & UPS_EASTING_ERROR) error_code |= MGRS_EASTING_ERROR; if(temp_error_code & UPS_LAT_ERROR) error_code |= MGRS_NORTHING_ERROR; } } else { if(temp_error_code & UPS_A_ERROR) error_code |= MGRS_A_ERROR; if(temp_error_code & UPS_INV_F_ERROR) error_code |= MGRS_INV_F_ERROR; } } } } return (error_code); } /* END OF Convert_MGRS_To_Geodetic */
void GRID_UTM (long *Zone, long *Letters, char *Hemisphere, double *Easting, double *Northing, long In_Precision, long *Error) { /* BEGIN GRID_UTM */ double fnltr; /* False northing for 3rd letter */ long ltrhi; /* 2nd letter range - High number */ long ltrlow; /* 2nd letter range - Low number */ long number; /* Value of ltrnum[0] + 1 */ /* double slam;*/ double slcm; /* Central meridian */ double sleast; /* Longitude east limit - UTM */ double slwest; /* Longitude west limit -UTM */ double sphi; /* Latitude (needed by UTMLIM) */ double spnor; /* North latitude limits based on 1st letter */ double spsou; /* South latitude limits based on 1st letter */ double xltr; /* Easting for 100,000 meter grid square */ double ylow; /* Lowest northing of area to nearest 100,000 */ double yltr; /* Northing for 100,000 meter grid square */ double yslow; /* Northing scaled down to less than 2 million*/ double Latitude = 0.0; double Longitude = 0.0; double divisor = 1.0; if ((*Zone == 32) && (Letters[0] == LETTER_X)) { *Error = TRUE; return; } if ((*Zone == 34) && (Letters[0] == LETTER_X)) { *Error = TRUE; return; } if ((*Zone == 36) && (Letters[0] == LETTER_X)) { *Error = TRUE; return; } number = Letters[0] + 1; sphi = 0.0; UTMLIM(&number,sphi,*Zone,&spsou,&spnor,&sleast,&slwest); Set_UTM_Parameters(OSSIM_MGRS_a,OSSIM_MGRS_f,*Zone); slcm = (double)(*Zone * 6 - 183) * DEGRAD; Convert_Geodetic_To_UTM(spsou,slcm,Zone,Hemisphere,&xltr,&yltr); ylow = ((double)((long)((double)((long)(yltr / ONEHT)) * ONEHT))); yslow = ylow; while (yslow >= TWOMIL) { yslow = yslow - TWOMIL; } yslow = ((double)((long)(yslow))); UTMSET(*Zone, <rlow, <rhi, &fnltr); LTR2UTM(Letters, ltrlow, ltrhi, Error, &xltr, &yltr, fnltr, yslow, ylow); *Easting = xltr + *Easting; *Northing = yltr + *Northing; /* check that point is within Zone Letter bounds */ Convert_UTM_To_Geodetic(*Zone,*Hemisphere,*Easting,*Northing,&Latitude,&Longitude); divisor = pow (10.0, In_Precision); if (((spsou - DEGRAD/divisor) <= Latitude) && (Latitude <= (spnor + DEGRAD/divisor))) return; else *Error = TRUE; return; }/* END OF GRID_UTM */