/* * Program: wwl * * This program combines two handy hamradio Maindensquare programs into one. * When used as locator, it will take the Maindenhead square on the * command line and write it back out as lat / long. * When used as wwl, it will calculate distance and azimuth * between the two Maidenhead squares given. * If only four characters of the Maidenhead square is given, this * program will auto fill in the missing two chars with 'AA' * * This version by va3db db@db.net db@FreeBSD.org Oct 1 2007 * rewritten completely. There were equator crossing bugs in the original * (dead) version of wwl on sunsite, so I rewrote it from scratch. * * wwl -- Originally by IK0ZSN Mirko Caserta * locator -- originally written by Harald M. * Stauss harald.stauss@web.de DO1JHS @ DB0GR.#BLN.DEU.EU * There is no code from the original (dead?) version of wwl or * the original (dead?) version of locator in this version. * * The bearing/distance code is from Amateur Radio Software by John * Morris, GM4ANB. * * wrote this file. As long as you retain this notice you * can do whatever you want with this code, except you may not * license it under any form of the GPL. * A postcard or QSL card showing me you appreciate * this code would be nice. Diane Bruce va3db */ #include #include #include #include #include #include #include #define SCRATCH_WWL_LEN 9 #define WWL_LEN 6 #define EARTHRADIUS 6371.33 volatile char *rcs="$Id: wwl.c,v 1.12 2007/10/15 19:53:08 db Exp db $"; struct location { double latitude; double longitude; }; static int is_valid_locator(const char wwl[]); static struct location convert_locator(char *wwl); static void upstring(char *s); static void bearing_dist(struct location *my_location, struct location *dx_location, int *dist, int *bearing); static double rad_to_deg(double radians); static double deg_to_rad(double degrees); static int locator = 0; /* Doing locator instead of wwl ? */ int main (int argc, char **argv) { int l, p; struct location my_location, dx_location; char my_wwl[SCRATCH_WWL_LEN], dx_wwl[SCRATCH_WWL_LEN]; if (argc < 2) { printf("wwl/locator by va3db 1.0\n"); printf("wwl home_locator dx_locator or\n"); printf("locator locator\n"); exit(EXIT_FAILURE); } if (strcmp(basename(argv[0]), "locator") == 0) { locator = 1; if (argc != 2) { fprintf(stderr, "Usage: locator wwl\n"); exit(EXIT_FAILURE); } } else { if (argc != 3) { fprintf(stderr, "Usage: wwl home_locator dx_locator\n"); exit(EXIT_FAILURE); } } snprintf(my_wwl, sizeof(my_wwl), "%sAA", argv[1]); my_wwl[WWL_LEN] ='\0'; my_location = convert_locator(my_wwl); if(!is_valid_locator(my_wwl)) { fprintf(stderr, "%s: not a valid locator\n", my_wwl); exit(EXIT_FAILURE); } if(locator) { printf("Locator : %s\n", my_wwl); printf("Coordinates: Long: (%c) %.2f Lat : (%c) %.4f\n", (my_location.longitude < 0.) ? 'W' : 'E', rad_to_deg(my_location.longitude), (my_location.latitude > 0.) ? 'N' : 'S', rad_to_deg(my_location.latitude)); exit(EXIT_SUCCESS); } snprintf(dx_wwl, sizeof(dx_wwl), "%sAA", argv[2]); dx_wwl[WWL_LEN] ='\0'; dx_location = convert_locator(dx_wwl); if (!is_valid_locator(dx_wwl)) { printf("%s: not a valid locator\n", dx_wwl); exit(EXIT_FAILURE); } bearing_dist(&my_location, &dx_location, &p, &l); printf("qrb: %d kilometers, azimuth: %d degrees\n", p, l); exit(EXIT_SUCCESS); } /* * is_valid_locator * check for valid locator * * inputs - string to locator * output - 1 if valid locator 0 if not * side effects - */ static int is_valid_locator(const char wwl[]) { if (strlen(wwl) != WWL_LEN) return 0; if (wwl[0] < 'A' || wwl[0] > 'R' || wwl[1] < 'A' || wwl[1] > 'R' || wwl[2] < '0' || wwl[2] > '9' || wwl[3] < '0' || wwl[3] > '9' || wwl[4] < 'A' || wwl[4] > 'X' || wwl[5] < 'A' || wwl[5] > 'X' ) return(0); else return(1); } /* * convert_locator * * inputs - string to convert * output - return a struct location * side effects - none */ static struct location convert_locator(char *wwl) { struct location loc; upstring(wwl); loc.latitude = (double)(wwl[1] - 'A') * 10 - 90 + (double)(wwl[3] - '0') + (double)(wwl[5] - 'A') / 24 + 1 / 48; loc.latitude = deg_to_rad(loc.latitude); loc.longitude = (double)(wwl[0] - 'A') * 20. - 180. + (double)(wwl[2] - '0') * 2 + (double)(wwl[4] - 'A') / 12 + 1 / 24; loc.longitude = deg_to_rad(loc.longitude); return(loc); } /* * upstring * convert string to upper case * * inputs - string to convert to upper case modified in place */ static void upstring(char *s) { while(*s != '\0') { *s = toupper(*s); s++; } } /* * Convert degrees to radians * * input - degrees * output - radians * side effects - none */ static double deg_to_rad(double degrees) { return(degrees/180.) * M_PI; } /* * Convert radians to degrees * * input - radians * output - degrees * side effects - none */ static double rad_to_deg(double radians) { return((radians/M_PI) * 180.); } /* * * Given location of start and location of end, calculate * bearing and azimuth * * inputs - pointer to my location * - pointer to dx location * - pointer to result for dist * - pointer to result for bearing * output - dist and bearing as integer * side effects - none */ static void bearing_dist(struct location *my_location, struct location *dx_location, int *dist, int *bearing) { double co, he, e, hn, n, ca, az; hn = my_location->latitude; he = my_location->longitude; n = dx_location->latitude; e = dx_location->longitude; co = cos(he - e) * cos(hn) * cos(n) + sin(hn) * sin(n); ca = atan2(sqrt(1 - pow(co,2)), co); az = atan2(sin(e - he) * cos(n) * cos(hn), sin(n) - sin(hn) * cos(ca)); if( az < 0) az += 2 * M_PI; /* Round up azimuth */ *bearing = (double)((int)((rad_to_deg(az) * 10.) + 5))/10; /* Round up distance */ *dist = (double)((int)(EARTHRADIUS * ca * 10. + 5))/10; }