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
|
/*
* 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 <ik0zsn@amsat.org>
* 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.
*
* <db@FreeBSD.ORG> 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 <stdio.h>
#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#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 by va3db 1.3\n");
printf("wwl home_locator dx_locator\n");
exit(EXIT_FAILURE);
}
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;
}
|