/*
* Copyright (C) 2006, 2007 John Costigan.
*
* POI and GPS-Info code originally written by Cezary Jackiewicz.
*
* Default map data provided by http://www.openstreetmap.org/
*
* This file is part of Maemo Mapper.
*
* Maemo Mapper 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 3 of the License, or
* (at your option) any later version.
*
* Maemo Mapper is distributed in the hope that it will be 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.
*
* You should have received a copy of the GNU General Public License
* along with Maemo Mapper. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#define _GNU_SOURCE
#include
#include
#include
#ifndef LEGACY
# include
#else
# include
#endif
#include "types.h"
#include "data.h"
#include "defines.h"
#include "gpx.h"
#include "util.h"
gboolean convert_iaru_loc_to_lat_lon(const gchar* txt_lon, gdouble* lat, gdouble* lon);
/**
* Pop up a modal dialog box with simple error information in it.
*/
void
popup_error(GtkWidget *window, const gchar *error)
{
GtkWidget *dialog;
printf("%s(\"%s\")\n", __PRETTY_FUNCTION__, error);
dialog = hildon_note_new_information(GTK_WINDOW(window), error);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
vprintf("%s(): return\n", __PRETTY_FUNCTION__);
}
void
deg_format(gdouble coor, gchar *scoor, gchar neg_char, gchar pos_char)
{
gdouble min;
gdouble acoor = fabs(coor);
printf("%s()\n", __PRETTY_FUNCTION__);
switch(_degformat)
{
case IARU_LOC:
case UK_OSGB:
case UK_NGR:
case UK_NGR6:
// These formats should not be formatted in the same way
// - they need to be converted first, therefore if we reach
// this bit of code use the first available format - drop through.
case DDPDDDDD:
sprintf(scoor, "%.5f°", coor);
break;
case DDPDDDDD_NSEW:
sprintf(scoor, "%.5f° %c", acoor,
coor < 0.0 ? neg_char : pos_char);
break;
case NSEW_DDPDDDDD:
sprintf(scoor, "%c %.5f°",
coor < 0.0 ? neg_char : pos_char,
acoor);
break;
case DD_MMPMMM:
sprintf(scoor, "%d°%06.3f'",
(int)coor, (acoor - (int)acoor)*60.0);
break;
case DD_MMPMMM_NSEW:
sprintf(scoor, "%d°%06.3f' %c",
(int)acoor, (acoor - (int)acoor)*60.0,
coor < 0.0 ? neg_char : pos_char);
break;
case NSEW_DD_MMPMMM:
sprintf(scoor, "%c %d° %06.3f'",
coor < 0.0 ? neg_char : pos_char,
(int)acoor, (acoor - (int)acoor)*60.0);
break;
case DD_MM_SSPS:
min = (acoor - (int)acoor)*60.0;
sprintf(scoor, "%d°%02d'%04.1f\"", (int)coor, (int)min,
((min - (int)min)*60.0));
break;
case DD_MM_SSPS_NSEW:
min = (acoor - (int)acoor)*60.0;
sprintf(scoor, "%d°%02d'%04.1f\" %c", (int)acoor, (int)min,
((min - (int)min)*60.0),
coor < 0.0 ? neg_char : pos_char);
break;
case NSEW_DD_MM_SSPS:
min = (acoor - (int)acoor)*60.0;
sprintf(scoor, "%c %d° %02d' %04.1f\"",
coor < 0.0 ? neg_char : pos_char,
(int)acoor, (int)min,
((min - (int)min)*60.0));
break;
}
vprintf("%s(): return\n", __PRETTY_FUNCTION__);
}
/** Return the location (in units) of the given string address. This function
* makes a call to the internet, so it may take some time. */
Point locate_address(GtkWidget *parent, const gchar *addr)
{
Path temp;
Point retval = _point_null;
GnomeVFSResult vfs_result;
gint size;
gchar *bytes = NULL;
gchar *addr_escaped;
gchar *buffer;
printf("%s(%s)\n", __PRETTY_FUNCTION__, addr);
addr_escaped = gnome_vfs_escape_string(addr);
buffer = g_strdup_printf(_route_dl_url, addr_escaped, addr_escaped);
g_free(addr_escaped);
/* Attempt to download the route from the server. */
if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
buffer, &size, &bytes)))
{
g_free(buffer);
g_free(bytes);
popup_error(parent, _("Failed to connect to GPX Directions server"));
return _point_null;
}
g_free(buffer);
MACRO_PATH_INIT(temp);
if(strncmp(bytes, " 1) {
f_flag = 1;
v += f/n;
}
}
/* allow for extra sep char at the end */
if (*p && strchr(sep, *p)) {
p++;
} else if (utf8_deg && *p == 0xc2 && *(p+1) == 0xb0) {
p += 2;
}
*d = v;
if (endptr) *endptr = p;
return f_flag ? 2 : 3;
}
if (endptr) *endptr = p;
return *p == 0;
}
static gdouble
strdmstod_2(gchar *nptr, gchar **endptr)
{
gint ret;
guchar *p;
gdouble d, m, s;
p = nptr;
/* degrees */
ret = strdmstod_1(&d, p, endptr, "dD@", 1);
switch (ret) {
case 0: return 0.0;
case 1:
if (endptr) *endptr = (char *)nptr;
return 0.0;
case 2: return d;
}
/* minutes */
p = *endptr;
m = 0.0;
ret = strdmstod_1(&m, p, endptr, "mM'", 0);
switch (ret) {
case 0: return 0.0;
case 1: return d;
case 2: return d + m/60.0;
}
/* seconds */
p = *endptr;
ret = strdmstod_1(&s, p, endptr, "sS\"", 0);
switch (ret) {
case 0: return 0.0;
case 1: return d + m/60.0;
case 2:
case 3: return d + m/60.0 + s/3600.0;
}
/* can't be here */
return 0.0;
}
/*
* format: / \s* [+-NSWE]? \s* ( d | D \s+ m | D \s+ M \s+ s ) [NSWE]? /x
* where D := / \d+[@d°]? /ix
* M := / \d+['m]? /ix
* d := / D | \d+[,.]\d+[@d°]? /ix
* m := / M | \d+[,.]\d+['m]? /ix
* s := / S | \d+[,.]\d+["s]? /ix
*
* and N or W are treated as positive, S or E are treated as negative,
* they may occur only once.
*/
gdouble
strdmstod(const gchar *nptr, gchar **endptr)
{
gint s;
gchar *p, *end;
gchar *sign = 0;
gdouble d;
p = (char *)nptr;
while(*p && isspace(*p))
p++;
if(!*p) {
if(endptr)
*endptr = (char *)nptr;
return 0.0;
}
if(strchr("nwseNWSE-+", *p)) {
sign = p;
p++;
}
d = strdmstod_2(p, &end);
if(p == end && d == 0.0) {
if(endptr) *endptr = end;
return d;
}
p = end;
while(*p && isspace(*p))
p++;
s = 1;
if(sign == 0) {
if(*p && strchr("nwseNWSE", *p)) {
if(tolower(*p) == 's' || tolower(*p) == 'w')
s = -1;
p++;
}
} else {
if(tolower(*sign) == 's' || tolower(*sign) == 'w' || *sign == '-')
s = -1;
printf("s: %d\n", s);
}
if(endptr) *endptr = p;
return s * d;
}
double marc(double bf0, double n, double phi0, double phi)
{
return bf0 * (((1 + n + ((5 / 4) * (n * n)) + ((5 / 4) * (n * n * n))) * (phi - phi0))
- (((3 * n) + (3 * (n * n)) + ((21 / 8) * (n * n * n))) * (sin(phi - phi0)) * (cos(phi + phi0)))
+ ((((15 / 8) * (n * n)) + ((15 / 8) * (n * n * n))) * (sin(2 * (phi - phi0))) * (cos(2 * (phi + phi0))))
- (((35 / 24) * (n * n * n)) * (sin(3 * (phi - phi0))) * (cos(3 * (phi + phi0)))));
}
gboolean os_grid_check_lat_lon(double lat, double lon)
{
// TODO - Check exact OS Grid range
if(lat < 50.0 || lat > 62 || lon < -7.5 || lon > 2.2 )
{
return FALSE;
}
else
{
return TRUE;
}
}
gboolean coord_system_check_lat_lon (gdouble lat, gdouble lon, gint *fallback_deg_format)
{
// Is the current coordinate system applicable to the provided lat and lon?
gboolean valid = FALSE;
switch(_degformat)
{
case UK_OSGB:
case UK_NGR:
case UK_NGR6:
valid = os_grid_check_lat_lon(lat, lon);
if(fallback_deg_format != NULL) *fallback_deg_format = DDPDDDDD;
break;
default:
valid = TRUE;
break;
}
return valid;
}
gboolean convert_lat_long_to_os_grid(double lat, double lon, int *easting, int *northing)
{
if(!os_grid_check_lat_lon(lat, lon))
{
return FALSE;
}
const double deg2rad_multi = (2 * PI / 360);
const double phi = lat * deg2rad_multi; // convert latitude to radians
const double lam = lon * deg2rad_multi; // convert longitude to radians
const double a = 6377563.396; // OSGB semi-major axis
const double b = 6356256.91; // OSGB semi-minor axis
const double e0 = 400000; // easting of false origin
const double n0 = -100000; // northing of false origin
const double f0 = 0.9996012717; // OSGB scale factor on central meridian
const double e2 = 0.0066705397616; // OSGB eccentricity squared
const double lam0 = -0.034906585039886591; // OSGB false east
const double phi0 = 0.85521133347722145; // OSGB false north
const double af0 = a * f0;
const double bf0 = b * f0;
// easting
double slat2 = sin(phi) * sin(phi);
double nu = af0 / (sqrt(1 - (e2 * (slat2))));
double rho = (nu * (1 - e2)) / (1 - (e2 * slat2));
double eta2 = (nu / rho) - 1;
double p = lam - lam0;
double IV = nu * cos(phi);
double clat3 = pow(cos(phi), 3);
double tlat2 = tan(phi) * tan(phi);
double V = (nu / 6) * clat3 * ((nu / rho) - tlat2);
double clat5 = pow(cos(phi), 5);
double tlat4 = pow(tan(phi), 4);
double VI = (nu / 120) * clat5 * ((5 - (18 * tlat2)) + tlat4 + (14 * eta2) - (58 * tlat2 * eta2));
double east = e0 + (p * IV) + (pow(p, 3) * V) + (pow(p, 5) * VI);
// northing
double n = (af0 - bf0) / (af0 + bf0);
double M = marc(bf0, n, phi0, phi);
double I = M + (n0);
double II = (nu / 2) * sin(phi) * cos(phi);
double III = ((nu / 24) * sin(phi) * pow(cos(phi), 3)) * (5 - pow(tan(phi), 2) + (9 * eta2));
double IIIA = ((nu / 720) * sin(phi) * clat5) * (61 - (58 * tlat2) + tlat4);
double north = I + ((p * p) * II) + (pow(p, 4) * III) + (pow(p, 6) * IIIA);
// make whole number values
*easting = round(east); // round to whole number
*northing = round(north); // round to whole number
return TRUE;
}
gboolean convert_os_grid_to_bng(gint easting, gint northing, gchar* bng)
{
gdouble eX = (gdouble)easting / 500000.0;
gdouble nX = (gdouble)northing / 500000.0;
gdouble tmp = floor(eX) - 5.0 * floor(nX) + 17.0;
gchar eing[12];
gchar ning[12];
nX = 5.0 * (nX - floor(nX));
eX = 20.0 - 5.0 * floor(nX) + floor(5.0 * (eX - floor(eX)));
if (eX > 7.5) eX = eX + 1; // I is not used
if (tmp > 7.5) tmp = tmp + 1; // I is not used
snprintf(eing, 12, "%u", easting);
snprintf(ning, 12, "%u", northing);
snprintf(eing, (_degformat == UK_NGR ? 5 : 4), "%s", eing+1);
snprintf(ning, (_degformat == UK_NGR ? 5 : 4), "%s", ning+1);
sprintf(bng, "%c%c%s%s",
(char)(tmp + 65),
(char)(eX + 65),
eing, ning
);
return TRUE;
}
gint convert_str_to_int(const gchar *str)
{
gint i=0;
gint result = 0;
while(str[i] >= '0' && str[i] <= '9')
{
gint v = str[i] - '0';
result = (result * 10) + v;
i++;
}
return result;
}
gboolean convert_os_xy_to_latlon(const gchar *easting, const gchar *northing, gdouble *d_lat, gdouble *d_lon)
{
const double deg2rad_multi = (2 * PI / 360);
const gdouble N = (gdouble)convert_str_to_int(northing);
const gdouble E = (gdouble)convert_str_to_int(easting);
const gdouble a = 6377563.396, b = 6356256.910; // Airy 1830 major & minor semi-axes
const gdouble F0 = 0.9996012717; // NatGrid scale factor on central meridian
const gdouble lat0 = 49*PI/180, lon0 = -2*PI/180; // NatGrid true origin
const gdouble N0 = -100000, E0 = 400000; // northing & easting of true origin, metres
const gdouble e2 = 1 - (b*b)/(a*a); // eccentricity squared
const gdouble n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;
gdouble lat=lat0, M=0;
do {
lat = (N-N0-M)/(a*F0) + lat;
const gdouble Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
const gdouble Mb = (3*n + 3*n*n + (21/8)*n3) * sin(lat-lat0) * cos(lat+lat0);
const gdouble Mc = ((15/8)*n2 + (15/8)*n3) * sin(2*(lat-lat0)) * cos(2*(lat+lat0));
const gdouble Md = (35/24)*n3 * sin(3*(lat-lat0)) * cos(3*(lat+lat0));
M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
} while (N-N0-M >= 0.00001); // ie until < 0.01mm
const gdouble cosLat = cos(lat), sinLat = sin(lat);
const gdouble nu = a*F0/sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature
const gdouble rho = a*F0*(1-e2)/pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature
const gdouble eta2 = nu/rho-1;
const gdouble tanLat = tan(lat);
const gdouble tan2lat = tanLat*tanLat, tan4lat = tan2lat*tan2lat, tan6lat = tan4lat*tan2lat;
const gdouble secLat = 1/cosLat;
const gdouble nu3 = nu*nu*nu, nu5 = nu3*nu*nu, nu7 = nu5*nu*nu;
const gdouble VII = tanLat/(2*rho*nu);
const gdouble VIII = tanLat/(24*rho*nu3)*(5+3*tan2lat+eta2-9*tan2lat*eta2);
const gdouble IX = tanLat/(720*rho*nu5)*(61+90*tan2lat+45*tan4lat);
const gdouble X = secLat/nu;
const gdouble XI = secLat/(6*nu3)*(nu/rho+2*tan2lat);
const gdouble XII = secLat/(120*nu5)*(5+28*tan2lat+24*tan4lat);
const gdouble XIIA = secLat/(5040*nu7)*(61+662*tan2lat+1320*tan4lat+720*tan6lat);
const gdouble dE = (E-E0), dE2 = dE*dE, dE3 = dE2*dE, dE4 = dE2*dE2, dE5 = dE3*dE2;
const gdouble dE6 = dE4*dE2, dE7 = dE5*dE2;
lat = lat - VII*dE2 + VIII*dE4 - IX*dE6;
const gdouble lon = lon0 + X*dE - XI*dE3 + XII*dE5 - XIIA*dE7;
*d_lon = lon / deg2rad_multi;
*d_lat = lat / deg2rad_multi;
return TRUE;
}
gboolean convert_os_ngr_to_latlon(const gchar *text, gdouble *d_lat, gdouble *d_lon)
{
// get numeric values of letter references, mapping A->0, B->1, C->2, etc:
gint l1;
gint l2;
gchar easting[7], northing[7];
if( ((gchar)text[0])>='a' && ((gchar)text[0]) <= 'z' )
l1 = text[0] - (gint)'a'; // lower case
else if( ((gchar)text[0])>='A' && ((gchar)text[0]) <= 'Z' )
l1 = text[0] - (gint)'A'; // upper case
else
return FALSE; // Not a letter - invalid grid ref
if( ((gchar)text[1])>='a' && ((gchar)text[1]) <= 'z' )
l2 = text[1] - (gint)'a'; // lower case
else if( ((gchar)text[1])>='A' && ((gchar)text[1]) <= 'Z' )
l2 = text[1] - (gint)'A'; // upper case
else
return FALSE; // Not a letter - invalid grid ref
// shuffle down letters after 'I' since 'I' is not used in grid:
if (l1 > 7) l1--;
if (l2 > 7) l2--;
// convert grid letters into 100km-square indexes from false origin (grid square SV):
gdouble e = ((l1-2)%5)*5 + (l2%5);
gdouble n = (19-floor(l1/5)*5) - floor(l2/5);
// skip grid letters to get numeric part of ref, stripping any spaces:
gchar *gridref = (gchar*)(text+2);
// user may have entered a space, so remove any spaces
while(gridref[0] == ' ')
{
gridref = (gchar*)(text+1);
}
// floor the length incase a space has been added
const gint len = (gint)floor((gdouble)strlen(gridref)/2.00); // normally this will be 4, often 3
if(len>5 || len <3) return FALSE;
snprintf(easting, 2+len, "%u%s", (gint)e, gridref);
snprintf(northing, 2+len, "%u%s", (gint)n, gridref+len);
fprintf(stderr, "easting = %s, northing = %s\n", easting, northing);
switch (len)
{
case 3:
easting[4] = '0';
easting[5] = '0';
northing[4] = '0';
northing[5] = '0';
break;
case 4:
easting[5] = '0';
northing[5] = '0';
break;
// 10-digit refs are already 1m
}
easting[6] = '\0';
northing[6] = '\0';
convert_os_xy_to_latlon(easting, northing, d_lat, d_lon);
return TRUE;
}
// Attempt to convert any user entered grid reference to a double lat/lon
// return TRUE on valid
gboolean parse_coords(const gchar* txt_lat, const gchar* txt_lon, gdouble* lat, gdouble* lon)
{
gboolean valid = FALSE;
// UK_NGR starts with two letters, and then all numbers - it may contain spaces - no lon will be entered
if( _degformat == UK_NGR || _degformat == UK_NGR6 )
{
valid = convert_os_ngr_to_latlon(txt_lat, lat, lon);
if(!valid || *lat < -90. || *lat > 90.) { valid = FALSE; }
else if(*lon < -180. || *lon > 180.) { valid = FALSE; }
}
// UK_OSGB contains two 6 digit integers
else if( _degformat == UK_OSGB)
{
valid = convert_os_xy_to_latlon(txt_lat, txt_lon, lat, lon);
if(!valid || *lat < -90. || *lat > 90.) { valid = FALSE; }
else if(*lon < -180. || *lon > 180.) { valid = FALSE; }
}
else if( _degformat == IARU_LOC)
{
valid = convert_iaru_loc_to_lat_lon(txt_lat, lat, lon);
if(!valid || *lat < -90. || *lat > 90.) { valid = FALSE; }
else if(*lon < -180. || *lon > 180.) { valid = FALSE; }
}
// It must either be invalid, or a lat/lon format
else
{
gchar* error_check;
*lat = strdmstod(txt_lat, &error_check);
if(txt_lat == error_check || *lat < -90. || *lat > 90.) { valid = FALSE; }
else { valid = TRUE; }
if(valid == TRUE)
{
*lon = strdmstod(txt_lon, &error_check);
if(txt_lon == error_check || *lon < -180. || *lon > 180.) { valid = FALSE; }
}
}
return valid;
}
gboolean convert_iaru_loc_to_lat_lon(const gchar* txt_lon, gdouble* lat, gdouble* lon)
{
gint u_first = 0;
gint u_second = 0;
gint u_third = 0;
gint u_fourth = 0;
gint u_fifth = 0;
gint u_sixth = 0;
gint u_seventh = 0;
gint u_eighth = 0;
if(strlen(txt_lon) >= 1)
{
if( ((gchar)txt_lon[0])>='a' && ((gchar)txt_lon[0]) <= 'z' )
u_first = txt_lon[0] - (gint)'a'; // lower case
else if( ((gchar)txt_lon[0])>='A' && ((gchar)txt_lon[0]) <= 'Z' )
u_first = txt_lon[0] - (gint)'A'; // upper case
}
if(strlen(txt_lon) >= 2)
{
if( ((gchar)txt_lon[1])>='a' && ((gchar)txt_lon[1]) <= 'z' )
u_second = txt_lon[1] - (gint)'a'; // lower case
else if( ((gchar)txt_lon[1])>='A' && ((gchar)txt_lon[1]) <= 'Z' )
u_second = txt_lon[1] - (gint)'A'; // upper case
}
if(strlen(txt_lon) >= 3)
u_third = txt_lon[2] - (gint)'0';
if(strlen(txt_lon) >= 4)
u_fourth = txt_lon[3] - (gint)'0';
if(strlen(txt_lon) >= 5)
{
if( ((gchar)txt_lon[4])>='a' && ((gchar)txt_lon[4]) <= 'z' )
u_fifth = txt_lon[4] - (gint)'a'; // lower case
else if( ((gchar)txt_lon[4])>='A' && ((gchar)txt_lon[4]) <= 'Z' )
u_fifth = txt_lon[4] - (gint)'A'; // upper case
}
if(strlen(txt_lon) >= 6)
{
if( ((gchar)txt_lon[5])>='a' && ((gchar)txt_lon[5]) <= 'z' )
u_sixth = txt_lon[5] - (gint)'a'; // lower case
else if( ((gchar)txt_lon[5])>='A' && ((gchar)txt_lon[5]) <= 'Z' )
u_sixth = txt_lon[5] - (gint)'A'; // upper case
}
if(strlen(txt_lon) >= 7)
u_seventh= txt_lon[6] - (gint)'0';
if(strlen(txt_lon) >= 8)
u_eighth = txt_lon[7] - (gint)'0';
*lat = ((gdouble)u_first * 20.0) + ((gdouble)u_third * 2.0) + ((gdouble)u_fifth * (2.0/24.0)) + ((gdouble)u_seventh * (2.0/240.0)) - 90.0;
*lon = ((gdouble)u_second * 10.0) + ((gdouble)u_fourth) + ((gdouble)u_sixth * (1.0/24.0)) + ((gdouble)u_eighth * (1.0/240.0)) - 180.0;
return TRUE;
}
void convert_lat_lon_to_iaru_loc(gdouble d_lat, gdouble d_lon, gchar *loc)
{
const gdouble d_a_lat = (d_lat+90.0);
const gdouble d_a_lon = (d_lon+180.0);
const gint i_first = (gint)floor(d_a_lon/20.0);
const gint i_second = (gint)floor(d_a_lat/10.0);
const gint i_third = (gint)floor((d_a_lon - (20.0*i_first))/2.0);
const gint i_fourth = (gint)floor((d_a_lat - (10.0*i_second)));
const gint i_fifth = (gint)floor((d_a_lon - (20.0*i_first) - (2.0*i_third))/(5.0/60.0));
const gint i_sixth = (gint)floor((d_a_lat - (10.0*i_second) - (i_fourth))/(2.5/60.0));
const gint i_seventh = (gint)floor((d_a_lon - (20.0*i_first) - (2.0*i_third)
- ((2.0/24.0)*i_fifth))/(2.0/240.0) );
const gint i_eighth = (gint)floor((d_a_lat - (10.0*i_second) - (i_fourth)
- ((1.0/24.0)*i_sixth))/(1.0/240.0));
sprintf(loc, "%c%c%u%u%c%c%u%u",
'A'+i_first,
'A'+i_second,
i_third,
i_fourth,
'a' + i_fifth,
'a' + i_sixth,
i_seventh,
i_eighth);
}
gboolean convert_lat_lon_to_bng(gdouble lat, gdouble lon, gchar* bng)
{
gint easting, northing;
if( convert_lat_long_to_os_grid(lat, lon, &easting, &northing) )
{
if( convert_os_grid_to_bng(easting, northing, bng) )
{
return TRUE;
}
}
return FALSE;
}
void format_lat_lon(gdouble d_lat, gdouble d_lon, gchar* lat, gchar* lon)
{
gint east = 0;
gint north = 0;
switch (_degformat)
{
case UK_OSGB:
if(convert_lat_long_to_os_grid(d_lat, d_lon, &east, &north))
{
sprintf(lat, "%06d", east);
sprintf(lon, "%06d", north);
}
else
{
// Failed (possibly out of range), so use defaults
lat_format(d_lat, lat);
lon_format(d_lon, lon);
}
break;
case UK_NGR:
case UK_NGR6:
if(convert_lat_lon_to_bng(d_lat, d_lon, lat))
{
lon[0] = 0;
}
else
{
// Failed (possibly out of range), so use defaults
lat_format(d_lat, lat);
lat_format(d_lon, lon);
}
break;
case IARU_LOC:
convert_lat_lon_to_iaru_loc(d_lat, d_lon, lat);
break;
default:
lat_format(d_lat, lat);
lon_format(d_lon, lon);
break;
}
}
/* Custom version of g_ascii_strtoll, since Gregale does not support
* GLIB 2.12. */
gint64
g_ascii_strtoll(const gchar *nptr, gchar **endptr, guint base)
{
gchar *minus = g_strstr_len(nptr, -1, "");
if(minus)
return -g_ascii_strtoull(minus + 1, endptr, base);
else
return g_ascii_strtoull(nptr, endptr, base);
}
#if 0
struct t_case {
gchar *fmt;
gdouble value;
} t_cases[] = {
{ "12°", 12 },
{ "+12d", 12 },
{ "-12.345d", -12.345 },
{ "12.345 E", -12.345 },
{ "12d34m", 12.5666667 },
{ "N 12 34", 12.5666667 },
{ "S 12d34.56m", -12.576 },
{ "W 12 34.56", 12.576 },
{ "E 12d34m56s", -12.582222 },
{ "12 34 56 S", -12.582222 },
{ "12 34 56", 12.582222 },
{ "12d34m56.7s E", -12.582417 },
{ "12 34 56.7 W", 12.582417 },
{ "12° 34 56.7 W", 12.582417 },
{ 0, 0 }
};
int
strdmstod_test()
{
struct t_case *t;
gint fail, ok;
fail = ok = 0;
for (t = t_cases; t->fmt; t++) {
gdouble v;
gchar *endp;
v = strdmstod(t->fmt, &endp);
if (endp == t->fmt || *endp != 0) {
fprintf(stderr, "FAIL syntax %s\n", t->fmt);
fail++;
} else if (fabs(v - t->value) > 0.000001) {
fprintf(stderr, "FAIL value %s -> %.10g (%.10g)\n",
t->fmt, v, t->value);
fail++;
} else {
ok++;
}
}
if (fail == 0) {
fprintf(stderr, "ALL TESTS OK\n");
} else {
fprintf(stderr, "FAIL %d, OK %d\n", fail, ok);
}
}
#endif