Fix:maptool:Another name for faroe islands
[navit-package] / 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
43 struct vehicle {
44         struct vehicle_methods meth;
45         struct vehicle_priv *priv;
46         struct callback_list *cbl;
47         struct log *nmea_log, *gpx_log;
48         struct attr **attrs;
49
50         // cursor
51         struct cursor *cursor;
52         struct callback *animate_callback;
53         struct event_timeout *animate_timer;
54         struct point cursor_pnt;
55         struct graphics *gra;
56         struct graphics_gc *bg;
57         struct transformation *trans;
58         int angle;
59         int speed;
60         int sequence;
61 };
62
63 static void vehicle_draw_do(struct vehicle *this_, int lazy);
64 static void vehicle_log_nmea(struct vehicle *this_, struct log *log);
65 static void vehicle_log_gpx(struct vehicle *this_, struct log *log);
66 static void vehicle_log_textfile(struct vehicle *this_, struct log *log);
67 static void vehicle_log_binfile(struct vehicle *this_, struct log *log);
68 static int vehicle_add_log(struct vehicle *this_, struct log *log);
69
70
71
72 /**
73  * Creates a new vehicle
74  */
75 struct vehicle *
76 vehicle_new(struct attr *parent, struct attr **attrs)
77 {
78         struct vehicle *this_;
79         struct attr *source;
80         struct vehicle_priv *(*vehicletype_new) (struct vehicle_methods *
81                                                  meth,
82                                                  struct callback_list *
83                                                  cbl,
84                                                  struct attr ** attrs);
85         char *type, *colon;
86         struct pcoord center;
87
88         dbg(1, "enter\n");
89         source = attr_search(attrs, NULL, attr_source);
90         if (!source) {
91                 dbg(0, "no source\n");
92                 return NULL;
93         }
94
95         type = g_strdup(source->u.str);
96         colon = strchr(type, ':');
97         if (colon)
98                 *colon = '\0';
99         dbg(1, "source='%s' type='%s'\n", source->u.str, type);
100
101         vehicletype_new = plugin_get_vehicle_type(type);
102         if (!vehicletype_new) {
103                 dbg(0, "invalid type '%s'\n", type);
104                 return NULL;
105         }
106         this_ = g_new0(struct vehicle, 1);
107         this_->cbl = callback_list_new();
108         this_->priv = vehicletype_new(&this_->meth, this_->cbl, attrs);
109         if (!this_->priv) {
110                 dbg(0, "vehicletype_new failed\n");
111                 callback_list_destroy(this_->cbl);
112                 g_free(this_);
113                 return NULL;
114         }
115         this_->attrs=attr_list_dup(attrs);
116
117         this_->trans=transform_new();
118         center.pro=projection_screen;
119         center.x=0;
120         center.y=0;
121         transform_setup(this_->trans, &center, 16, 0);
122
123         dbg(1, "leave\n");
124         return this_;
125 }
126
127 /**
128  * Destroys a vehicle
129  * 
130  * @param this_ The vehicle to destroy
131  */
132 void
133 vehicle_destroy(struct vehicle *this_)
134 {
135         if (this_->animate_callback) {
136                 callback_destroy(this_->animate_callback);
137                 event_remove_timeout(this_->animate_timer);
138         }
139         transform_destroy(this_->trans);
140         this_->meth.destroy(this_->priv);
141         callback_list_destroy(this_->cbl);
142         attr_list_free(this_->attrs);
143         g_free(this_);
144 }
145
146 /**
147  * Creates an attribute iterator to be used with vehicles
148  */
149 struct attr_iter *
150 vehicle_attr_iter_new(void)
151 {
152         return (struct attr_iter *)g_new0(void *,1);
153 }
154
155 /**
156  * Destroys a vehicle attribute iterator
157  *
158  * @param iter a vehicle attr_iter
159  */
160 void
161 vehicle_attr_iter_destroy(struct attr_iter *iter)
162 {
163         g_free(iter);
164 }
165
166
167
168 /**
169  * Generic get function
170  *
171  * @param this_ A vehicle
172  * @param type The attribute type to look for
173  * @param attr A struct attr to store the attribute
174  * @param iter A vehicle attr_iter
175  */
176 int
177 vehicle_get_attr(struct vehicle *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
178 {
179         int ret;
180         if (this_->meth.position_attr_get) {
181                 ret=this_->meth.position_attr_get(this_->priv, type, attr);
182                 if (ret)
183                         return ret;
184         }
185         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
186 }
187
188 /**
189  * Generic set function
190  *
191  * @param this_ A vehicle
192  * @param attr
193  * @param attrs
194  */
195 int
196 vehicle_set_attr(struct vehicle *this_, struct attr *attr)
197 {
198         int ret=1;
199         if (this_->meth.set_attr)
200                 ret=this_->meth.set_attr(this_->priv, attr);
201         if (ret == 1 && attr->type != attr_navit)
202                 this_->attrs=attr_generic_set_attr(this_->attrs, attr);
203         return ret != 0;
204 }
205
206 /**
207  * Generic add function
208  *
209  * @param this_ A vehicle
210  * @param attr A struct attr
211  */
212 int
213 vehicle_add_attr(struct vehicle *this_, struct attr *attr)
214 {
215         int ret=1;
216         switch (attr->type) {
217         case attr_callback:
218                 callback_list_add(this_->cbl, attr->u.callback);
219                 break;
220         case attr_log:
221                 ret=vehicle_add_log(this_, attr->u.log);
222                 break;
223         // currently supporting oldstyle cursor config.
224         case attr_cursor:
225                 vehicle_set_cursor(this_, attr->u.cursor);
226                 break;
227         default:
228                 break;
229         }
230         if (ret)
231                 this_->attrs=attr_generic_add_attr(this_->attrs, attr);
232         return ret;
233 }
234
235 /**
236  * @brief Generic remove function.
237  *
238  * Used to remove a callback from the vehicle.
239  * @param this_ A vehicle
240  * @param attr
241  */
242 int
243 vehicle_remove_attr(struct vehicle *this_, struct attr *attr)
244 {
245         switch (attr->type) {
246         case attr_callback:
247                 callback_list_remove(this_->cbl, attr->u.callback);
248                 break;
249         default:
250                 return 0;
251         }
252         return 1;
253 }
254
255
256
257 /**
258  * Sets the cursor of a vehicle.
259  *
260  * @param this_ A vehicle
261  * @param cursor A cursor
262  * @author Ralph Sennhauser (10/2009)
263  */ 
264 void
265 vehicle_set_cursor(struct vehicle *this_, struct cursor *cursor)
266 {
267         if (!cursor) {  // we require this for now.
268                 return;
269         }
270
271         if (this_->animate_callback) {
272                 event_remove_timeout(this_->animate_timer);
273                 this_->animate_timer=NULL;              // dangling pointer! prevent double freeing.
274                 callback_destroy(this_->animate_callback);
275                 this_->animate_callback=NULL;   // dangling pointer! prevent double freeing.
276         }
277         if (cursor->interval) {
278                 this_->animate_callback=callback_new_2(callback_cast(vehicle_draw_do), this_, 0);
279                 this_->animate_timer=event_add_timeout(cursor->interval, 1, this_->animate_callback);
280         }
281
282         if (this_->gra) {
283                 this_->cursor_pnt.x+=(this_->cursor->w - cursor->w)/2;
284                 this_->cursor_pnt.y+=(this_->cursor->h - cursor->h)/2;
285                 graphics_overlay_resize(this_->gra, &this_->cursor_pnt, cursor->w, cursor->h, 65535, 0);
286         }
287
288         struct point sc;
289         sc.x=cursor->w/2;
290         sc.y=cursor->h/2;
291         transform_set_screen_center(this_->trans, &sc);
292
293         this_->cursor=cursor;
294 }
295
296 /**
297  * Draws a vehicle on top of a graphics.
298  *
299  * @param this_ The vehicle
300  * @param gra The graphics
301  * @param pnt Screen coordinates of the vehicle.
302  * @param lazy use lazy draw mode.
303  * @param angle The angle relative to the map.
304  * @param speed The speed of the vehicle.
305  */
306 void
307 vehicle_draw(struct vehicle *this_, struct graphics *gra, struct point *pnt, int lazy, int angle, int speed)
308 {
309         if (angle < 0)
310                 angle+=360;
311         dbg(1,"enter this=%p gra=%p pnt=%p lazy=%d dir=%d speed=%d\n", this_, gra, pnt, lazy, angle, speed);
312         dbg(1,"point %d,%d\n", pnt->x, pnt->y);
313         if (!this_->cursor)
314                 return;
315         this_->cursor_pnt=*pnt;
316         this_->cursor_pnt.x-=this_->cursor->w/2;
317         this_->cursor_pnt.y-=this_->cursor->h/2;
318         this_->angle=angle;
319         this_->speed=speed;
320         if (!this_->gra) {
321                 struct color c;
322                 this_->gra=graphics_overlay_new(gra, &this_->cursor_pnt, this_->cursor->w, this_->cursor->h, 65535, 0);
323                 if (this_->gra) {
324                         this_->bg=graphics_gc_new(this_->gra);
325                         c.r=0; c.g=0; c.b=0; c.a=0;
326                         graphics_gc_set_foreground(this_->bg, &c);
327                         graphics_background_gc(this_->gra, this_->bg);
328                 }
329         }
330         vehicle_draw_do(this_, lazy);
331 }
332
333
334
335 static void
336 vehicle_draw_do(struct vehicle *this_, int lazy)
337 {
338         if (!this_->cursor || !this_->cursor->attrs || !this_->gra)
339                 return;
340
341         struct point p;
342         struct cursor *cursor=this_->cursor;
343         int speed=this_->speed;
344         int angle=this_->angle;
345         int sequence=this_->sequence;
346
347         transform_set_yaw(this_->trans, -this_->angle);
348         graphics_draw_mode(this_->gra, draw_mode_begin);
349         p.x=0;
350         p.y=0;
351         graphics_draw_rectangle(this_->gra, this_->bg, &p, cursor->w, cursor->h);
352         struct attr **attr=cursor->attrs;
353         int match=0;
354         while (*attr) {
355                 if ((*attr)->type == attr_itemgra) {
356                         struct itemgra *itm=(*attr)->u.itemgra;
357                         dbg(1,"speed %d-%d %d\n", itm->speed_range.min, itm->speed_range.max, speed);
358                         if (speed >= itm->speed_range.min && speed <= itm->speed_range.max &&  
359                             angle >= itm->angle_range.min && angle <= itm->angle_range.max &&  
360                             sequence >= itm->sequence_range.min && sequence <= itm->sequence_range.max) {
361                                 graphics_draw_itemgra(this_->gra, itm, this_->trans);
362                         }
363                         if (sequence < itm->sequence_range.max)
364                                 match=1;
365                 }
366                 ++attr;
367         }
368         graphics_draw_drag(this_->gra, &this_->cursor_pnt);
369         graphics_draw_mode(this_->gra, lazy ? draw_mode_end_lazy : draw_mode_end);
370         if (this_->animate_callback) {
371                 ++this_->sequence;
372                 if (cursor->sequence_range && cursor->sequence_range->max < this_->sequence)
373                         this_->sequence=cursor->sequence_range->min;
374                 if (! match && ! cursor->sequence_range)
375                         this_->sequence=0;
376         }
377 }
378
379 static void
380 vehicle_log_nmea(struct vehicle *this_, struct log *log)
381 {
382         struct attr pos_attr;
383         if (!this_->meth.position_attr_get)
384                 return;
385         if (!this_->meth.position_attr_get(this_->priv, attr_position_nmea, &pos_attr))
386                 return;
387         log_write(log, pos_attr.u.str, strlen(pos_attr.u.str), 0);
388 }
389
390 void
391 vehicle_log_gpx_add_tag(char *tag, char **logstr)
392 {
393         char *ext_start="\t<extensions>\n";
394         char *ext_end="\t</extensions>\n";
395         char *trkpt_end="</trkpt>";
396         char *start=NULL,*end=NULL;
397         if (!*logstr) {
398                 start=g_strdup(ext_start);
399                 end=g_strdup(ext_end);
400         } else {
401                 char *str=strstr(*logstr, ext_start);
402                 int len;
403                 if (str) {
404                         len=str-*logstr+strlen(ext_start);
405                         start=g_strdup(*logstr);
406                         start[len]='\0';
407                         end=g_strdup(str+strlen(ext_start));
408                 } else {
409                         str=strstr(*logstr, trkpt_end);
410                         len=str-*logstr;
411                         end=g_strdup_printf("%s%s",ext_end,str);
412                         str=g_strdup(*logstr);
413                         str[len]='\0';
414                         start=g_strdup_printf("%s%s",str,ext_start);
415                         g_free(str);
416                 }
417         }
418         *logstr=g_strdup_printf("%s%s%s",start,tag,end);
419         g_free(start);
420         g_free(end);
421 }
422
423 static void
424 vehicle_log_gpx(struct vehicle *this_, struct log *log)
425 {
426         struct attr attr,*attrp;
427         enum attr_type *attr_types;
428         char *logstr;
429         char *extensions="\t<extensions>\n";
430
431         if (!this_->meth.position_attr_get)
432                 return;
433         if (log_get_attr(log, attr_attr_types, &attr, NULL))
434                 attr_types=attr.u.attr_types;
435         else
436                 attr_types=NULL;
437         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &attr))
438                 return;
439         logstr=g_strdup_printf("<trkpt lat=\"%f\" lon=\"%f\">\n",attr.u.coord_geo->lat,attr.u.coord_geo->lng);
440         if (attr_types && attr_types_contains_default(attr_types, attr_position_time_iso8601, 0)) {
441                 if (this_->meth.position_attr_get(this_->priv, attr_position_time_iso8601, &attr)) {
442                         logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",attr.u.str);
443                 } else {
444                         char *timep = current_to_iso8601();
445                         logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",timep);
446                         g_free(timep);
447                 }
448         }
449         if (attr_types_contains_default(attr_types, attr_position_direction,0) && this_->meth.position_attr_get(this_->priv, attr_position_direction, &attr))
450                 logstr=g_strconcat_printf(logstr,"\t<course>%.1f</course>\n",*attr.u.numd);
451         if (attr_types_contains_default(attr_types, attr_position_speed, 0) && this_->meth.position_attr_get(this_->priv, attr_position_speed, &attr))
452                 logstr=g_strconcat_printf(logstr,"\t<speed>%.2f</speed>\n",*attr.u.numd);
453         if (attr_types_contains_default(attr_types, attr_profilename, 0) && (attrp=attr_search(this_->attrs, NULL, attr_profilename))) {
454                 logstr=g_strconcat_printf(logstr,"%s\t\t<navit:profilename>%s</navit:profilename>\n",extensions,attrp->u.str);
455                 extensions="";
456         }
457         if (attr_types_contains_default(attr_types, attr_position_radius, 0) && this_->meth.position_attr_get(this_->priv, attr_position_radius, &attr)) {
458                 logstr=g_strconcat_printf(logstr,"%s\t\t<navit:radius>%.2f</navit:radius>\n",extensions,*attr.u.numd);
459                 extensions="";
460         }
461         if (!strcmp(extensions,"")) {
462                 logstr=g_strconcat_printf(logstr,"\t</extensions>\n");
463         }
464         logstr=g_strconcat_printf(logstr,"</trkpt>\n");
465         callback_list_call_attr_1(this_->cbl, attr_log_gpx, &logstr);
466         log_write(log, logstr, strlen(logstr), 0);
467         g_free(logstr);
468 }
469
470 static void
471 vehicle_log_textfile(struct vehicle *this_, struct log *log)
472 {
473         struct attr pos_attr;
474         char *logstr;
475         if (!this_->meth.position_attr_get)
476                 return;
477         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
478                 return;
479         logstr=g_strdup_printf("%f %f type=trackpoint\n", pos_attr.u.coord_geo->lng, pos_attr.u.coord_geo->lat);
480         callback_list_call_attr_1(this_->cbl, attr_log_textfile, &logstr);
481         log_write(log, logstr, strlen(logstr), 0);
482 }
483
484 static void
485 vehicle_log_binfile(struct vehicle *this_, struct log *log)
486 {
487         struct attr pos_attr;
488         int *buffer;
489         int *buffer_new;
490         int len,limit=1024,done=0,radius=25;
491         struct coord c;
492         enum log_flags flags;
493
494         if (!this_->meth.position_attr_get)
495                 return;
496         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
497                 return;
498         transform_from_geo(projection_mg, pos_attr.u.coord_geo, &c);
499         if (!c.x || !c.y)
500                 return;
501         while (!done) {
502                 buffer=log_get_buffer(log, &len);
503                 if (! buffer || !len) {
504                         buffer_new=g_malloc(5*sizeof(int));
505                         buffer_new[0]=2;
506                         buffer_new[1]=type_track;
507                         buffer_new[2]=0;
508                 } else {
509                         buffer_new=g_malloc((buffer[0]+3)*sizeof(int));
510                         memcpy(buffer_new, buffer, (buffer[0]+1)*sizeof(int));
511                 }
512                 dbg(1,"c=0x%x,0x%x\n",c.x,c.y);
513                 buffer_new[buffer_new[0]+1]=c.x;
514                 buffer_new[buffer_new[0]+2]=c.y;
515                 buffer_new[0]+=2;
516                 buffer_new[2]+=2;
517                 if (buffer_new[2] > limit) {
518                         int count=buffer_new[2]/2;
519                         struct coord out[count];
520                         struct coord *in=(struct coord *)(buffer_new+3);
521                         int count_out=transform_douglas_peucker(in, count, radius, out);
522                         memcpy(in, out, count_out*2*sizeof(int));
523                         buffer_new[0]+=(count_out-count)*2;     
524                         buffer_new[2]+=(count_out-count)*2;     
525                         flags=log_flag_replace_buffer|log_flag_force_flush|log_flag_truncate;
526                 } else {
527                         flags=log_flag_replace_buffer|log_flag_keep_pointer|log_flag_keep_buffer|log_flag_force_flush;
528                         done=1;
529                 }
530                 log_write(log, (char *)buffer_new, (buffer_new[0]+1)*sizeof(int), flags);
531         }
532 }
533
534 static int
535 vehicle_add_log(struct vehicle *this_, struct log *log)
536 {
537         struct callback *cb;
538         struct attr type_attr;
539         if (!log_get_attr(log, attr_type, &type_attr, NULL))
540                 return 1;
541
542         if (!strcmp(type_attr.u.str, "nmea")) {
543                 cb=callback_new_attr_2(callback_cast(vehicle_log_nmea), attr_position_coord_geo, this_, log);
544         } else if (!strcmp(type_attr.u.str, "gpx")) {
545                 char *header = "<?xml version='1.0' encoding='UTF-8'?>\n"
546                         "<gpx version='1.1' creator='Navit http://navit.sourceforge.net'\n"
547                         "     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
548                         "     xmlns:navit='http://www.navit-project.org/schema/navit'\n"
549                         "     xmlns='http://www.topografix.com/GPX/1/1'\n"
550                         "     xsi:schemaLocation='http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'>\n"
551                         "<trk>\n"
552                         "<trkseg>\n";
553                 char *trailer = "</trkseg>\n</trk>\n</gpx>\n";
554                 log_set_header(log, header, strlen(header));
555                 log_set_trailer(log, trailer, strlen(trailer));
556                 cb=callback_new_attr_2(callback_cast(vehicle_log_gpx), attr_position_coord_geo, this_, log);
557         } else if (!strcmp(type_attr.u.str, "textfile")) {
558                 char *header = "type=track\n";
559                 log_set_header(log, header, strlen(header));
560                 cb=callback_new_attr_2(callback_cast(vehicle_log_textfile), attr_position_coord_geo, this_, log);
561         } else if (!strcmp(type_attr.u.str, "binfile")) {
562                 cb=callback_new_attr_2(callback_cast(vehicle_log_binfile), attr_position_coord_geo, this_, log);
563         } else
564                 return 1;
565         callback_list_add(this_->cbl, cb);
566         return 0;
567 }
568