diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-05 08:25:33 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2012-12-05 10:33:58 -0800 |
commit | 708df33539ef3b6d3cfde435df93fd4475cdde75 (patch) | |
tree | 7fbc0c287d0d06feac66d7895a412215c4f73b11 /save-xml.c | |
parent | 1e074f3fb2a933ec5cadb0129cb1d71f8be351c3 (diff) | |
download | subsurface-708df33539ef3b6d3cfde435df93fd4475cdde75.tar.gz |
Save latitude/longitude using integer math
I hate using floating point, this tries to at least make parts of it be
integer logic, and avoid the whole locale issue. This still keeps the
latitude and longitude internally as a floating point value, and parses
it that way, but I'm slowly moving towards less and less FP use.
We're going to use micro-degrees for location information: that's
sufficient to about a tenth of a meter precision, and it fits in a
32-bit integer.
If you specify dive sites with more precision than that, you may have
OCD.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'save-xml.c')
-rw-r--r-- | save-xml.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/save-xml.c b/save-xml.c index d4bc36cab..948f2ed08 100644 --- a/save-xml.c +++ b/save-xml.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <errno.h> #include <time.h> +#include <math.h> #include "dive.h" @@ -177,6 +178,35 @@ static void save_salinity(FILE *f, struct dive *dive) fputs(" />\n", f); } +/* + * Format degrees to within 6 decimal places. That's about 0.1m + * on a great circle (ie longitude at equator). And micro-degrees + * is also enough to fit in a fixed-point 32-bit integer. + */ +static int format_degrees(char *buffer, double value) +{ + int udeg = round(value * 1000000.0); + const char *sign = ""; + + if (udeg < 0) { + sign = "-"; + udeg = -udeg; + } + return sprintf(buffer, "%s%u.%06u", + sign, udeg / 1000000, udeg % 1000000); +} + +static int format_location(char *buffer, double latitude, double longitude) +{ + int len = sprintf(buffer, "gps='"); + + len += format_degrees(buffer+len, latitude); + buffer[len++] = ' '; + len += format_degrees(buffer+len, longitude); + buffer[len++] = '\''; + + return len; +} static void show_location(FILE *f, struct dive *dive) { @@ -192,20 +222,16 @@ static void show_location(FILE *f, struct dive *dive) * you dove a few meters away. */ if (latitude || longitude) { - int len = snprintf(buffer, sizeof(buffer)-4, - " <location gps="); - char *buf = buffer + len; - - len = strlen(g_ascii_formatd(buf, 80, "'%.12g ", latitude)); - buf += len; - len = strlen(g_ascii_formatd(buf, 80, "%.12g'>", longitude)); - buf += len; - len = buf - buffer; + int len = sprintf(buffer, " <location "); + + len += format_location(buffer+len, latitude, longitude); if (!dive->location) { - memcpy(&buffer[len-1], "/>\n", 4); + memcpy(buffer+len, "/>\n", 4); fputs(buffer, f); return; } + buffer[len++] = '>'; + buffer[len] = 0; prefix = buffer; } show_utf8(f, dive->location, prefix,"</location>\n", 0); |