/*
 *      gc.c
 *
 *      Great Circle.  This program is used to determine bearing
 *      and range to a station given latitude and longitude.
 *
 *      Ver 1.03 By S. R. Sampson, N5OWK
 *      Public Domain (p) November 1989
 *
 *      Ref: Air Force Manual 51-40, "Air Navigation", 1 February 1987
 *
 *      Usage examples:
 *
 *      gc 35.19n97.27w 0s0e            (Moore to Prime/Equator)
 *      gc 35.19N97.27W 38.51n77.02W    (Moore to Washington D.C.)
 *      gc 33.56n118.24w 55.45n37.35e   (L.A. to Moscow U.S.S.R.)
 *	gc 35N70W 35N71W		(No decimal points used)
 */

/* Includes */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

/* Defines */

#define RADIAN  (180.0 / M_PI)

/* Globals */

double  tmp,
        dist,
        range,
        bearing,
        QTH_Lat,
        QTH_Long,
        DEST_Lat,
        DEST_Long,
        Delta_Long;

/* Simple Declare, No Prototypes */

/*
 *      Error routine
 */

void err(type)
int     type;
{
        switch(type)  {
        case 1:
                printf("\007Latitude Out of Range (90N to 90S)\n");
                break;
        case 2:
                printf("\007Longitude Out of Range (180W to 180E)\n");
                break;
        case 3:
                printf("\007Minutes Out of Range (0 to 59)\n");
        }

        exit(1);
}

/*
 *      Convert Degrees and Minutes to Decimal
 */

double dm2dec(n)
double  n;
{
        double  t;

        t = (int)n;
        n -= t;
        n /= .60;

        if (n >= 1.0)
                err(3);

        return (n + t);
}

/*
 *      Parse the input line
 *
 *      dd(.mm)[NnSs]ddd(.mm)[EeWw]
 */

void parse(s, lat, lon)
char    *s;
double  *lat, *lon;
{
        register char   *i, *t;
        int             l;

        l = strlen(s);
        for (i = s; i < (s + l); ++i)  {
                switch(toupper(*i))  {
                case 'N':
                        *i = '\0';
                        t = i + 1;
                        *lat = atof(s);
                        break;
                case 'S':
                        *i = '\0';
                        t = i + 1;
                        *lat = -atof(s);
                        break;
                case 'E':
                        *i = '\0';
                        *lon = -atof(t);
                        break;
                case 'W':
                        *i = '\0';
                        *lon = atof(t);
                }
        }

        *lat = dm2dec(*lat);
        *lon = dm2dec(*lon);

        if (*lat > 90.0 || *lat < -90.0)
                err(1);

        if (*lon > 180.0 || *lon < -180.0)
                err(2);

        /* Prevent ACOS() Domain Error */

        if (*lat == 90.0)
                *lat = 89.9;

        if (*lat == -90.0)
                *lat = -89.9;
}

main(argc, argv)
register int  argc;
register char **argv;
{
        if (argc != 3)  {
                printf("Usage: gc station1 station2\n\n");
                printf("This program computes Great Circle Bearing and Range\n");
                printf("given the latitude and longitude (degrees and minutes).\n\n");
                printf("You must input the lat/long of the two stations.\n");
                printf("The output will then be relative from station1 to station2.\n\n");
                printf("Input the two station lat/longs using the following format:\n\n");
                printf("\tdd.mmHddd.mmG  lead/lagging zeros can be left out.\n\n");
                printf("d = Degrees, m = Minutes, H = Hemisphere (N or S), G = Greenwich (W or E)\n");

                exit(1);
        }

        /* Process the command line data */

        parse(argv[1], &QTH_Lat, &QTH_Long);
        parse(argv[2], &DEST_Lat, &DEST_Long);

        /* Compute the Bearing and Range, From the Formula in Chapter 23 */

        Delta_Long = DEST_Long - QTH_Long;

        QTH_Lat    /= RADIAN;   /* Convert variables to Radians */
        QTH_Long   /= RADIAN;
        DEST_Lat   /= RADIAN;
        Delta_Long /= RADIAN;

        tmp = (sin(QTH_Lat) * sin(DEST_Lat)) +
                (cos(QTH_Lat) * cos(DEST_Lat) * cos(Delta_Long));

        dist = acos(tmp);
        range = 60.0 * (dist * RADIAN);

        tmp = (sin(DEST_Lat) - (sin(QTH_Lat) * cos(dist))) /
                (sin(dist) * cos(QTH_Lat));

        bearing = acos(tmp) * RADIAN;

        if (Delta_Long > 0.0)
                bearing = 360.0 - bearing;

        /* Computations complete, show answer */

        printf("\nBearing is %.0f Degrees for %.0f Nautical Miles\n",
                bearing, range);

        exit(0);
}

/* EOF */
