]> git.street.me.uk Git - andy/viking.git/blob - src/viktrack.c
Copying libcurl.m4
[andy/viking.git] / src / viktrack.c
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 <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include "coords.h"
29 #include "vikcoord.h"
30 #include "viktrack.h"
31 #include "globals.h"
32
33 VikTrack *vik_track_new()
34 {
35   VikTrack *tr = g_malloc0 ( sizeof ( VikTrack ) );
36   tr->ref_count = 1;
37   return tr;
38 }
39
40 void 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
48 void 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
59 void vik_track_ref(VikTrack *tr)
60 {
61   tr->ref_count++;
62 }
63
64 void vik_track_free(VikTrack *tr)
65 {
66   if ( tr->ref_count-- > 1 )
67     return;
68
69   if ( tr->comment )
70     g_free ( tr->comment );
71   g_list_foreach ( tr->trackpoints, (GFunc) g_free, NULL );
72   g_list_free( tr->trackpoints );
73   g_free ( tr );
74 }
75
76 VikTrack *vik_track_copy ( const VikTrack *tr )
77 {
78   VikTrack *new_tr = vik_track_new();
79   VikTrackpoint *new_tp;
80   GList *tp_iter = tr->trackpoints;
81   new_tr->visible = tr->visible;
82   new_tr->trackpoints = NULL;
83   while ( tp_iter )
84   {
85     new_tp = g_malloc ( sizeof ( VikTrackpoint ) );
86     *new_tp = *((VikTrackpoint *)(tp_iter->data));
87     new_tr->trackpoints = g_list_append ( new_tr->trackpoints, new_tp );
88     tp_iter = tp_iter->next;
89   }
90   vik_track_set_comment(new_tr,tr->comment);
91   return new_tr;
92 }
93
94 VikTrackpoint *vik_trackpoint_new()
95 {
96   return g_malloc0(sizeof(VikTrackpoint));
97 }
98
99 void vik_trackpoint_free(VikTrackpoint *tp)
100 {
101   g_free(tp);
102 }
103
104 VikTrackpoint *vik_trackpoint_copy(VikTrackpoint *tp)
105 {
106   VikTrackpoint *rv = vik_trackpoint_new();
107   *rv = *tp;
108   return rv;
109 }
110
111 gdouble vik_track_get_length(const VikTrack *tr)
112 {
113   gdouble len = 0.0;
114   if ( tr->trackpoints )
115   {
116     GList *iter = tr->trackpoints->next;
117     while (iter)
118     {
119       if ( ! VIK_TRACKPOINT(iter->data)->newsegment )
120         len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
121                                 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
122       iter = iter->next;
123     }
124   }
125   return len;
126 }
127
128 gdouble vik_track_get_length_including_gaps(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       len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
137                               &(VIK_TRACKPOINT(iter->prev->data)->coord) );
138       iter = iter->next;
139     }
140   }
141   return len;
142 }
143
144 gulong vik_track_get_tp_count(const VikTrack *tr)
145 {
146   gulong num = 0;
147   GList *iter = tr->trackpoints;
148   while ( iter )
149   {
150     num++;
151     iter = iter->next;
152   }
153   return num;
154 }
155
156 gulong vik_track_get_dup_point_count ( const VikTrack *tr )
157 {
158   gulong num = 0;
159   GList *iter = tr->trackpoints;
160   while ( iter )
161   {
162     if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
163                        &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
164       num++;
165     iter = iter->next;
166   }
167   return num;
168 }
169
170 void vik_track_remove_dup_points ( VikTrack *tr )
171 {
172   GList *iter = tr->trackpoints;
173   while ( iter )
174   {
175     if ( iter->next && vik_coord_equals ( &(VIK_TRACKPOINT(iter->data)->coord),
176                        &(VIK_TRACKPOINT(iter->next->data)->coord) ) )
177     {
178       g_free ( iter->next->data );
179       tr->trackpoints = g_list_delete_link ( tr->trackpoints, iter->next );
180     }
181     else
182       iter = iter->next;
183   }
184 }
185
186 guint vik_track_get_segment_count(const VikTrack *tr)
187 {
188   guint num = 1;
189   GList *iter = tr->trackpoints;
190   if ( !iter )
191     return 0;
192   while ( (iter = iter->next) )
193   {
194     if ( VIK_TRACKPOINT(iter->data)->newsegment )
195       num++;
196   }
197   return num;
198 }
199
200 VikTrack **vik_track_split_into_segments(VikTrack *t, guint *ret_len)
201 {
202   VikTrack **rv;
203   VikTrack *tr;
204   guint i;
205   guint segs = vik_track_get_segment_count(t);
206   GList *iter;
207
208   if ( segs < 2 )
209   {
210     *ret_len = 0;
211     return NULL;
212   }
213
214   rv = g_malloc ( segs * sizeof(VikTrack *) );
215   tr = vik_track_copy ( t );
216   rv[0] = tr;
217   iter = tr->trackpoints;
218
219   i = 1;
220   while ( (iter = iter->next) )
221   {
222     if ( VIK_TRACKPOINT(iter->data)->newsegment )
223     {
224       iter->prev->next = NULL;
225       iter->prev = NULL;
226       rv[i] = vik_track_new();
227       if ( tr->comment )
228         vik_track_set_comment ( rv[i], tr->comment );
229       rv[i]->visible = tr->visible;
230       rv[i]->trackpoints = iter;
231       i++;
232     }
233   }
234   *ret_len = segs;
235   return rv;
236 }
237
238 void vik_track_reverse ( VikTrack *tr )
239 {
240   GList *iter;
241   tr->trackpoints = g_list_reverse(tr->trackpoints);
242
243   /* fix 'newsegment' */
244   iter = g_list_last ( tr->trackpoints );
245   while ( iter )
246   {
247     if ( ! iter->next ) /* last segment, was first, cancel newsegment. */
248       VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
249     if ( ! iter->prev ) /* first segment by convention has newsegment flag. */
250       VIK_TRACKPOINT(iter->data)->newsegment = TRUE;
251     else if ( VIK_TRACKPOINT(iter->data)->newsegment && iter->next )
252     {
253       VIK_TRACKPOINT(iter->next->data)->newsegment = TRUE;
254       VIK_TRACKPOINT(iter->data)->newsegment = FALSE;
255     }
256     iter = iter->prev;
257   }
258 }
259
260 gdouble vik_track_get_average_speed(const VikTrack *tr)
261 {
262   gdouble len = 0.0;
263   guint32 time = 0;
264   if ( tr->trackpoints )
265   {
266     GList *iter = tr->trackpoints->next;
267     while (iter)
268     {
269       if ( VIK_TRACKPOINT(iter->data)->has_timestamp && 
270           VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
271           (! VIK_TRACKPOINT(iter->data)->newsegment) )
272       {
273         len += vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
274                                 &(VIK_TRACKPOINT(iter->prev->data)->coord) );
275         time += ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
276       }
277       iter = iter->next;
278     }
279   }
280   return (time == 0) ? 0 : ABS(len/time);
281 }
282
283 gdouble vik_track_get_max_speed(const VikTrack *tr)
284 {
285   gdouble maxspeed = 0.0, speed = 0.0;
286   if ( tr->trackpoints )
287   {
288     GList *iter = tr->trackpoints->next;
289     while (iter)
290     {
291       if ( VIK_TRACKPOINT(iter->data)->has_timestamp && 
292           VIK_TRACKPOINT(iter->prev->data)->has_timestamp &&
293           (! VIK_TRACKPOINT(iter->data)->newsegment) )
294       {
295         speed =  vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord), &(VIK_TRACKPOINT(iter->prev->data)->coord) )
296                  / ABS(VIK_TRACKPOINT(iter->data)->timestamp - VIK_TRACKPOINT(iter->prev->data)->timestamp);
297         if ( speed > maxspeed )
298           maxspeed = speed;
299       }
300       iter = iter->next;
301     }
302   }
303   return maxspeed;
304 }
305
306 void vik_track_convert ( VikTrack *tr, VikCoordMode dest_mode )
307 {
308   GList *iter = tr->trackpoints;
309   while (iter)
310   {
311     vik_coord_convert ( &(VIK_TRACKPOINT(iter->data)->coord), dest_mode );
312     iter = iter->next;
313   }
314 }
315
316 /* I understood this when I wrote it ... maybe ... Basically it eats up the
317  * proper amounts of length on the track and averages elevation over that. */
318 gdouble *vik_track_make_elevation_map ( const VikTrack *tr, guint16 num_chunks )
319 {
320   gdouble *pts;
321   gdouble total_length, chunk_length, current_dist, current_area_under_curve, current_seg_length, dist_along_seg = 0.0;
322   gdouble altitude1, altitude2;
323   guint16 current_chunk;
324   gboolean ignore_it = FALSE;
325
326   GList *iter = tr->trackpoints;
327
328   if (!iter->next) /* one-point track */
329           return NULL;
330
331   { /* test if there's anything worth calculating */
332     gboolean okay = FALSE;
333     while ( iter )
334     {
335       if ( VIK_TRACKPOINT(iter->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
336         okay = TRUE; break;
337       }
338       iter = iter->next;
339     }
340     if ( ! okay )
341       return NULL;
342   }
343
344
345
346   g_assert ( num_chunks < 16000 );
347
348   pts = g_malloc ( sizeof(gdouble) * num_chunks );
349
350   total_length = vik_track_get_length_including_gaps ( tr );
351   chunk_length = total_length / num_chunks;
352
353   current_dist = 0.0;
354   current_area_under_curve = 0;
355   current_chunk = 0;
356   current_seg_length = 0;
357
358   current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
359       &(VIK_TRACKPOINT(iter->next->data)->coord) );
360   altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
361   altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
362   dist_along_seg = 0;
363
364   while ( current_chunk < num_chunks ) {
365
366     /* go along current seg */
367     if ( current_seg_length && (current_seg_length - dist_along_seg) > chunk_length ) {
368       dist_along_seg += chunk_length;
369
370       /*        /
371        *   pt2 *
372        *      /x       altitude = alt_at_pt_1 + alt_at_pt_2 / 2 = altitude1 + slope * dist_value_of_pt_inbetween_pt1_and_pt2
373        *     /xx   avg altitude = area under curve / chunk len
374        *pt1 *xxx   avg altitude = altitude1 + (altitude2-altitude1)/(current_seg_length)*(dist_along_seg + (chunk_len/2))
375        *   / xxx
376        *  /  xxx
377        **/
378
379       if ( ignore_it )
380         pts[current_chunk] = VIK_DEFAULT_ALTITUDE;
381       else
382         pts[current_chunk] = altitude1 + (altitude2-altitude1)*((dist_along_seg - (chunk_length/2))/current_seg_length);
383
384       current_chunk++;
385     } else {
386       /* finish current seg */
387       if ( current_seg_length ) {
388         gdouble altitude_at_dist_along_seg = altitude1 + (altitude2-altitude1)/(current_seg_length)*dist_along_seg;
389         current_dist = current_seg_length - dist_along_seg;
390         current_area_under_curve = current_dist*(altitude_at_dist_along_seg + altitude2)*0.5;
391       } else { current_dist = current_area_under_curve = 0; } /* should only happen if first current_seg_length == 0 */
392
393       /* get intervening segs */
394       iter = iter->next;
395       while ( iter && iter->next ) {
396         current_seg_length = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
397             &(VIK_TRACKPOINT(iter->next->data)->coord) );
398         altitude1 = VIK_TRACKPOINT(iter->data)->altitude;
399         altitude2 = VIK_TRACKPOINT(iter->next->data)->altitude;
400         ignore_it = VIK_TRACKPOINT(iter->next->data)->newsegment;
401
402         if ( chunk_length - current_dist >= current_seg_length ) {
403           current_dist += current_seg_length;
404           current_area_under_curve += current_seg_length * (altitude1+altitude2) * 0.5;
405           iter = iter->next;
406         } else {
407           break;
408         }
409       }
410
411       /* final seg */
412       dist_along_seg = chunk_length - current_dist;
413       if ( ignore_it || !iter->next ) {
414         pts[current_chunk] = current_area_under_curve / current_dist;
415       } 
416       else {
417         current_area_under_curve += dist_along_seg * (altitude1 + (altitude2 - altitude1)*dist_along_seg/current_seg_length);
418         pts[current_chunk] = current_area_under_curve / chunk_length;
419       }
420
421       current_dist = 0;
422       current_chunk++;
423     }
424   }
425
426   return pts;
427 }
428
429
430 void vik_track_get_total_elevation_gain(const VikTrack *tr, gdouble *up, gdouble *down)
431 {
432   gdouble diff;
433   *up = *down = 0;
434   if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE )
435   {
436     GList *iter = tr->trackpoints->next;
437     while (iter)
438     {
439       diff = VIK_TRACKPOINT(iter->data)->altitude - VIK_TRACKPOINT(iter->prev->data)->altitude;
440       if ( diff > 0 )
441         *up += diff;
442       else
443         *down -= diff;
444       iter = iter->next;
445     }
446   } else
447     *up = *down = VIK_DEFAULT_ALTITUDE;
448 }
449
450 typedef struct {
451   double a, b, c, d;
452 } spline_coeff_t;
453
454 void compute_spline(int n, double *x, double *f, spline_coeff_t *p) 
455 {
456   double *h, *alpha, *B, *m;
457   int i;
458   int orig_n = n;
459   double new_x[3], new_f[3];
460   
461   if (n==0) return;
462   if (n==1) {
463     new_x[0] = x[0];
464     new_f[0] = f[0];
465     new_x[1] = x[0]+0.00001;
466     new_f[1] = f[0];
467     x = new_x;
468     f = new_f;
469     n = 3;
470   }
471   if (n==2) {
472     new_x[0] = x[0];
473     new_f[0] = f[0];
474     new_x[1] = x[1];
475     new_f[1] = f[1];
476     new_x[2] = x[1] + x[1]-x[0];
477     new_f[2] = f[1] + f[1]-f[0];
478     x = new_x;
479     f = new_f;
480     n = 3;
481   }
482   
483   /* we're solving a linear system of equations of the form Ax = B. 
484    * The matrix a is tridiagonal and consists of coefficients in 
485    * the h[] and alpha[] arrays. 
486    */
487
488   h = (double *)malloc(sizeof(double) * (n-1));
489   for (i=0; i<n-1; i++) {
490     h[i] = x[i+1]-x[i];
491   }
492
493   alpha = (double *)malloc(sizeof(double) * (n-2));
494   for (i=0; i<n-2; i++) {
495     alpha[i] = 2 * (h[i] + h[i+1]);
496   }
497
498   /* B[] is the vector on the right hand side of the equation */
499   B = (double *)malloc(sizeof(double) * (n-2));
500   for (i=0; i<n-2; i++) {
501     B[i] = 6 * ((f[i+2] - f[i+1])/h[i+1] - (f[i+1] - f[i])/h[i]);
502   }
503
504   /* Now solve the n-2 by n-2 system */
505   m = (double *)malloc(sizeof(double) * (n-2));
506   for (i=1; i<=n-3; i++) {
507     /*
508     d0 = alpha 0   
509     a0 = h1          
510     c0 = h1          
511
512       di = di - (ai-1 / di-1) * ci-1
513       bi = bi - (ai-1 / di-1) * bi-1
514       ;
515     */
516     alpha[i] = alpha[i] - (h[i]/alpha[i-1]) * h[i];
517     B[i] = B[i] - (h[i]/alpha[i-1]) * B[i-1];
518   }
519   /*  xn-3 = bn-3 / dn-3; */
520   m[n-3] = B[n-3]/alpha[n-3];
521   for (i=n-4; i>=0; i--) {
522     m[i] = (B[i]-h[i+1]*m[i+1])/alpha[i];
523   }
524
525   for (i=0; i<orig_n-1; i++) {
526     double mi, mi1;
527     mi = (i==(n-2)) ? 0 : m[i];
528     mi1 = (i==0) ? 0 : m[i-1];
529
530     p[i].a = f[i+1];
531     p[i].b = (f[i+1] - f[i]) / h[i]  +  h[i] * (2*mi + mi1) / 6;
532     p[i].c = mi/2;
533     p[i].d = (mi-mi1)/(6*h[i]);
534   }
535
536   free(alpha);
537   free(B);
538   free(h);
539   free(m);
540 }
541
542 /* by Alex Foobarian */
543 gdouble *vik_track_make_speed_map ( const VikTrack *tr, guint16 num_chunks )
544 {
545   gdouble *v, *s, *t;
546   gdouble duration, chunk_dur, T, s_prev, s_now;
547   time_t t1, t2;
548   int i, pt_count, numpts, spline;
549   GList *iter;
550   spline_coeff_t *p;
551   GList *mytr;
552
553   if ( ! tr->trackpoints )
554     return NULL;
555
556   g_assert ( num_chunks < 16000 );
557
558 #ifdef XXXXXXXXXXXXXXXXXX
559   iter = tr->trackpoints;
560   while (iter) {
561     
562   }
563 #endif /*XXXXXXXXXXXXXXXXXX*/
564
565   t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
566   t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
567   duration = t2 - t1;
568
569   if ( !t1 || !t2 || !duration )
570     return NULL;
571
572   if (duration < 0) {
573     fprintf(stderr, "negative duration: unsorted trackpoint timestamps?\n");
574     return NULL;
575   }
576   pt_count = vik_track_get_tp_count(tr);
577
578   v = g_malloc ( sizeof(gdouble) * num_chunks );
579   chunk_dur = duration / num_chunks;
580
581   s = g_malloc(sizeof(double) * pt_count);
582   t = g_malloc(sizeof(double) * pt_count);
583   p = g_malloc(sizeof(spline_coeff_t) * (pt_count-1));
584
585   iter = tr->trackpoints->next;
586   numpts = 0;
587   s[0] = 0;
588   t[0] = VIK_TRACKPOINT(iter->prev->data)->timestamp;
589   numpts++;
590   while (iter) {
591     s[numpts] = s[numpts-1] + vik_coord_diff ( &(VIK_TRACKPOINT(iter->prev->data)->coord), &(VIK_TRACKPOINT(iter->data)->coord) );
592     t[numpts] = VIK_TRACKPOINT(iter->data)->timestamp;
593     numpts++;
594     iter = iter->next;
595   }
596
597   compute_spline(numpts, t, s, p);
598
599   /*
600   printf("Got spline\n");
601   for (i=0; i<numpts-1; i++) {
602     printf("a = %15f  b = %15f  c = %15f  d = %15f\n", p[i].a, p[i].b, p[i].c, p[i].d);
603   }
604   */
605
606   /* the spline gives us distances at chunk_dur intervals. from these,
607    * we obtain average speed in each interval.
608    */
609   spline = 0;
610   T = t[spline];
611   s_prev = 
612       p[spline].d * pow(T - t[spline+1], 3) + 
613       p[spline].c * pow(T - t[spline+1], 2) + 
614       p[spline].b * (T - t[spline+1]) + 
615       p[spline].a;
616   for (i = 0; i < num_chunks; i++, T+=chunk_dur) {
617     while (T > t[spline+1]) {
618       spline++;
619     }
620     s_now = 
621       p[spline].d * pow(T - t[spline+1], 3) + 
622       p[spline].c * pow(T - t[spline+1], 2) + 
623       p[spline].b * (T - t[spline+1]) + 
624       p[spline].a;
625     v[i] = (s_now - s_prev) / chunk_dur;
626     s_prev = s_now;
627     /* 
628      * old method of averages
629     v[i] = (s[spline+1]-s[spline])/(t[spline+1]-t[spline]);
630     */
631   }
632   g_free(s);
633   g_free(t);
634   g_free(p);
635   return v;
636 }
637
638 /* by Alex Foobarian */
639 VikTrackpoint *vik_track_get_closest_tp_by_percentage_dist ( VikTrack *tr, gdouble reldist )
640 {
641   gdouble dist = vik_track_get_length_including_gaps(tr) * reldist;
642   gdouble current_dist = 0.0;
643   gdouble current_inc = 0.0;
644   if ( tr->trackpoints )
645   {
646     GList *iter = tr->trackpoints->next;
647     GList *last_iter = NULL;
648     while (iter)
649     {
650       current_inc = vik_coord_diff ( &(VIK_TRACKPOINT(iter->data)->coord),
651                                      &(VIK_TRACKPOINT(iter->prev->data)->coord) );
652       current_dist += current_inc;
653       if ( current_dist >= dist )
654         break;
655       last_iter = iter;
656       iter = iter->next;
657     }
658     if (!iter) /* passing the end the track */
659       return (last_iter ? last_iter->data : NULL);
660     /* we've gone past the dist already, was prev trackpoint closer? */
661     /* should do a vik_coord_average_weighted() thingy. */
662     if ( iter->prev && abs(current_dist-current_inc-dist) < abs(current_dist-dist) )
663       iter = iter->prev;
664
665     return VIK_TRACKPOINT(iter->data);
666
667   }
668   return NULL;
669 }
670
671 gboolean vik_track_get_minmax_alt ( const VikTrack *tr, gdouble *min_alt, gdouble *max_alt )
672 {
673   *min_alt = 25000;
674   *max_alt = -5000;
675   if ( tr && tr->trackpoints && tr->trackpoints->data && (VIK_TRACKPOINT(tr->trackpoints->data)->altitude != VIK_DEFAULT_ALTITUDE) ) {
676     GList *iter = tr->trackpoints->next;
677     gdouble tmp_alt;
678     while (iter)
679     {
680       tmp_alt = VIK_TRACKPOINT(iter->data)->altitude;
681       if ( tmp_alt > *max_alt )
682         *max_alt = tmp_alt;
683       if ( tmp_alt < *min_alt )
684         *min_alt = tmp_alt;
685       iter = iter->next;
686     }
687     return TRUE;
688   }
689   return FALSE;
690 }
691
692 void vik_track_marshall ( VikTrack *tr, guint8 **data, guint *datalen)
693 {
694   GList *tps;
695   GByteArray *b = g_byte_array_new();
696   guint len;
697   guint intp, ntp;
698
699   g_byte_array_append(b, (guint8 *)tr, sizeof(*tr));
700
701   /* we'll fill out number of trackpoints later */
702   intp = b->len;
703   g_byte_array_append(b, (guint8 *)&len, sizeof(len));
704
705   tps = tr->trackpoints;
706   ntp = 0;
707   while (tps) {
708     g_byte_array_append(b, (guint8 *)tps->data, sizeof(VikTrackpoint));
709     tps = tps->next;
710     ntp++;
711   }
712   *(guint *)(b->data + intp) = ntp;
713
714   len = (tr->comment) ? strlen(tr->comment)+1 : 0; 
715   g_byte_array_append(b, (guint8 *)&len, sizeof(len)); 
716   if (tr->comment) g_byte_array_append(b, (guint8 *)tr->comment, len);
717
718   *data = b->data;
719   *datalen = b->len;
720   g_byte_array_free(b, FALSE);
721 }
722
723 VikTrack *vik_track_unmarshall (guint8 *data, guint datalen)
724 {
725   guint len;
726   VikTrack *new_tr = vik_track_new();
727   VikTrackpoint *new_tp;
728   guint ntp;
729   gint i;
730
731   /* only the visibility is needed */
732   new_tr->visible = ((VikTrack *)data)->visible;
733   data += sizeof(*new_tr);
734
735   ntp = *(guint *)data;
736   data += sizeof(ntp);
737
738   for (i=0; i<ntp; i++) {
739     new_tp = vik_trackpoint_new();
740     memcpy(new_tp, data, sizeof(*new_tp));
741     data += sizeof(*new_tp);
742     new_tr->trackpoints = g_list_append(new_tr->trackpoints, new_tp);
743   }
744
745   len = *(guint *)data;
746   data += sizeof(len);
747   if (len) {
748     new_tr->comment = g_strdup((gchar *)data);
749   }
750   return new_tr;
751 }