]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrack.c
Fix <GTK 2.24 combo box usage.
[andy/viking.git] / src / viktrack.c
index f5309cce3020b707c2bf36a9250e32badb1a8eda..6eb685ad5c7a71382ccd96af730946e6eb9df870 100644 (file)
@@ -90,7 +90,8 @@ void vik_track_free(VikTrack *tr)
   g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
   g_list_free( tr->trackpoints );
   if (tr->property_dialog)
   g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
   g_list_free( tr->trackpoints );
   if (tr->property_dialog)
-    gtk_widget_destroy ( GTK_WIDGET(tr->property_dialog) );
+    if ( GTK_IS_WIDGET(tr->property_dialog) )
+      gtk_widget_destroy ( GTK_WIDGET(tr->property_dialog) );
   g_free ( tr );
 }
 
   g_free ( tr );
 }
 
@@ -411,7 +412,8 @@ gdouble *vik_track_make_elevation_map ( const VikTrack *tr, guint16 num_chunks )
        **/
 
       if ( ignore_it )
        **/
 
       if ( ignore_it )
-        pts[current_chunk] = VIK_DEFAULT_ALTITUDE;
+       // Seemly can't determine average for this section - so use last known good value (much better than just sticking in zero)
+        pts[current_chunk] = altitude1;
       else
         pts[current_chunk] = altitude1 + (altitude2-altitude1)*((dist_along_seg - (chunk_length/2))/current_seg_length);
 
       else
         pts[current_chunk] = altitude1 + (altitude2-altitude1)*((dist_along_seg - (chunk_length/2))/current_seg_length);
 
@@ -543,12 +545,10 @@ gdouble *vik_track_make_speed_map ( const VikTrack *tr, guint16 num_chunks )
      */
     if (t[0] + i*chunk_dur >= t[index]) {
       gdouble acc_t = 0, acc_s = 0;
      */
     if (t[0] + i*chunk_dur >= t[index]) {
       gdouble acc_t = 0, acc_s = 0;
-      numpts = 0;
       while (t[0] + i*chunk_dur >= t[index]) {
        acc_s += (s[index+1]-s[index]);
        acc_t += (t[index+1]-t[index]);
        index++;
       while (t[0] + i*chunk_dur >= t[index]) {
        acc_s += (s[index+1]-s[index]);
        acc_t += (t[index+1]-t[index]);
        index++;
-       numpts++;
       }
       v[i] = acc_s/acc_t;
     } 
       }
       v[i] = acc_s/acc_t;
     } 
@@ -564,6 +564,247 @@ gdouble *vik_track_make_speed_map ( const VikTrack *tr, guint16 num_chunks )
   return v;
 }
 
   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;
+}
+
+/**
+ * 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;
+}
+
 /* by Alex Foobarian */
 VikTrackpoint *vik_track_get_closest_tp_by_percentage_dist ( VikTrack *tr, gdouble reldist, gdouble *meters_from_start )
 {
 /* by Alex Foobarian */
 VikTrackpoint *vik_track_get_closest_tp_by_percentage_dist ( VikTrack *tr, gdouble reldist, gdouble *meters_from_start )
 {
@@ -826,6 +1067,20 @@ void vik_track_apply_dem_data ( VikTrack *tr )
   }
 }
 
   }
 }
 
+/*
+ * Apply DEM data (if available) - to only the last trackpoint
+ */
+void vik_track_apply_dem_data_last_trackpoint ( VikTrack *tr )
+{
+  gint16 elev;
+  if ( tr->trackpoints ) {
+    /* As in vik_track_apply_dem_data above - use 'best' interpolation method */
+    elev = a_dems_get_elev_by_coord ( &(VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->coord), VIK_DEM_INTERPOL_BEST );
+    if ( elev != VIK_DEM_INVALID_ELEVATION )
+      VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->altitude = elev;
+  }
+}
+
 /* appends t2 to t1, leaving t2 with no trackpoints */
 void vik_track_steal_and_append_trackpoints ( VikTrack *t1, VikTrack *t2 )
 {
 /* appends t2 to t1, leaving t2 with no trackpoints */
 void vik_track_steal_and_append_trackpoints ( VikTrack *t1, VikTrack *t2 )
 {
@@ -841,9 +1096,8 @@ void vik_track_steal_and_append_trackpoints ( VikTrack *t1, VikTrack *t2 )
 }
 
 /* starting at the end, looks backwards for the last "double point", a duplicate trackpoint.
 }
 
 /* starting at the end, looks backwards for the last "double point", a duplicate trackpoint.
- * this is indicative of magic scissors continued use. If there is no double point,
- * deletes all the trackpoints. Returns the new end of the track (or the start if
- * there are no double points
+ * If there is no double point, deletes all the trackpoints.
+ * Returns the new end of the track (or the start if there are no double points)
  */
 VikCoord *vik_track_cut_back_to_double_point ( VikTrack *tr )
 {
  */
 VikCoord *vik_track_cut_back_to_double_point ( VikTrack *tr )
 {