diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2015-02-13 00:04:14 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2015-02-13 12:42:44 -0800 |
commit | 8c3efd2a22959f684b7604a405d66abc0831a9e1 (patch) | |
tree | 821439c85cf4df82d40da84f09a5cf0c56dee387 | |
parent | d4f2b7214863b2a40ebcf69e7add113412f795b8 (diff) | |
download | subsurface-8c3efd2a22959f684b7604a405d66abc0831a9e1.tar.gz |
Improve parsing of older XML files in order to auto create dive sites
While the existing code worked with a couple of hand crafted examples it
turns out it did a poor job with most of my files. Oops.
Depending on whether we find name or coordinates first, we need to
identify existing sites in either case and do the right thing.
The challeng here are multiple dives at the same site with slightly
different GPS coordinates. If the name is read first, these all get merged
into one (and we warn about the different GPS data). But if GPS gets read
first, we create separate dive sites with the same name.
We need a sane UI to consolidate these - but we can't completely automate
this... it's possible that these ARE the same site and the GPS data is
just imprecise (for example, multiple dives at the same time with GPS
locations from the Subsurface companion app). The user should be able to
either pick one of the GPS locations, or keep multiple (for example,
different buoyes for the same site and you want to keep the different
markers).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r-- | divesite.c | 10 | ||||
-rw-r--r-- | divesite.h | 26 | ||||
-rw-r--r-- | parse-xml.c | 54 |
3 files changed, 60 insertions, 30 deletions
diff --git a/divesite.c b/divesite.c index d9351e1af..bccbe37e2 100644 --- a/divesite.c +++ b/divesite.c @@ -58,16 +58,6 @@ uint32_t create_dive_site_with_gps(const char *name, degrees_t latitude, degrees return ds->uuid; } -/* this either returns the uuid for a site with that name or creates an entry */ -uint32_t dive_site_uuid_by_name(const char *name) -{ - uint32_t id = get_dive_site_uuid_by_name(name); - if (id == 0) - id = create_dive_site(name); - - return id; -} - /* if the uuid is valid, just get the site, otherwise create it first; * so you can call this with dive->dive_site_uuid and you'll either get the existing * dive site or it will create a new one - so make sure you assign the uuid back to diff --git a/divesite.h b/divesite.h index f0cf08067..5b1d1959d 100644 --- a/divesite.h +++ b/divesite.h @@ -46,20 +46,38 @@ static inline struct dive_site *get_dive_site_by_uuid(uint32_t uuid) } /* there could be multiple sites of the same name - return the first one */ -static inline uint32_t get_dive_site_uuid_by_name(const char *name) +static inline uint32_t get_dive_site_uuid_by_name(const char *name, struct dive_site **dsp) { int i; struct dive_site *ds; - for_each_dive_site (i, ds) - if (ds->name == name) + for_each_dive_site (i, ds) { + if (ds->name == name) { + if (dsp) + *dsp = ds; + return ds->uuid; + } + } + return 0; +} + +/* there could be multiple sites at the same GPS fix - return the first one */ +static inline uint32_t get_dive_site_uuid_by_gps(degrees_t latitude, degrees_t longitude, struct dive_site **dsp) +{ + int i; + struct dive_site *ds; + for_each_dive_site (i, ds) { + if (ds->latitude.udeg == latitude.udeg && ds->longitude.udeg == longitude.udeg) { + if (dsp) + *dsp = ds; return ds->uuid; + } + } return 0; } struct dive_site *alloc_dive_site(); uint32_t create_dive_site(const char *name); uint32_t create_dive_site_with_gps(const char *name, degrees_t latitude, degrees_t longitude); -uint32_t dive_site_uuid_by_name(const char *name); struct dive_site *get_or_create_dive_site_by_uuid(uint32_t uuid); #ifdef __cplusplus diff --git a/parse-xml.c b/parse-xml.c index 6cc2d881a..55744d275 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -982,7 +982,7 @@ static void divinglog_place(char *place, uint32_t *uuid) city ? city : "", country ? ", " : "", country ? country : ""); - *uuid = get_dive_site_uuid_by_name(buffer); + *uuid = get_dive_site_uuid_by_name(buffer, NULL); if (*uuid == 0) *uuid = create_dive_site(buffer); @@ -1165,14 +1165,20 @@ static void gps_location(char *buffer, struct dive_site *ds) static void gps_in_dive(char *buffer, struct dive *dive) { char *end; - fprintf(stderr, "called gps_in_dive with buffer |%s|\n", buffer); + struct dive_site *ds = NULL; degrees_t latitude = parse_degrees(buffer, &end); degrees_t longitude = parse_degrees(end, &end); fprintf(stderr, "got lat %f lon %f\n", latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); uint32_t uuid = dive->dive_site_uuid; if (uuid == 0) { - fprintf(stderr, "found no uuid in dive, creating a divesite without name and above GPS\n"); - dive->dive_site_uuid = create_dive_site_with_gps("", latitude, longitude); + uuid = get_dive_site_uuid_by_gps(latitude, longitude, &ds); + if (ds) { + fprintf(stderr, "found dive site {%s} with these coordinates\n", ds->name); + dive->dive_site_uuid = uuid; + } else { + fprintf(stderr, "found no uuid in dive, no existing dive site with these coordinates, creating a new divesite without name and above GPS\n"); + dive->dive_site_uuid = create_dive_site_with_gps("", latitude, longitude); + } } else { fprintf(stderr, "found uuid in dive, checking to see if we should add GPS\n"); struct dive_site *ds = get_dive_site_by_uuid(uuid); @@ -1183,6 +1189,13 @@ static void gps_in_dive(char *buffer, struct dive *dive) fprintf(stderr, "dive site uuid in dive, but gps location (%10.6f/%10.6f) different from dive location (%10.6f/%10.6f)\n", ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0, latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + int len = ds->notes ? strlen(ds->notes) : 0; + len += sizeof("\nalternative coordinates") + 24; + char *notes = malloc(len); + snprintf(notes, len, "%s\nalternative coordinates %11.6f/%11.6f", + ds->notes ?: "", latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + free(ds->notes); + ds->notes = notes; } else { fprintf(stderr, "let's add the gps coordinates to divesite with uuid %8x and name %s\n", ds->uuid, ds->name ?: "(none)"); ds->latitude = latitude; @@ -1194,21 +1207,30 @@ static void gps_in_dive(char *buffer, struct dive *dive) static void add_dive_site(char *buffer, struct dive *dive) { fprintf(stderr, "add_dive_site with name %s\n", buffer); - int size; - size = trimspace(buffer); + int size = trimspace(buffer); if(size) { - if (dive->dive_site_uuid) { - // we have a uuid, let's hope there's no name - struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid); - if (!ds) { - fprintf(stderr, "dive contains a non-existing dive site uuid %x\n", dive->dive_site_uuid); - exit(1); - } - if (!same_string(ds->name, buffer)) { - fprintf(stderr, "dive links to dive site of different name %s / %s\n", ds->name, buffer); - exit(1); + uint32_t uuid = dive->dive_site_uuid; + struct dive_site *ds = get_dive_site_by_uuid(uuid); + if (uuid && !ds) { + // that's strange - we have a uuid but it doesn't exist - let's just ignore it + fprintf(stderr, "dive contains a non-existing dive site uuid %x\n", dive->dive_site_uuid); + uuid = 0; + } + if (!uuid) + // if the dive doesn't have a uuid, check if there's already a dive site by this name + uuid = get_dive_site_uuid_by_name(buffer, &ds); + if (ds) { + // we have a uuid, let's hope there isn't a different name + fprintf(stderr, "have existing site with name {%s} gps %f/%f ", ds->name, ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0); + if (same_string(ds->name, "")) { + fprintf(stderr, "so now add name {%s}\n", buffer); + ds->name = copy_string(buffer); + } else if (!same_string(ds->name, buffer)) { + // coin toss, let's just keep the first name we found + fprintf(stderr, "which means the dive already links to dive site of different name {%s} / {%s}\n", ds->name, buffer); } } else { + fprintf(stderr, "no uuid, create new dive site with name {%s}\n", buffer); dive->dive_site_uuid = create_dive_site(buffer); } } |