File: bearing.c

package info (click to toggle)
splat 1.4.2-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,332 kB
  • sloc: cpp: 8,650; ansic: 993; sh: 442; lisp: 244; makefile: 31
file content (369 lines) | stat: -rw-r--r-- 8,479 bytes parent folder | download | duplicates (2)
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/***************************************************************************\
*     bearing: Determines distance and azimuth bearing between locations    *
*                     specified in a pair of .qth files                     *
*			  Last update: 08-Jan-2014			    *
*****************************************************************************
*      Project started on December 7, 2007 by John A. Magliacane, KD2BD     *
*****************************************************************************
*                                                                           *
* This program is free software; you can redistribute it and/or modify it   *
* under the terms of the GNU General Public License as published by the     *
* Free Software Foundation; either version 2 of the License or any later    *
* version.								    *
*									    *
* This program is distributed in the hope that it will useful, but WITHOUT  *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     *
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License     *
* for more details.							    *
*									    *
*****************************************************************************
*      gcc -Wall -O3 -s -lm -fomit-frame-pointer bearing.c -o bearing       *
\***************************************************************************/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

char 	string[255];

double	TWOPI=6.283185307179586, PI=3.141592653589793,
	deg2rad=1.74532925199e-02, KM_PER_MILE=1.609344;

struct site {	double lat;
		double lon;
		double azimuth;
		char name[50];
	    } 	site;


double arccos(double x, double y)
{
	/* This function implements the arc cosine function,
	   returning a value between 0 and TWOPI. */

	double result=0.0;

	if (y>0.0)
		result=acos(x/y);

	if (y<0.0)
		result=PI+acos(x/y);

	return result;
}

char *dec2dms(double decimal)
{
	/* Converts decimal degrees to degrees, minutes, seconds,
	   (DMS) and returns the result as a character string. */

	char	sign;
	int	degrees, minutes, seconds;
	double	a, b, c, d;

	if (decimal<0.0)
	{
		decimal=-decimal;
		sign=-1;
	}

	else
		sign=1;

	a=floor(decimal);
	b=60.0*(decimal-a);
	c=floor(b);
	d=60.0*(b-c);

	degrees=(int)a;
	minutes=(int)c;
	seconds=(int)d;

	if (seconds<0)
		seconds=0;

	if (seconds>59)
		seconds=59;

	string[0]=0;
	sprintf(string,"%d%c %d\' %d\"", degrees*sign, 176, minutes, seconds);
	return (string);
}

double Distance(struct site site1, struct site site2)
{
	/* This function returns the great circle distance
	   in miles between any two site locations. */

	double	lat1, lon1, lat2, lon2, distance;

	lat1=site1.lat*deg2rad;
	lon1=site1.lon*deg2rad;
	lat2=site2.lat*deg2rad;
	lon2=site2.lon*deg2rad;

	distance=3959.0*acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos((lon1)-(lon2)));

	return distance;
}

double Azimuth(struct site source, struct site destination)
{
	/* This function returns the azimuth (in degrees) to the
	   destination as seen from the location of the source. */

	double	dest_lat, dest_lon, src_lat, src_lon,
		beta, azimuth, diff, num, den, fraction;

	dest_lat=destination.lat*deg2rad;
	dest_lon=destination.lon*deg2rad;

	src_lat=source.lat*deg2rad;
	src_lon=source.lon*deg2rad;
		
	/* Calculate Surface Distance */

	beta=acos(sin(src_lat)*sin(dest_lat)+cos(src_lat)*cos(dest_lat)*cos(src_lon-dest_lon));

	/* Calculate Azimuth */

	num=sin(dest_lat)-(sin(src_lat)*cos(beta));
	den=cos(src_lat)*sin(beta);
	fraction=num/den;

	/* Trap potential problems in acos() due to rounding */

	if (fraction>=1.0)
		fraction=1.0;

	if (fraction<=-1.0)
		fraction=-1.0;

	/* Calculate azimuth */

	azimuth=acos(fraction);

	/* Reference it to True North */

	diff=dest_lon-src_lon;

	if (diff<=-PI)
		diff+=TWOPI;

	if (diff>=PI)
		diff-=TWOPI;

	if (diff>0.0)
		azimuth=TWOPI-azimuth;

	return (azimuth/deg2rad);		
}

