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"
44 struct vehicle_methods meth;
45 struct vehicle_priv *priv;
46 struct callback_list *cbl;
47 struct log *nmea_log, *gpx_log;
51 struct cursor *cursor;
52 struct callback *animate_callback;
53 struct event_timeout *animate_timer;
54 struct point cursor_pnt;
56 struct graphics_gc *bg;
57 struct transformation *trans;
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);
73 * Creates a new vehicle
76 vehicle_new(struct attr *parent, struct attr **attrs)
78 struct vehicle *this_;
80 struct vehicle_priv *(*vehicletype_new) (struct vehicle_methods *
82 struct callback_list *
84 struct attr ** attrs);
89 source = attr_search(attrs, NULL, attr_source);
91 dbg(0, "no source\n");
95 type = g_strdup(source->u.str);
96 colon = strchr(type, ':');
99 dbg(1, "source='%s' type='%s'\n", source->u.str, type);
101 vehicletype_new = plugin_get_vehicle_type(type);
102 if (!vehicletype_new) {
103 dbg(0, "invalid type '%s'\n", type);
106 this_ = g_new0(struct vehicle, 1);
107 this_->cbl = callback_list_new();
108 this_->priv = vehicletype_new(&this_->meth, this_->cbl, attrs);
110 dbg(0, "vehicletype_new failed\n");
111 callback_list_destroy(this_->cbl);
115 this_->attrs=attr_list_dup(attrs);
117 this_->trans=transform_new();
118 center.pro=projection_screen;
121 transform_setup(this_->trans, ¢er, 16, 0);
130 * @param this_ The vehicle to destroy
133 vehicle_destroy(struct vehicle *this_)
135 if (this_->animate_callback) {
136 callback_destroy(this_->animate_callback);
137 event_remove_timeout(this_->animate_timer);
139 transform_destroy(this_->trans);
140 this_->meth.destroy(this_->priv);
141 callback_list_destroy(this_->cbl);
142 attr_list_free(this_->attrs);
147 * Creates an attribute iterator to be used with vehicles
150 vehicle_attr_iter_new(void)
152 return (struct attr_iter *)g_new0(void *,1);
156 * Destroys a vehicle attribute iterator
158 * @param iter a vehicle attr_iter
161 vehicle_attr_iter_destroy(struct attr_iter *iter)
169 * Generic get function
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
177 vehicle_get_attr(struct vehicle *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
180 if (this_->meth.position_attr_get) {
181 ret=this_->meth.position_attr_get(this_->priv, type, attr);
185 return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
189 * Generic set function
191 * @param this_ A vehicle
196 vehicle_set_attr(struct vehicle *this_, struct attr *attr)
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);
207 * Generic add function
209 * @param this_ A vehicle
210 * @param attr A struct attr
213 vehicle_add_attr(struct vehicle *this_, struct attr *attr)
216 switch (attr->type) {
218 callback_list_add(this_->cbl, attr->u.callback);
221 ret=vehicle_add_log(this_, attr->u.log);
223 // currently supporting oldstyle cursor config.
225 vehicle_set_cursor(this_, attr->u.cursor);
231 this_->attrs=attr_generic_add_attr(this_->attrs, attr);
236 * @brief Generic remove function.
238 * Used to remove a callback from the vehicle.
239 * @param this_ A vehicle
243 vehicle_remove_attr(struct vehicle *this_, struct attr *attr)
245 switch (attr->type) {
247 callback_list_remove(this_->cbl, attr->u.callback);
258 * Sets the cursor of a vehicle.
260 * @param this_ A vehicle
261 * @param cursor A cursor
262 * @author Ralph Sennhauser (10/2009)
265 vehicle_set_cursor(struct vehicle *this_, struct cursor *cursor)
267 if (!cursor) { // we require this for now.
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.
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);
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);
291 transform_set_screen_center(this_->trans, &sc);
293 this_->cursor=cursor;
297 * Draws a vehicle on top of a graphics.
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.
307 vehicle_draw(struct vehicle *this_, struct graphics *gra, struct point *pnt, int lazy, int angle, int speed)
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);
315 this_->cursor_pnt=*pnt;
316 this_->cursor_pnt.x-=this_->cursor->w/2;
317 this_->cursor_pnt.y-=this_->cursor->h/2;
322 this_->gra=graphics_overlay_new(gra, &this_->cursor_pnt, this_->cursor->w, this_->cursor->h, 65535, 0);
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);
330 vehicle_draw_do(this_, lazy);
336 vehicle_draw_do(struct vehicle *this_, int lazy)
338 if (!this_->cursor || !this_->cursor->attrs || !this_->gra)
342 struct cursor *cursor=this_->cursor;
343 int speed=this_->speed;
344 int angle=this_->angle;
345 int sequence=this_->sequence;
347 transform_set_yaw(this_->trans, -this_->angle);
348 graphics_draw_mode(this_->gra, draw_mode_begin);
351 graphics_draw_rectangle(this_->gra, this_->bg, &p, cursor->w, cursor->h);
352 struct attr **attr=cursor->attrs;
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);
363 if (sequence < itm->sequence_range.max)
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) {
372 if (cursor->sequence_range && cursor->sequence_range->max < this_->sequence)
373 this_->sequence=cursor->sequence_range->min;
374 if (! match && ! cursor->sequence_range)
380 vehicle_log_nmea(struct vehicle *this_, struct log *log)
382 struct attr pos_attr;
383 if (!this_->meth.position_attr_get)
385 if (!this_->meth.position_attr_get(this_->priv, attr_position_nmea, &pos_attr))
387 log_write(log, pos_attr.u.str, strlen(pos_attr.u.str), 0);
391 vehicle_log_gpx_add_tag(char *tag, char **logstr)
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;
398 start=g_strdup(ext_start);
399 end=g_strdup(ext_end);
401 char *str=strstr(*logstr, ext_start);
404 len=str-*logstr+strlen(ext_start);
405 start=g_strdup(*logstr);
407 end=g_strdup(str+strlen(ext_start));
409 str=strstr(*logstr, trkpt_end);
411 end=g_strdup_printf("%s%s",ext_end,str);
412 str=g_strdup(*logstr);
414 start=g_strdup_printf("%s%s",str,ext_start);
418 *logstr=g_strdup_printf("%s%s%s",start,tag,end);
424 vehicle_log_gpx(struct vehicle *this_, struct log *log)
426 struct attr attr,*attrp;
427 enum attr_type *attr_types;
429 char *extensions="\t<extensions>\n";
431 if (!this_->meth.position_attr_get)
433 if (log_get_attr(log, attr_attr_types, &attr, NULL))
434 attr_types=attr.u.attr_types;
437 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &attr))
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);
444 char *timep = current_to_iso8601();
445 logstr=g_strconcat_printf(logstr,"\t<time>%s</time>\n",timep);
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);
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);
461 if (!strcmp(extensions,"")) {
462 logstr=g_strconcat_printf(logstr,"\t</extensions>\n");
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);
471 vehicle_log_textfile(struct vehicle *this_, struct log *log)
473 struct attr pos_attr;
475 if (!this_->meth.position_attr_get)
477 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
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);
485 vehicle_log_binfile(struct vehicle *this_, struct log *log)
487 struct attr pos_attr;
490 int len,limit=1024,done=0,radius=25;
492 enum log_flags flags;
494 if (!this_->meth.position_attr_get)
496 if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
498 transform_from_geo(projection_mg, pos_attr.u.coord_geo, &c);
502 buffer=log_get_buffer(log, &len);
503 if (! buffer || !len) {
504 buffer_new=g_malloc(5*sizeof(int));
506 buffer_new[1]=type_track;
509 buffer_new=g_malloc((buffer[0]+3)*sizeof(int));
510 memcpy(buffer_new, buffer, (buffer[0]+1)*sizeof(int));
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;
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;
527 flags=log_flag_replace_buffer|log_flag_keep_pointer|log_flag_keep_buffer|log_flag_force_flush;
530 log_write(log, (char *)buffer_new, (buffer_new[0]+1)*sizeof(int), flags);
535 vehicle_add_log(struct vehicle *this_, struct log *log)
538 struct attr type_attr;
539 if (!log_get_attr(log, attr_type, &type_attr, NULL))
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"
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);
565 callback_list_add(this_->cbl, cb);