X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/8499a412948056d494f375f55a0a330b9e826c0a..9cdc601fa56a10312099cfabd16b5c8d628a0e67:/src/gpspoint.c?ds=inline diff --git a/src/gpspoint.c b/src/gpspoint.c index 933ff5b9..bee2d337 100644 --- a/src/gpspoint.c +++ b/src/gpspoint.c @@ -2,6 +2,7 @@ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager * * Copyright (C) 2003-2005, Evan Battaglia + * Copyright (C) 2012-2013, Rob Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,21 +19,32 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_MATH_H #include +#endif + #include "viking.h" #include +#ifdef HAVE_STRING_H #include +#endif #include /* strtod */ +typedef struct { + FILE *f; + gboolean is_route; +} TP_write_info_type; -static void a_gpspoint_write_track ( const gchar *name, VikTrack *t, FILE *f ); -static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, FILE *f ); -static void a_gpspoint_write_waypoint ( const gchar *name, VikWaypoint *wp, FILE *f ); - +static void a_gpspoint_write_track ( const gpointer id, const VikTrack *t, FILE *f ); +static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, TP_write_info_type *write_info ); +static void a_gpspoint_write_waypoint ( const gpointer id, const VikWaypoint *wp, FILE *f ); /* outline for file gpspoint.c @@ -53,10 +65,9 @@ static char line_buffer[2048]; #define GPSPOINT_TYPE_NONE 0 #define GPSPOINT_TYPE_WAYPOINT 1 #define GPSPOINT_TYPE_TRACKPOINT 2 -/* #define GPSPOINT_TYPE_ROUTEPOINT 3 */ +#define GPSPOINT_TYPE_ROUTEPOINT 3 #define GPSPOINT_TYPE_TRACK 4 - -/* #define GPSPOINT_TYPE_ROUTE 5 */ +#define GPSPOINT_TYPE_ROUTE 5 static VikTrack *current_track; /* pointer to pointer to first GList */ @@ -64,6 +75,10 @@ static gint line_type = GPSPOINT_TYPE_NONE; static struct LatLon line_latlon; static gchar *line_name; static gchar *line_comment; +static gchar *line_description; +static gchar *line_color; +static gint line_name_label = 0; +static gint line_dist_label = 0; static gchar *line_image; static gchar *line_symbol; static gboolean line_newsegment = FALSE; @@ -136,7 +151,12 @@ static gchar *deslashndup ( const gchar *str, guint16 len ) return rv; } -void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { +/* + * Returns whether file read was a success + * No obvious way to test for a 'gpspoint' file, + * thus set a flag if any actual tag found during processing of the file + */ +gboolean a_gpspoint_read_file(VikTrwLayer *trw, FILE *f, const gchar *dirpath ) { VikCoordMode coord_mode = vik_trw_layer_get_coord_mode ( trw ); gchar *tag_start, *tag_end; g_assert ( f != NULL && trw != NULL ); @@ -145,8 +165,9 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { line_newsegment = FALSE; line_image = NULL; line_symbol = NULL; - current_track = NULL; + gboolean have_read_something = FALSE; + while (fgets(line_buffer, 2048, f)) { gboolean inside_quote = 0; @@ -155,10 +176,13 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { line_buffer[strlen(line_buffer)-1] = '\0'; /* chop off newline */ /* for gpspoint files wrapped inside */ - if ( strlen(line_buffer) >= 13 && strncmp ( line_buffer, "~EndLayerData", 13 ) == 0 ) + if ( strlen(line_buffer) >= 13 && strncmp ( line_buffer, "~EndLayerData", 13 ) == 0 ) { + // Even just a blank TRW is ok when in a .vik file + have_read_something = TRUE; break; + } -/* each line: nullify stuff, make thing if nes, free name if ness */ + /* each line: nullify stuff, make thing if nes, free name if ness */ tag_start = line_buffer; for (;;) { @@ -193,9 +217,12 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { } if (line_type == GPSPOINT_TYPE_WAYPOINT && line_name) { + have_read_something = TRUE; VikWaypoint *wp = vik_waypoint_new(); wp->visible = line_visible; wp->altitude = line_altitude; + wp->has_timestamp = line_has_timestamp; + wp->timestamp = line_timestamp; vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &line_latlon ); @@ -204,38 +231,56 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { line_name = NULL; if ( line_comment ) - { vik_waypoint_set_comment ( wp, line_comment ); - line_comment = NULL; - } - if ( line_image ) - { - vik_waypoint_set_image ( wp, line_image ); - line_image = NULL; + if ( line_description ) + vik_waypoint_set_description ( wp, line_description ); + + if ( line_image ) { + // Ensure the filename is absolute + if ( g_path_is_absolute ( line_image ) ) + vik_waypoint_set_image ( wp, line_image ); + else { + // Otherwise create the absolute filename from the directory of the .vik file & and the relative filename + gchar *full = g_strconcat(dirpath, G_DIR_SEPARATOR_S, line_image, NULL); + gchar *absolute = file_realpath_dup ( full ); // resolved into the canonical name + vik_waypoint_set_image ( wp, absolute ); + g_free ( absolute ); + g_free ( full ); + } } if ( line_symbol ) - { vik_waypoint_set_symbol ( wp, line_symbol ); - line_symbol = NULL; - } } - else if (line_type == GPSPOINT_TYPE_TRACK && line_name) + else if ((line_type == GPSPOINT_TYPE_TRACK || line_type == GPSPOINT_TYPE_ROUTE) && line_name) { + have_read_something = TRUE; VikTrack *pl = vik_track_new(); + // NB don't set defaults here as all properties are stored in the GPS_POINT format + //vik_track_set_defaults ( pl ); /* Thanks to Peter Jones for this Fix */ if (!line_name) line_name = g_strdup("UNK"); pl->visible = line_visible; + pl->is_route = (line_type == GPSPOINT_TYPE_ROUTE); if ( line_comment ) - { vik_track_set_comment ( pl, line_comment ); - line_comment = NULL; + + if ( line_description ) + vik_track_set_description ( pl, line_description ); + + if ( line_color ) + { + if ( gdk_color_parse ( line_color, &(pl->color) ) ) + pl->has_color = TRUE; } + pl->draw_name_mode = line_name_label; + pl->max_number_dist_labels = line_dist_label; + pl->trackpoints = NULL; vik_trw_layer_filein_add_track ( trw, line_name, pl ); g_free ( line_name ); @@ -243,37 +288,41 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { current_track = pl; } - else if (line_type == GPSPOINT_TYPE_TRACKPOINT && current_track) + else if ((line_type == GPSPOINT_TYPE_TRACKPOINT || line_type == GPSPOINT_TYPE_ROUTEPOINT) && current_track) { + have_read_something = TRUE; VikTrackpoint *tp = vik_trackpoint_new(); vik_coord_load_from_latlon ( &(tp->coord), coord_mode, &line_latlon ); tp->newsegment = line_newsegment; tp->has_timestamp = line_has_timestamp; tp->timestamp = line_timestamp; tp->altitude = line_altitude; + vik_trackpoint_set_name ( tp, line_name ); if (line_extended) { - tp->extended = TRUE; tp->speed = line_speed; tp->course = line_course; tp->nsats = line_sat; tp->fix_mode = line_fix; } - else { - tp->extended = FALSE; - } current_track->trackpoints = g_list_append ( current_track->trackpoints, tp ); } if (line_name) g_free ( line_name ); line_name = NULL; - if (line_comment) + if (line_comment) g_free ( line_comment ); + if (line_description) + g_free ( line_description ); + if (line_color) + g_free ( line_color ); if (line_image) g_free ( line_image ); if (line_symbol) g_free ( line_symbol ); line_comment = NULL; + line_description = NULL; + line_color = NULL; line_image = NULL; line_symbol = NULL; line_type = GPSPOINT_TYPE_NONE; @@ -289,7 +338,11 @@ void a_gpspoint_read_file(VikTrwLayer *trw, FILE *f ) { line_course = NAN; line_sat = 0; line_fix = 0; + line_name_label = 0; + line_dist_label = 0; } + + return have_read_something; } /* Tag will be of a few defined forms: @@ -355,6 +408,10 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con line_type = GPSPOINT_TYPE_TRACKPOINT; else if (value_len == 8 && strncasecmp( value, "waypoint", value_len ) == 0 ) line_type = GPSPOINT_TYPE_WAYPOINT; + else if (value_len == 5 && strncasecmp( value, "route", value_len ) == 0 ) + line_type = GPSPOINT_TYPE_ROUTE; + else if (value_len == 10 && strncasecmp( value, "routepoint", value_len ) == 0 ) + line_type = GPSPOINT_TYPE_ROUTEPOINT; else /* all others are ignored */ line_type = GPSPOINT_TYPE_NONE; @@ -363,7 +420,7 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con { if (line_name == NULL) { - line_name = g_strndup ( value, value_len ); + line_name = deslashndup ( value, value_len ); } } else if (key_len == 7 && strncasecmp( key, "comment", key_len ) == 0 && value != NULL) @@ -371,6 +428,24 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con if (line_comment == NULL) line_comment = deslashndup ( value, value_len ); } + else if (key_len == 11 && strncasecmp( key, "description", key_len ) == 0 && value != NULL) + { + if (line_description == NULL) + line_description = deslashndup ( value, value_len ); + } + else if (key_len == 5 && strncasecmp( key, "color", key_len ) == 0 && value != NULL) + { + if (line_color == NULL) + line_color = deslashndup ( value, value_len ); + } + else if (key_len == 14 && strncasecmp( key, "draw_name_mode", key_len ) == 0 && value != NULL) + { + line_name_label = atoi(value); + } + else if (key_len == 18 && strncasecmp( key, "number_dist_labels", key_len ) == 0 && value != NULL) + { + line_dist_label = atoi(value); + } else if (key_len == 5 && strncasecmp( key, "image", key_len ) == 0 && value != NULL) { if (line_image == NULL) @@ -378,15 +453,15 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con } else if (key_len == 8 && strncasecmp( key, "latitude", key_len ) == 0 && value != NULL) { - line_latlon.lat = g_strtod(value, NULL); + line_latlon.lat = g_ascii_strtod(value, NULL); } else if (key_len == 9 && strncasecmp( key, "longitude", key_len ) == 0 && value != NULL) { - line_latlon.lon = g_strtod(value, NULL); + line_latlon.lon = g_ascii_strtod(value, NULL); } else if (key_len == 8 && strncasecmp( key, "altitude", key_len ) == 0 && value != NULL) { - line_altitude = g_strtod(value, NULL); + line_altitude = g_ascii_strtod(value, NULL); } else if (key_len == 7 && strncasecmp( key, "visible", key_len ) == 0 && value[0] != 'y' && value[0] != 'Y' && value[0] != 't' && value[0] != 'T') { @@ -398,7 +473,7 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con } else if (key_len == 8 && strncasecmp( key, "unixtime", key_len ) == 0 && value != NULL) { - line_timestamp = g_strtod(value, NULL); + line_timestamp = g_ascii_strtod(value, NULL); if ( line_timestamp != 0x80000000 ) line_has_timestamp = TRUE; } @@ -412,11 +487,11 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con } else if (key_len == 5 && strncasecmp( key, "speed", key_len ) == 0 && value != NULL) { - line_speed = g_strtod(value, NULL); + line_speed = g_ascii_strtod(value, NULL); } else if (key_len == 6 && strncasecmp( key, "course", key_len ) == 0 && value != NULL) { - line_course = g_strtod(value, NULL); + line_course = g_ascii_strtod(value, NULL); } else if (key_len == 3 && strncasecmp( key, "sat", key_len ) == 0 && value != NULL) { @@ -428,14 +503,20 @@ static void gpspoint_process_key_and_value ( const gchar *key, gint key_len, con } } -static void a_gpspoint_write_waypoint ( const gchar *name, VikWaypoint *wp, FILE *f ) +static void a_gpspoint_write_waypoint ( const gpointer id, const VikWaypoint *wp, FILE *f ) { static struct LatLon ll; gchar *s_lat, *s_lon; + // Sanity clause + if ( wp && !(wp->name) ) { + return; + } vik_coord_to_latlon ( &(wp->coord), &ll ); s_lat = a_coords_dtostr(ll.lat); s_lon = a_coords_dtostr(ll.lon); - fprintf ( f, "type=\"waypoint\" latitude=\"%s\" longitude=\"%s\" name=\"%s\"", s_lat, s_lon, name ); + gchar *tmp_name = slashdup(wp->name); + fprintf ( f, "type=\"waypoint\" latitude=\"%s\" longitude=\"%s\" name=\"%s\"", s_lat, s_lon, tmp_name ); + g_free ( tmp_name ); g_free ( s_lat ); g_free ( s_lon ); @@ -444,41 +525,77 @@ static void a_gpspoint_write_waypoint ( const gchar *name, VikWaypoint *wp, FILE fprintf ( f, " altitude=\"%s\"", s_alt ); g_free(s_alt); } + if ( wp->has_timestamp ) + fprintf ( f, " unixtime=\"%ld\"", wp->timestamp ); if ( wp->comment ) { gchar *tmp_comment = slashdup(wp->comment); fprintf ( f, " comment=\"%s\"", tmp_comment ); g_free ( tmp_comment ); } + if ( wp->description ) + { + gchar *tmp_description = slashdup(wp->description); + fprintf ( f, " description=\"%s\"", tmp_description ); + g_free ( tmp_description ); + } if ( wp->image ) { - gchar *tmp_image = slashdup(wp->image); - fprintf ( f, " image=\"%s\"", tmp_image ); + gchar *tmp_image = NULL; + gchar *cwd = NULL; + if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) { + cwd = g_get_current_dir(); + if ( cwd ) + tmp_image = g_strdup ( file_GetRelativeFilename ( cwd, wp->image ) ); + } + + // if cwd not available - use image filename as is + // this should be an absolute path as set in thumbnails + if ( !cwd ) + tmp_image = slashdup(wp->image); + + if ( tmp_image ) + fprintf ( f, " image=\"%s\"", tmp_image ); + + g_free ( cwd ); g_free ( tmp_image ); } if ( wp->symbol ) { - fprintf ( f, " symbol=\"%s\"", wp->symbol ); + // Due to changes in garminsymbols - the symbol name is now in Title Case + // However to keep newly generated .vik files better compatible with older Viking versions + // The symbol names will always be lowercase + gchar *tmp_symbol = g_utf8_strdown(wp->symbol, -1); + fprintf ( f, " symbol=\"%s\"", tmp_symbol ); + g_free ( tmp_symbol ); } if ( ! wp->visible ) fprintf ( f, " visible=\"n\"" ); fprintf ( f, "\n" ); } -static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, FILE *f ) +static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, TP_write_info_type *write_info ) { static struct LatLon ll; gchar *s_lat, *s_lon; vik_coord_to_latlon ( &(tp->coord), &ll ); + FILE *f = write_info->f; + /* TODO: modify a_coords_dtostr() to accept (optional) buffer * instead of doing malloc/free everytime */ s_lat = a_coords_dtostr(ll.lat); s_lon = a_coords_dtostr(ll.lon); - fprintf ( f, "type=\"trackpoint\" latitude=\"%s\" longitude=\"%s\"", s_lat, s_lon ); + fprintf ( f, "type=\"%spoint\" latitude=\"%s\" longitude=\"%s\"", write_info->is_route ? "route" : "track", s_lat, s_lon ); g_free ( s_lat ); g_free ( s_lon ); + if ( tp->name ) { + gchar *name = slashdup(tp->name); + fprintf ( f, " name=\"%s\"", name ); + g_free(name); + } + if ( tp->altitude != VIK_DEFAULT_ALTITUDE ) { gchar *s_alt = a_coords_dtostr(tp->altitude); fprintf ( f, " altitude=\"%s\"", s_alt ); @@ -489,7 +606,7 @@ static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, FILE *f ) if ( tp->newsegment ) fprintf ( f, " newsegment=\"yes\"" ); - if (tp->extended) { + if (!isnan(tp->speed) || !isnan(tp->course) || tp->nsats > 0) { fprintf ( f, " extended=\"yes\"" ); if (!isnan(tp->speed)) { gchar *s_speed = a_coords_dtostr(tp->speed); @@ -510,27 +627,59 @@ static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, FILE *f ) } -static void a_gpspoint_write_track ( const gchar *name, VikTrack *t, FILE *f ) +static void a_gpspoint_write_track ( const gpointer id, const VikTrack *trk, FILE *f ) { - if ( t->comment ) - { - gchar *tmp_comment = slashdup(t->comment); - fprintf ( f, "type=\"track\" name=\"%s\" comment=\"%s\"%s\n", name, tmp_comment, t->visible ? "" : " visible=\"n\"" ); - g_free ( tmp_comment ); + // Sanity clauses + if ( !trk ) + return; + if ( !(trk->name) ) + return; + + gchar *tmp_name = slashdup(trk->name); + fprintf ( f, "type=\"%s\" name=\"%s\"", trk->is_route ? "route" : "track", tmp_name ); + g_free ( tmp_name ); + + if ( trk->comment ) { + gchar *tmp = slashdup(trk->comment); + fprintf ( f, " comment=\"%s\"", tmp ); + g_free ( tmp ); } - else - fprintf ( f, "type=\"track\" name=\"%s\"%s\n", name, t->visible ? "" : " visible=\"n\"" ); - g_list_foreach ( t->trackpoints, (GFunc) a_gpspoint_write_trackpoint, f ); - fprintf ( f, "type=\"trackend\"\n" ); + + if ( trk->description ) { + gchar *tmp = slashdup(trk->description); + fprintf ( f, " description=\"%s\"", tmp ); + g_free ( tmp ); + } + + if ( trk->has_color ) { + fprintf ( f, " color=#%.2x%.2x%.2x", (int)(trk->color.red/256),(int)(trk->color.green/256),(int)(trk->color.blue/256)); + } + + if ( trk->draw_name_mode > 0 ) + fprintf ( f, " draw_name_mode=\"%d\"", trk->draw_name_mode ); + + if ( trk->max_number_dist_labels > 0 ) + fprintf ( f, " number_dist_labels=\"%d\"", trk->max_number_dist_labels ); + + if ( ! trk->visible ) { + fprintf ( f, " visible=\"n\"" ); + } + fprintf ( f, "\n" ); + + TP_write_info_type tp_write_info = { f, trk->is_route }; + g_list_foreach ( trk->trackpoints, (GFunc) a_gpspoint_write_trackpoint, &tp_write_info ); + fprintf ( f, "type=\"%send\"\n", trk->is_route ? "route" : "track" ); } void a_gpspoint_write_file ( VikTrwLayer *trw, FILE *f ) { GHashTable *tracks = vik_trw_layer_get_tracks ( trw ); + GHashTable *routes = vik_trw_layer_get_routes ( trw ); GHashTable *waypoints = vik_trw_layer_get_waypoints ( trw ); fprintf ( f, "type=\"waypointlist\"\n" ); g_hash_table_foreach ( waypoints, (GHFunc) a_gpspoint_write_waypoint, f ); fprintf ( f, "type=\"waypointlistend\"\n" ); g_hash_table_foreach ( tracks, (GHFunc) a_gpspoint_write_track, f ); + g_hash_table_foreach ( routes, (GHFunc) a_gpspoint_write_track, f ); }