kopia lustrzana https://github.com/Hamlib/Hamlib
2003-08-20
Update: locator.c incoporated Dave Hines' code to work with extended locators as long as 6 lon/lat pairs. Changed locator array to be a nul terminated string as created by longlat2locator(). testloc.c changed to accomodate nul terminated string from longlat2locator(). git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@1516 7ae35d74-ebe9-4afe-98af-79ac388436b8Hamlib-1.2.0
rodzic
b8b048189e
commit
9efbb5e911
190
src/locator.c
190
src/locator.c
|
@ -12,8 +12,9 @@
|
|||
* Hamlib Interface - locator and bearing conversion calls
|
||||
* Copyright (c) 2001-2002 by Stephane Fillod
|
||||
* Copyright (c) 2003 by Nate Bargmann
|
||||
* Copyright (c) 2003 by Dave Hines
|
||||
*
|
||||
* $Id: locator.c,v 1.7 2003-08-19 23:41:08 n0nb Exp $
|
||||
* $Id: locator.c,v 1.8 2003-08-21 03:11:27 n0nb Exp $
|
||||
*
|
||||
* Code to determine bearing and range was taken from the Great Circle,
|
||||
* by S. R. Sampson, N5OWK.
|
||||
|
@ -83,8 +84,7 @@
|
|||
*
|
||||
* \sa dec2dms()
|
||||
*/
|
||||
double dms2dec(int degrees, int minutes, int seconds)
|
||||
{
|
||||
double dms2dec(int degrees, int minutes, int seconds) {
|
||||
if (degrees >= 0)
|
||||
return (double)degrees + (double)minutes/60. + (double)seconds/3600.;
|
||||
else
|
||||
|
@ -108,8 +108,7 @@ double dms2dec(int degrees, int minutes, int seconds)
|
|||
*
|
||||
* \sa dms2dec()
|
||||
*/
|
||||
void dec2dms(double dec, int *degrees, int *minutes, int *seconds)
|
||||
{
|
||||
void dec2dms(double dec, int *degrees, int *minutes, int *seconds) {
|
||||
int deg, min, sec, is_neg = 0;
|
||||
double st;
|
||||
|
||||
|
@ -172,15 +171,38 @@ void dec2dms(double dec, int *degrees, int *minutes, int *seconds)
|
|||
*seconds = sec;
|
||||
}
|
||||
|
||||
/* The following is contributed by Dave Hines
|
||||
*
|
||||
* begin dph
|
||||
*/
|
||||
/*
|
||||
* These are the constants used when converting between Maidenhead grid
|
||||
* locators and longitude/latitude values. MAX_LOCATOR_PAIRS is the maximum
|
||||
* number of locator character pairs to convert. This number MUST NOT exceed
|
||||
* the number of pairs of values in range[] & weight[].
|
||||
* Setting MAX_LOCATOR_PAIRS to 3 will convert the currently defined 6
|
||||
* character locators. A value of 4 will convert the extended 8 character
|
||||
* locators described in section 3L of "The IARU region 1 VHF managers
|
||||
* handbook". Values of 5 and 6 will extent the format even more, to the
|
||||
* longest definition I have seen for locators. Beware that there seems to be
|
||||
* no universally accepted standard for 10 & 12 character locators.
|
||||
* Note that the loc_char_weight values are in minutes of arc, to avoid
|
||||
* constants which can't be represented precisely in either binary or decimal.
|
||||
*/
|
||||
const static double loc_char_weight[] = { 600.0, 60.0, 2.5, 0.25, 0.01, 0.001 };
|
||||
const static int loc_char_range[] = { 18, 10, 24, 10, 25, 10 };
|
||||
#define MAX_LOCATOR_PAIRS 6
|
||||
|
||||
/* end dph */
|
||||
|
||||
/**
|
||||
* \brief Convert Maidenhead grid locator to longitude/latitude
|
||||
* \param longitude The location where to store longitude, decimal
|
||||
* \param latitude The location where to store latitude, decimal
|
||||
* \param locator The locator--four or six char nul terminated string
|
||||
* \param locator The locator--2 through 12 char nul terminated string
|
||||
*
|
||||
* Convert Maidenhead grid locator to longitude/latitude (decimal).
|
||||
* The locator be either in 4 or 6 chars long format. locator2longlat
|
||||
* The locator should be in 2 through 12 chars long format. locator2longlat
|
||||
* is case insensitive, however it checks for locator validity.
|
||||
*
|
||||
* Decimal long/lat is computed to center of grid square, i.e. given
|
||||
|
@ -189,60 +211,48 @@ void dec2dms(double dec, int *degrees, int *minutes, int *seconds)
|
|||
* in the center of the given subsquare, i.e. 2' 30" from west boundary
|
||||
* and 1' 15" from south boundary.
|
||||
*
|
||||
* \todo Support for greater accuracy as proposed by Dave Hines to
|
||||
* six pairs of grid designators.
|
||||
*
|
||||
* \return RIG_OK to indicate conversion went ok, -RIG_EINVAL if locator
|
||||
* exceeds RR99xx or is malformed (not of 4 or 6 character format).
|
||||
* exceeds RR99xx or is malformed (not of 2 through 12 character format).
|
||||
*
|
||||
* \sa longlat2locator()
|
||||
*/
|
||||
int locator2longlat(double *longitude, double *latitude, const char *locator)
|
||||
{
|
||||
char loc[6];
|
||||
int length;
|
||||
|
||||
if (locator[4] != '\0' && locator[6] != '\0')
|
||||
return -RIG_EINVAL;
|
||||
/* begin dph */
|
||||
|
||||
loc[0] = toupper(locator[0]);
|
||||
loc[1] = toupper(locator[1]);
|
||||
loc[2] = locator[2];
|
||||
loc[3] = locator[3];
|
||||
if (locator[4] != '\0') {
|
||||
loc[4] = toupper(locator[4]);
|
||||
loc[5] = toupper(locator[5]);
|
||||
length = 6;
|
||||
} else {
|
||||
/* center of 4 character grid */
|
||||
loc[4] = 'M';
|
||||
loc[5] = 'M';
|
||||
length = 4;
|
||||
}
|
||||
if (loc[0] < 'A' || loc[0] > 'R' ||
|
||||
loc[1] < 'A' || loc[1] > 'R' ||
|
||||
loc[2] < '0' || loc[2] > '9' ||
|
||||
loc[3] < '0' || loc[3] > '9' ||
|
||||
loc[4] < 'A' || loc[4] > 'X' ||
|
||||
loc[5] < 'A' || loc[5] > 'X' ) {
|
||||
return -RIG_EINVAL;
|
||||
int locator2longlat(double *longitude, double *latitude, const char *locator) {
|
||||
int x_or_y, paircount = strlen(locator) / 2;
|
||||
int locvalue, pair;
|
||||
double xy[2], minutes;
|
||||
|
||||
if (paircount > MAX_LOCATOR_PAIRS) /* Max. locator length to allow */
|
||||
paircount = MAX_LOCATOR_PAIRS;
|
||||
|
||||
for (x_or_y = 0; x_or_y < 2; ++x_or_y) { /* For x(=long) and y(=lat) */
|
||||
minutes = 0.0;
|
||||
|
||||
for (pair = 0; pair < paircount; ++pair) {
|
||||
locvalue = locator[pair*2 + x_or_y];
|
||||
|
||||
locvalue -= (loc_char_range[pair] == 10) ? '0' : /* Value of digit */
|
||||
(isupper(locvalue)) ? 'A' : 'a'; /* or letter. */
|
||||
|
||||
if (((unsigned) locvalue) >= loc_char_range[pair]) /* Check range */
|
||||
return -RIG_EINVAL; /* Non-letter/digit or out of range */
|
||||
|
||||
minutes += locvalue * loc_char_weight[pair];
|
||||
}
|
||||
minutes += loc_char_weight[paircount-1] / 2.0; /* Center coordinate */
|
||||
|
||||
xy[x_or_y] = minutes / 60.0 - 90.0;
|
||||
}
|
||||
|
||||
*longitude = 20.0 * (loc[0]-'A') - 180.0 + 2.0 * (loc[2]-'0') +
|
||||
(loc[4]-'A')/12.0;
|
||||
|
||||
/* move east to center of subsquare */
|
||||
if (length == 6)
|
||||
*longitude += 0.04166666;
|
||||
|
||||
*latitude = 10.0 * (loc[1]-'A') - 90.0 + (loc[3]-'0') +
|
||||
(loc[5]-'A')/24.0;
|
||||
/* move north to center of subsquare */
|
||||
if (length == 6)
|
||||
*latitude += 0.020833333;
|
||||
/* Don't seg. fault if longitude or latitude pointers are null */
|
||||
if (longitude != NULL) *longitude = xy[0] * 2;
|
||||
if (latitude != NULL) *latitude = xy[1];
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
/* end dph */
|
||||
|
||||
/**
|
||||
* \brief Convert longitude/latitude to Maidenhead grid locator
|
||||
|
@ -251,63 +261,35 @@ int locator2longlat(double *longitude, double *latitude, const char *locator)
|
|||
* \param locator The location where to store the locator
|
||||
*
|
||||
* Convert longitude/latitude (decimal) to Maidenhead grid locator.
|
||||
* \a locator must point to an array at least 6 char long.
|
||||
*
|
||||
* \todo Support for greater accuracy as proposed by Dave Hines to
|
||||
* six pairs of grid designators.
|
||||
* \a locator must point to an array at least MAX_LOCATOR_PAIRS*2 char plus nul long.
|
||||
*
|
||||
* \sa locator2longlat()
|
||||
*/
|
||||
void longlat2locator(double longitude, double latitude, char *locator)
|
||||
{
|
||||
double tmp, min_sec;
|
||||
|
||||
tmp = longitude;
|
||||
/* begin dph */
|
||||
|
||||
/* Ideally, the input should be constrained to
|
||||
* >= -180. && < 179.9999999999999
|
||||
*/
|
||||
if (tmp == 180.)
|
||||
tmp = -tmp;
|
||||
void longlat2locator(double longitude, double latitude, char *locator) {
|
||||
int x_or_y, pair, locvalue;
|
||||
double tmp;
|
||||
|
||||
/* with input of -180 to 179 this expression will evaluate
|
||||
* to 1 to 359 or degrees east of -180 degrees longitude.
|
||||
*/
|
||||
tmp = fmod(tmp, 360) + 180.;
|
||||
for (x_or_y = 0; x_or_y < 2; ++x_or_y) {
|
||||
tmp = ((x_or_y == 0) ? longitude / 2. : latitude);
|
||||
|
||||
/* determine west side of the field. Fields always start at
|
||||
* a longitude that is a multiple of 20. Fields advance
|
||||
* eastward from -180 deg West longitude.
|
||||
*/
|
||||
locator[0] = 'A' + (int)floor(tmp/20.);
|
||||
tmp = fmod(tmp, 20.);
|
||||
/* The 1e-6 here guards against floating point rounding errors */
|
||||
tmp = fmod(tmp + 270., 180.) * 60. + 1e-6;
|
||||
for (pair = 0; pair < MAX_LOCATOR_PAIRS; ++pair) {
|
||||
locvalue = (int) (tmp / loc_char_weight[pair]);
|
||||
|
||||
/* at this point tmp = degrees east of west boundary
|
||||
* of the field.
|
||||
*/
|
||||
locator[2] = '0' + (int)floor(tmp/2.);
|
||||
|
||||
min_sec = 12. * fabs(floor(longitude)-longitude);
|
||||
|
||||
/* When tmp is an odd value, then we must be sure that
|
||||
* the subsquare is referenced to 'm' as the longitude
|
||||
* subsquare range spans 2 degrees.
|
||||
*/
|
||||
if ((int)tmp % 2)
|
||||
locator[4] = 'm' + (int)floor(min_sec);
|
||||
else
|
||||
locator[4] = 'a' + (int)floor(min_sec);
|
||||
|
||||
/* input should be constrained to >= -90. && < 90. */
|
||||
tmp = fmod(latitude, 360) + 90.;
|
||||
|
||||
locator[1] = 'A' + (int)floor(tmp/10.);
|
||||
tmp = fmod(tmp, 10.);
|
||||
locator[3] = '0' + (int)floor(tmp);
|
||||
tmp = 24. * fabs(floor(latitude)-latitude);
|
||||
locator[5] = 'a' + (int)floor(tmp);
|
||||
/* assert(locvalue < loc_char_range[pair]); */
|
||||
tmp -= loc_char_weight[pair] * locvalue;
|
||||
locvalue += (loc_char_range[pair] == 10) ? '0':'A';
|
||||
locator[pair*2 + x_or_y] = locvalue;
|
||||
}
|
||||
}
|
||||
locator[MAX_LOCATOR_PAIRS * 2] = '\0';
|
||||
}
|
||||
|
||||
/* end dph */
|
||||
|
||||
/**
|
||||
* \brief Calculate the distance and bearing between two points.
|
||||
|
@ -330,8 +312,7 @@ void longlat2locator(double longitude, double latitude, char *locator)
|
|||
* \sa distance_long_path(), azimuth_long_path()
|
||||
*/
|
||||
int qrb(double lon1, double lat1, double lon2, double lat2,
|
||||
double *distance, double *azimuth)
|
||||
{
|
||||
double *distance, double *azimuth) {
|
||||
double delta_long, tmp, arc, cosaz, az;
|
||||
|
||||
if (!distance || !azimuth)
|
||||
|
@ -367,14 +348,14 @@ int qrb(double lon1, double lat1, double lon2, double lat2,
|
|||
|
||||
tmp = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(delta_long);
|
||||
|
||||
if (tmp > .999999) {
|
||||
if (tmp > .999999) {
|
||||
/* Station points coincide, use an Omni! */
|
||||
*distance = 0.0;
|
||||
*azimuth = 0.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tmp < -.999999) {
|
||||
if (tmp < -.999999) {
|
||||
/*
|
||||
* points are antipodal, it's straight down.
|
||||
* Station is equal distance in all Azimuths.
|
||||
|
@ -444,8 +425,7 @@ int qrb(double lon1, double lat1, double lon2, double lat2,
|
|||
*
|
||||
* \sa qrb()
|
||||
*/
|
||||
double distance_long_path(double distance)
|
||||
{
|
||||
double distance_long_path(double distance) {
|
||||
return (ARC_IN_KM * 360.0) - distance;
|
||||
}
|
||||
|
||||
|
@ -459,8 +439,6 @@ double distance_long_path(double distance)
|
|||
*
|
||||
* \sa qrb()
|
||||
*/
|
||||
double azimuth_long_path(double azimuth)
|
||||
{
|
||||
double azimuth_long_path(double azimuth) {
|
||||
return 360.0 - azimuth;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,8 @@
|
|||
#include <hamlib/rotator.h>
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char recodedloc[8], *loc1, *loc2;
|
||||
int main (int argc, char *argv[]) {
|
||||
char recodedloc[13], *loc1, *loc2;
|
||||
double lon1 = 0, lat1, lon2, lat2;
|
||||
double distance, az;
|
||||
int deg, min, sec;
|
||||
|
@ -46,7 +45,7 @@ int main (int argc, char *argv[])
|
|||
printf(" Recoded lat: %f\n", lat1);
|
||||
|
||||
longlat2locator(lon1, lat1, recodedloc);
|
||||
recodedloc[6] = '\0';
|
||||
// recodedloc[6] = '\0';
|
||||
printf(" Recoded: %s\n", recodedloc);
|
||||
|
||||
if (loc2 == NULL)
|
||||
|
@ -70,7 +69,7 @@ int main (int argc, char *argv[])
|
|||
printf(" Recoded lat: %f\n", lat2);
|
||||
|
||||
longlat2locator(lon2, lat2, recodedloc);
|
||||
recodedloc[6] = '\0';
|
||||
// recodedloc[6] = '\0';
|
||||
printf(" Recoded: %s\n", recodedloc);
|
||||
|
||||
retcode = qrb(lon1, lat1, lon2, lat2, &distance, &az);
|
||||
|
|
Ładowanie…
Reference in New Issue