double ReadBearing(char *input)
{
	/* This function takes numeric input in the form of a character
	   string, and returns an equivalent bearing in degrees as a
	   decimal number (double).  The input may either be expressed
	   in decimal format (40.139722) or degree, minute, second
	   format (40 08 23).  This function also safely handles
	   extra spaces found either leading, trailing, or
	   embedded within the numbers expressed in the
	   input string.  Decimal seconds are permitted. */
 
	double	seconds, bearing=0.0;
	char	string[20];
	int	a, b, length, degrees, minutes;

	/* Copy "input" to "string", and ignore any extra
	   spaces that might be present in the process. */

	string[0]=0;
	length=strlen(input);

	for (a=0, b=0; a<length && a<18; a++)
	{
		if ((input[a]!=32 && input[a]!='\n') || (input[a]==32 && input[a+1]!=32 && input[a+1]!='\n' && b!=0))
		{
			string[b]=input[a];
			b++;
		}	 
	}

	string[b]=0;

	/* Count number of spaces in the clean string. */

	length=strlen(string);

	for (a=0, b=0; a<length; a++)
		if (string[a]==32)
			b++;

	if (b==0)  /* Decimal Format (40.139722) */
		sscanf(string,"%lf",&bearing);

	if (b==2)  /* Degree, Minute, Second Format (40 08 23.xx) */
	{
		sscanf(string,"%d %d %lf",&degrees, &minutes, &seconds);

		bearing=fabs((double)degrees);
		bearing+=fabs(((double)minutes)/60.0);
		bearing+=fabs(seconds/3600.0);

		if ((degrees<0) || (minutes<0) || (seconds<0.0))
			bearing=-bearing;
	}

	/* Anything else returns a 0.0 */

	if (bearing>360.0 || bearing<-90.0)
		bearing=0.0;

	return bearing;
}

struct site LoadQTH(char *filename)
{
	/* This function reads SPLAT! .qth (site location) files.
	   The latitude and longitude may be expressed either in
	   decimal degrees, or in degree, minute, second format.
	   Antenna height is assumed to be expressed in feet above
	   ground level (AGL), unless followed by the letter 'M',
	   or 'm', or by the word "meters" or "Meters", in which
	   case meters is assumed, and is handled accordingly. */

	int	x;
	char	string[50], qthfile[255];
	struct	site tempsite;
	FILE	*fd=NULL;

	for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
		qthfile[x]=filename[x];

	qthfile[x]='.';
	qthfile[x+1]='q';
	qthfile[x+2]='t';
	qthfile[x+3]='h';
	qthfile[x+4]=0;

	tempsite.lat=91.0;
	tempsite.lon=361.0;
	tempsite.name[0]=0;
	tempsite.azimuth=0.0;

	fd=fopen(qthfile,"r");

	if (fd!=NULL)
	{
		/* Site Name */
		fgets(string,49,fd);

		/* Strip <CR> and/or <LF> from end of site name */

		for (x=0; string[x]!=13 && string[x]!=10 && string[x]!=0; tempsite.name[x]=string[x], x++);

		tempsite.name[x]=0;

		/* Site Latitude */
		fgets(string,49,fd);
		tempsite.lat=ReadBearing(string);

		/* Site Longitude */
		fgets(string,49,fd);
		tempsite.lon=ReadBearing(string);

		fclose(fd);
	}

	return tempsite;
}

int main(int argc, char *argv[])
{
	int		x, y;
	unsigned char	sitenum, metric, error;
	double		distance, azimuth;
	struct		site point[2];

	if (argc==1)
	{
		fprintf(stdout,"\nProvides distance and azimuth bearing between two site locations.\n");
		fprintf(stdout,"\nUsage: bearing site1(.qth) site2(.qth)");
		fprintf(stdout,"\n       bearing site1(.qth) site2(.qth) -metric\n\n");
		fflush(stdout);
		return 1;
	}

	metric=0;
	error=0;
	y=argc-1;
	sitenum=0;

	point[0].lat=91.0;
	point[0].lon=361.0;
	point[1].lat=91.0;
	point[1].lon=361.0;

	/* Scan for command line arguments */

	for (x=1; x<=y; x++)
	{
		if (strcmp(argv[x],"-metric")==0)
		{
			metric=1;
			x++;
		}

		/* Read Receiver Location */

		if (x<=y && argv[x][0] && argv[x][0]!='-' && sitenum<2)
		{
			point[sitenum]=LoadQTH(argv[x]);

			if (point[sitenum].lat>90.0 || point[sitenum].lon>360.0)
				fprintf(stderr,"\n%c*** \"%s\" is not a valid .qth file!",7,argv[x]);
			else
				sitenum++;
		}
	}

	if (sitenum<2)
	{
		fprintf(stderr,"\n%c*** ERROR: Not enough valid sites specified!\n\n",7);
		exit (-1);
	}

	for (x=0; x<sitenum; x++)
	{
		if (point[x].lat>90.0 && point[x].lon>360.0)
		{
			fprintf(stderr,"\n*** ERROR: site #%d not found!",x+1);
			error=1;
		}
	}

	if (error)
		return -1;

	else
	{
		/* Perform the calculations and display the results */

		distance=Distance(point[0],point[1]);
		azimuth=Azimuth(point[0],point[1]);

		printf("\nThe distance between %s and %s is\n",point[0].name, point[1].name);

		if (metric)
			printf("%.2f kilometers",distance*KM_PER_MILE);
		else
			printf("%.2f miles",distance);

		printf(" at a bearing of %.2f%c azimuth.\n\n",azimuth, 176);
	}

	return 0;
}