コード例 #1
0
ファイル: gpx.c プロジェクト: idaohang/viking-1
static void gpx_write_track ( const gchar *name, VikTrack *t, GpxWritingContext *context )
{
  FILE *f = context->file;
  gchar *tmp;
  gboolean first_tp_is_newsegment = FALSE; /* must temporarily make it not so, but we want to restore state. not that it matters. */

  tmp = entitize ( name );
  fprintf ( f, "<trk%s>\n  <name>%s</name>\n", t->visible ? "" : " hidden=\"hidden\"", tmp );
  g_free ( tmp );

  if ( t->comment )
  {
    tmp = entitize ( t->comment );
    fprintf ( f, "  <desc>%s</desc>\n", tmp );
    g_free ( tmp );
  }

  fprintf ( f, "  <trkseg>\n" );

  if ( t->trackpoints && t->trackpoints->data ) {
    first_tp_is_newsegment = VIK_TRACKPOINT(t->trackpoints->data)->newsegment;
    VIK_TRACKPOINT(t->trackpoints->data)->newsegment = FALSE; /* so we won't write </trkseg><trkseg> already */
    g_list_foreach ( t->trackpoints, (GFunc) gpx_write_trackpoint, context );
    VIK_TRACKPOINT(t->trackpoints->data)->newsegment = first_tp_is_newsegment; /* restore state */
  }

  fprintf ( f, "</trkseg>\n</trk>\n" );
}
コード例 #2
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/*
 * 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;
  }
}
コード例 #3
0
ファイル: gpx.c プロジェクト: idaohang/viking
static void gpx_write_track ( VikTrack *t, GpxWritingContext *context )
{
  // Don't write invisible tracks when specified
  if (context->options && !context->options->hidden && !t->visible)
    return;

  FILE *f = context->file;
  gchar *tmp;
  gboolean first_tp_is_newsegment = FALSE; /* must temporarily make it not so, but we want to restore state. not that it matters. */

  // Sanity clause
  if ( t->name )
    tmp = entitize ( t->name );
  else
    tmp = g_strdup ("track");

  // NB 'hidden' is not part of any GPX standard - this appears to be a made up Viking 'extension'
  //  luckily most other GPX processing software ignores things they don't understand
  fprintf ( f, "<%s%s>\n  <name>%s</name>\n",
	    t->is_route ? "rte" : "trk",
	    t->visible ? "" : " hidden=\"hidden\"",
	    tmp );
  g_free ( tmp );

  if ( t->comment )
  {
    tmp = entitize ( t->comment );
    fprintf ( f, "  <cmt>%s</cmt>\n", tmp );
    g_free ( tmp );
  }

  if ( t->description )
  {
    tmp = entitize ( t->description );
    fprintf ( f, "  <desc>%s</desc>\n", tmp );
    g_free ( tmp );
  }

  /* No such thing as a rteseg! */
  if ( !t->is_route )
    fprintf ( f, "  <trkseg>\n" );

  if ( t->trackpoints && t->trackpoints->data ) {
    first_tp_is_newsegment = VIK_TRACKPOINT(t->trackpoints->data)->newsegment;
    VIK_TRACKPOINT(t->trackpoints->data)->newsegment = FALSE; /* so we won't write </trkseg><trkseg> already */
    g_list_foreach ( t->trackpoints, (GFunc) gpx_write_trackpoint, context );
    VIK_TRACKPOINT(t->trackpoints->data)->newsegment = first_tp_is_newsegment; /* restore state */
  }

  /* NB apparently no such thing as a rteseg! */
  if (!t->is_route)
    fprintf ( f, "  </trkseg>\n");

  fprintf ( f, "</%s>\n", t->is_route ? "rte" : "trk" );
}
コード例 #4
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/**
 * Based on a simple average speed, but with a twist - to give a moving average.
 *  . GPSs often report a moving average in their statistics output
 *  . bicycle speedos often don't factor in time when stopped - hence reporting a moving average for speed
 *
 * Often GPS track will record every second but not when stationary
 * This method doesn't use samples that differ over the specified time limit - effectively skipping that time chunk from the total time
 *
 * Suggest to use 60 seconds as the stop length (as the default used in the TrackWaypoint draw stops factor)
 */
