]> err.no Git - mapper/blob - src/track.c
Allow a bit faster movement for the random gps simulator.
[mapper] / src / track.c
1 #include <config.h>
2
3 #include <libgnomevfs/gnome-vfs.h>
4 #include <sqlite3.h>
5
6 #include "utils.h"
7 #include "gps.h"
8 #include "map.h"
9 #include "route.h"
10 #include "settings.h"
11 #include "mapper-types.h"
12 #include "ui-common.h"
13 #include "file.h"
14
15 #include "track.h"
16 #include "latlon.h"
17 #include "path.h"
18 #include "gpx.h"
19 #include "speak.h"
20
21 struct sql_select_stmt {
22         sqlite3_stmt *select_track;
23         sqlite3_stmt *select_track_nodes;
24         sqlite3_stmt *insert_track;
25         sqlite3_stmt *insert_track_node;
26         sqlite3_stmt *delete_track_nodes;
27         sqlite3_stmt *delete_track;
28 };
29 static struct sql_select_stmt sql;
30
31 void
32 track_init(void)
33 {
34 memset(&_track, 0, sizeof(_track));
35 MACRO_PATH_INIT(_track);
36 }
37
38 void
39 track_deinit(void)
40 {
41 MACRO_PATH_FREE(_track);
42 }
43
44 void 
45 track_clear(void)
46 {
47 GtkWidget *confirm;
48
49 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), _("Clear the track?"));
50
51 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
52         _track.tail = _track.head;
53         map_force_redraw();
54 }
55 gtk_widget_destroy(confirm);
56 }
57
58 gdouble
59 track_calculate_distance_from(Point *point)
60 {
61 gdouble lat1, lon1, lat2, lon2;
62 gdouble sum = 0.0;
63 Point *curr;
64 unit2latlon(_gps->data.unitx, _gps->data.unity, lat1, lon1);
65
66 /* Skip _track.tail because that should be _gps. */
67 for (curr = _track.tail; curr > point; --curr) {
68         if (curr->unity) {
69                 unit2latlon(curr->unitx, curr->unity, lat2, lon2);
70                 sum += calculate_distance(lat1, lon1, lat2, lon2);
71                 lat1 = lat2;
72                 lon1 = lon2;
73         }
74 }
75 return sum;
76 }
77
78 void 
79 track_show_distance_from(Point * point)
80 {
81 gchar buffer[80];
82 gdouble sum;
83
84 sum = track_calculate_distance_from(point);
85
86 g_snprintf(buffer, sizeof(buffer), "%s: %.02f %s", _("Distance"),
87          sum * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
88 MACRO_BANNER_SHOW_INFO(_window, buffer);
89 }
90
91 void 
92 track_show_distance_from_last()
93 {
94 /* Find last zero point. */
95 if (_track.head != _track.tail) {
96         Point *point;
97         /* Find last zero point. */
98         for (point = _track.tail; point->unity; point--) {
99         }
100         track_show_distance_from(point);
101 } else {
102         MACRO_BANNER_SHOW_INFO(_window, _("The current track is empty."));
103 }
104 }
105
106 void 
107 track_show_distance_from_first()
108 {
109 if (_track.head != _track.tail) {
110         track_show_distance_from(_track.head);
111 } else {
112         MACRO_BANNER_SHOW_INFO(_window, _("The current track is empty."));
113 }
114 }
115
116 /**
117  * Add a point to the _track list.  This function is slightly overloaded,
118  * since it is what houses the check for "have we moved
119  * significantly": it also initiates the re-calculation of the _near_point
120  * data, as well as calling osso_display_state_on() when we have the focus.
121  *
122  * If a non-zero time is given, then the current position (as taken from the
123  * _gps variable) is appended to _track with the given time.  If time is zero,
124  * then _point_null is appended to _track with time zero (this produces a "break"
125  * in the track).
126  */
127 void 
128 track_add(GpsData *gps)
129 {
130 gboolean show_directions = TRUE;
131 gint announce_thres_unsquared;
132
133 if (!gps) {
134         MACRO_PATH_INCREMENT_TAIL(_track);
135         *_track.tail=_point_null;
136         return;
137 }
138
139 if (abs((gint)gps->unitx-_track.tail->unitx) > _draw_width || abs((gint)gps->unity-_track.tail->unity) > _draw_width) {
140
141         /* If gps is available, update the nearest-waypoint data. */
142         if (gps && _route.head != _route.tail && (gps->newly_fixed ? (route_find_nearest_point(), TRUE) : route_update_nears(TRUE))) {
143                 /* Nearest waypoint has changed - re-render paths. */
144                 map_render_paths();
145                 MACRO_QUEUE_DRAW_AREA();
146         }
147
148         if (_show_tracks & TRACKS_MASK) {
149                 gint tx1, ty1, tx2, ty2;
150
151                 /* Instead of calling map_render_paths(), we'll draw the new line
152                  * ourselves and call gtk_widget_queue_draw_area(). */
153                 map_render_segment(_gc[COLORABLE_TRACK], _gc[COLORABLE_TRACK_BREAK],
154                                         _track.tail->unitx, _track.tail->unity, gps->unitx, gps->unity);
155
156                 if (_track.tail->unity && _track.tail->unitx) {
157                         tx1 = unit2x(_track.tail->unitx);
158                         ty1 = unit2y(_track.tail->unity);
159                         tx2 = unit2x(gps->unitx);
160                         ty2 = unit2y(gps->unity);
161                         gtk_widget_queue_draw_area(_map_widget,
162                                            MIN(tx1, tx2) - _draw_width, 
163                                            MIN(ty1, ty2) - _draw_width,
164                                            abs(tx1 - tx2) + (2 * _draw_width),
165                                            abs(ty1 - ty2) + (2 * _draw_width));
166                 }
167         }
168
169         MACRO_PATH_INCREMENT_TAIL(_track);
170         _track.tail->unitx=gps->unitx;
171         _track.tail->unity=gps->unity;
172         _track.tail->time=gps->time;
173         _track.tail->altitude=gps->altitude;
174 }
175
176 if (_autoroute_data.enabled && !_autoroute_data.in_progress && _near_point_dist_squared > 400) {
177         MACRO_BANNER_SHOW_INFO(_window, _("Recalculating directions..."));
178         _autoroute_data.in_progress = TRUE;
179         show_directions = FALSE;
180         g_idle_add((GSourceFunc)auto_route_dl_idle, NULL);
181 }
182
183 announce_thres_unsquared=(20+(guint)gps->speed)*_announce_notice_ratio*3;
184
185 /* Check if we should announce upcoming waypoints. */
186 if (gps && show_directions && _next_way_dist_squared < (announce_thres_unsquared * announce_thres_unsquared)) {
187         if (_enable_voice && strcmp(_next_way->desc, _last_spoken_phrase)) {
188                 g_free(_last_spoken_phrase);
189                 _last_spoken_phrase=g_strdup(_next_way->desc);
190                 speak_text(_last_spoken_phrase);
191         }
192         MACRO_BANNER_SHOW_INFO(_window, _next_way->desc);
193 }
194
195 /* Keep the display on if we are moving. */
196 KEEP_DISPLAY_ON();
197 }
198
199 gboolean 
200 track_insert_break(void)
201 {
202 if (_track.tail->unity) {
203         guint x1, y1;
204
205         /* To mark a "waypoint" in a track, we'll add a (0, 0) point and then
206          * another instance of the most recent track point. */
207         MACRO_PATH_INCREMENT_TAIL(_track);
208         *_track.tail=_point_null;
209         MACRO_PATH_INCREMENT_TAIL(_track);
210         *_track.tail=_track.tail[-2];
211
212         /* Instead of calling map_render_paths(), we'll just draw the waypoint ourselves. */
213         x1 = unit2bufx(_track.tail->unitx);
214         y1 = unit2bufy(_track.tail->unity);
215         map_render_waypoint(x1, y1, _gc[COLORABLE_TRACK_BREAK]);
216 }
217 return FALSE;
218 }
219
220 gboolean
221 track_open(void)
222 {
223 gchar *buffer;
224 gint size;
225 gboolean r = FALSE;
226
227 if (file_open_get_contents(&_track_file_uri, &buffer, &size)) {
228         if (parse_gpx(&_track, buffer, size, -1)) {
229                 map_force_redraw();
230                 MACRO_BANNER_SHOW_INFO(_window, _("Track Opened"));
231                 r = TRUE;
232         } else {
233                 popup_error(_window, _("Error parsing GPX file."));
234         }
235         g_free(buffer);
236 }
237 return r;
238 }
239
240 gboolean
241 track_save(void)
242 {
243 GnomeVFSHandle *handle;
244 gboolean r = FALSE;
245
246 if (file_save(&_track_file_uri, &_track_file_uri, &handle)) {
247         if (write_gpx(&_track, handle)) {
248                 MACRO_BANNER_SHOW_INFO(_window, _("Track Saved"));
249                 r = TRUE;
250                 track_clear();
251         } else {
252                 popup_error(_window, _("Error writing GPX file."));
253         }
254         gnome_vfs_close(handle);
255 }
256 return r;
257 }
258
259 /**
260  * Add a text description at current point
261  * 
262  */
263 void 
264 track_insert_mark_text(gchar *text)
265 {
266 MACRO_PATH_INCREMENT_WTAIL(_track);
267 _track.wtail->point = _track.tail;
268 _track.wtail->desc = text;
269 }
270
271 /**
272  * Ask for a text description for the current point
273  *
274  */
275 gboolean
276 track_insert_mark(void)
277 {
278 gdouble lat, lon;
279 gchar tmp1[16], tmp2[16], *p_latlon;
280 GtkWidget *dialog;
281 GtkWidget *table;
282 GtkWidget *label;
283 GtkWidget *txt_scroll;
284 GtkWidget *txt_desc;
285
286 dialog = gtk_dialog_new_with_buttons(_("Insert Mark"),
287                                      GTK_WINDOW(_window),
288                                      GTK_DIALOG_MODAL, GTK_STOCK_OK,
289                                      GTK_RESPONSE_ACCEPT,
290                                      GTK_STOCK_CANCEL,
291                                      GTK_RESPONSE_REJECT, NULL);
292
293 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table = gtk_table_new(2, 2, FALSE), TRUE, TRUE, 0);
294
295 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Lat, Lon")), 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
296 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
297
298 unit2latlon(_gps->data.unitx, _gps->data.unity, lat, lon);
299 lat_format(_degformat, lat, tmp1);
300 lon_format(_degformat, lon, tmp2);
301 p_latlon = g_strdup_printf("%s, %s", tmp1, tmp2);
302 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(p_latlon), 1, 2, 0, 1, GTK_FILL, 0, 2, 4);
303 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
304 g_free(p_latlon);
305
306 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Description")), 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
307 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
308
309 txt_scroll = gtk_scrolled_window_new(NULL, NULL);
310 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll), GTK_SHADOW_IN);
311 gtk_table_attach(GTK_TABLE(table), txt_scroll, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
312
313 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
314
315 txt_desc = gtk_text_view_new();
316 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
317
318 gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
319 gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 450, 80);
320
321 gtk_widget_show_all(dialog);
322
323 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
324         GtkTextBuffer *tbuf;
325         GtkTextIter ti1, ti2;
326
327         tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
328         gtk_text_buffer_get_iter_at_offset(tbuf, &ti1, 0);
329         gtk_text_buffer_get_end_iter(tbuf, &ti2);
330
331         if (gtk_text_buffer_get_char_count(tbuf)>0) {
332                 track_insert_mark_text(gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE));
333         } else {
334                 popup_error(dialog, _("Please provide a description for the mark."));
335                 continue;
336         }
337
338         map_render_paths();
339         MACRO_QUEUE_DRAW_AREA();
340         break;
341 }
342 gtk_widget_destroy(dialog);
343 return TRUE;
344 }