]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/viktrack.c
Add Terraserver
[andy/viking.git] / src / viktrack.c
... / ...
CommitLineData
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
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.
10 *
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.
15 *
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
19 *
20 */
21
22#include <glib.h>
23#include <time.h>
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27#include "coords.h"
28#include "vikcoord.h"
29#include "viktrack.h"
30#include "globals.h"
31#include "dems.h"
32
33VikTrack *vik_track_new()
34{
35 VikTrack *tr = g_malloc0 ( sizeof ( VikTrack ) );
36 tr->ref_count = 1;
37 return tr;
38}
39
40void vik_track_set_comment_no_copy(VikTrack *tr, gchar *comment)
41{
42 if ( tr->comment )
43 g_free ( tr->comment );
44 tr->comment = comment;
45}
46
47
48void vik_track_set_comment(VikTrack *tr, const gchar *comment)
49{
50 if ( tr->comment )
51 g_free ( tr->comment );
52
53 if ( comment && comment[0] != '\0' )
54 tr->comment = g_strdup(comment);
55 else
56 tr->comment = NULL;
57}
58
59void vik_track_ref(VikTrack *tr)
60{
61 tr->ref_count++;
62}
63
64void vik_track_set_property_dialog(VikTrack *tr, GtkWidget *dialog)
65{
66 /* Warning: does not check for existing dialog */
67 tr->property_dialog = dialog;
68}
69
70void vik_track_clear_property_dialog(VikTrack *tr)
71{
72 tr->property_dialog = NULL;
73}
74
75void vik_track_free(VikTrack *tr)
76{
77 if ( tr->ref_count-- > 1 )
78 return;
79
80 if ( tr->comment )
81 g_free ( tr->comment );
82 g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
83 g_list_free( tr->trackpoints );
84 if (tr->property_dialog)
85 gtk_widget_destroy ( GTK_WIDGET(tr->property_dialog) );
86 g_free ( tr );
87}
88
89VikTrack *vik_track_copy ( const VikTrack *tr )
90{
91 VikTrack *new_tr = vik_track_new();
92 VikTrackpoint *new_tp;
93 GList *tp_iter = tr->trackpoints;
94 new_tr->visible = tr->visible;
95 new_tr->trackpoints = NULL;
96 while ( tp_iter )
97 {
98 new_tp = g_malloc ( sizeof ( VikTrackpoint ) );
99 *new_tp = *((VikTrackpoint *)(tp_iter->data));
100 new_tr->trackpoints = g_list_append ( new_tr->trackpoints, new_tp );
101 tp_iter = tp_iter->next;
102 }
103 vik_track_set_comment(new_tr,tr->comment);
104 return new_tr;
105}
106
107VikTrackpoint *vik_trackpoint_new()
108{
109 VikTrackpoint *tp = g_malloc0(sizeof(VikTrackpoint));
110 tp->extended = FALSE;
111 tp->speed = NAN;
112 tp->course = NAN;
113 return tp;
114}
115
116void vik_trackpoint_free(VikTrackpoint *tp)
117{
118 g_free(tp);
119}
120
121VikTrackpoint *vik_trackpoint_copy(VikTrackpoint *tp)
122{
123 VikTrackpoint *rv = vik_trackpoint_new();
124 *rv = *tp;
125 return rv;
126}
127
128gdouble vik_track_get_length(const VikTrack *tr)
129{
130 gdouble len = 0.0;
131 if ( tr->trackpoints )
132 {
133 GList *iter = tr->trackpoints->next;
134 while (iter)
135 {
136 if ( ! VIK_TRACKPOINT(iter->data)->newsegment )
137 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
138 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
139 iter = iter->next;
140 }
141 }
142 return len;
143}
144
145gdouble vik_track_get_length_including_gaps(const VikTrack *tr)
146{
147 gdouble len = 0.0;
148 if ( tr->trackpoints )
149 {
150 GList *iter = tr->trackpoints->next;
151 while (iter)
152 {
153 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
154 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
155 iter = iter->next;
156 }
157 }
158 return len;
159}
160
161gulong vik_track_get_tp_count(const VikTrack *tr)
162{
163 gulong num = 0;
164 GList *iter = tr->trackpoints;
165 while ( iter )
166 {
167 num++;
168 iter = iter->next;
169 }
170 return num;
171}
172
173gulong vik_track_get_dup_point_count ( const VikTrack *tr )
174{
175 gulong num = 0;
176 GList *iter = tr->trackpoints;
177 while ( iter )
178 {
179 if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
180 &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
181 num++;
182 iter = iter->next;
183 }
184 return num;
185}
186
187void vik_track_remove_dup_points ( VikTrack *tr )
188{
189 GList *iter = tr->trackpoints;
190 while ( iter )
191 {
192 if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
193 &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
194 {
195 g_free ( iter->next->data );
196 tr->trackpoints = g_list_delete_link ( tr->trackpoints, iter->next );
197 }
198 else
199 iter = iter->next;
200 }
201}
202
203guint vik_track_get_segment_count(const VikTrack *tr)
204{
205 guint num = 1;
206 GList *iter = tr->trackpoints;
207 if ( !iter )
208 return 0;
209 while ( (iter = iter->next) )
210 {
211 if ( VIK_TRACKPOINT(iter->data)->newsegment )
212 num++;
213 }
214 return num;
215}
216
217VikTrack **vik_track_split_into_segments(VikTrack *t, guint *ret_len)
218{
219 VikTrack **rv;
220 VikTrack *tr;
221 guint i;
222 guint segs = vik_track_get_segment_count(t);
223 GList *iter;
224
225 if ( segs < 2 )
226 {
227 *ret_len = 0;
228 return NULL;
229 }
230
231 rv = g_malloc ( segs * sizeof(VikTrack *) );
232 tr = vik_track_copy ( t );
233 rv[0] = tr;
234 iter = tr->trackpoints;
235
236 i = 1;
237 while ( (iter = iter->next) )
238 {
239 if ( VIK_TRACKPOINT(iter->data)->newsegment )
240 {
241 iter->prev->next = NULL;
242 iter->prev = NULL;
243 rv[i] = vik_track_new();
244 if ( tr->comment )
245 vik_track_set_comment ( rv[i], tr->comment );
246 rv[i]->visible = tr->visible;
247 rv[i]->trackpoints = iter;
248 i++;
249 }
250 }
251 *ret_len = segs;
252 return rv;
253}
254
255void vik_track_reverse ( VikTrack *tr )
256{
257 GList *iter;
258 tr->trackpoints = g_list_reverse(tr->trackpoints);
259
260 /* fix 'newsegment' */
261 iter = g_list_last ( tr->trackpoints );
262 while ( iter )
263 {
264 if ( ! iter->next ) /* last segment, was first, cancel newsegment. */
265 VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
266 if ( ! iter->prev ) /* first segment by convention has newsegment flag. */
267 VIK_TRACKPOINT(iter->data)->newsegment = TRUE;
268 else if ( VIK_TRACKPOINT(iter->data)->newsegment && iter->next )
269 {
270 VIK_TRACKPOINT(iter->next->data)->newsegment = TRUE;
271 VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
272 }
273 iter = iter->prev;
274 }
275}
276
277gdouble vik_track_get_average_speed(const VikTrack *tr)
278{
279 gdouble len = 0.0;
280 guint32 time = 0;
281 if ( tr->trackpoints )
282 {
283 GList *iter = tr->trackpoints->next;
284 while (iter)
285 {
286 if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
287 VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
288 (! VIK_TRACKPOINT(iter->data)->newsegment) )
289 {
290 len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
291 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
292 time += ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
293 }
294 iter = iter->next;
295 }
296 }
297 return (time == 0) ? 0 : ABS(len/time);
298}
299
300gdouble vik_track_get_max_speed(const VikTrack *tr)
301{
302 gdouble maxspeed = 0.0, speed = 0.0;
303 if ( tr->trackpoints )
304 {
305 GList *iter = tr->trackpoints->next;
306 while (iter)
307 {
308 if ( VIK_TRACKPOINT(iter->data)->has_timestamp &&
309 VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
310 (! VIK_TRACKPOINT(iter->data)->newsegment) )
311 {
312 speed = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord), &(VIK_TRACKPOINT(iter->prev->data)->coord) )
313 / ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
314 if ( speed > maxspeed )
315 maxspeed = speed;
316 }
317 iter = iter->next;
318 }
319 }
320 return maxspeed;
321}
322
323void vik_track_convert ( VikTrack *tr, VikCoordMode dest_mode )
324{
325 GList *iter = tr->trackpoints;
326 while (iter)
327 {
328 vik_coord_convert ( &(VIK_TRACKPOINT(iter->data)->coord), dest_mode );
329 iter = iter->next;
330 }
331}
332
333/* I understood this when I wrote it ... maybe ... Basically it eats up the
334 * proper amounts of length on the track and averages elevation over that. */
335gdouble *vik_track_make_elevation_map ( const VikTrack *tr, guint16 num_chunks )
336{
337 gdouble *pts;
338 gdouble total_length, chunk_length, current_dist, current_area_under_curve, current_seg_length, dist_along_seg = 0.0;
339 gdouble altitude1, altitude2;
340 guint16 current_chunk;
341 gboolean ignore_it = FALSE;
342
343 GList *iter = tr->trackpoints;
344
345 if (!iter || !iter->next) /* zero- or one-point track */
346 return NULL;
347
348 { /* test if there's anything worth calculating */
349 gboolean okay = FALSE;
350 while ( iter )
351 {
352 if ( VIK_TRACKPOINT(iter->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
353 okay = TRUE; break;
354 }
355 iter = iter->next;
356 }
357 if ( ! okay )
358 return NULL;
359 }
360
361 iter = tr->trackpoints;
362
363 g_assert ( num_chunks < 16000 );
364
365 pts = g_malloc ( sizeof(gdouble) * num_chunks );
366
367 total_length = vik_track_get_length_including_gaps ( tr );
368 chunk_length = total_length / num_chunks;
369
370 /* Zero chunk_length (eg, track of 2 tp with the same loc) will cause crash */
371 if (chunk_length <= 0)
372 return NULL;
373
374 current_dist = 0.0;
375 current_area_under_curve = 0;
376 current_chunk = 0;
377 current_seg_length = 0;
378
379 current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
380 &(VIK_TRACKPOINT(iter->next->data)->coord) );
381 altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
382 altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
383 dist_along_seg = 0;
384
385 while ( current_chunk < num_chunks ) {
386
387 /* go along current seg */
388 if ( current_seg_length && (current_seg_length - dist_along_seg) > chunk_length ) {
389 dist_along_seg += chunk_length;
390
391 /* /
392 * pt2 *
393 * /x altitude = alt_at_pt_1 + alt_at_pt_2 / 2 = altitude1 + slope * dist_value_of_pt_inbetween_pt1_and_pt2
394 * /xx avg altitude = area under curve / chunk len
395 *pt1 *xxx avg altitude = altitude1 + (altitude2-altitude1)/(current_seg_length)*(dist_along_seg + (chunk_len/2))
396 * / xxx
397 * / xxx
398 **/
399
400 if ( ignore_it )
401 pts[current_chunk] = VIK_DEFAULT_ALTITUDE;
402 else
403 pts[current_chunk] = altitude1 + (altitude2-altitude1)*((dist_along_seg - (chunk_length/2))/current_seg_length);
404
405 current_chunk++;
406 } else {
407 /* finish current seg */
408 if ( current_seg_length ) {
409 gdouble altitude_at_dist_along_seg = altitude1 + (altitude2-altitude1)/(current_seg_length)*dist_along_seg;
410 current_dist = current_seg_length - dist_along_seg;
411 current_area_under_curve = current_dist*(altitude_at_dist_along_seg + altitude2)*0.5;
412 } else { current_dist = current_area_under_curve = 0; } /* should only happen if first current_seg_length == 0 */
413
414 /* get intervening segs */
415 iter = iter->next;
416 while ( iter && iter->next ) {
417 current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
418 &(VIK_TRACKPOINT(iter->next->data)->coord) );
419 altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
420 altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
421 ignore_it = VIK_TRACKPOINT(iter->next->data)->newsegment;
422
423 if ( chunk_length - current_dist >= current_seg_length ) {
424 current_dist += current_seg_length;
425 current_area_under_curve += current_seg_length * (altitude1+altitude2) * 0.5;
426 iter = iter->next;
427 } else {
428 break;
429 }
430 }
431
432 /* final seg */
433 dist_along_seg = chunk_length - current_dist;
434 if ( ignore_it || !iter->next ) {
435 pts[current_chunk] = current_area_under_curve / current_dist;
436 if (!iter->next) {
437 int i;
438 for (i = current_chunk + 1; i < num_chunks; i++)
439 pts[i] = pts[current_chunk];
440 break;
441 }
442 }
443 else {
444 current_area_under_curve += dist_along_seg * (altitude1 + (altitude2 - altitude1)*dist_along_seg/current_seg_length);
445 pts[current_chunk] = current_area_under_curve / chunk_length;
446 }
447
448 current_dist = 0;
449 current_chunk++;
450 }
451 }
452
453 return pts;
454}
455
456
457void vik_track_get_total_elevation_gain(const VikTrack *tr, gdouble *up, gdouble *down)
458{
459 gdouble diff;
460 *up = *down = 0;
461 if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE )
462 {
463 GList *iter = tr->trackpoints->next;
464 while (iter)
465 {
466 diff = VIK_TRACKPOINT(iter->data)->altitude - VIK_TRACKPOINT(iter->prev->data)->altitude;
467 if ( diff > 0 )
468 *up += diff;
469 else
470 *down -= diff;
471 iter = iter->next;
472 }
473 } else
474 *up = *down = VIK_DEFAULT_ALTITUDE;
475}
476
477
478/* by Alex Foobarian */
479gdouble *vik_track_make_speed_map ( const VikTrack *tr, guint16 num_chunks )
480{
481 gdouble *v, *s, *t;
482 gdouble duration, chunk_dur;
483 time_t t1, t2;
484 int i, pt_count, numpts, index;
485 GList *iter;
486
487 if ( ! tr->trackpoints )
488 return NULL;
489
490 g_assert ( num_chunks < 16000 );
491
492 t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
493 t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
494 duration = t2 - t1;
495
496 if ( !t1 || !t2 || !duration )
497 return NULL;
498
499 if (duration < 0) {
500 g_warning("negative duration: unsorted trackpoint timestamps?");
501 return NULL;
502 }
503 pt_count = vik_track_get_tp_count(tr);
504
505 v = g_malloc ( sizeof(gdouble) * num_chunks );
506 chunk_dur = duration / num_chunks;
507
508 s = g_malloc(sizeof(double) * pt_count);
509 t = g_malloc(sizeof(double) * pt_count);
510
511 iter = tr->trackpoints->next;
512 numpts = 0;
513 s[0] = 0;
514 t[0] = VIK_TRACKPOINT(iter->prev->data)->timestamp;
515 numpts++;
516 while (iter) {
517 s[numpts] = s[numpts-1] + vik_coord_diff ( &(VIK_TRACKPOINT(iter->prev->data)->coord), &(VIK_TRACKPOINT(iter->data)->coord) );
518 t[numpts] = VIK_TRACKPOINT(iter->data)->timestamp;
519 numpts++;
520 iter = iter->next;
521 }
522
523 /* In the following computation, we iterate through periods of time of duration chunk_dur.
524 * The first period begins at the beginning of the track. The last period ends at the end of the track.
525 */
526 index = 0; /* index of the current trackpoint. */
527 for (i = 0; i < num_chunks; i++) {
528 /* we are now covering the interval from t[0] + i*chunk_dur to t[0] + (i+1)*chunk_dur.
529 * find the first trackpoint outside the current interval, averaging the speeds between intermediate trackpoints.
530 */
531 if (t[0] + i*chunk_dur >= t[index]) {
532 gdouble acc_t = 0, acc_s = 0;
533 numpts = 0;
534 while (t[0] + i*chunk_dur >= t[index]) {
535 acc_s += (s[index+1]-s[index]);
536 acc_t += (t[index+1]-t[index]);
537 index++;
538 numpts++;
539 }
540 v[i] = acc_s/acc_t;
541 }
542 else if (i) {
543 v[i] = v[i-1];
544 }
545 else {
546 v[i] = 0;
547 }
548 }
549 g_free(s);
550 g_free(t);
551 return v;
552}
553
554/* by Alex Foobarian */
555VikTrackpoint *vik_track_get_closest_tp_by_percentage_dist ( VikTrack *tr, gdouble reldist, gdouble *meters_from_start )
556{
557 gdouble dist = vik_track_get_length_including_gaps(tr) * reldist;
558 gdouble current_dist = 0.0;
559 gdouble current_inc = 0.0;
560 if ( tr->trackpoints )
561 {
562 GList *iter = tr->trackpoints->next;
563 GList *last_iter = NULL;
564 gdouble last_dist = 0.0;
565 while (iter)
566 {
567 current_inc = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
568 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
569 last_dist = current_dist;
570 current_dist += current_inc;
571 if ( current_dist >= dist )
572 break;
573 last_iter = iter;
574 iter = iter->next;
575 }
576 if (!iter) { /* passing the end the track */
577 if (last_iter) {
578 if (meters_from_start)
579 *meters_from_start = last_dist;
580 return(VIK_TRACKPOINT(last_iter->data));
581 }
582 else
583 return NULL;
584 }
585 /* we've gone past the dist already, was prev trackpoint closer? */
586 /* should do a vik_coord_average_weighted() thingy. */
587 if ( iter->prev && abs(current_dist-current_inc-dist) < abs(current_dist-dist) ) {
588 if (meters_from_start)
589 *meters_from_start = last_dist;
590 iter = iter->prev;
591 }
592 else
593 if (meters_from_start)
594 *meters_from_start = current_dist;
595
596 return VIK_TRACKPOINT(iter->data);
597
598 }
599 return NULL;
600}
601
602VikTrackpoint *vik_track_get_closest_tp_by_percentage_time ( VikTrack *tr, gdouble reltime, time_t *seconds_from_start )
603{
604 time_t t_pos, t_start, t_end, t_total;
605 t_start = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
606 t_end = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
607 t_total = t_end - t_start;
608
609 t_pos = t_start + t_total * reltime;
610
611 if ( !tr->trackpoints )
612 return NULL;
613
614 GList *iter = tr->trackpoints;
615
616 while (iter) {
617 if (VIK_TRACKPOINT(iter->data)->timestamp == t_pos)
618 break;
619 if (VIK_TRACKPOINT(iter->data)->timestamp > t_pos) {
620 if (iter->prev == NULL) /* first trackpoint */
621 break;
622 time_t t_before = t_pos - VIK_TRACKPOINT(iter->prev)->timestamp;
623 time_t t_after = VIK_TRACKPOINT(iter->data)->timestamp - t_pos;
624 if (t_before <= t_after)
625 iter = iter->prev;
626 break;
627 }
628 else if ((iter->next == NULL) && (t_pos < (VIK_TRACKPOINT(iter->data)->timestamp + 3))) /* last trackpoint: accommodate for round-off */
629 break;
630 iter = iter->next;
631 }
632
633 if (!iter)
634 return NULL;
635 if (seconds_from_start)
636 *seconds_from_start = VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
637 return VIK_TRACKPOINT(iter->data);
638}
639
640gboolean vik_track_get_minmax_alt ( const VikTrack *tr, gdouble *min_alt, gdouble *max_alt )
641{
642 *min_alt = 25000;
643 *max_alt = -5000;
644 if ( tr && tr->trackpoints && tr->trackpoints->data && (VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE) ) {
645 GList *iter = tr->trackpoints->next;
646 gdouble tmp_alt;
647 while (iter)
648 {
649 tmp_alt = VIK_TRACKPOINT(iter->data)->altitude;
650 if ( tmp_alt > *max_alt )
651 *max_alt = tmp_alt;
652 if ( tmp_alt < *min_alt )
653 *min_alt = tmp_alt;
654 iter = iter->next;
655 }
656 return TRUE;
657 }
658 return FALSE;
659}
660
661void vik_track_marshall ( VikTrack *tr, guint8 **data, guint *datalen)
662{
663 GList *tps;
664 GByteArray *b = g_byte_array_new();
665 guint len;
666 guint intp, ntp;
667
668 g_byte_array_append(b, (guint8 *)tr, sizeof(*tr));
669
670 /* we'll fill out number of trackpoints later */
671 intp = b->len;
672 g_byte_array_append(b, (guint8 *)&len, sizeof(len));
673
674 tps = tr->trackpoints;
675 ntp = 0;
676 while (tps) {
677 g_byte_array_append(b, (guint8 *)tps->data, sizeof(VikTrackpoint));
678 tps = tps->next;
679 ntp++;
680 }
681 *(guint *)(b->data + intp) = ntp;
682
683 len = (tr->comment) ? strlen(tr->comment)+1 : 0;
684 g_byte_array_append(b, (guint8 *)&len, sizeof(len));
685 if (tr->comment) g_byte_array_append(b, (guint8 *)tr->comment, len);
686
687 *data = b->data;
688 *datalen = b->len;
689 g_byte_array_free(b, FALSE);
690}
691
692VikTrack *vik_track_unmarshall (guint8 *data, guint datalen)
693{
694 guint len;
695 VikTrack *new_tr = vik_track_new();
696 VikTrackpoint *new_tp;
697 guint ntp;
698 gint i;
699
700 /* only the visibility is needed */
701 new_tr->visible = ((VikTrack *)data)->visible;
702 data += sizeof(*new_tr);
703
704 ntp = *(guint *)data;
705 data += sizeof(ntp);
706
707 for (i=0; i<ntp; i++) {
708 new_tp = vik_trackpoint_new();
709 memcpy(new_tp, data, sizeof(*new_tp));
710 data += sizeof(*new_tp);
711 new_tr->trackpoints = g_list_append(new_tr->trackpoints, new_tp);
712 }
713
714 len = *(guint *)data;
715 data += sizeof(len);
716 if (len) {
717 new_tr->comment = g_strdup((gchar *)data);
718 }
719 return new_tr;
720}
721
722void vik_track_apply_dem_data ( VikTrack *tr )
723{
724 GList *tp_iter;
725 gint16 elev;
726 tp_iter = tr->trackpoints;
727 while ( tp_iter ) {
728 /* TODO: of the 4 possible choices we have for choosing an elevation
729 * (trackpoint in between samples), choose the one with the least elevation change
730 * as the last */
731 elev = a_dems_get_elev_by_coord ( &(VIK_TRACKPOINT(tp_iter->data)->coord), VIK_DEM_INTERPOL_BEST );
732 if ( elev != VIK_DEM_INVALID_ELEVATION )
733 VIK_TRACKPOINT(tp_iter->data)->altitude = elev;
734 tp_iter = tp_iter->next;
735 }
736}
737
738/* appends t2 to t1, leaving t2 with no trackpoints */
739void vik_track_steal_and_append_trackpoints ( VikTrack *t1, VikTrack *t2 )
740{
741 if ( t1->trackpoints ) {
742 GList *tpiter = t1->trackpoints;
743 while ( tpiter->next )
744 tpiter = tpiter->next;
745 tpiter->next = t2->trackpoints;
746 t2->trackpoints->prev = tpiter;
747 } else
748 t1->trackpoints = t2->trackpoints;
749 t2->trackpoints = NULL;
750}
751
752/* starting at the end, looks backwards for the last "double point", a duplicate trackpoint.
753 * this is indicative of magic scissors continued use. If there is no double point,
754 * deletes all the trackpoints. Returns the new end of the track (or the start if
755 * there are no double points
756 */
757VikCoord *vik_track_cut_back_to_double_point ( VikTrack *tr )
758{
759 GList *iter = tr->trackpoints;
760 VikCoord *rv;
761
762 if ( !iter )
763 return NULL;
764 while ( iter->next )
765 iter = iter->next;
766
767
768 while ( iter->prev ) {
769 if ( vik_coord_equals((VikCoord *)iter->data, (VikCoord *)iter->prev->data) ) {
770 GList *prev = iter->prev;
771
772 rv = g_malloc(sizeof(VikCoord));
773 *rv = *((VikCoord *) iter->data);
774
775 /* truncate trackpoint list */
776 iter->prev = NULL; /* pretend it's the end */
777 g_list_foreach ( iter, (GFunc) g_free, NULL );
778 g_list_free( iter );
779
780 prev->next = NULL;
781
782 return rv;
783 }
784 iter = iter->prev;
785 }
786
787 /* no double point found! */
788 rv = g_malloc(sizeof(VikCoord));
789 *rv = *((VikCoord *) tr->trackpoints->data);
790 g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
791 g_list_free( tr->trackpoints );
792 tr->trackpoints = NULL;
793 return rv;
794}
795