gdouble vik_track_get_average_speed_moving (const VikTrack *tr, int stop_length_seconds)
{
  gdouble len = 0.0;
  guint32 time = 0;
  if ( tr->trackpoints )
  {
    GList *iter = tr->trackpoints->next;
    while (iter)
    {
      if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
          VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
          (! VIK_TRACKPOINT(iter->data)->newsegment) )
      {
	if ( ( VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp ) < stop_length_seconds ) {
	  len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
				  &(VIK_TRACKPOINT(iter->prev->data)->coord) );
	
	  time += ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
	}
      }
      iter = iter->next;
    }
  }
  return (time == 0) ? 0 : ABS(len/time);
}
コード例 #5
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
gulong vik_track_get_dup_point_count ( const VikTrack *tr )
{
  gulong num = 0;
  GList *iter = tr->trackpoints;
  while ( iter )
  {
    if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
                       &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
      num++;
    iter = iter->next;
  }
  return num;
}
コード例 #6
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
VikTrackpoint* vik_track_get_tp_by_max_speed ( const VikTrack *tr )
{
  gdouble maxspeed = 0.0, speed = 0.0;

  if ( !tr->trackpoints )
    return NULL;

  GList *iter = tr->trackpoints;
  VikTrackpoint *max_speed_tp = NULL;

  while (iter) {
    if (iter->prev) {
      if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
	   VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
	   (! VIK_TRACKPOINT(iter->data)->newsegment) ) {
	speed =  vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord), &(VIK_TRACKPOINT(iter->prev->data)->coord) )
	  / ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
	if ( speed > maxspeed ) {
	  maxspeed = speed;
	  max_speed_tp = VIK_TRACKPOINT(iter->data);
	}
      }
    }
    iter = iter->next;
  }
  
  if (!max_speed_tp)
    return NULL;

  return max_speed_tp;
}
コード例 #7
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
void vik_track_remove_dup_points ( VikTrack *tr )
{
  GList *iter = tr->trackpoints;
  while ( iter )
  {
    if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
                       &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
    {
      g_free ( iter->next->data );
      tr->trackpoints = g_list_delete_link ( tr->trackpoints, iter->next );
    }
    else
      iter = iter->next;
  }
}
コード例 #8
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
gdouble vik_track_get_length_including_gaps(const VikTrack *tr)
{
  gdouble len = 0.0;
  if ( tr->trackpoints )
  {
    GList *iter = tr->trackpoints->next;
    while (iter)
    {
      len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
                              &(VIK_TRACKPOINT(iter->prev->data)->coord) );
      iter = iter->next;
    }
  }
  return len;
}
コード例 #9
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
void vik_track_apply_dem_data ( VikTrack *tr )
{
  GList *tp_iter;
  gint16 elev;
  tp_iter = tr->trackpoints;
  while ( tp_iter ) {
    /* TODO: of the 4 possible choices we have for choosing an elevation
     * (trackpoint in between samples), choose the one with the least elevation change
     * as the last */
    elev = a_dems_get_elev_by_coord ( &(VIK_TRACKPOINT(tp_iter->data)->coord), VIK_DEM_INTERPOL_BEST );
    if ( elev != VIK_DEM_INVALID_ELEVATION )
      VIK_TRACKPOINT(tp_iter->data)->altitude = elev;
    tp_iter = tp_iter->next;
  }
}
コード例 #10
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/* by Alex Foobarian */
VikTrackpoint *vik_track_get_closest_tp_by_percentage_dist ( VikTrack *tr, gdouble reldist, gdouble *meters_from_start )
{
  gdouble dist = vik_track_get_length_including_gaps(tr) * reldist;
  gdouble current_dist = 0.0;
  gdouble current_inc = 0.0;
  if ( tr->trackpoints )
  {
    GList *iter = tr->trackpoints->next;
    GList *last_iter = NULL;
    gdouble last_dist = 0.0;
    while (iter)
    {
      current_inc = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
                                     &(VIK_TRACKPOINT(iter->prev->data)->coord) );
      last_dist = current_dist;
      current_dist += current_inc;
      if ( current_dist >= dist )
        break;
      last_iter = iter;
      iter = iter->next;
    }
    if (!iter) { /* passing the end the track */
      if (last_iter) {
        if (meters_from_start)
          *meters_from_start = last_dist;
        return(VIK_TRACKPOINT(last_iter->data));
      }
      else
        return NULL;
    }
    /* we've gone past the dist already, was prev trackpoint closer? */
    /* should do a vik_coord_average_weighted() thingy. */
    if ( iter->prev && abs(current_dist-current_inc-dist) < abs(current_dist-dist) ) {
      if (meters_from_start)
        *meters_from_start = last_dist;
      iter = iter->prev;
    }
    else
      if (meters_from_start)
        *meters_from_start = current_dist;

    return VIK_TRACKPOINT(iter->data);

  }
  return NULL;
}
コード例 #11
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
void vik_track_convert ( VikTrack *tr, VikCoordMode dest_mode )
{
  GList *iter = tr->trackpoints;
  while (iter)
  {
    vik_coord_convert ( &(VIK_TRACKPOINT(iter->data)->coord), dest_mode );
    iter = iter->next;
  }
}
コード例 #12
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
void vik_track_get_total_elevation_gain(const VikTrack *tr, gdouble *up, gdouble *down)
{
  gdouble diff;
  *up = *down = 0;
  if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE )
  {
    GList *iter = tr->trackpoints->next;
    while (iter)
    {
      diff = VIK_TRACKPOINT(iter->data)->altitude - VIK_TRACKPOINT(iter->prev->data)->altitude;
      if ( diff > 0 )
        *up += diff;
      else
        *down -= diff;
      iter = iter->next;
    }
  } else
    *up = *down = VIK_DEFAULT_ALTITUDE;
}
コード例 #13
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
gboolean vik_track_get_minmax_alt ( const VikTrack *tr, gdouble *min_alt, gdouble *max_alt )
{
  *min_alt = 25000;
  *max_alt = -5000;
  if ( tr && tr->trackpoints && tr->trackpoints->data && (VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE) ) {
    GList *iter = tr->trackpoints->next;
    gdouble tmp_alt;
    while (iter)
    {
      tmp_alt = VIK_TRACKPOINT(iter->data)->altitude;
      if ( tmp_alt > *max_alt )
        *max_alt = tmp_alt;
      if ( tmp_alt < *min_alt )
        *min_alt = tmp_alt;
      iter = iter->next;
    }
    return TRUE;
  }
  return FALSE;
}
コード例 #14
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
void vik_track_reverse ( VikTrack *tr )
{
  GList *iter;
  tr->trackpoints = g_list_reverse(tr->trackpoints);

  /* fix 'newsegment' */
  iter = g_list_last ( tr->trackpoints );
  while ( iter )
  {
    if ( ! iter->next ) /* last segment, was first, cancel newsegment. */
      VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
    if ( ! iter->prev ) /* first segment by convention has newsegment flag. */
      VIK_TRACKPOINT(iter->data)->newsegment = TRUE;
    else if ( VIK_TRACKPOINT(iter->data)->newsegment && iter->next )
    {
      VIK_TRACKPOINT(iter->next->data)->newsegment = TRUE;
      VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
    }
    iter = iter->prev;
  }
}
コード例 #15
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
VikTrackpoint* vik_track_get_tp_by_min_alt ( const VikTrack *tr )
{
  gdouble minalt = 25000.0;
  if ( !tr->trackpoints )
    return NULL;

  GList *iter = tr->trackpoints;
  VikTrackpoint *min_alt_tp = NULL;

  while (iter) {
    if ( VIK_TRACKPOINT(iter->data)->altitude < minalt ) {
      minalt = VIK_TRACKPOINT(iter->data)->altitude;
      min_alt_tp = VIK_TRACKPOINT(iter->data);
    }
    iter = iter->next;
  }

  if (!min_alt_tp)
    return NULL;

  return min_alt_tp;
}
コード例 #16
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
guint vik_track_get_segment_count(const VikTrack *tr)
{
  guint num = 1;
  GList *iter = tr->trackpoints;
  if ( !iter )
    return 0;
  while ( (iter = iter->next) )
  {
    if ( VIK_TRACKPOINT(iter->data)->newsegment )
      num++;
  }
  return num;
}
コード例 #17
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
VikTrackpoint *vik_track_get_closest_tp_by_percentage_time ( VikTrack *tr, gdouble reltime, time_t *seconds_from_start )
{
  time_t t_pos, t_start, t_end, t_total;
  t_start = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
  t_end = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
  t_total = t_end - t_start;

  t_pos = t_start + t_total * reltime;

  if ( !tr->trackpoints )
    return NULL;

  GList *iter = tr->trackpoints;

  while (iter) {
    if (VIK_TRACKPOINT(iter->data)->timestamp == t_pos)
      break;
    if (VIK_TRACKPOINT(iter->data)->timestamp > t_pos) {
      if (iter->prev == NULL)  /* first trackpoint */
        break;
      time_t t_before = t_pos - VIK_TRACKPOINT(iter->prev)->timestamp;
      time_t t_after = VIK_TRACKPOINT(iter->data)->timestamp - t_pos;
      if (t_before <= t_after)
        iter = iter->prev;
      break;
    }
    else if ((iter->next == NULL) && (t_pos < (VIK_TRACKPOINT(iter->data)->timestamp + 3))) /* last trackpoint: accommodate for round-off */
      break;
    iter = iter->next;
  }

  if (!iter)
    return NULL;
  if (seconds_from_start)
    *seconds_from_start = VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
  return VIK_TRACKPOINT(iter->data);
}
コード例 #18
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
gdouble vik_track_get_max_speed(const VikTrack *tr)
{
  gdouble maxspeed = 0.0, speed = 0.0;
  if ( tr->trackpoints )
  {
    GList *iter = tr->trackpoints->next;
    while (iter)
    {
      if ( VIK_TRACKPOINT(iter->data)->has_timestamp && 
          VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
          (! VIK_TRACKPOINT(iter->data)->newsegment) )
      {
        speed =  vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord), &(VIK_TRACKPOINT(iter->prev->data)->coord) )
                 / ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
        if ( speed > maxspeed )
          maxspeed = speed;
      }
      iter = iter->next;
    }
  }
  return maxspeed;
}
コード例 #19
0
/**
 * Correlate the image against the specified track
 */
