summaryrefslogtreecommitdiffstats
path: root/save-xml.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2012-12-05 08:25:33 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-12-05 10:33:58 -0800
commit708df33539ef3b6d3cfde435df93fd4475cdde75 (patch)
tree7fbc0c287d0d06feac66d7895a412215c4f73b11 /save-xml.c
parent1e074f3fb2a933ec5cadb0129cb1d71f8be351c3 (diff)
downloadsubsurface-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.c46
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);