1 /***************************************************************************\
2 * bearing: Determines distance and azimuth bearing between locations *
3 * specified in a pair of .qth files *
4 * Last update: 08-Feb-2009 *
5 *****************************************************************************
6 * Project started on December 7, 2007 by John A. Magliacane, KD2BD *
7 *****************************************************************************
9 * This program is free software; you can redistribute it and/or modify it *
10 * under the terms of the GNU General Public License as published by the *
11 * Free Software Foundation; either version 2 of the License or any later *
14 * This program is distributed in the hope that it will useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
19 *****************************************************************************
20 * gcc -Wall -O3 -s -lm -fomit-frame-pointer bearing.c -o bearing *
21 \***************************************************************************/
32 double TWOPI=6.283185307179586, PI=3.141592653589793,
33 deg2rad=1.74532925199e-02, KM_PER_MILE=1.609344;
35 struct site { double lat;
42 double arccos(double x, double y)
44 /* This function implements the arc cosine function,
45 returning a value between 0 and TWOPI. */
58 char *dec2dms(double decimal)
60 /* Converts decimal degrees to degrees, minutes, seconds,
61 (DMS) and returns the result as a character string. */
64 int degrees, minutes, seconds;
92 sprintf(string,"%d%c %d\' %d\"", degrees*sign, 176, minutes, seconds);
96 double Distance(struct site site1, struct site site2)
98 /* This function returns the great circle distance
99 in miles between any two site locations. */
101 double lat1, lon1, lat2, lon2, distance;
103 lat1=site1.lat*deg2rad;
104 lon1=site1.lon*deg2rad;
105 lat2=site2.lat*deg2rad;
106 lon2=site2.lon*deg2rad;
108 distance=3959.0*acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos((lon1)-(lon2)));
113 double Azimuth(struct site source, struct site destination)
115 /* This function returns the azimuth (in degrees) to the
116 destination as seen from the location of the source. */
118 double dest_lat, dest_lon, src_lat, src_lon,
119 beta, azimuth, diff, num, den, fraction;
121 dest_lat=destination.lat*deg2rad;
122 dest_lon=destination.lon*deg2rad;
124 src_lat=source.lat*deg2rad;
125 src_lon=source.lon*deg2rad;
127 /* Calculate Surface Distance */
129 beta=acos(sin(src_lat)*sin(dest_lat)+cos(src_lat)*cos(dest_lat)*cos(src_lon-dest_lon));
131 /* Calculate Azimuth */
133 num=sin(dest_lat)-(sin(src_lat)*cos(beta));
134 den=cos(src_lat)*sin(beta);
137 /* Trap potential problems in acos() due to rounding */
145 /* Calculate azimuth */
147 azimuth=acos(fraction);
149 /* Reference it to True North */
151 diff=dest_lon-src_lon;
160 azimuth=TWOPI-azimuth;
162 return (azimuth/deg2rad);
165 double ReadBearing(char *input)
167 /* This function takes numeric input in the form of a character
168 string, and returns an equivalent bearing in degrees as a
169 decimal number (double). The input may either be expressed
170 in decimal format (40.139722) or degree, minute, second
171 format (40 08 23). This function also safely handles
172 extra spaces found either leading, trailing, or
173 embedded within the numbers expressed in the
174 input string. Decimal seconds are permitted. */
176 double seconds, bearing=0.0;
178 int a, b, length, degrees, minutes;
180 /* Copy "input" to "string", and ignore any extra
181 spaces that might be present in the process. */
184 length=strlen(input);
186 for (a=0, b=0; a<length && a<18; a++)
188 if ((input[a]!=32 && input[a]!='\n') || (input[a]==32 && input[a+1]!=32 && input[a+1]!='\n' && b!=0))
197 /* Count number of spaces in the clean string. */
199 length=strlen(string);
201 for (a=0, b=0; a<length; a++)
205 if (b==0) /* Decimal Format (40.139722) */
206 sscanf(string,"%lf",&bearing);
208 if (b==2) /* Degree, Minute, Second Format (40 08 23.xx) */
210 sscanf(string,"%d %d %lf",°rees, &minutes, &seconds);
212 bearing=fabs((double)degrees);
213 bearing+=fabs(((double)minutes)/60.0);
214 bearing+=fabs(seconds/3600.0);
216 if ((degrees<0) || (minutes<0) || (seconds<0.0))
220 /* Anything else returns a 0.0 */
222 if (bearing>360.0 || bearing<-90.0)
228 struct site LoadQTH(char *filename)
230 /* This function reads SPLAT! .qth (site location) files.
231 The latitude and longitude may be expressed either in
232 decimal degrees, or in degree, minute, second format.
233 Antenna height is assumed to be expressed in feet above
234 ground level (AGL), unless followed by the letter 'M',
235 or 'm', or by the word "meters" or "Meters", in which
236 case meters is assumed, and is handled accordingly. */
239 char string[50], qthfile[255], *s=NULL;
240 struct site tempsite;
243 for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
244 qthfile[x]=filename[x];
255 tempsite.azimuth=0.0;
257 fd=fopen(qthfile,"r");
262 s=fgets(string,49,fd);
264 /* Strip <CR> and/or <LF> from end of site name */
266 for (x=0; string[x]!=13 && string[x]!=10 && string[x]!=0; tempsite.name[x]=string[x], x++);
271 s=fgets(string,49,fd);
272 tempsite.lat=ReadBearing(string);
275 s=fgets(string,49,fd);
276 tempsite.lon=ReadBearing(string);
284 int main(int argc, char *argv[])
287 unsigned char sitenum, metric, error;
288 double distance, azimuth;
289 struct site point[2];
293 fprintf(stdout,"\nProvides distance and azimuth bearing between two site locations.\n");
294 fprintf(stdout,"\nUsage: bearing site1(.qth) site2(.qth)");
295 fprintf(stdout,"\n bearing site1(.qth) site2(.qth) -metric\n\n");
310 /* Scan for command line arguments */
314 if (strcmp(argv[x],"-metric")==0)
320 /* Read Receiver Location */
322 if (x<=y && argv[x][0] && argv[x][0]!='-' && sitenum<2)
324 point[sitenum]=LoadQTH(argv[x]);
326 if (point[sitenum].lat>90.0 || point[sitenum].lon>360.0)
327 fprintf(stderr,"\n%c*** \"%s\" is not a valid .qth file!",7,argv[x]);
335 fprintf(stderr,"\n%c*** ERROR: Not enough valid sites specified!\n\n",7);
339 for (x=0; x<sitenum; x++)
341 if (point[x].lat>90.0 && point[x].lon>360.0)
343 fprintf(stderr,"\n*** ERROR: site #%d not found!",x+1);
353 /* Perform the calculations and display the results */
355 distance=Distance(point[0],point[1]);
356 azimuth=Azimuth(point[0],point[1]);
358 printf("\nThe distance between %s and %s is\n",point[0].name, point[1].name);
361 printf("%.2f kilometers",distance*KM_PER_MILE);
363 printf("%.2f miles",distance);
365 printf(" at a bearing of %.2f%c azimuth.\n\n",azimuth, 176);