static void trw_layer_geotag_track ( const gchar *name, VikTrack *track, geotag_options_t *options )
{
	// If already found match then don't need to check this track
	if ( options->found_match )
		return;

	VikTrackpoint *trkpt;
	VikTrackpoint *trkpt_next;

	GList *mytrkpt = track->trackpoints;
	for ( mytrkpt = mytrkpt; mytrkpt; mytrkpt = mytrkpt->next ) {

		// Do something for this trackpoint...

		trkpt = VIK_TRACKPOINT(mytrkpt->data);

		// is it exactly this point?
		if ( options->PhotoTime == trkpt->timestamp ) {
			options->coord = trkpt->coord;
			options->altitude = trkpt->altitude;
			options->found_match = TRUE;
			break;
		}

		// Now need two trackpoints, hence check next is available
		if ( !mytrkpt->next ) break;
		trkpt_next = VIK_TRACKPOINT(mytrkpt->next->data);

		// TODO need to use 'has_timestamp' property
		if ( trkpt->timestamp == trkpt_next->timestamp ) continue;
		if ( trkpt->timestamp > trkpt_next->timestamp ) continue;

		// When interpolating between segments, no need for any special segment handling
		if ( !options->ov.interpolate_segments )
			// Don't check between segments
			if ( trkpt_next->newsegment )
				// Simply move on to consider next point
				continue;

		// Too far
		if ( trkpt->timestamp > options->PhotoTime ) break;

		// Is is between this and the next point?
		if ( (options->PhotoTime > trkpt->timestamp) && (options->PhotoTime < trkpt_next->timestamp) ) {
			options->found_match = TRUE;
			// Interpolate
			/* Calculate the "scale": a decimal giving the relative distance
			 * in time between the two points. Ie, a number between 0 and 1 -
			 * 0 is the first point, 1 is the next point, and 0.5 would be
			 * half way. */
			gdouble scale = (gdouble)trkpt_next->timestamp - (gdouble)trkpt->timestamp;
			scale = ((gdouble)options->PhotoTime - (gdouble)trkpt->timestamp) / scale;

			struct LatLon ll_result, ll1, ll2;

			vik_coord_to_latlon ( &(trkpt->coord), &ll1 );
			vik_coord_to_latlon ( &(trkpt_next->coord), &ll2 );

			ll_result.lat = ll1.lat + ((ll2.lat - ll1.lat) * scale);

			// NB This won't cope with going over the 180 degrees longitude boundary
			ll_result.lon = ll1.lon + ((ll2.lon - ll1.lon) * scale);

			// set coord
			vik_coord_load_from_latlon ( &(options->coord), VIK_COORD_LATLON, &ll_result );

			// Interpolate elevation
			options->altitude = trkpt->altitude + ((trkpt_next->altitude - trkpt->altitude) * scale);
			break;
		}
			
	}
}
コード例 #20
0
ファイル: viktrwlayer_tpwin.c プロジェクト: guyou/viking
/**
 * vik_trw_layer_tpwin_set_tp:
 * @tpwin:      The Trackpoint Edit Window
 * @tpl:        The #Glist of trackpoints pointing at the current trackpoint
 * @track_name: The name of the track in which the trackpoint belongs
 * @is_route:   Is the track of the trackpoint actually a route?
 *
 * Sets the Trackpoint Edit Window to the values of the current trackpoint given in @tpl.
 *
 */
