コード例 #1
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;
}
コード例 #2
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;
}
コード例 #3
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);
		}
	}
}
コード例 #4
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;
}
コード例 #5
0
ファイル: vikutils.c プロジェクト: idaohang/viking
/**
 * vu_trackpoint_formatted_message:
 * @format_code:  String describing the message to generate
 * @trkpt:        The trackpoint for which the message is generated about
 * @trkpt_prev:   A trackpoint (presumed previous) for interpolating values with the other trackpoint (such as speed)
 * @trk:          The track in which the trackpoints reside
 * @climb:        Vertical speed (Out of band (i.e. not in a trackpoint) value for display currently only for GPSD usage)
 *
 *  TODO: One day replace this cryptic format code with some kind of tokenizer parsing
 *    thus would make it more user friendly and maybe even GUI controlable.
 * However for now at least there is some semblance of user control
 */
gchar* vu_trackpoint_formatted_message ( gchar *format_code, VikTrackpoint *trkpt, VikTrackpoint *trkpt_prev, VikTrack *trk, gdouble climb )
{
	if ( !trkpt )
		return NULL;

	gint len = 0;
	if ( format_code )
		len = strlen ( format_code );
	if ( len > FMT_MAX_NUMBER_CODES )
		len = FMT_MAX_NUMBER_CODES;

	gchar* values[FMT_MAX_NUMBER_CODES];
	int i;
	for ( i = 0; i < FMT_MAX_NUMBER_CODES; i++ ) {
		values[i] = '\0';
	}

	gchar *speed_units_str = NULL;
	vik_units_speed_t speed_units = a_vik_get_units_speed ();
	switch (speed_units) {
	case VIK_UNITS_SPEED_MILES_PER_HOUR:
		speed_units_str = g_strdup ( _("mph") );
		break;
	case VIK_UNITS_SPEED_METRES_PER_SECOND:
		speed_units_str = g_strdup ( _("m/s") );
		break;
	case VIK_UNITS_SPEED_KNOTS:
		speed_units_str = g_strdup ( _("knots") );
		break;
	default:
		// VIK_UNITS_SPEED_KILOMETRES_PER_HOUR:
		speed_units_str = g_strdup ( _("km/h") );
		break;
	}

	gchar *separator = g_strdup ( " | " );

	for ( i = 0; i < len; i++ ) {
		switch ( g_ascii_toupper ( format_code[i] ) ) {
		case 'G': values[i] = g_strdup ( _("GPSD") ); break; // GPS Preamble
		case 'K': values[i] = g_strdup ( _("Trkpt") ); break; // Trkpt Preamble

		case 'S': {
			gdouble speed = 0.0;
			gchar *speedtype = NULL;
			if ( isnan(trkpt->speed) && trkpt_prev ) {
				if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) {
					if ( trkpt->timestamp != trkpt_prev->timestamp ) {

						// Work out from previous trackpoint location and time difference
						speed = vik_coord_diff(&(trkpt->coord), &(trkpt_prev->coord)) / ABS(trkpt->timestamp - trkpt_prev->timestamp);
						speedtype = g_strdup ( "*" ); // Interpolated
					}
					else
						speedtype = g_strdup ( "**" );
				}
				else
					speedtype = g_strdup ( "**" );
			}
			else {
				speed = trkpt->speed;
				speedtype = g_strdup ( "" );
			}
			switch (speed_units) {
			case VIK_UNITS_SPEED_KILOMETRES_PER_HOUR:
				speed = VIK_MPS_TO_KPH(speed);
				break;
			case VIK_UNITS_SPEED_MILES_PER_HOUR:
				speed = VIK_MPS_TO_MPH(speed);
				break;
			case VIK_UNITS_SPEED_KNOTS:
				speed = VIK_MPS_TO_KNOTS(speed);
				break;
			default:
				// VIK_UNITS_SPEED_METRES_PER_SECOND:
				// Already in m/s so nothing to do
				break;
			}

			values[i] = g_strdup_printf ( _("%sSpeed%s %.1f%s"), separator, speedtype, speed, speed_units_str );
			g_free ( speedtype );
			break;
		}

		case 'B': {
			gdouble speed = 0.0;
			gchar *speedtype = NULL;
			if ( isnan(climb) && trkpt_prev ) {
				if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) {
					if ( trkpt->timestamp != trkpt_prev->timestamp ) {
						// Work out from previous trackpoint altitudes and time difference
						// 'speed' can be negative if going downhill
						speed = (trkpt->altitude - trkpt_prev->altitude) / ABS(trkpt->timestamp - trkpt_prev->timestamp);
						speedtype = g_strdup ( "*" ); // Interpolated
					}
					else
						speedtype = g_strdup ( "**" ); // Unavailable
				}
				else
					speedtype = g_strdup ( "**" );
			}
			else {
				speed = climb;
				speedtype = g_strdup ( "" );
			}
			switch (speed_units) {
			case VIK_UNITS_SPEED_KILOMETRES_PER_HOUR:
				speed = VIK_MPS_TO_KPH(speed);
				break;
			case VIK_UNITS_SPEED_MILES_PER_HOUR:
				speed = VIK_MPS_TO_MPH(speed);
				break;
			case VIK_UNITS_SPEED_KNOTS:
				speed = VIK_MPS_TO_KNOTS(speed);
				break;
			default:
				// VIK_UNITS_SPEED_METRES_PER_SECOND:
				// Already in m/s so nothing to do
				break;
			}
			// Go for 2dp as expect low values for vertical speeds
			values[i] = g_strdup_printf ( _("%sClimb%s %.2f%s"), separator, speedtype, speed, speed_units_str );
			g_free ( speedtype );
			break;
		}

		case 'A': {
			vik_units_height_t height_units = a_vik_get_units_height ();
			switch (height_units) {
			case VIK_UNITS_HEIGHT_FEET:
				values[i] = g_strdup_printf ( _("%sAlt %dfeet"), separator, (int)round(VIK_METERS_TO_FEET(trkpt->altitude)) );
				break;
			default:
				//VIK_UNITS_HEIGHT_METRES:
				values[i] = g_strdup_printf ( _("%sAlt %dm"), separator, (int)round(trkpt->altitude) );
				break;
			}
			break;
		}

		case 'C': {
			gint heading = isnan(trkpt->course) ? 0 : (gint)round(trkpt->course);
			values[i] = g_strdup_printf ( _("%sCourse %03d\302\260" ), separator, heading );
			break;
		}

		case 'P': {
			if ( trkpt_prev ) {
				gint diff = (gint) round ( vik_coord_diff ( &(trkpt->coord), &(trkpt_prev->coord) ) );

				gchar *dist_units_str = NULL;
				vik_units_distance_t dist_units = a_vik_get_units_distance ();
				// expect the difference between track points to be small hence use metres or yards
				switch (dist_units) {
				case VIK_UNITS_DISTANCE_MILES:
				case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
					dist_units_str = g_strdup ( _("yards") );
					break;
				default:
					// VIK_UNITS_DISTANCE_KILOMETRES:
					dist_units_str = g_strdup ( _("m") );
					break;
				}

				values[i] = g_strdup_printf ( _("%sDistance diff %d%s"), separator, diff, dist_units_str );

				g_free ( dist_units_str );
			}
			break;
		}

		case 'T': {
			gchar *msg;
			if ( trkpt->has_timestamp ) {
				// Compact date time format
				msg = vu_get_time_string ( &(trkpt->timestamp), "%x %X", &(trkpt->coord), NULL );
			}
			else
				msg = g_strdup ("--");
			values[i] = g_strdup_printf ( _("%sTime %s"), separator, msg );
			g_free ( msg );
			break;
		}

		case 'M': {
			if ( trkpt_prev ) {
				if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) {
					time_t t_diff = trkpt->timestamp - trkpt_prev->timestamp;
					values[i] = g_strdup_printf ( _("%sTime diff %lds"), separator, t_diff );
				}
			}
			break;
		}

		case 'X': values[i] = g_strdup_printf ( _("%sNo. of Sats %d"), separator, trkpt->nsats ); break;

		case 'F': {
			if ( trk ) {
				// Distance to the end 'Finish' (along the track)
				gdouble distd =	vik_track_get_length_to_trackpoint (trk, trkpt);
				gdouble diste =	vik_track_get_length_including_gaps ( trk );
				gdouble dist = diste - distd;
				gchar *dist_units_str = NULL;
				vik_units_distance_t dist_units = a_vik_get_units_distance ();
				switch (dist_units) {
				case VIK_UNITS_DISTANCE_MILES:
					dist_units_str = g_strdup ( _("miles") );
					dist = VIK_METERS_TO_MILES(dist);
					break;
				case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
					dist_units_str = g_strdup ( _("NM") );
					dist = VIK_METERS_TO_NAUTICAL_MILES(dist);
					break;
				default:
					// VIK_UNITS_DISTANCE_KILOMETRES:
					dist_units_str = g_strdup ( _("km") );
					dist = dist / 1000.0;
					break;
				}
				values[i] = g_strdup_printf ( _("%sTo End %.2f%s"), separator, dist, dist_units_str );
				g_free ( dist_units_str );
			}
			break;
		}

		case 'D': {
			if ( trk ) {
				// Distance from start (along the track)
				gdouble distd =	vik_track_get_length_to_trackpoint (trk, trkpt);
				gchar *dist_units_str = NULL;
				vik_units_distance_t dist_units = a_vik_get_units_distance ();
				switch (dist_units) {
				case VIK_UNITS_DISTANCE_MILES:
					dist_units_str = g_strdup ( _("miles") );
					distd = VIK_METERS_TO_MILES(distd);
					break;
				case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
					dist_units_str = g_strdup ( _("NM") );
					distd = VIK_METERS_TO_NAUTICAL_MILES(distd);
					break;
				default:
					// VIK_UNITS_DISTANCE_KILOMETRES:
					dist_units_str = g_strdup ( _("km") );
					distd = distd / 1000.0;
					break;
				}
				values[i] = g_strdup_printf ( _("%sDistance along %.2f%s"), separator, distd, dist_units_str );
				g_free ( dist_units_str );
			}
			break;
		}

		case 'L': {
			// Location (Lat/Long)
			gchar *lat = NULL, *lon = NULL;
			struct LatLon ll;
			vik_coord_to_latlon (&(trkpt->coord), &ll);
			a_coords_latlon_to_string ( &ll, &lat, &lon );
			values[i] = g_strdup_printf ( "%s%s %s", separator, lat, lon );
			g_free ( lat );
			g_free ( lon );
			break;
		}

		case 'N': // Name of track
			values[i] = g_strdup_printf ( _("%sTrack: %s"), separator, trk->name );
			break;

		case 'E': // Name of trackpoint if available
			if ( trkpt->name )
				values[i] = g_strdup_printf ( "%s%s", separator, trkpt->name );
			else
				values[i] = g_strdup ( "" );
			break;

		default:
			break;
		}
	}

	g_free ( separator );
	g_free ( speed_units_str );

	gchar *msg = g_strconcat ( values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], NULL );

	for ( i = 0; i < FMT_MAX_NUMBER_CODES; i++ ) {
		if ( values[i] != '\0' )
			g_free ( values[i] );
	}
	
	return msg;
}