2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2009 Navit Team
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.
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.
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.
30 #include "transform.h"
34 #include "transform.h"
35 #include "projection.h"
42 #include "xmlconfig.h"
45 struct object_func *func;
47 struct vehicle_methods meth;
48 struct vehicle_priv *priv;
49 struct callback_list *cbl;
50 struct log *nmea_log, *gpx_log;
55 struct cursor *cursor;
57 struct callback *animate_callback;
58 struct event_timeout *animate_timer;
59 struct point cursor_pnt;
61 struct graphics_gc *bg;
62 struct transformation *trans;
66 GHashTable *log_to_cb;
69 struct object_func vehicle_func;
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);
81 * Creates a new vehicle
84 vehicle_new(struct attr *parent, struct attr **attrs)
86 struct vehicle *this_;
88 struct vehicle_priv *(*vehicletype_new) (struct vehicle_methods *
90 struct callback_list *
92 struct attr ** attrs);
97 source = attr_search(attrs, NULL, attr_source);
99 dbg(0, "no source\n");
103 type = g_strdup(source->u.str);
104 colon = strchr(type, ':');
107 dbg(1, "source='%s' type='%s'\n", source->u.str, type);
109 vehicletype_new = plugin_get_vehicle_type(type);
110 if (!vehicletype_new) {
111 dbg(0, "invalid type '%s'\n", type);
116 this_ = g_new0(struct vehicle, 1);
117 this_->func=&vehicle_func;
119 this_->cbl = callback_list_new();
120 this_->priv = vehicletype_new(&this_->meth, this_->cbl, attrs);
122 dbg(0, "vehicletype_new failed\n");
123 callback_list_destroy(this_->cbl);
127 this_->attrs=attr_list_dup(attrs);
129 this_->trans=transform_new();
130 center.pro=projection_screen;
133 transform_setup(this_->trans, ¢er, 16, 0);
136 this_->log_to_cb=g_hash_table_new(NULL,NULL);
143 * @param this_ The vehicle to destroy
146 vehicle_destroy(struct vehicle *this_)
148 if (this_->animate_callback) {
149 callback_destroy(this_->animate_callback);
150 event_remove_timeout(this_->animate_timer);
152 transform_destroy(this_->trans);
153 this_->meth.destroy(this_->priv);
154 callback_list_destroy(this_->cbl);
155 attr_list_free(this_->attrs);
157 graphics_gc_destroy(this_->bg);
159 graphics_free(this_->gra);
164 vehicle_ref(struct vehicle *this_)
167 dbg(0,"refcount %d\n",this_->refcount);
172 vehicle_unref(struct vehicle *this_)
177 dbg(0,"refcount %d\n",this_->refcount);
178 if (this_->refcount <= 0)
179 vehicle_destroy(this_);
183 * Creates an attribute iterator to be used with vehicles
186 vehicle_attr_iter_new(void)
188 return (struct attr_iter *)g_new0(void *,1);
192 * Destroys a vehicle attribute iterator
194 * @param iter a vehicle attr_iter
197 vehicle_attr_iter_destroy(struct attr_iter *iter)
205 * Generic get function
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
213 vehicle_get_attr(struct vehicle *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
216 if (this_->meth.position_attr_get) {
217 ret=this_->meth.position_attr_get(this_->priv, type, attr);
221 if (type == attr_log_gpx_desc) {
222 attr->u.str = this_->gpx_desc;
225 return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
229 * Generic set function
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
236 vehicle_set_attr(struct vehicle *this_, struct attr *attr)
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;
245 if (ret == 1 && attr->type != attr_navit && attr->type != attr_pdl_gps_update)
246 this_->attrs=attr_generic_set_attr(this_->attrs, attr);
251 * Generic add function
253 * @param this_ A vehicle
254 * @param attr A struct attr
257 vehicle_add_attr(struct vehicle *this_, struct attr *attr)
260 switch (attr->type) {
262 callback_list_add(this_->cbl, attr->u.callback);
265 ret=vehicle_add_log(this_, attr->u.log);
267 // currently supporting oldstyle cursor config.
269 this_->cursor_fixed=1;
270 vehicle_set_cursor(this_, attr->u.cursor, 1);
276 this_->attrs=attr_generic_add_attr(this_->attrs, attr);
281 * @brief Generic remove function.
283 * Used to remove a callback from the vehicle.
284 * @param this_ A vehicle
288 vehicle_remove_attr(struct vehicle *this_, struct attr *attr)
291 switch (attr->type) {
293 callback_list_remove(this_->cbl, attr->u.callback);
296 cb=g_hash_table_lookup(this_->log_to_cb, attr->u.log);
299 g_hash_table_remove(this_->log_to_cb, attr->u.log);
300 callback_list_remove(this_->cbl, cb);
303 this_->attrs=attr_generic_remove_attr(this_->attrs, attr);
312 * Sets the cursor of a vehicle.
314 * @param this_ A vehicle
315 * @param cursor A cursor
316 * @author Ralph Sennhauser (10/2009)
319 vehicle_set_cursor(struct vehicle *this_, struct cursor *cursor, int overwrite)
322 if (this_->cursor_fixed && !overwrite)
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.
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);
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);
344 if (!this_->cursor && this_->gra)
345 graphics_overlay_disable(this_->gra, 0);
348 if (this_->cursor && this_->gra)
349 graphics_overlay_disable(this_->gra, 1);
351 transform_set_screen_center(this_->trans, &sc);
353 this_->cursor=cursor;
357 * Draws a vehicle on top of a graphics.
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.
367 vehicle_draw(struct vehicle *this_, struct graphics *gra, struct point *pnt, int lazy, int angle, int speed)
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;
378 this_->cursor_pnt.x-=this_->cursor->w/2;
379 this_->cursor_pnt.y-=this_->cursor->h/2;
382 this_->gra=graphics_overlay_new(gra, &this_->cursor_pnt, this_->cursor->w, this_->cursor->h, 65535, 0);
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);
390 vehicle_draw_do(this_, lazy);
394 vehicle_get_cursor_data(struct vehicle *this, struct point *pnt, int *angle, int *speed)
396 *pnt=this->cursor_pnt;
404 vehicle_draw_do(struct vehicle *this_, int lazy)
407 struct cursor *cursor=this_->cursor;
408 int speed=this_->speed;
409 int angle=this_->angle;
410 int sequence=this_->sequence;
415 if (!this_->cursor || !this_->cursor->attrs || !this_->gra)
419 while (attr && *attr) {
420 if ((*attr)->type == attr_name)
421 label=(*attr)->u.str;
424 transform_set_yaw(this_->trans, -this_->angle);
425 graphics_draw_mode(this_->gra, draw_mode_begin);
428 graphics_draw_rectangle(this_->gra, this_->bg, &p, cursor->w, cursor->h);
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);
439 if (sequence < itm->sequence_range.max)
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) {
448 if (cursor->sequence_range && cursor->sequence_range->max < this_->sequence)
449 this_->sequence=cursor->sequence_range->min;
450 if (! match && ! cursor->sequence_range)
456 * Writes to an NMEA log.
458 * @param this_ Pointer to the vehicle structure of the data source
459 * @param log Pointer to a log structure for the log file
462 vehicle_log_nmea(struct vehicle *this_, struct log *log)
464 struct attr pos_attr;
465 if (!this_->meth.position_attr_get)
467 if (!this_->meth.position_attr_get(this_->priv, attr_position_nmea, &pos_attr))
469 log_write(log, pos_attr.u.str, strlen(pos_attr.u.str), 0);
473 vehicle_log_gpx_add_tag(char *tag, char **logstr)
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;
480 start=g_strdup(ext_start);
481 end=g_strdup(ext_end);
483 char *str=strstr(*logstr, ext_start);
486 len=str-*logstr+strlen(ext_start);
487 start=g_strdup(*logstr);
489 end=g_strdup(str+strlen(ext_start));
491 str=strstr(*logstr, trkpt_end);
493 end=g_strdup_printf("%s%s",ext_end,str);
494 str=g_strdup(*logstr);
496 start=g_strdup_printf("%s%s",str,ext_start);
500 *logstr=g_strdup_printf("%s%s%s",start,tag,end);
506 * Writes to a GPX log.
508 * @param this_ Pointer to the vehicle structure of the data source
509 * @param log Pointer to a log structure for the log file
512 vehicle_log_gpx(struct vehicle *this_, struct log *log)
514 struct attr attr,*attrp, fix_attr;
515 enum attr_type *attr_types;
517 char *extensions="\t<extensions>\n";
519 if (!this_->meth.position_attr_get)
521 if (log_get_attr(log, attr_attr_types, &attr, NULL))
522 attr_types=attr.u.attr_types;
525 if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
526 if ( fix_attr.u.num == 0 )
529 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &attr))
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);
536 char *timep = current_to_iso8601();
537 logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",timep);
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;
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)
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);
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);
574 if (!strcmp(extensions,"")) {
575 logstr=g_strconcat_printf(logstr,"\t</extensions>\n");
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);
584 * Writes to a text log.
586 * @param this_ Pointer to the vehicle structure of the data source
587 * @param log Pointer to a log structure for the log file
590 vehicle_log_textfile(struct vehicle *this_, struct log *log)
592 struct attr pos_attr,fix_attr;
594 if (!this_->meth.position_attr_get)
596 if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
597 if (fix_attr.u.num == 0)
600 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
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);
608 * Writes to a binary log.
610 * @param this_ Pointer to the vehicle structure of the data source
611 * @param log Pointer to a log structure for the log file
614 vehicle_log_binfile(struct vehicle *this_, struct log *log)
616 struct attr pos_attr, fix_attr;
619 int len,limit=1024,done=0,radius=25;
621 enum log_flags flags;
623 if (!this_->meth.position_attr_get)
625 if (this_->meth.position_attr_get(this_->priv, attr_position_fix_type, &fix_attr)) {
626 if (fix_attr.u.num == 0)
629 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
631 transform_from_geo(projection_mg, pos_attr.u.coord_geo, &c);
635 buffer=log_get_buffer(log, &len);
636 if (! buffer || !len) {
637 buffer_new=g_malloc(5*sizeof(int));
639 buffer_new[1]=type_track;
642 buffer_new=g_malloc((buffer[0]+3)*sizeof(int));
643 memcpy(buffer_new, buffer, (buffer[0]+1)*sizeof(int));
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;
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;
660 flags=log_flag_replace_buffer|log_flag_keep_pointer|log_flag_keep_buffer|log_flag_force_flush;
663 log_write(log, (char *)buffer_new, (buffer_new[0]+1)*sizeof(int), flags);
668 * Register a new log to receive data.
670 * @param this_ Pointer to the vehicle structure of the data source
671 * @param log Pointer to a log structure for the log file
674 vehicle_add_log(struct vehicle *this_, struct log *log)
677 struct attr type_attr;
678 if (!log_get_attr(log, attr_type, &type_attr, NULL))
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"
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);
704 g_hash_table_insert(this_->log_to_cb, log, cb);
705 callback_list_add(this_->cbl, cb);
709 struct object_func vehicle_func = {
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,