/** * Make a speed/distance map */ gdouble *vik_track_make_speed_dist_map ( const VikTrack *tr, guint16 num_chunks ) { gdouble *v, *s, *t; time_t t1, t2; gint i, pt_count, numpts, index; GList *iter; gdouble duration, total_length, chunk_length; if ( ! tr->trackpoints ) return NULL; t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp; t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp; duration = t2 - t1; if ( !t1 || !t2 || !duration ) return NULL; if (duration < 0) { g_warning("negative duration: unsorted trackpoint timestamps?"); return NULL; } total_length = vik_track_get_length_including_gaps ( tr ); chunk_length = total_length / num_chunks; pt_count = vik_track_get_tp_count(tr); if (chunk_length <= 0) { return NULL; } v = g_malloc ( sizeof(gdouble) * num_chunks ); s = g_malloc ( sizeof(double) * pt_count ); t = g_malloc ( sizeof(double) * pt_count ); // No special handling of segments ATM... iter = tr->trackpoints->next; numpts = 0; s[0] = 0; t[0] = VIK_TRACKPOINT(iter->prev->data)->timestamp; numpts++; while (iter) { s[numpts] = s[numpts-1] + vik_coord_diff ( &(VIK_TRACKPOINT(iter->prev->data)->coord), &(VIK_TRACKPOINT(iter->data)->coord) ); t[numpts] = VIK_TRACKPOINT(iter->data)->timestamp; numpts++; iter = iter->next; } // Iterate through a portion of the track to get an average speed for that part // This will essentially interpolate between segments, which I think is right given the usage of 'get_length_including_gaps' index = 0; /* index of the current trackpoint. */ for (i = 0; i < num_chunks; i++) { // Similar to the make_speed_map, but instead of using a time chunk, use a distance chunk if (s[0] + i*chunk_length >= s[index]) { gdouble acc_t = 0, acc_s = 0; while (s[0] + i*chunk_length >= s[index]) { acc_s += (s[index+1]-s[index]); acc_t += (t[index+1]-t[index]); index++; } v[i] = acc_s/acc_t; } else if (i) { v[i] = v[i-1]; } else { v[i] = 0; } } g_free(s); g_free(t); return v; }
/** * Make a distance/time map, heavily based on the vik_track_make_speed_map method */ gdouble *vik_track_make_distance_map ( const VikTrack *tr, guint16 num_chunks ) { gdouble *v, *s, *t; gdouble duration, chunk_dur; time_t t1, t2; int i, pt_count, numpts, index; GList *iter; if ( ! tr->trackpoints ) return NULL; t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp; t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp; duration = t2 - t1; if ( !t1 || !t2 || !duration ) return NULL; if (duration < 0) { g_warning("negative duration: unsorted trackpoint timestamps?"); return NULL; } pt_count = vik_track_get_tp_count(tr); v = g_malloc ( sizeof(gdouble) * num_chunks ); chunk_dur = duration / num_chunks; s = g_malloc(sizeof(double) * pt_count); t = g_malloc(sizeof(double) * pt_count); iter = tr->trackpoints->next; numpts = 0; s[0] = 0; t[0] = VIK_TRACKPOINT(iter->prev->data)->timestamp; numpts++; while (iter) { s[numpts] = s[numpts-1] + vik_coord_diff ( &(VIK_TRACKPOINT(iter->prev->data)->coord), &(VIK_TRACKPOINT(iter->data)->coord) ); t[numpts] = VIK_TRACKPOINT(iter->data)->timestamp; numpts++; iter = iter->next; } /* In the following computation, we iterate through periods of time of duration chunk_dur. * The first period begins at the beginning of the track. The last period ends at the end of the track. */ index = 0; /* index of the current trackpoint. */ for (i = 0; i < num_chunks; i++) { /* we are now covering the interval from t[0] + i*chunk_dur to t[0] + (i+1)*chunk_dur. * find the first trackpoint outside the current interval, averaging the distance between intermediate trackpoints. */ if (t[0] + i*chunk_dur >= t[index]) { gdouble acc_s = 0; // No need for acc_t while (t[0] + i*chunk_dur >= t[index]) { acc_s += (s[index+1]-s[index]); index++; } // The only bit that's really different from the speed map - just keep an accululative record distance v[i] = i ? v[i-1]+acc_s : acc_s; } else if (i) { v[i] = v[i-1]; } else { v[i] = 0; } } g_free(s); g_free(t); return v; }
/** * This uses the 'time' based method to make the graph, (which is a simpler compared to the elevation/distance) * This results in a slightly blocky graph when it does not have many trackpoints: <60 * NB Somehow the elevation/distance applies some kind of smoothing algorithm, * but I don't think any one understands it any more (I certainly don't ATM) */ gdouble *vik_track_make_elevation_time_map ( const VikTrack *tr, guint16 num_chunks ) { time_t t1, t2; gdouble duration, chunk_dur; GList *iter = tr->trackpoints; if (!iter || !iter->next) /* zero- or one-point track */ return NULL; /* test if there's anything worth calculating */ gboolean okay = FALSE; while ( iter ) { if ( VIK_TRACKPOINT(iter->data)->altitude != VIK_DEFAULT_ALTITUDE ) { okay = TRUE; break; } iter = iter->next; } if ( ! okay ) return NULL; t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp; t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp; duration = t2 - t1; if ( !t1 || !t2 || !duration ) return NULL; if (duration < 0) { g_warning("negative duration: unsorted trackpoint timestamps?"); return NULL; } gint pt_count = vik_track_get_tp_count(tr); // Reset iterator back to the beginning iter = tr->trackpoints; gdouble *pts = g_malloc ( sizeof(gdouble) * num_chunks ); // The return altitude values gdouble *s = g_malloc(sizeof(double) * pt_count); // calculation altitudes gdouble *t = g_malloc(sizeof(double) * pt_count); // calculation times chunk_dur = duration / num_chunks; s[0] = VIK_TRACKPOINT(iter->data)->altitude; t[0] = VIK_TRACKPOINT(iter->data)->timestamp; iter = tr->trackpoints->next; gint numpts = 1; while (iter) { s[numpts] = VIK_TRACKPOINT(iter->data)->altitude; t[numpts] = VIK_TRACKPOINT(iter->data)->timestamp; numpts++; iter = iter->next; } /* In the following computation, we iterate through periods of time of duration chunk_dur. * The first period begins at the beginning of the track. The last period ends at the end of the track. */ gint index = 0; /* index of the current trackpoint. */ gint i; for (i = 0; i < num_chunks; i++) { /* we are now covering the interval from t[0] + i*chunk_dur to t[0] + (i+1)*chunk_dur. * find the first trackpoint outside the current interval, averaging the heights between intermediate trackpoints. */ if (t[0] + i*chunk_dur >= t[index]) { gdouble acc_s = s[index]; // initialise to first point while (t[0] + i*chunk_dur >= t[index]) { acc_s += (s[index+1]-s[index]); index++; } pts[i] = acc_s; } else if (i) { pts[i] = pts[i-1]; } else { pts[i] = 0; } } g_free(s); g_free(t); return pts; }
/** * @val_analyse_track: * @trk: The track to be analyse * * Function to collect statistics, using the internal track functions */ static void val_analyse_track ( VikTrack *trk ) { //val_reset ( TS_TRACK ); gdouble min_alt; gdouble max_alt; gdouble up; gdouble down; gdouble length = 0.0; gdouble length_gaps = 0.0; gdouble max_speed = 0.0; gulong trackpoints = 0; guint segments = 0; tracks_stats[TS_TRACKS].count++; trackpoints = vik_track_get_tp_count (trk); segments = vik_track_get_segment_count (trk); length = vik_track_get_length (trk); length_gaps = vik_track_get_length_including_gaps (trk); max_speed = vik_track_get_max_speed (trk); if ( !trk->is_route ) { // Eddington number will be in the current Units distance preference gdouble e_len; switch (a_vik_get_units_distance ()) { case VIK_UNITS_DISTANCE_MILES: e_len = VIK_METERS_TO_MILES(length); break; case VIK_UNITS_DISTANCE_NAUTICAL_MILES: e_len = VIK_METERS_TO_NAUTICAL_MILES(length); break; //VIK_UNITS_DISTANCE_KILOMETRES default: e_len = length/1000.0; break; } gdouble *gd = g_malloc ( sizeof(gdouble) ); *gd = e_len; tracks_stats[TS_TRACKS].e_list = g_list_prepend ( tracks_stats[TS_TRACKS].e_list, gd ); } int ii; for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { tracks_stats[ii].trackpoints += trackpoints; tracks_stats[ii].segments += segments; tracks_stats[ii].length += length; tracks_stats[ii].length_gaps += length_gaps; if ( max_speed > tracks_stats[ii].max_speed ) tracks_stats[ii].max_speed = max_speed; } if ( vik_track_get_minmax_alt (trk, &min_alt, &max_alt) ) { for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { if ( min_alt < tracks_stats[ii].min_alt ) tracks_stats[ii].min_alt = min_alt; if ( max_alt > tracks_stats[ii].max_alt ) tracks_stats[ii].max_alt = max_alt; } } vik_track_get_total_elevation_gain (trk, &up, &down ); for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { tracks_stats[ii].elev_gain += up; tracks_stats[ii].elev_loss += down; } if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->timestamp ) { time_t t1, t2; t1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data)->timestamp; t2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data)->timestamp; // Assume never actually have a track with a time of 0 (1st Jan 1970) for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { if ( tracks_stats[ii].start_time == 0) tracks_stats[ii].start_time = t1; if ( tracks_stats[ii].end_time == 0) tracks_stats[ii].end_time = t2; } // Initialize to the first value for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { if (t1 < tracks_stats[ii].start_time) tracks_stats[ii].start_time = t1; if (t2 > tracks_stats[ii].end_time) tracks_stats[ii].end_time = t2; } for (ii = 0; ii < G_N_ELEMENTS(tracks_stats); ii++) { tracks_stats[ii].duration = tracks_stats[ii].duration + (int)(t2-t1); } } }