void vik_trw_layer_tpwin_set_tp ( VikTrwLayerTpwin *tpwin, GList *tpl, const gchar *track_name, gboolean is_route )
{
  static char tmp_str[64];
  static struct LatLon ll;
  VikTrackpoint *tp = VIK_TRACKPOINT(tpl->data);

  if ( tp->name )
    gtk_entry_set_text ( GTK_ENTRY(tpwin->trkpt_name), tp->name );
  else
    gtk_editable_delete_text ( GTK_EDITABLE(tpwin->trkpt_name), 0, -1 );
  gtk_widget_set_sensitive ( tpwin->trkpt_name, TRUE );

  /* Only can insert if not at the end (otherwise use extend track) */
  gtk_widget_set_sensitive ( tpwin->button_insert, (gboolean) GPOINTER_TO_INT (tpl->next) );
  gtk_widget_set_sensitive ( tpwin->button_delete, TRUE );

  /* We can only split up a track if it's not an endpoint. Makes sense to me. */
  gtk_widget_set_sensitive ( tpwin->button_split, tpl->next && tpl->prev );

  gtk_widget_set_sensitive ( tpwin->button_forward, (gboolean) GPOINTER_TO_INT (tpl->next) );
  gtk_widget_set_sensitive ( tpwin->button_back, (gboolean) GPOINTER_TO_INT (tpl->prev) );

  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->lat), TRUE );
  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->lon), TRUE );
  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->alt), TRUE );
  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->ts), tp->has_timestamp );
  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->time), tp->has_timestamp );
  // Enable adding timestamps - but not on routepoints
  if ( !tp->has_timestamp && !is_route ) {
    gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->time), TRUE );
    GtkWidget *img = gtk_image_new_from_stock ( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU );
    gtk_button_set_image ( GTK_BUTTON(tpwin->time), img );
  }
  else

  vik_trw_layer_tpwin_set_track_name ( tpwin, track_name );

  tpwin->sync_to_tp_block = TRUE; /* don't update while setting data. */

  vik_coord_to_latlon ( &(tp->coord), &ll );
  gtk_spin_button_set_value ( tpwin->lat, ll.lat );
  gtk_spin_button_set_value ( tpwin->lon, ll.lon );
  vik_units_height_t height_units = a_vik_get_units_height ();
  switch (height_units) {
  case VIK_UNITS_HEIGHT_METRES:
    gtk_spin_button_set_value ( tpwin->alt, tp->altitude );
    break;
  case VIK_UNITS_HEIGHT_FEET:
    gtk_spin_button_set_value ( tpwin->alt, VIK_METERS_TO_FEET(tp->altitude) );
    break;
  default:
    gtk_spin_button_set_value ( tpwin->alt, tp->altitude );
    g_critical("Houston, we've had a problem. height=%d", height_units);
  }

  tpwin_update_times ( tpwin, tp );

  tpwin->sync_to_tp_block = FALSE; // don't update while setting data.

  vik_units_speed_t speed_units = a_vik_get_units_speed ();
  vik_units_distance_t dist_units = a_vik_get_units_distance ();
  if ( tpwin->cur_tp )
  {
    switch (dist_units) {
    case VIK_UNITS_DISTANCE_KILOMETRES:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f m", vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)));
      break;
    case VIK_UNITS_DISTANCE_MILES:
    case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f yards", vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord))*1.0936133);
      break;
    default:
      g_critical("Houston, we've had a problem. distance=%d", dist_units);
    }

    gtk_label_set_text ( tpwin->diff_dist, tmp_str );
    if ( tp->has_timestamp && tpwin->cur_tp->has_timestamp )
    {
      g_snprintf ( tmp_str, sizeof(tmp_str), "%ld s", tp->timestamp - tpwin->cur_tp->timestamp);
      gtk_label_set_text ( tpwin->diff_time, tmp_str );
      if ( tp->timestamp == tpwin->cur_tp->timestamp )
        gtk_label_set_text ( tpwin->diff_speed, "--" );
      else
      {
	switch (speed_units) {
	case VIK_UNITS_SPEED_KILOMETRES_PER_HOUR:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f km/h", VIK_MPS_TO_KPH(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_MILES_PER_HOUR:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f mph", VIK_MPS_TO_MPH(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_METRES_PER_SECOND:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f m/s", vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / ABS(tp->timestamp - tpwin->cur_tp->timestamp) );
	  break;
	case VIK_UNITS_SPEED_KNOTS:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f knots", VIK_MPS_TO_KNOTS(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_SECONDS_PER_KM:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f s/km", VIK_MPS_TO_PACE_SPK(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_MINUTES_PER_KM:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f min/km", VIK_MPS_TO_PACE_MPK(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_SECONDS_PER_MILE:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f sec/mi", VIK_MPS_TO_PACE_SPM(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	case VIK_UNITS_SPEED_MINUTES_PER_MILE:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f min/mi", VIK_MPS_TO_PACE_MPM(vik_coord_diff(&(tp->coord), &(tpwin->cur_tp->coord)) / (ABS(tp->timestamp - tpwin->cur_tp->timestamp))) );
	  break;
	default:
	  g_snprintf ( tmp_str, sizeof(tmp_str), "--" );
	  g_critical("Houston, we've had a problem. speed=%d", speed_units);
	}
        gtk_label_set_text ( tpwin->diff_speed, tmp_str );
      }
    }
    else
    {
      gtk_label_set_text ( tpwin->diff_time, NULL );
      gtk_label_set_text ( tpwin->diff_speed, NULL );
    }
  }

  if ( isnan(tp->course) )
    g_snprintf ( tmp_str, sizeof(tmp_str), "--" );
  else
    g_snprintf ( tmp_str, sizeof(tmp_str), "%05.1f\302\260", tp->course );
  gtk_label_set_text ( tpwin->course, tmp_str );

  if ( isnan(tp->speed) )
    g_snprintf ( tmp_str, sizeof(tmp_str), "--" );
  else {
    switch (speed_units) {
    case VIK_UNITS_SPEED_MILES_PER_HOUR:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f mph", VIK_MPS_TO_MPH(tp->speed) );
      break;
    case VIK_UNITS_SPEED_METRES_PER_SECOND:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f m/s", tp->speed );
      break;
    case VIK_UNITS_SPEED_KNOTS:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f knots", VIK_MPS_TO_KNOTS(tp->speed) );
      break;
    case VIK_UNITS_SPEED_SECONDS_PER_KM:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f s/km", VIK_MPS_TO_PACE_SPK(tp->speed) );
      break;
    case VIK_UNITS_SPEED_MINUTES_PER_KM:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f min/km", VIK_MPS_TO_PACE_MPK(tp->speed) );
      break;
    case VIK_UNITS_SPEED_SECONDS_PER_MILE:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f s/mi", VIK_MPS_TO_PACE_SPM(tp->speed) );
      break;
    case VIK_UNITS_SPEED_MINUTES_PER_MILE:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f min/mi", VIK_MPS_TO_PACE_MPM(tp->speed) );
      break;
    default:
      // VIK_UNITS_SPEED_KILOMETRES_PER_HOUR:
      g_snprintf ( tmp_str, sizeof(tmp_str), "%.2f km/h", VIK_MPS_TO_KPH(tp->speed) );
      break;
    }
  }
  gtk_label_set_text ( tpwin->speed, tmp_str );

  switch (dist_units) {
  case VIK_UNITS_DISTANCE_KILOMETRES:
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f m", tp->hdop );
    gtk_label_set_text ( tpwin->hdop, tmp_str );
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f m", tp->pdop );
    gtk_label_set_text ( tpwin->pdop, tmp_str );
    break;
  case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
  case VIK_UNITS_DISTANCE_MILES:
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f yards", tp->hdop*1.0936133 );
    gtk_label_set_text ( tpwin->hdop, tmp_str );
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f yards", tp->pdop*1.0936133 );
    gtk_label_set_text ( tpwin->pdop, tmp_str );
    break;
  default:
    g_critical("Houston, we've had a problem. distance=%d", dist_units);
  }

  switch (height_units) {
  case VIK_UNITS_HEIGHT_METRES:
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f m", tp->vdop );
    break;
  case VIK_UNITS_HEIGHT_FEET:
    g_snprintf ( tmp_str, sizeof(tmp_str), "%.5f feet", VIK_METERS_TO_FEET(tp->vdop) );
    break;
  default:
    g_snprintf ( tmp_str, sizeof(tmp_str), "--" );
    g_critical("Houston, we've had a problem. height=%d", height_units);
  }
  gtk_label_set_text ( tpwin->vdop, tmp_str );

  g_snprintf ( tmp_str, sizeof(tmp_str), "%d / %d", tp->nsats, tp->fix_mode );
  gtk_label_set_text ( tpwin->sat, tmp_str );

  tpwin->cur_tp = tp;
}
コード例 #21
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/**
 * 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;
}
コード例 #22
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/**
 * 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;
}
コード例 #23
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/**
 * 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;
}
コード例 #24
0
ファイル: viktrack.c プロジェクト: evanbattaglia/viking
/* I understood this when I wrote it ... maybe ... Basically it eats up the
 * proper amounts of length on the track and averages elevation over that. */
gdouble *vik_track_make_elevation_map ( const VikTrack *tr, guint16 num_chunks )
{
  gdouble *pts;
  gdouble total_length, chunk_length, current_dist, current_area_under_curve, current_seg_length, dist_along_seg = 0.0;
  gdouble altitude1, altitude2;
  guint16 current_chunk;
  gboolean ignore_it = FALSE;

  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;
  }

  iter = tr->trackpoints;

  g_assert ( num_chunks < 16000 );

  pts = g_malloc ( sizeof(gdouble) * num_chunks );

  total_length = vik_track_get_length_including_gaps ( tr );
  chunk_length = total_length / num_chunks;

  /* Zero chunk_length (eg, track of 2 tp with the same loc) will cause crash */
  if (chunk_length <= 0) {
    g_free(pts);
    return NULL;
  }

  current_dist = 0.0;
  current_area_under_curve = 0;
  current_chunk = 0;
  current_seg_length = 0;

  current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
      &(VIK_TRACKPOINT(iter->next->data)->coord) );
  altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
  altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
  dist_along_seg = 0;

  while ( current_chunk < num_chunks ) {

    /* go along current seg */
    if ( current_seg_length && (current_seg_length - dist_along_seg) > chunk_length ) {
      dist_along_seg += chunk_length;

      /*        /
       *   pt2 *
       *      /x       altitude = alt_at_pt_1 + alt_at_pt_2 / 2 = altitude1 + slope * dist_value_of_pt_inbetween_pt1_and_pt2
       *     /xx   avg altitude = area under curve / chunk len
       *pt1 *xxx   avg altitude = altitude1 + (altitude2-altitude1)/(current_seg_length)*(dist_along_seg + (chunk_len/2))
       *   / xxx
       *  /  xxx
       **/

      if ( ignore_it )
	// 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);

      current_chunk++;
    } else {
      /* finish current seg */
      if ( current_seg_length ) {
        gdouble altitude_at_dist_along_seg = altitude1 + (altitude2-altitude1)/(current_seg_length)*dist_along_seg;
        current_dist = current_seg_length - dist_along_seg;
        current_area_under_curve = current_dist*(altitude_at_dist_along_seg + altitude2)*0.5;
      } else { current_dist = current_area_under_curve = 0; } /* should only happen if first current_seg_length == 0 */

      /* get intervening segs */
      iter = iter->next;
      while ( iter && iter->next ) {
        current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
            &(VIK_TRACKPOINT(iter->next->data)->coord) );
        altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
        altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
        ignore_it = VIK_TRACKPOINT(iter->next->data)->newsegment;

        if ( chunk_length - current_dist >= current_seg_length ) {
          current_dist += current_seg_length;
          current_area_under_curve += current_seg_length * (altitude1+altitude2) * 0.5;
          iter = iter->next;
        } else {
          break;
        }
      }

      /* final seg */
      dist_along_seg = chunk_length - current_dist;
      if ( ignore_it || ( iter && !iter->next ) ) {
        pts[current_chunk] = current_area_under_curve / current_dist;
        if (!iter->next) {
          int i;
          for (i = current_chunk + 1; i < num_chunks; i++)
            pts[i] = pts[current_chunk];
          break;
        }
      } 
      else {
        current_area_under_curve += dist_along_seg * (altitude1 + (altitude2 - altitude1)*dist_along_seg/current_seg_length);
        pts[current_chunk] = current_area_under_curve / chunk_length;
      }

      current_dist = 0;
      current_chunk++;
    }
  }

  return pts;
}
コード例 #25
0
/**
 * @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);
		}
	}
}