10
#include <glib/gstdio.h>
12
#include <sys/types.h>
16
#include <libxml/parser.h>
17
#include <libxml/tree.h>
18
#include <libxml/encoding.h>
19
#include <libxml/xmlwriter.h>
22
#include "tile_management.h"
25
#include "interface.h"
27
#include "converter.h"
28
#include "map_management.h"
32
#define GPX_ENCODING "utf-8"
35
* This is a GSList containing the waypoints of the route
36
* which we are planing. It is the central data structure for route.c
38
static GSList *route = NULL;
40
static GdkPixbuf *wp_icon = NULL;
41
static int wp_icon_width = 0;
42
static int wp_icon_height = 0;
54
* Append a new waypoint at the end of the route.
57
append_waypoint_to_route (double lat, double lon)
59
waypoint_t *tp = g_new0 (waypoint_t,1);
64
route = g_slist_append (route, tp);
68
* Change the position of the given waypoint to the new position.
71
change_waypoint_of_route (waypoint_t *tp, double lat, double lon)
78
* Delete the given waypoint from the route.
81
delete_waypoint_of_route (waypoint_t *wp)
83
route = g_slist_remove (route, wp);
88
* Insert a new waypoint before the given waypoint. This waypoint lies
89
* between the given waypoint and the waypoint before this waypoint.
92
insert_waypoint_before_of_route (waypoint_t *wp)
94
waypoint_t *previous_wp;
97
position = g_slist_index (route, wp);
99
previous_wp = g_slist_nth_data (route, position - 1);
101
waypoint_t *new_wp = g_new0 (waypoint_t,1);
103
new_wp->lat = previous_wp->lat - (previous_wp->lat - wp->lat) / 2;
104
new_wp->lon = previous_wp->lon - (previous_wp->lon - wp->lon) / 2;
106
route = g_slist_insert (route, new_wp, position + 0);
111
* Find the waypoint which wp_icon is at the given mouse position.
112
* Return that waypoint or NULL if none was found.
115
find_routepoint (int mouse_x, int mouse_y)
120
int pixel_x, pixel_y, x,y;
122
for (list = route; list != NULL; list = list->next)
124
waypoint_t *tp = list->data;
129
pixel_x = lon2pixel (global_zoom, lon);
130
pixel_y = lat2pixel (global_zoom, lat);
132
x = pixel_x - global_x + wp_icon_width / 2;
133
y = pixel_y - global_y - wp_icon_height / 2;
135
if (abs (x - mouse_x) < wp_icon_width / 2 &&
136
abs (y - mouse_y) < wp_icon_height / 2)
147
draw_arrow (GdkGC *gc, int start_x, int start_y, int end_x, int end_y)
150
double angle = atan2 (end_y - start_y, end_x - start_x) + M_PI;
151
double arrow_length = 20;
152
double arrow_degrees = M_PI / 10;
154
/* https://kapo-cpp.blogspot.com/2008/10/drawing-arrows-with-cairo.html */
156
x1 = end_x + arrow_length * cos (angle - arrow_degrees);
157
y1 = end_y + arrow_length * sin (angle - arrow_degrees);
158
x2 = end_x + arrow_length * cos (angle + arrow_degrees);
159
y2 = end_y + arrow_length * sin (angle + arrow_degrees);
161
gdk_draw_line (pixmap, gc, start_x, start_y, end_x, end_y);
162
gdk_draw_line (pixmap, gc, end_x, end_y, x1, y1);
163
gdk_draw_line (pixmap, gc, x1, y1, x2, y2);
164
gdk_draw_line (pixmap, gc, x2, y2, end_x, end_y);
169
draw_line_of_route (GdkGC *gc, int x1, int y1, int x2, int y2)
171
if (abs (x1-x2) > 30 || abs (y1-y2) > 30) {
172
/* Line is long enough. Draw arrow */
173
draw_arrow (gc, x1, y1, x2, y2);
175
/* short line. Omit arrow. */
176
gdk_draw_line (pixmap, gc, x1, y1, x2, y2);
181
* This function draws the current route on the screen.
187
int pixel_x, pixel_y, x,y, last_x = 0, last_y = 0;
191
gboolean is_line = FALSE;
193
/* Load icon if not already loaded: */
195
wp_icon = load_wp_icon ();
196
wp_icon_width = gdk_pixbuf_get_width (wp_icon);
197
wp_icon_height = gdk_pixbuf_get_height (wp_icon);
200
/* Create GC for drawing the route line */
201
gc = gdk_gc_new (pixmap);
205
gdk_gc_set_rgb_fg_color (gc, &color);
206
gdk_gc_set_line_attributes (gc, 5, GDK_LINE_SOLID,
207
GDK_CAP_ROUND, GDK_JOIN_ROUND);
209
/* [1] paint line first */
210
for (list = route; list != NULL; list = list->next)
212
waypoint_t *tp = list->data;
217
pixel_x = lon2pixel (global_zoom, lon);
218
pixel_y = lat2pixel (global_zoom, lat);
220
x = pixel_x - global_x;
221
y = pixel_y - global_y;
225
draw_line_of_route (gc, last_x, last_y, x, y);
226
gtk_widget_queue_draw_area (map_drawable,
236
/* [2] paint flags after line */
237
for (list = route; list != NULL; list = list->next)
239
waypoint_t *tp = list->data;
244
pixel_x = lon2pixel (global_zoom, lon);
245
pixel_y = lat2pixel (global_zoom, lat);
247
x = pixel_x - global_x;
248
y = pixel_y - global_y;
251
gdk_draw_arc (pixmap,
258
gdk_draw_pixbuf (pixmap,
263
wp_icon_width,wp_icon_height,
264
GDK_RGB_DITHER_NONE, 0, 0);
266
gtk_widget_queue_draw_area (map_drawable,
275
* Find the bounding box of the given GSList containin waypoints.
278
get_way_bbox (GSList *ways)
289
for (list = ways; list != NULL; list = list->next)
291
waypoint_t *tp = list->data;
295
bbox.lat1 = (lat > bbox.lat1) ? lat : bbox.lat1;
296
bbox.lat2 = (lat < bbox.lat2) ? lat : bbox.lat2;
297
bbox.lon1 = (lon < bbox.lon1) ? lon : bbox.lon1;
298
bbox.lon2 = (lon > bbox.lon2) ? lon : bbox.lon2;
305
* Write a single route point to the XML file in GPX format.
309
write_rtept (xmlTextWriterPtr writer, waypoint_t *wp, int no)
311
xmlTextWriterStartElement (writer, BAD_CAST "rtept");
312
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "lat",
313
"%f", rad2deg (wp->lat));
314
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "lon",
315
"%f", rad2deg (wp->lon));
316
xmlTextWriterEndElement (writer); /* </rtept> */
320
* Save the route in GPX format to the given URI.
323
save_route_as_gpx (const char *uri)
326
xmlTextWriterPtr writer;
329
char now_as_string[200];
333
if (uri == NULL) return;
335
bbox_t bbox = get_way_bbox (route);
338
* this initialize the library and check potential ABI mismatches
339
* between the version it was compiled for and the actual shared
344
/* Create a new XmlWriter for uri, with no compression. */
345
writer = xmlNewTextWriterFilename (uri, 0);
346
if (writer == NULL) {
347
printf ("testXmlwriterFilename: Error creating the xml writer\n");
351
/* We would like to indent the elements for better readability. */
352
xmlTextWriterSetIndent (writer, 1);
354
/* Start the document with the xml default for the version,
355
* encoding and the default for the standalone
357
rc = xmlTextWriterStartDocument (writer, "1.0", GPX_ENCODING, "no");
359
printf ("testXmlwriterFilename: Error at xmlTextWriterStartDocument\n");
363
xmlTextWriterStartElement (writer, BAD_CAST "gpx");
364
xmlTextWriterWriteAttribute (writer, BAD_CAST "version",
366
xmlTextWriterWriteAttribute (writer, BAD_CAST "creator",
367
BAD_CAST PACKAGE_STRING);
368
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns:xsi",
369
BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
370
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns:topografix",
371
BAD_CAST "http://www.topografix.com/GPX/Private/TopoGrafix/0/1");
372
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns",
373
BAD_CAST "http://www.topografix.com/GPX/1/1");
374
xmlTextWriterWriteAttribute (writer, BAD_CAST "xsi:schemaLocation",
375
BAD_CAST "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd");
377
xmlTextWriterStartElement (writer, BAD_CAST "metadata");
379
/* save current time into GPX file: */
381
gmtime_r (&now, &now_as_tm);
382
strftime (now_as_string, sizeof (now_as_string), "%Y-%m-%dT%H:%M:%SZ",
384
xmlTextWriterWriteElement (writer, BAD_CAST "time",
385
BAD_CAST now_as_string);
387
xmlTextWriterStartElement (writer, BAD_CAST "bounds");
388
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "minlat",
389
"%f", rad2deg (bbox.lat2));
390
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "minlon",
391
"%f", rad2deg (bbox.lon1));
392
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "maxlat",
393
"%f", rad2deg (bbox.lat1));
394
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "maxlon",
395
"%f", rad2deg (bbox.lon2));
396
xmlTextWriterEndElement (writer); /* </bounds> */
398
xmlTextWriterEndElement (writer); /* </metadata> */
400
xmlTextWriterStartElement (writer, BAD_CAST "rte");
402
for (list = route, no = 1; list != NULL; list = list->next, no++)
404
waypoint_t *wp = list->data;
405
write_rtept (writer, wp, no);
408
xmlTextWriterEndElement (writer); /* </rte> */
409
xmlTextWriterEndElement (writer); /* </gpx> */
411
xmlTextWriterEndDocument (writer);
413
xmlFreeTextWriter (writer);
417
* Save a route to a TomTom ITN file format.
420
save_route_as_tomtom_itn (const char *uri)
426
if (uri == NULL) return;
428
tomtom = fopen (uri, "w");
429
if (tomtom == NULL) {
430
perror ("opening file to save tomtom.");
432
for (list = route, no = 1;
434
list = list->next, no++)
436
waypoint_t *wp = list->data;
437
fprintf (tomtom, "%d|%d|WP%d|0\n",
438
(int) (rad2deg (wp->lon) * 100000),
439
(int) (rad2deg (wp->lat) * 100000),
448
* Take all routepoints from a DOM tree containing GPX nodes.
452
parse_gpx_routepoints (xmlNode *node)
454
xmlNode *cur_node = NULL;
457
for (cur_node = node; cur_node; cur_node = cur_node->next)
459
if (cur_node->type == XML_ELEMENT_NODE)
461
if (xmlStrEqual (cur_node->name, BAD_CAST "rtept"))
464
waypoint_t *tp = g_new0 (waypoint_t, 1);
466
lat = atof ((char *) xmlGetProp (cur_node,
468
lon = atof ((char *) xmlGetProp (cur_node,
471
tp->lat = deg2rad (lat);
472
tp->lon = deg2rad (lon);
474
list = g_slist_append (list, tp);
477
list = g_slist_concat (list,
478
parse_gpx_routepoints (cur_node->children));
485
* Load a route from a given GPX file.
488
load_route_as_gpx (const char *file)
492
xmlNode *root_element = NULL;
496
doc = xmlReadFile (file, NULL, 0);
499
printf ("error: could not parse file %s\n", file);
502
root_element = xmlDocGetRootElement (doc);
503
list = parse_gpx_routepoints (root_element);
511
* Load a route from a file with a supported file format.
514
load_route (const char *filename)
518
if (filename == NULL) return;
520
route = load_route_as_gpx (filename);
523
bbox = get_way_bbox (route);
530
choose_save_file (char *currentName)
532
char *filename = NULL;
534
dialog = gtk_file_chooser_dialog_new ("Save File",
536
GTK_FILE_CHOOSER_ACTION_SAVE,
537
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
538
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
540
gtk_file_chooser_set_do_overwrite_confirmation
541
(GTK_FILE_CHOOSER (dialog), TRUE);
542
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
545
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
547
filename = gtk_file_chooser_get_filename
548
(GTK_FILE_CHOOSER (dialog));
551
gtk_widget_destroy (dialog);
559
char *filename = NULL;
561
dialog = gtk_file_chooser_dialog_new ("Open File", NULL,
562
GTK_FILE_CHOOSER_ACTION_OPEN,
569
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
571
filename = gtk_file_chooser_get_filename
572
(GTK_FILE_CHOOSER (dialog));
574
gtk_widget_destroy (dialog);