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 );
}
VikTrackpoint *tp = g_malloc0(sizeof(VikTrackpoint));
tp->speed = NAN;
tp->course = NAN;
+ tp->altitude = VIK_DEFAULT_ALTITUDE;
+ tp->hdop = VIK_DEFAULT_DOP;
+ tp->vdop = VIK_DEFAULT_DOP;
+ tp->pdop = VIK_DEFAULT_DOP;
return tp;
}
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)
+ if (chunk_length <= 0) {
+ g_free(pts);
return NULL;
+ }
current_dist = 0.0;
current_area_under_curve = 0;
**/
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);
*/
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++;
- numpts++;
}
v[i] = acc_s/acc_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;
+}
+
+/**
+ * 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 )
{
return VIK_TRACKPOINT(iter->data);
}
+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;
+}
+
+VikTrackpoint* vik_track_get_tp_by_max_alt ( const VikTrack *tr )
+{
+ gdouble maxalt = -5000.0;
+ if ( !tr->trackpoints )
+ return NULL;
+
+ GList *iter = tr->trackpoints;
+ VikTrackpoint *max_alt_tp = NULL;
+
+ while (iter) {
+ if ( VIK_TRACKPOINT(iter->data)->altitude > maxalt ) {
+ maxalt = VIK_TRACKPOINT(iter->data)->altitude;
+ max_alt_tp = VIK_TRACKPOINT(iter->data);
+ }
+ iter = iter->next;
+ }
+
+ if (!max_alt_tp)
+ return NULL;
+
+ return max_alt_tp;
+}
+
+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;
+}
+
gboolean vik_track_get_minmax_alt ( const VikTrack *tr, gdouble *min_alt, gdouble *max_alt )
{
*min_alt = 25000;
}
}
+/*
+ * 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 )
{
}
/* 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 )
{