2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 VikTrack *vik_track_new()
32 VikTrack *tr = g_malloc ( sizeof ( VikTrack ) );
33 tr->trackpoints = NULL;
39 void vik_track_set_comment_no_copy(VikTrack *tr, gchar *comment)
42 g_free ( tr->comment );
43 tr->comment = comment;
47 void vik_track_set_comment(VikTrack *tr, const gchar *comment)
50 g_free ( tr->comment );
52 if ( comment && comment[0] != '\0' )
53 tr->comment = g_strdup(comment);
58 void vik_track_ref(VikTrack *tr)
63 void vik_track_free(VikTrack *tr)
65 if ( tr->ref_count-- > 1 )
69 g_free ( tr->comment );
70 g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
71 g_list_free( tr->trackpoints );
75 VikTrack *vik_track_copy ( const VikTrack *tr )
77 VikTrack *new_tr = vik_track_new();
78 VikTrackpoint *new_tp;
79 GList *tp_iter = tr->trackpoints;
80 new_tr->visible = tr->visible;
81 new_tr->trackpoints = NULL;
84 new_tp = g_malloc ( sizeof ( VikTrackpoint ) );
85 *new_tp = *((VikTrackpoint *)(tp_iter->data));
86 new_tr->trackpoints = g_list_append ( new_tr->trackpoints, new_tp );
87 tp_iter = tp_iter->next;
89 vik_track_set_comment(new_tr,tr->comment);
93 VikTrackpoint *vik_trackpoint_new()
95 return g_malloc0(sizeof(VikTrackpoint));
98 void vik_trackpoint_free(VikTrackpoint *tp)
103 VikTrackpoint *vik_trackpoint_copy(VikTrackpoint *tp)
105 VikTrackpoint *rv = vik_trackpoint_new();
110 gdouble vik_track_get_length(const VikTrack *tr)
113 if ( tr->trackpoints )
115 GList *iter = tr->trackpoints->next;
118 if ( ! VIK_TRACKPOINT(iter->data)->newsegment )
119 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
120 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
127 gdouble vik_track_get_length_including_gaps(const VikTrack *tr)
130 if ( tr->trackpoints )
132 GList *iter = tr->trackpoints->next;
135 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
136 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
143 gulong vik_track_get_tp_count(const VikTrack *tr)
146 GList *iter = tr->trackpoints;
155 gulong vik_track_get_dup_point_count ( const VikTrack *tr )
158 GList *iter = tr->trackpoints;
161 if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
162 &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
169 void vik_track_remove_dup_points ( VikTrack *tr )
171 GList *iter = tr->trackpoints;
174 if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
175 &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
177 g_free ( iter->next->data );
178 tr->trackpoints = g_list_delete_link ( tr->trackpoints, iter->next );
185 guint vik_track_get_segment_count(const VikTrack *tr)
188 GList *iter = tr->trackpoints;
191 while ( (iter = iter->next) )
193 if ( VIK_TRACKPOINT(iter->data)->newsegment )
199 VikTrack **vik_track_split_into_segments(VikTrack *t, guint *ret_len)
204 guint segs = vik_track_get_segment_count(t);
213 rv = g_malloc ( segs * sizeof(VikTrack *) );
214 tr = vik_track_copy ( t );
216 iter = tr->trackpoints;
219 while ( (iter = iter->next) )
221 if ( VIK_TRACKPOINT(iter->data)->newsegment )
223 iter->prev->next = NULL;
225 rv[i] = vik_track_new();
227 vik_track_set_comment ( rv[i], tr->comment );
228 rv[i]->visible = tr->visible;
229 rv[i]->trackpoints = iter;
237 void vik_track_reverse ( VikTrack *tr )
240 tr->trackpoints = g_list_reverse(tr->trackpoints);
242 /* fix 'newsegment' */
243 iter = g_list_last ( tr->trackpoints );
246 if ( ! iter->next ) /* last segment, was first, cancel newsegment. */
247 VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
248 if ( ! iter->prev ) /* first segment by convention has newsegment flag. */
249 VIK_TRACKPOINT(iter->data)->newsegment = TRUE;
250 else if ( VIK_TRACKPOINT(iter->data)->newsegment && iter->next )
252 VIK_TRACKPOINT(iter->next->data)->newsegment = TRUE;
253 VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
259 gdouble vik_track_get_average_speed(const VikTrack *tr)
263 if ( tr->trackpoints )
265 GList *iter = tr->trackpoints->next;
268 if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
269 VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
270 (! VIK_TRACKPOINT(iter->data)->newsegment) )
272 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
273 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
274 time += ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
279 return (time == 0) ? 0 : ABS(len/time);
282 gdouble vik_track_get_max_speed(const VikTrack *tr)
284 gdouble maxspeed = 0.0, speed = 0.0;
285 if ( tr->trackpoints )
287 GList *iter = tr->trackpoints->next;
290 if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
291 VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
292 (! VIK_TRACKPOINT(iter->data)->newsegment) )
294 speed = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord), &(VIK_TRACKPOINT(iter->prev->data)->coord) )
295 / ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
296 if ( speed > maxspeed )
305 void vik_track_convert ( VikTrack *tr, VikCoordMode dest_mode )
307 GList *iter = tr->trackpoints;
310 vik_coord_convert ( &(VIK_TRACKPOINT(iter->data)->coord), dest_mode );
315 /* I understood this when I wrote it ... maybe ... Basically it eats up the
316 * proper amounts of length on the track and averages elevation over that. */
317 gdouble *vik_track_make_elevation_map ( const VikTrack *tr, guint16 num_chunks )
320 gdouble total_length, chunk_length, current_dist, current_area_under_curve, current_seg_length, dist_along_seg = 0.0;
321 gdouble altitude1, altitude2;
322 guint16 current_chunk;
323 gboolean ignore_it = FALSE;
325 GList *iter = tr->trackpoints;
327 g_assert ( num_chunks < 16000 );
329 pts = g_malloc ( sizeof(gdouble) * num_chunks );
331 total_length = vik_track_get_length_including_gaps ( tr );
332 chunk_length = total_length / num_chunks;
335 current_area_under_curve = 0;
337 current_seg_length = 0;
339 current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
340 &(VIK_TRACKPOINT(iter->next->data)->coord) );
341 altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
342 altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
345 while ( current_chunk < num_chunks ) {
347 /* go along current seg */
348 if ( current_seg_length && (current_seg_length - dist_along_seg) > chunk_length ) {
349 dist_along_seg += chunk_length;
353 * /x altitude = alt_at_pt_1 + alt_at_pt_2 / 2 = altitude1 + slope * dist_value_of_pt_inbetween_pt1_and_pt2
354 * /xx avg altitude = area under curve / chunk len
355 *pt1 *xxx avg altitude = altitude1 + (altitude2-altitude1)/(current_seg_length)*(dist_along_seg + (chunk_len/2))
361 pts[current_chunk] = VIK_DEFAULT_ALTITUDE;
363 pts[current_chunk] = altitude1 + (altitude2-altitude1)*((dist_along_seg - (chunk_length/2))/current_seg_length);
367 /* finish current seg */
368 if ( current_seg_length ) {
369 gdouble altitude_at_dist_along_seg = altitude1 + (altitude2-altitude1)/(current_seg_length)*dist_along_seg;
370 current_dist = current_seg_length - dist_along_seg;
371 current_area_under_curve = current_dist*(altitude_at_dist_along_seg + altitude2)*0.5;
372 } else { current_dist = current_area_under_curve = 0; } /* should only happen if first current_seg_length == 0 */
374 /* get intervening segs */
376 while ( iter && iter->next ) {
377 current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
378 &(VIK_TRACKPOINT(iter->next->data)->coord) );
379 altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
380 altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
381 ignore_it = VIK_TRACKPOINT(iter->next->data)->newsegment;
383 if ( chunk_length - current_dist >= current_seg_length ) {
384 current_dist += current_seg_length;
385 current_area_under_curve += current_seg_length * (altitude1+altitude2) * 0.5;
393 dist_along_seg = chunk_length - current_dist;
394 if ( ignore_it || !iter->next ) {
395 pts[current_chunk] = current_area_under_curve / current_dist;
398 current_area_under_curve += dist_along_seg * (altitude1 + (altitude2 - altitude1)*dist_along_seg/current_seg_length);
399 pts[current_chunk] = current_area_under_curve / chunk_length;
411 void vik_track_get_total_elevation_gain(const VikTrack *tr, gdouble *up, gdouble *down)
415 if ( tr->trackpoints )
417 GList *iter = tr->trackpoints->next;
420 diff = VIK_TRACKPOINT(iter->data)->altitude - VIK_TRACKPOINT(iter->prev->data)->altitude;