Recreate the navit git/gerrit project that vanished
[profile/ivi/navit.git] / navit / vehicle.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2009 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <time.h>
24 #include "config.h"
25 #include "debug.h"
26 #include "coord.h"
27 #include "item.h"
28 #include "log.h"
29 #include "plugin.h"
30 #include "transform.h"
31 #include "util.h"
32 #include "event.h"
33 #include "coord.h"
34 #include "transform.h"
35 #include "projection.h"
36 #include "point.h"
37 #include "graphics.h"
38 #include "callback.h"
39 #include "color.h"
40 #include "layout.h"
41 #include "vehicle.h"
42 #include "xmlconfig.h"
43
44 struct vehicle {
45         struct object_func *func;
46         int refcount;
47         struct vehicle_methods meth;
48         struct vehicle_priv *priv;
49         struct callback_list *cbl;
50         struct log *nmea_log, *gpx_log;
51         char *gpx_desc;
52         struct attr **attrs;
53
54         // cursor
55         struct cursor *cursor;
56         int cursor_fixed;
57         struct callback *animate_callback;
58         struct event_timeout *animate_timer;
59         struct point cursor_pnt;
60         struct graphics *gra;
61         struct graphics_gc *bg;
62         struct transformation *trans;
63         int angle;
64         int speed;
65         int sequence;
66         GHashTable *log_to_cb;
67 };
68
69 struct object_func vehicle_func;
70
71 static void vehicle_draw_do(struct vehicle *this_, int lazy);
72 static void vehicle_log_nmea(struct vehicle *this_, struct log *log);
73 static void vehicle_log_gpx(struct vehicle *this_, struct log *log);
74 static void vehicle_log_textfile(struct vehicle *this_, struct log *log);
75 static void vehicle_log_binfile(struct vehicle *this_, struct log *log);
76 static int vehicle_add_log(struct vehicle *this_, struct log *log);
77
78
79
80 /**
81  * Creates a new vehicle
82  */
83 struct vehicle *
84 vehicle_new(struct attr *parent, struct attr **attrs)
85 {
86         struct vehicle *this_;
87         struct attr *source;
88         struct vehicle_priv *(*vehicletype_new) (struct vehicle_methods *
89                                                  meth,
90                                                  struct callback_list *
91                                                  cbl,
92                                                  struct attr ** attrs);
93         char *type, *colon;
94         struct pcoord center;
95
96         dbg(1, "enter\n");
97         source = attr_search(attrs, NULL, attr_source);
98         if (!source) {
99                 dbg(0, "no source\n");
100                 return NULL;
101         }
102
103         type = g_strdup(source->u.str);
104         colon = strchr(type, ':');
105         if (colon)
106                 *colon = '\0';
107         dbg(1, "source='%s' type='%s'\n", source->u.str, type);
108
109         vehicletype_new = plugin_get_vehicle_type(type);
110         if (!vehicletype_new) {
111                 dbg(0, "invalid type '%s'\n", type);
112                 g_free(type);
113                 return NULL;
114         }
115         g_free(type);
116         this_ = g_new0(struct vehicle, 1);
117         this_->func=&vehicle_func;
118         this_->refcount = 1;
119         this_->cbl = callback_list_new();
120         this_->priv = vehicletype_new(&this_->meth, this_->cbl, attrs);
121         if (!this_->priv) {
122                 dbg(0, "vehicletype_new failed\n");
123                 callback_list_destroy(this_->cbl);
124                 g_free(this_);
125                 return NULL;
126         }
127         this_->attrs=attr_list_dup(attrs);
128
129         this_->trans=transform_new();
130         center.pro=projection_screen;
131         center.x=0;
132         center.y=0;
133         transform_setup(this_->trans, &center, 16, 0);
134
135         dbg(1, "leave\n");
136         this_->log_to_cb=g_hash_table_new(NULL,NULL);
137         return this_;
138 }
139
140 /**
141  * Destroys a vehicle
142  * 
143  * @param this_ The vehicle to destroy
144  */
145 void
146 vehicle_destroy(struct vehicle *this_)
147 {
148         if (this_->animate_callback) {
149                 callback_destroy(this_->animate_callback);
150                 event_remove_timeout(this_->animate_timer);
151         }
152         transform_destroy(this_->trans);
153         this_->meth.destroy(this_->priv);
154         callback_list_destroy(this_->cbl);
155         attr_list_free(this_->attrs);
156         if (this_->bg)
157                 graphics_gc_destroy(this_->bg);
158         if (this_->gra)
159                 graphics_free(this_->gra);
160         g_free(this_);
161 }
162
163 struct vehicle *
164 vehicle_ref(struct vehicle *this_)
165 {
166         this_->refcount++;
167         dbg(0,"refcount %d\n",this_->refcount);
168         return this_;
169 }
170
171 void
172 vehicle_unref(struct vehicle *this_)
173 {
174         if(!this_)
175                 return;
176         this_->refcount--;
177         dbg(0,"refcount %d\n",this_->refcount);
178         if (this_->refcount <= 0)
179                 vehicle_destroy(this_);
180 }
181
182 /**
183  * Creates an attribute iterator to be used with vehicles
184  */
185 struct attr_iter *
186 vehicle_attr_iter_new(void)
187 {
188         return (struct attr_iter *)g_new0(void *,1);
189 }
190
191 /**
192  * Destroys a vehicle attribute iterator
193  *
194  * @param iter a vehicle attr_iter
195  */
196 void
197 vehicle_attr_iter_destroy(struct attr_iter *iter)
198 {
199         g_free(iter);
200 }
201
202
203
204 /**
205  * Generic get function
206  *
207  * @param this_ Pointer to a vehicle structure
208  * @param type The attribute type to look for
209  * @param attr Pointer to an attr structure to store the attribute
210  * @param iter A vehicle attr_iter
211  */
212 int
213 vehicle_get_attr(struct vehicle *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
214 {
215         int ret;
216         if (this_->meth.position_attr_get) {
217                 ret=this_->meth.position_attr_get(this_->priv, type, attr);
218                 if (ret)
219                         return ret;
220         }
221         if (type == attr_log_gpx_desc) {
222                 attr->u.str = this_->gpx_desc;
223                 return 1;
224         }
225         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
226 }
227
228 /**
229  * Generic set function
230  *
231  * @param this_ Pointer to a vehicle structure
232  * @param attr Pointer to an attr structure for the attribute to be set
233  * @return nonzero on success, zero on failure
234  */
235 int
236 vehicle_set_attr(struct vehicle *this_, struct attr *attr)
237 {
238         int ret=1;
239         if (this_->meth.set_attr)
240                 ret=this_->meth.set_attr(this_->priv, attr);
241         if (ret == 1 && attr->type == attr_log_gpx_desc) {
242                 g_free(this_->gpx_desc);
243                 this_->gpx_desc = attr->u.str;
244         }
245         if (ret == 1 && attr->type != attr_navit && attr->type != attr_pdl_gps_update)
246                 this_->attrs=attr_generic_set_attr(this_->attrs, attr);
247         return ret != 0;
248 }
249
250 /**
251  * Generic add function
252  *
253  * @param this_ A vehicle
254  * @param attr A struct attr
255  */
256 int
257 vehicle_add_attr(struct vehicle *this_, struct attr *attr)
258 {
259         int ret=1;
260         switch (attr->type) {
261         case attr_callback:
262                 callback_list_add(this_->cbl, attr->u.callback);
263                 break;
264         case attr_log:
265                 ret=vehicle_add_log(this_, attr->u.log);
266                 break;
267         // currently supporting oldstyle cursor config.
268         case attr_cursor:
269                 this_->cursor_fixed=1;
270                 vehicle_set_cursor(this_, attr->u.cursor, 1);
271                 break;
272         default:
273                 break;
274         }
275         if (ret)
276                 this_->attrs=attr_generic_add_attr(this_->attrs, attr);
277         return ret;
278 }
279
280 /**
281  * @brief Generic remove function.
282  *
283  * Used to remove a callback from the vehicle.
284  * @param this_ A vehicle
285  * @param attr
286  */
287 int
288 vehicle_remove_attr(struct vehicle *this_, struct attr *attr)
289 {
290         struct callback *cb;
291         switch (attr->type) {
292         case attr_callback:
293                 callback_list_remove(this_->cbl, attr->u.callback);
294                 break;
295         case attr_log:
296                 cb=g_hash_table_lookup(this_->log_to_cb, attr->u.log);
297                 if (!cb)
298                         return 0;
299                 g_hash_table_remove(this_->log_to_cb, attr->u.log);
300                 callback_list_remove(this_->cbl, cb);
301                 break;
302         default:
303                 this_->attrs=attr_generic_remove_attr(this_->attrs, attr);
304                 return 0;
305         }
306         return 1;
307 }
308
309
310
311 /**
312  * Sets the cursor of a vehicle.
313  *
314  * @param this_ A vehicle
315  * @param cursor A cursor
316  * @author Ralph Sennhauser (10/2009)
317  */ 
318 void
319 vehicle_set_cursor(struct vehicle *this_, struct cursor *cursor, int overwrite)
320 {
321         struct point sc;
322         if (this_->cursor_fixed && !overwrite)
323                 return;
324         if (this_->animate_callback) {
325                 event_remove_timeout(this_->animate_timer);
326                 this_->animate_timer=NULL;              // dangling pointer! prevent double freeing.
327                 callback_destroy(this_->animate_callback);
328                 this_->animate_callback=NULL;   // dangling pointer! prevent double freeing.
329         }
330         if (cursor && cursor->interval) {
331                 this_->animate_callback=callback_new_2(callback_cast(vehicle_draw_do), this_, 0);
332                 this_->animate_timer=event_add_timeout(cursor->interval, 1, this_->animate_callback);
333         }
334
335         if (cursor && this_->gra && this_->cursor) {
336                 this_->cursor_pnt.x+=(this_->cursor->w - cursor->w)/2;
337                 this_->cursor_pnt.y+=(this_->cursor->h - cursor->h)/2;
338                 graphics_overlay_resize(this_->gra, &this_->cursor_pnt, cursor->w, cursor->h, 65535, 0);
339         }
340
341         if (cursor) { 
342                 sc.x=cursor->w/2;
343                 sc.y=cursor->h/2;
344                 if (!this_->cursor && this_->gra)
345                         graphics_overlay_disable(this_->gra, 0);
346         } else {
347                 sc.x=sc.y=0;
348                 if (this_->cursor && this_->gra)
349                         graphics_overlay_disable(this_->gra, 1);
350         }
351         transform_set_screen_center(this_->trans, &sc);
352
353         this_->cursor=cursor;
354 }
355
356 /**
357  * Draws a vehicle on top of a graphics.
358  *
359  * @param this_ The vehicle
360  * @param gra The graphics
361  * @param pnt Screen coordinates of the vehicle.
362  * @param lazy use lazy draw mode.
363  * @param angle The angle relative to the map.
364  * @param speed The speed of the vehicle.
365  */
366 void
367 vehicle_draw(struct vehicle *this_, struct graphics *gra, struct point *pnt, int lazy, int angle, int speed)
368 {
369         if (angle < 0)
370                 angle+=360;
371         dbg(1,"enter this=%p gra=%p pnt=%p lazy=%d dir=%d speed=%d\n", this_, gra, pnt, lazy, angle, speed);
372         dbg(1,"point %d,%d\n", pnt->x, pnt->y);
373         this_->cursor_pnt=*pnt;
374         this_->angle=angle;
375         this_->speed=speed;
376         if (!this_->cursor)
377                 return;
378         this_->cursor_pnt.x-=this_->cursor->w/2;
379         this_->cursor_pnt.y-=this_->cursor->h/2;
380         if (!this_->gra) {
381                 struct color c;
382                 this_->gra=graphics_overlay_new(gra, &this_->cursor_pnt, this_->cursor->w, this_->cursor->h, 65535, 0);
383                 if (this_->gra) {
384                         this_->bg=graphics_gc_new(this_->gra);
385                         c.r=0; c.g=0; c.b=0; c.a=0;
386                         graphics_gc_set_foreground(this_->bg, &c);
387                         graphics_background_gc(this_->gra, this_->bg);
388                 }
389         }
390         vehicle_draw_do(this_, lazy);
391 }
392
393 int
394 vehicle_get_cursor_data(struct vehicle *this, struct point *pnt, int *angle, int *speed)
395 {
396         *pnt=this->cursor_pnt;
397         *angle=this->angle;
398         *speed=this->speed;
399         return 1;
400 }
401
402
403 static void
404 vehicle_draw_do(struct vehicle *this_, int lazy)
405 {
406         struct point p;
407         struct cursor *cursor=this_->cursor;
408         int speed=this_->speed;
409         int angle=this_->angle;
410         int sequence=this_->sequence;
411         struct attr **attr;
412         char *label=NULL;
413         int match=0;
414
415         if (!this_->cursor || !this_->cursor->attrs || !this_->gra)
416                 return;
417
418         attr=this_->attrs;
419         while (attr && *attr) {
420                 if ((*attr)->type == attr_name) 
421                         label=(*attr)->u.str;
422                 attr++;
423         }
424         transform_set_yaw(this_->trans, -this_->angle);
425         graphics_draw_mode(this_->gra, draw_mode_begin);
426         p.x=0;
427         p.y=0;
428         graphics_draw_rectangle(this_->gra, this_->bg, &p, cursor->w, cursor->h);
429         attr=cursor->attrs;
430         while (*attr) {
431                 if ((*attr)->type == attr_itemgra) {
432                         struct itemgra *itm=(*attr)->u.itemgra;
433                         dbg(1,"speed %d-%d %d\n", itm->speed_range.min, itm->speed_range.max, speed);
434                         if (speed >= itm->speed_range.min && speed <= itm->speed_range.max &&  
435                             angle >= itm->angle_range.min && angle <= itm->angle_range.max &&  
436                             sequence >= itm->sequence_range.min && sequence <= itm->sequence_range.max) {
437                                 graphics_draw_itemgra(this_->gra, itm, this_->trans, label);
438                         }
439                         if (sequence < itm->sequence_range.max)
440                                 match=1;
441                 }
442                 ++attr;
443         }
444         graphics_draw_drag(this_->gra, &this_->cursor_pnt);
445         graphics_draw_mode(this_->gra, lazy ? draw_mode_end_lazy : draw_mode_end);
446         if (this_->animate_callback) {
447                 ++this_->sequence;
448                 if (cursor->sequence_range && cursor->sequence_range->max < this_->sequence)
449                         this_->sequence=cursor->sequence_range->min;
450                 if (! match && ! cursor->sequence_range)
451                         this_->sequence=0;
452         }
453 }
454
455 /**
456  * Writes to an NMEA log.
457  *
458  * @param this_ Pointer to the vehicle structure of the data source
459  * @param log Pointer to a log structure for the log file
460  */
461 static void
462 vehicle_log_nmea(struct vehicle *this_, struct log *log)
463 {
464         struct attr pos_attr;
465         if (!this_->meth.position_attr_get)
466                 return;
467         if (!this_->meth.position_attr_get(this_->priv, attr_position_nmea, &pos_attr))
468                 return;
469         log_write(log, pos_attr.u.str, strlen(pos_attr.u.str), 0);
470 }
471
472 void
473 vehicle_log_gpx_add_tag(char *tag, char **logstr)
474 {
475         char *ext_start="\t<extensions>\n";
476         char *ext_end="\t</extensions>\n";
477         char *trkpt_end="</trkpt>";
478         char *start=NULL,*end=NULL;
479         if (!*logstr) {
480                 start=g_strdup(ext_start);
481                 end=g_strdup(ext_end);
482         } else {
483                 char *str=strstr(*logstr, ext_start);
484                 int len;
485                 if (str) {
486                         len=str-*logstr+strlen(ext_start);
487                         start=g_strdup(*logstr);
488                         start[len]='\0';
489                         end=g_strdup(str+strlen(ext_start));
490                 } else {
491                         str=strstr(*logstr, trkpt_end);
492                         len=str-*logstr;
493                         end=g_strdup_printf("%s%s",ext_end,str);
494                         str=g_strdup(*logstr);
495                         str[len]='\0';
496                         start=g_strdup_printf("%s%s",str,ext_start);
497                         g_free(str);
498                 }
499         }
500         *logstr=g_strdup_printf("%s%s%s",start,tag,end);
501         g_free(start);
502         g_free(end);
503 }
504
505 /**
506  * Writes to a GPX log.
507  *
508  * @param this_ Pointer to the vehicle structure of the data source
509  * @param log Pointer to a log structure for the log file
510  */
511 static void
512 vehicle_log_gpx(struct vehicle *this_, struct log *log)
513 {
514         struct attr attr,*attrp, fix_attr;
515         enum attr_type *attr_types;
516         char *logstr;
517         char *extensions="\t<extensions>\n";
518
519         if (!this_->meth.position_attr_get)
520                 return;
521         if (log_get_attr(log, attr_attr_types, &attr, NULL))
522                 attr_types=attr.u.attr_types;
523         else
524                 attr_types=NULL;
525         if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
526                 if ( fix_attr.u.num == 0 ) 
527                         return; 
528         }
529         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &attr))
530                 return;
531         logstr=g_strdup_printf("<trkpt lat=\"%f\" lon=\"%f\">\n",attr.u.coord_geo->lat,attr.u.coord_geo->lng);
532         if (attr_types && attr_types_contains_default(attr_types, attr_position_time_iso8601, 0)) {
533                 if (this_->meth.position_attr_get(this_->priv, attr_position_time_iso8601, &attr)) {
534                         logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",attr.u.str);
535                 } else {
536                         char *timep = current_to_iso8601();
537                         logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",timep);
538                         g_free(timep);
539                 }
540         }
541         if (this_->gpx_desc) {
542                 logstr=g_strconcat_printf(logstr,"\t<desc>%s</desc>\n",this_->gpx_desc);
543                 g_free(this_->gpx_desc);
544                 this_->gpx_desc = NULL;
545         }
546         if (attr_types_contains_default(attr_types, attr_position_height,0) && this_->meth.position_attr_get(this_->priv, attr_position_height, &attr))
547                 logstr=g_strconcat_printf(logstr,"\t<ele>%.6f</ele>\n",*attr.u.numd);
548         // <magvar> magnetic variation in degrees; we might use position_magnetic_direction and position_direction to figure it out
549         // <geoidheight> Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message (field 11, which vehicle_wince.c ignores)
550         // <name> GPS name (arbitrary)
551         // <cmt> comment
552         // <src> Source of data
553         // <link> Link to additional information (URL)
554         // <sym> Text of GPS symbol name
555         // <type> Type (classification)
556         // <fix> Type of GPS fix {'none'|'2d'|'3d'|'dgps'|'pps'}, leave out if unknown. Similar to position_fix_type but more detailed.
557         if (attr_types_contains_default(attr_types, attr_position_sats_used,0) && this_->meth.position_attr_get(this_->priv, attr_position_sats_used, &attr))
558                 logstr=g_strconcat_printf(logstr,"\t<sat>%d</sat>\n",attr.u.num);
559         if (attr_types_contains_default(attr_types, attr_position_hdop,0) && this_->meth.position_attr_get(this_->priv, attr_position_hdop, &attr))
560                 logstr=g_strconcat_printf(logstr,"\t<hdop>%.6f</hdop>\n",*attr.u.numd);
561         // <vdop>, <pdop> Vertical and position dilution of precision, no corresponding attribute
562         if (attr_types_contains_default(attr_types, attr_position_direction,0) && this_->meth.position_attr_get(this_->priv, attr_position_direction, &attr))
563                 logstr=g_strconcat_printf(logstr,"\t<course>%.1f</course>\n",*attr.u.numd);
564         if (attr_types_contains_default(attr_types, attr_position_speed, 0) && this_->meth.position_attr_get(this_->priv, attr_position_speed, &attr))
565                 logstr=g_strconcat_printf(logstr,"\t<speed>%.2f</speed>\n",(*attr.u.numd / 3.6));
566         if (attr_types_contains_default(attr_types, attr_profilename, 0) && (attrp=attr_search(this_->attrs, NULL, attr_profilename))) {
567                 logstr=g_strconcat_printf(logstr,"%s\t\t<navit:profilename>%s</navit:profilename>\n",extensions,attrp->u.str);
568                 extensions="";
569         }
570         if (attr_types_contains_default(attr_types, attr_position_radius, 0) && this_->meth.position_attr_get(this_->priv, attr_position_radius, &attr)) {
571                 logstr=g_strconcat_printf(logstr,"%s\t\t<navit:radius>%.2f</navit:radius>\n",extensions,*attr.u.numd);
572                 extensions="";
573         }
574         if (!strcmp(extensions,"")) {
575                 logstr=g_strconcat_printf(logstr,"\t</extensions>\n");
576         }
577         logstr=g_strconcat_printf(logstr,"</trkpt>\n");
578         callback_list_call_attr_1(this_->cbl, attr_log_gpx, &logstr);
579         log_write(log, logstr, strlen(logstr), 0);
580         g_free(logstr);
581 }
582
583 /**
584  * Writes to a text log.
585  *
586  * @param this_ Pointer to the vehicle structure of the data source
587  * @param log Pointer to a log structure for the log file
588  */
589 static void
590 vehicle_log_textfile(struct vehicle *this_, struct log *log)
591 {
592         struct attr pos_attr,fix_attr;
593         char *logstr;
594         if (!this_->meth.position_attr_get)
595                 return;
596         if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
597                 if (fix_attr.u.num == 0) 
598                         return; 
599         }
600         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
601                 return;
602         logstr=g_strdup_printf("%f %f type=trackpoint\n", pos_attr.u.coord_geo->lng, pos_attr.u.coord_geo->lat);
603         callback_list_call_attr_1(this_->cbl, attr_log_textfile, &logstr);
604         log_write(log, logstr, strlen(logstr), 0);
605 }
606
607 /**
608  * Writes to a binary log.
609  *
610  * @param this_ Pointer to the vehicle structure of the data source
611  * @param log Pointer to a log structure for the log file
612  */
613 static void
614 vehicle_log_binfile(struct vehicle *this_, struct log *log)
615 {
616         struct attr pos_attr, fix_attr;
617         int *buffer;
618         int *buffer_new;
619         int len,limit=1024,done=0,radius=25;
620         struct coord c;
621         enum log_flags flags;
622
623         if (!this_->meth.position_attr_get)
624                 return;
625         if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
626                 if (fix_attr.u.num == 0) 
627                         return; 
628         }
629         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
630                 return;
631         transform_from_geo(projection_mg, pos_attr.u.coord_geo, &c);
632         if (!c.x || !c.y)
633                 return;
634         while (!done) {
635                 buffer=log_get_buffer(log, &len);
636                 if (! buffer || !len) {
637                         buffer_new=g_malloc(5*sizeof(int));
638                         buffer_new[0]=2;
639                         buffer_new[1]=type_track;
640                         buffer_new[2]=0;
641                 } else {
642                         buffer_new=g_malloc((buffer[0]+3)*sizeof(int));
643                         memcpy(buffer_new, buffer, (buffer[0]+1)*sizeof(int));
644                 }
645                 dbg(1,"c=0x%x,0x%x\n",c.x,c.y);
646                 buffer_new[buffer_new[0]+1]=c.x;
647                 buffer_new[buffer_new[0]+2]=c.y;
648                 buffer_new[0]+=2;
649                 buffer_new[2]+=2;
650                 if (buffer_new[2] > limit) {
651                         int count=buffer_new[2]/2;
652                         struct coord *out=g_alloca(sizeof(struct coord)*(count));
653                         struct coord *in=(struct coord *)(buffer_new+3);
654                         int count_out=transform_douglas_peucker(in, count, radius, out);
655                         memcpy(in, out, count_out*2*sizeof(int));
656                         buffer_new[0]+=(count_out-count)*2;     
657                         buffer_new[2]+=(count_out-count)*2;     
658                         flags=log_flag_replace_buffer|log_flag_force_flush|log_flag_truncate;
659                 } else {
660                         flags=log_flag_replace_buffer|log_flag_keep_pointer|log_flag_keep_buffer|log_flag_force_flush;
661                         done=1;
662                 }
663                 log_write(log, (char *)buffer_new, (buffer_new[0]+1)*sizeof(int), flags);
664         }
665 }
666
667 /**
668  * Register a new log to receive data.
669  *
670  * @param this_ Pointer to the vehicle structure of the data source
671  * @param log Pointer to a log structure for the log file
672  */
673 static int
674 vehicle_add_log(struct vehicle *this_, struct log *log)
675 {
676         struct callback *cb;
677         struct attr type_attr;
678         if (!log_get_attr(log, attr_type, &type_attr, NULL))
679                 return 1;
680
681         if (!strcmp(type_attr.u.str, "nmea")) {
682                 cb=callback_new_attr_2(callback_cast(vehicle_log_nmea), attr_position_coord_geo, this_, log);
683         } else if (!strcmp(type_attr.u.str, "gpx")) {
684                 char *header = "<?xml version='1.0' encoding='UTF-8'?>\n"
685                         "<gpx version='1.1' creator='Navit http://navit.sourceforge.net'\n"
686                         "     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
687                         "     xmlns:navit='http://www.navit-project.org/schema/navit'\n"
688                         "     xmlns='http://www.topografix.com/GPX/1/1'\n"
689                         "     xsi:schemaLocation='http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'>\n"
690                         "<trk>\n"
691                         "<trkseg>\n";
692                 char *trailer = "</trkseg>\n</trk>\n</gpx>\n";
693                 log_set_header(log, header, strlen(header));
694                 log_set_trailer(log, trailer, strlen(trailer));
695                 cb=callback_new_attr_2(callback_cast(vehicle_log_gpx), attr_position_coord_geo, this_, log);
696         } else if (!strcmp(type_attr.u.str, "textfile")) {
697                 char *header = "type=track\n";
698                 log_set_header(log, header, strlen(header));
699                 cb=callback_new_attr_2(callback_cast(vehicle_log_textfile), attr_position_coord_geo, this_, log);
700         } else if (!strcmp(type_attr.u.str, "binfile")) {
701                 cb=callback_new_attr_2(callback_cast(vehicle_log_binfile), attr_position_coord_geo, this_, log);
702         } else
703                 return 1;
704         g_hash_table_insert(this_->log_to_cb, log, cb);
705         callback_list_add(this_->cbl, cb);
706         return 0;
707 }
708
709 struct object_func vehicle_func = {
710         attr_vehicle,
711         (object_func_new)vehicle_new,
712         (object_func_get_attr)vehicle_get_attr,
713         (object_func_iter_new)vehicle_attr_iter_new,
714         (object_func_iter_destroy)vehicle_attr_iter_destroy,
715         (object_func_set_attr)vehicle_set_attr,
716         (object_func_add_attr)vehicle_add_attr,
717         (object_func_remove_attr)vehicle_remove_attr,
718         (object_func_init)NULL,
719         (object_func_destroy)vehicle_destroy,
720         (object_func_dup)NULL,
721         (object_func_ref)vehicle_ref,
722         (object_func_unref)vehicle_unref,
723 };