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