From da8d2e4b41d835f9b1c68a6472a75ef91d6c69e1 Mon Sep 17 00:00:00 2001 From: "Nate Bargmann, N0NB" Date: Thu, 21 Aug 2003 20:22:06 +0000 Subject: [PATCH] 2003-08-21 Update: locator.c -- added argument int pair_count to longlat2locator() and changed longlat2locator() from void to type int return. Changed *seconds argument in dms2dec() and dec2dms() from type int to type double. rotator.h -- function prototypes to match above. testloc.c -- modified to support changes in locator.c Added additional command line parameter, locator-length which is expected after the first locator and before the optional second locator. git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@1517 7ae35d74-ebe9-4afe-98af-79ac388436b8 --- include/hamlib/rotator.h | 10 ++-- src/locator.c | 118 ++++++++++++++++++++------------------- tests/testloc.c | 31 +++++----- 3 files changed, 82 insertions(+), 77 deletions(-) diff --git a/include/hamlib/rotator.h b/include/hamlib/rotator.h index 00b9532c2..62b0185ff 100644 --- a/include/hamlib/rotator.h +++ b/include/hamlib/rotator.h @@ -2,7 +2,7 @@ * Hamlib Interface - Rotator API header * Copyright (c) 2000-2003 by Stephane Fillod * - * $Id: rotator.h,v 1.7 2003-04-27 22:14:40 fillods Exp $ + * $Id: rotator.h,v 1.8 2003-08-21 20:22:06 n0nb Exp $ * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -334,15 +334,15 @@ extern HAMLIB_EXPORT(int) qrb HAMLIB_PARAMS((double lon1, double lat1, extern HAMLIB_EXPORT(double) distance_long_path HAMLIB_PARAMS((double distance)); extern HAMLIB_EXPORT(double) azimuth_long_path HAMLIB_PARAMS((double azimuth)); -extern HAMLIB_EXPORT(void) longlat2locator HAMLIB_PARAMS((double longitude, - double latitude, char *locator)); +extern HAMLIB_EXPORT(int) longlat2locator HAMLIB_PARAMS((double longitude, + double latitude, char *locator, int pair_count)); extern HAMLIB_EXPORT(int) locator2longlat HAMLIB_PARAMS((double *longitude, double *latitude, const char *locator)); extern HAMLIB_EXPORT(double) dms2dec HAMLIB_PARAMS((int degs, int minutes, - int seconds)); + double seconds)); extern HAMLIB_EXPORT(void) dec2dms HAMLIB_PARAMS((double dec, int *degrees, - int *minutes, int *seconds)); + int *minutes, double *seconds)); /*! \def rot_debug diff --git a/src/locator.c b/src/locator.c index 860395bdc..1fbb24159 100644 --- a/src/locator.c +++ b/src/locator.c @@ -14,7 +14,7 @@ * Copyright (c) 2003 by Nate Bargmann * Copyright (c) 2003 by Dave Hines * - * $Id: locator.c,v 1.8 2003-08-21 03:11:27 n0nb Exp $ + * $Id: locator.c,v 1.9 2003-08-21 20:22:06 n0nb Exp $ * * Code to determine bearing and range was taken from the Great Circle, * by S. R. Sampson, N5OWK. @@ -68,6 +68,38 @@ /* arc length for 1 degree, 60 Nautical Miles */ #define ARC_IN_KM 111.2 +/* 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. + * + * MAX_LOCATOR_PAIRS now sets the limit locator2longlat() will convert and + * sets the maximum length longlat2locator() will generate. Each function + * properly handles any value from 1 to 6 so MAX_LOCATOR_PAIRS should be + * left at 6. MIN_LOCATOR_PAIRS sets a floor on the shortest locator that + * should be handled. -N0NB + * + */ +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 +#define MIN_LOCATOR_PAIRS 1 + +/* end dph */ + #endif /* !DOC_HIDDEN */ /** @@ -84,11 +116,11 @@ * * \sa dec2dms() */ -double dms2dec(int degrees, int minutes, int seconds) { +double dms2dec(int degrees, int minutes, double seconds) { if (degrees >= 0) - return (double)degrees + (double)minutes/60. + (double)seconds/3600.; + return (double)degrees + (double)minutes/60. + seconds/3600.; else - return (double)degrees - (double)minutes/60. - (double)seconds/3600.; + return (double)degrees - (double)minutes/60. - seconds/3600.; } /** @@ -108,8 +140,8 @@ double dms2dec(int degrees, int minutes, int seconds) { * * \sa dms2dec() */ -void dec2dms(double dec, int *degrees, int *minutes, int *seconds) { - int deg, min, sec, is_neg = 0; +void dec2dms(double dec, int *degrees, int *minutes, double *seconds) { + int deg, min, is_neg = 0; double st; if (!degrees || !minutes || !seconds) @@ -147,54 +179,14 @@ void dec2dms(double dec, int *degrees, int *minutes, int *seconds) { st = 60. * (st-(double)deg); min = (int)floor(st); st = 60. * (st-(double)min); - sec = (int)floor(st); - - /* round fractional seconds up if greater than sec.5 - * round up min and deg if warranted. - */ - if (fmod(st, sec) >= 0.5) { - sec++; - if (sec == 60) { - sec = 0; - min++; - if (min == 60) { - min = 0; - deg++; - } - } - } /* set *degrees to original sign passed to dec */ (is_neg == 1) ? (*degrees = deg * -1) : (*degrees = deg); *minutes = min; - *seconds = sec; + *seconds = st; } -/* 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 @@ -212,7 +204,7 @@ const static int loc_char_range[] = { 18, 10, 24, 10, 25, 10 }; * and 1' 15" from south boundary. * * \return RIG_OK to indicate conversion went ok, -RIG_EINVAL if locator - * exceeds RR99xx or is malformed (not of 2 through 12 character format). + * exceeds RR99xx or exceeds length limit. Currently 1 to 6 lon/lat pairs. * * \sa longlat2locator() */ @@ -220,12 +212,16 @@ const static int loc_char_range[] = { 18, 10, 24, 10, 25, 10 }; /* begin dph */ int locator2longlat(double *longitude, double *latitude, const char *locator) { - int x_or_y, paircount = strlen(locator) / 2; + int x_or_y, paircount; int locvalue, pair; double xy[2], minutes; + paircount = strlen(locator) / 2; + if (paircount > MAX_LOCATOR_PAIRS) /* Max. locator length to allow */ paircount = MAX_LOCATOR_PAIRS; + else if (paircount < MIN_LOCATOR_PAIRS) + return -RIG_EINVAL; for (x_or_y = 0; x_or_y < 2; ++x_or_y) { /* For x(=long) and y(=lat) */ minutes = 0.0; @@ -241,7 +237,7 @@ int locator2longlat(double *longitude, double *latitude, const char *locator) { minutes += locvalue * loc_char_weight[pair]; } - minutes += loc_char_weight[paircount-1] / 2.0; /* Center coordinate */ + minutes += loc_char_weight[paircount - 1] / 2.0; /* Center coordinate */ xy[x_or_y] = minutes / 60.0 - 90.0; } @@ -259,34 +255,44 @@ int locator2longlat(double *longitude, double *latitude, const char *locator) { * \param longitude The longitude, decimal * \param latitude The latitude, decimal * \param locator The location where to store the locator + * \param pair_count The desired precision expressed as lon/lat pairs in the locator * * Convert longitude/latitude (decimal) to Maidenhead grid locator. - * \a locator must point to an array at least MAX_LOCATOR_PAIRS*2 char plus nul long. + * \a locator must point to an array at least pair_count * 2 char plus '\0'. + * + * \return RIG_OK if locator was successfully computed. -RIG_EINVAL if + * pair_count exceeds length limit. Currently 1 to 6 lon/lat pairs. * * \sa locator2longlat() */ /* begin dph */ -void longlat2locator(double longitude, double latitude, char *locator) { +int longlat2locator(double longitude, double latitude, + char *locator, int pair_count) { int x_or_y, pair, locvalue; - double tmp; + double tmp; + + if (pair_count < MIN_LOCATOR_PAIRS || pair_count > MAX_LOCATOR_PAIRS) + return -RIG_EINVAL; for (x_or_y = 0; x_or_y < 2; ++x_or_y) { tmp = ((x_or_y == 0) ? longitude / 2. : latitude); /* 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) { + for (pair = 0; pair < pair_count; ++pair) { locvalue = (int) (tmp / loc_char_weight[pair]); /* 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[pair * 2 + x_or_y] = locvalue; } } - locator[MAX_LOCATOR_PAIRS * 2] = '\0'; + locator[pair_count * 2] = '\0'; + + return RIG_OK; } /* end dph */ diff --git a/tests/testloc.c b/tests/testloc.c index 4efd4ade8..db4a1d0c4 100644 --- a/tests/testloc.c +++ b/tests/testloc.c @@ -15,17 +15,18 @@ int main (int argc, char *argv[]) { char recodedloc[13], *loc1, *loc2; double lon1 = 0, lat1, lon2, lat2; - double distance, az; - int deg, min, sec; - int retcode; + double distance, az, sec; + int deg, min; + int retcode, locator_length; - if (argc < 2) { - fprintf(stderr, "Usage: %s []\n", argv[0]); + if (argc < 3) { + fprintf(stderr, "Usage: %s []\n", argv[0]); exit(1); } loc1 = argv[1]; - loc2 = argc > 2 ? argv[2] : NULL; + locator_length = atoi(argv[2]); + loc2 = argc > 3 ? argv[3] : NULL; printf("Locator1: %s\n", loc1); retcode = locator2longlat(&lon1, &lat1, loc1); @@ -35,21 +36,20 @@ int main (int argc, char *argv[]) { } dec2dms(lon1, °, &min, &sec); - printf(" Longitude: %f, %d° %d' %d\"\n", lon1, deg, min, sec); + printf(" Longitude: %f, %d° %d' %.2f\"\n", lon1, deg, min, sec); lon1 = dms2dec(deg, min, sec); printf(" Recoded lon: %f\n", lon1); dec2dms(lat1, °, &min, &sec); - printf(" Latitude: %f, %d° %d' %d\"\n", lat1, deg, min, sec); + printf(" Latitude: %f, %d° %d' %.2f\"\n", lat1, deg, min, sec); lat1 = dms2dec(deg, min, sec); printf(" Recoded lat: %f\n", lat1); - longlat2locator(lon1, lat1, recodedloc); -// recodedloc[6] = '\0'; + longlat2locator(lon1, lat1, recodedloc, locator_length); printf(" Recoded: %s\n", recodedloc); if (loc2 == NULL) - exit(0); + exit(0); printf("\nLocator2: %s\n", loc2); retcode = locator2longlat(&lon2, &lat2, loc2); @@ -59,17 +59,16 @@ int main (int argc, char *argv[]) { } dec2dms(lon2, °, &min, &sec); - printf(" Longitude: %f, %d° %d' %d\"\n", lon2, deg, min, sec); + printf(" Longitude: %f, %d° %d' %.2f\"\n", lon2, deg, min, sec); lon2 = dms2dec(deg, min, sec); printf(" Recoded lon: %f\n", lon2); dec2dms(lat2, °, &min, &sec); - printf(" Latitude: %f, %d° %d' %d\"\n", lat2, deg, min, sec); + printf(" Latitude: %f, %d° %d' %.2f\"\n", lat2, deg, min, sec); lat2 = dms2dec(deg, min, sec); printf(" Recoded lat: %f\n", lat2); - longlat2locator(lon2, lat2, recodedloc); -// recodedloc[6] = '\0'; + longlat2locator(lon2, lat2, recodedloc, locator_length); printf(" Recoded: %s\n", recodedloc); retcode = qrb(lon1, lat1, lon2, lat2, &distance, &az); @@ -79,7 +78,7 @@ int main (int argc, char *argv[]) { } dec2dms(az, °, &min, &sec); printf("\nDistance: %.2fkm\n", distance); - printf("Bearing: %f, %d° %d' %d\"\n", az, deg, min, sec); + printf("Bearing: %f, %d° %d' %.2f\"\n", az, deg, min, sec); return 0; }