]> err.no Git - mapper/blob - src/path.c
2a8c3e770e265aacfbd42dfc3d7bca3f3ce51713
[mapper] / src / path.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2008 Kaj-Michael Lang
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 #include <config.h>
21
22 #include <glib.h>
23 #include <gtk/gtk.h>
24 #include <sqlite3.h>
25
26 #include "path.h"
27 #include "position.h"
28 #include "utils.h"
29 #include "gps.h"
30 #include "settings.h"
31 #include "latlon.h"
32 #include "gpx.h"
33
34 struct sql_select_stmt {
35         sqlite3_stmt *select_paths;
36         sqlite3_stmt *select_path_nodes;
37
38         sqlite3_stmt *insert_path;
39         sqlite3_stmt *insert_path_node;
40
41         sqlite3_stmt *delete_path;
42         sqlite3_stmt *delete_path_nodes;
43 };
44 static struct sql_select_stmt sql;
45
46 #define PATH_TABLE_PATHS "create table IF NOT EXISTS paths ( \
47         nid             int primary key, \
48         name    text not null, \
49         desc    text, \
50         t               int not null);"
51
52 #define PATH_TABLE_NODES "create table IF NOT EXISTS path_nodes ( \
53         nid             int not null, \
54         lat     real not null, \
55         lon     real not null, \
56         sats    int, \
57         speed   real, \
58         course  real, \
59         pdop    real, \
60         hdop    real, \
61         vdop    real, \
62         name    text default null, \
63         t               int not null);"
64
65 enum {
66         NEW_POINT,                              /* A new point was appended to track track */
67         NEW_BREAK,                              /* A break was appended to the track */
68         NEW_WAYPOINT,                   /* A new waypoint/marker has been added */
69         NEAR_WAYPOINT,                  /* We are near the next route waypoint, announce it */
70         REACHED_WAYPOINT,               /* We have reached the next route waypoint, announce it */
71         REACHED_DESTINATION,    /* We have reached the last route waypoint */
72         CLEARED,                                /* Path was cleared */
73         LAST_SIGNAL
74 };
75 static guint32 signals[LAST_SIGNAL] = {0};
76
77 G_DEFINE_TYPE(Path, path, G_TYPE_OBJECT);
78
79 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PATH_TYPE, PathPrivate))
80
81 static void
82 path_dispose(GObject *object)
83 {
84 g_debug("path_dispose");
85
86 G_OBJECT_CLASS(path_parent_class)->dispose(object);
87 }
88
89 static void
90 path_finalize(GObject *object)
91 {
92 Path *path=PATH(object);
93
94 g_debug("path_finalize");
95 MACRO_PATH_FREE(*path);
96
97 if (path->name)
98         g_free(path->name);
99 if (path->desc)
100         g_free(path->desc);
101 if (path->author)
102         g_free(path->author);
103 if (path->keywords)
104         g_free(path->keywords);
105 if (path->copyright)
106         g_free(path->copyright);
107 if (path->src)
108         g_free(path->src);
109 }
110
111 static void
112 path_class_init(PathClass *klass)
113 {
114 GObjectClass *object_class=G_OBJECT_CLASS(klass);
115
116 g_debug("path_class_init");
117
118 object_class->dispose=path_dispose;
119 object_class->finalize=path_finalize;
120 /* g_type_class_add_private (klass, sizeof(PathPrivate)); */
121
122 signals[NEW_POINT]=g_signal_new("new-point", G_OBJECT_CLASS_TYPE(object_class),
123         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(PathClass, new_point),
124         NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
125 signals[NEW_BREAK]=g_signal_new("new-break", G_OBJECT_CLASS_TYPE(object_class),
126         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(PathClass, new_break),
127         NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
128 signals[NEW_WAYPOINT]=g_signal_new("new-waypoint", G_OBJECT_CLASS_TYPE(object_class),
129         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(PathClass, new_waypoint),
130         NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
131 }
132
133 static void
134 path_init(Path *path)
135 {
136 g_debug("path_init");
137 MACRO_PATH_INIT(*path);
138 }
139
140 Path *
141 path_new(PathType type, guint id)
142 {
143 Path *p;
144
145 p=g_object_new(PATH_TYPE, NULL);
146 p->type=type;
147 p->id=id;
148 p->sensitivity=3;
149 return p;
150 }
151
152 void
153 path_free(Path *path)
154 {
155 g_return_if_fail(path);
156 g_object_unref(path);
157 }
158
159 void
160 path_clear(Path *path)
161 {
162 g_return_if_fail(path);
163 MACRO_PATH_FREE(*path);
164 path->length=path->avgspeed=0.0;
165 path->points=0;
166 }
167
168 static gboolean
169 path_resize(Path *path, guint size)
170 {
171 g_return_val_if_fail(path, FALSE);
172
173 if (path->head + size != path->cap) {
174         WayPoint *curr;
175         Point *old_head = path->head;
176
177         path->head = g_renew(Point, old_head, size);
178         g_assert(path->head);
179         path->cap = path->head + size;
180         if (path->head != old_head) {
181                 path->tail = path->head + (path->tail - old_head);
182
183                 /* Adjust all of the waypoints. */
184                 for (curr = path->whead - 1; curr++ != path->wtail;)
185                         curr->point = path->head + (curr->point - old_head);
186         }
187         return TRUE;
188 }
189 return FALSE;
190 }
191
192 static gboolean 
193 path_wresize(Path *path, guint wsize)
194 {
195 g_return_val_if_fail(path, FALSE);
196
197 if (path->whead + wsize != path->wcap) {
198         WayPoint *old_whead = path->whead;
199
200         path->whead = g_renew(WayPoint, old_whead, wsize);
201         path->wtail = path->whead + (path->wtail - old_whead);
202         path->wcap = path->whead + wsize;
203
204         return TRUE;
205 }
206 return FALSE;
207 }
208
209 /**
210  * path_add_waypoint:
211  * @path
212  * @lat
213  * @lon
214  * @desc
215  *
216  * Append a waypoint to path at given lat, lon with description desc
217  *
218  * Returns: TRUE
219  */
220 gboolean
221 path_add_waypoint(Path *path, gdouble lat, gdouble lon, gchar *desc)
222 {
223 guint unitx, unity;
224
225 latlon2unit(lat, lon, unitx, unity);
226 MACRO_PATH_INCREMENT_TAIL(*path);
227 path->tail->unitx=unitx;
228 path->tail->unity=unity;
229 path->tail->time=0;
230 path->tail->altitude=NAN;
231
232 MACRO_PATH_INCREMENT_WTAIL(*path);
233 path->wtail->point=path->tail;
234 path->wtail->desc=desc;
235
236 path_find_nearest_point(path);
237
238 g_signal_emit(G_OBJECT(path), signals[NEW_WAYPOINT], 0, NULL);
239
240 return TRUE;
241 }
242
243 /**
244  * path_add_point:
245  * @path
246  * @gps
247  *
248  * Append a point using given gps data. Adds a path break if gps is not valid.
249  *
250  * Returns: TRUE if the new point was added. FALSE is returned if new point distance was under sensitivity setting.
251  */
252 gboolean
253 path_add_point(Path *path, GpsData *gps)
254 {
255 guint unitx, unity;
256
257 g_return_val_if_fail(path, FALSE);
258
259 if (!gps) {
260         path_add_break(path);
261         return FALSE;
262 }
263
264 return path_add_latlon(path, gps->lat, gps->lon, gps->time, gps->speed, gps->altitude);
265 }
266
267 /**
268  * path_add_latlon:
269  * @path
270  * @lat
271  * @lon
272  * @ptime
273  * @speed
274  * @altitude
275  *
276  * Append a point with given lat,lon,ptime,speed and altitude to given path.
277  *
278  * Returns: TRUE if the new point was added. FALSE is returned if new point distance was under sensitivity setting.
279  */
280 gboolean 
281 path_add_latlon(Path *path, gdouble lat, gdouble lon, time_t ptime, gfloat speed, gfloat altitude)
282 {
283 guint unitx, unity;
284
285 latlon2unit(lat, lon, unitx, unity);
286
287 if (abs((gint)unitx-path->tail->unitx) > path->sensitivity || abs((gint)unity-path->tail->unity) > path->sensitivity) {
288         if (path->tail->unity && path->tail->unitx) {
289                 gdouble plat, plon;
290
291                 unit2latlon(path->tail->unitx, path->tail->unity, lat, lon);
292                 path->length+=calculate_distance(plat, plon, lat, lon);
293         }
294         MACRO_PATH_INCREMENT_TAIL(*path);
295         path->tail->unitx=unitx;
296         path->tail->unity=unity;
297         path->tail->time=ptime;
298         path->tail->altitude=altitude;
299         if (speed>path->maxspeed)
300                 path->maxspeed=speed;
301         path->tspeed+=speed;
302         path->avgspeed=(path->points>0) ? path->tspeed/path->points : 0.0;
303         path->points++;
304         g_debug("TRACK: %f %f (%d)", path->length, path->avgspeed, path->points);
305
306         g_signal_emit(G_OBJECT(path), signals[NEW_POINT], 0, NULL);
307         return TRUE;
308 }
309
310 return FALSE;
311
312 }
313
314 /**
315  * path_add_break:
316  * @path
317  *
318  * Add a break point to the path.
319  * 
320  * Returns: TRUE if break was added, FALSE if last point was a break already.
321  */
322 gboolean 
323 path_add_break(Path *path)
324 {
325 g_return_val_if_fail(path, FALSE);
326 g_return_val_if_fail(path->tail, FALSE);
327
328 if (path->tail->unity && path->tail->unitx) {
329         /* To mark a "break" in a track, we'll add a (0, 0) point and then 
330            another instance of the most recent track point. */
331
332         MACRO_PATH_INCREMENT_TAIL(*path);
333         *path->tail=_point_null;
334         MACRO_PATH_INCREMENT_TAIL(*path);
335         *path->tail=path->tail[-2];
336
337         g_signal_emit(G_OBJECT(path), signals[NEW_BREAK], 0, NULL);
338
339         return TRUE;
340 }
341 return FALSE;
342 }
343
344 /**
345  * path_has_points:
346  * @path
347  *
348  * Checks if given path has any path points
349  *
350  * Returns: TRUE if there are points, FALSE otherwise
351  */
352 gboolean
353 path_has_points(Path *path)
354 {
355 g_return_val_if_fail(path, FALSE);
356 return path->head==path->tail ? FALSE : TRUE;
357 }
358
359 /**
360  * path_has_waypoints:
361  * 
362  * Checks if given path has any waypoints
363  * 
364  * Returns: TRUE if there are waypoints, FALSE otherwise
365  */
366 gboolean
367 path_has_waypoints(Path *path)
368 {
369 g_return_val_if_fail(path, FALSE);
370 return path->whead==path->wtail ? FALSE : TRUE;
371 }
372
373 /**
374  * path_find_last_point:
375  * @path
376  *
377  * Returns: The last path point or NULL if path is empty
378  */
379 Point *
380 path_find_last_point(Path *path)
381 {
382 Point *p=NULL;
383
384 g_return_val_if_fail(path, NULL);
385
386 if (!path_has_points(path))
387         return p;
388
389 for (p=path->tail; !p->unity; p--) {
390 }
391 return p;
392 }
393
394 /**
395  * Updates near_point, next_way, and next_wpt.  If quick is FALSE (as
396  * it is when this function is called from route_find_nearest_point), then
397  * the entire list (starting from near_point) is searched.  Otherwise, we
398  * stop searching when we find a point that is farther away.
399  */
400 static gboolean 
401 path_update_nears(Path *path, Point *point, gboolean quick)
402 {
403 gboolean ret = FALSE;
404 Point *curr, *near;
405 WayPoint *wcurr, *wnext;
406 guint64 near_dist_squared;
407
408 g_return_val_if_fail(path, FALSE);
409
410 /* If we have waypoints (_next_way != NULL), then determine the "next
411  * waypoint", which is defined as the waypoint after the nearest point,
412  * UNLESS we've passed that waypoint, in which case the waypoint after
413  * that waypoint becomes the "next" waypoint. */
414 if (path->next_way) {
415         /* First, set near_dist_squared with the new distance from
416          * near_point. */
417         near = path->near_point;
418         near_dist_squared = DISTANCE_SQUARED(*point, *near);
419
420         /* Now, search path for a closer point.  If quick is TRUE, then we'll
421          * only search forward, only as long as we keep finding closer points.
422          */
423         for (curr = path->near_point; curr++ != path->tail;) {
424                 if (curr->unity) {
425                         guint dist_squared = DISTANCE_SQUARED(*point, *curr);
426                         if (dist_squared <= near_dist_squared) {
427                                 near = curr;
428                                 near_dist_squared = dist_squared;
429                         } else if (quick)
430                                 break;
431                 }
432         }
433
434         /* Update _near_point. */
435         path->near_point = near;
436         path->near_point_dist_squared = near_dist_squared;
437
438         for (wnext = wcurr = path->next_way; wcurr != path->wtail; wcurr++) {
439                 if (wcurr->point < near || (wcurr->point == near && quick 
440                                 && (path->next_wpt && (DISTANCE_SQUARED(*point, *near) > path->next_way_dist_squared
441                                 && DISTANCE_SQUARED(*point, *path->next_wpt) < path->next_wpt_dist_squared))))
442                     /* Okay, this else if expression warrants explanation.  If the
443                      * nearest track point happens to be a waypoint, then we want to
444                      * check if we have "passed" that waypoint.  To check this, we
445                      * test the distance from _gps to the waypoint and from _gps to
446                      * _next_wpt, and if the former is increasing and the latter is
447                      * decreasing, then we have passed the waypoint, and thus we
448                      * should skip it.  Note that if there is no _next_wpt, then
449                      * there is no next waypoint, so we do not skip it in that case. */
450                         wnext = wcurr + 1;
451                 else
452                         break;
453         }
454
455         if (wnext == path->wtail && (wnext->point < near || (wnext->point == near && quick
456                                           && (path->next_wpt && (DISTANCE_SQUARED (*point, *near) > path->next_way_dist_squared
457                                                && DISTANCE_SQUARED(*point, *path->next_wpt) < path->next_wpt_dist_squared)))))
458         {
459                 path->next_way = NULL;
460                 path->next_wpt = NULL;
461                 path->next_way_dist_squared = -1;
462                 path->next_wpt_dist_squared = -1;
463                 ret = TRUE;
464         }
465         /* Only update next_way (and consequently _next_wpt) if _next_way is
466          * different, and record that fact for return. */
467         else {
468                 if (!quick || path->next_way != wnext) {
469                         path->next_way = wnext;
470                         path->next_wpt = wnext->point;
471                         if (path->next_wpt == path->tail)
472                                 path->next_wpt = NULL;
473                         else {
474                                 while (!(++path->next_wpt)->unity) {
475                                         if (path->next_wpt == path->tail) {
476                                                 path->next_wpt = NULL;
477                                                 break;
478                                         }
479                                 }
480                         }
481                         ret = TRUE;
482                 }
483                 path->next_way_dist_squared = DISTANCE_SQUARED(*point, *wnext->point);
484                 if (path->next_wpt)
485                         path->next_wpt_dist_squared = DISTANCE_SQUARED(*point, *path->next_wpt);
486         }
487 }
488 return ret;
489 }
490
491 /**
492  * path_find_nearest_point:
493  *
494  * Reset the near_point data by searching the entire path for the nearest point and waypoint.
495  */
496 void 
497 path_find_nearest_point(Path *path)
498 {
499 g_return_if_fail(path);
500
501 /* Initialize near_point to first non-zero point. */
502 path->near_point=path->head;
503 while (!path->near_point->unity && path->near_point != path->tail)
504         path->near_point++;
505
506 /* Initialize next_way */
507 if (path->wtail==path->whead)
508         path->next_way=NULL;
509 else
510         path->next_way=path->whead;
511 path->next_way_dist_squared=-1;
512
513 /* Initialize next_wpt */
514 path->next_wpt=NULL;
515 path->next_wpt_dist_squared=-1;
516
517 }
518
519 /**
520  * path_find_nearest_waypoint:
521  *
522  */
523 WayPoint *
524 path_find_nearest_waypoint(Path *path, guint unitx, guint unity)
525 {
526 WayPoint *wcurr;
527 WayPoint *wnear;
528 guint64 nearest_squared;
529 Point pos = { unitx, unity, 0, NAN };
530
531 g_return_val_if_fail(path, NULL);
532
533 wcurr=wnear=path->whead;
534 if (wcurr && wcurr->point && wcurr!=path->wtail) {
535         nearest_squared=DISTANCE_SQUARED(pos, *(wcurr->point));
536
537         while (wcurr++!=path->wtail) {
538                 guint64 test_squared=DISTANCE_SQUARED(pos, *(wcurr->point));
539                 if (test_squared < nearest_squared) {
540                         wnear=wcurr;
541                         nearest_squared=test_squared;
542                 }
543         }
544 }
545
546 if (wnear && wnear->point) {
547         if (abs(unitx - wnear->point->unitx) < path->sensitivity && abs(unity - wnear->point->unity) < path->sensitivity)
548                 return wnear;
549 }
550
551 return NULL;
552 }
553
554 /**
555  * path_check_waypoint_announce:
556  * @path
557  * @gps 
558  *
559  * Check if we should announce upcoming waypoint.
560  *
561  */
562 static void
563 path_check_waypoint_announce(Path *path, GpsData *gps)
564 {
565 guint a_thres_near, a_thres_at;
566
567 g_return_if_fail(path);
568 g_return_if_fail(gps);
569
570 if (!path->next_way)
571         return;
572
573 a_thres_near=(20+(guint)gps->speed)*path->announce_notice_ratio*3;
574 a_thres_at=(20+(guint)gps->speed);
575
576 if (path->next_way_dist_squared<(a_thres_near * a_thres_near) && path->next_way!=path->announced_waypoint) {
577         g_signal_emit(G_OBJECT(path), signals[NEAR_WAYPOINT], 0, NULL);
578         path->announced_waypoint=path->next_way;
579 } else if (path->next_way_dist_squared<(a_thres_at * a_thres_at) && path->next_way!=path->announced_waypoint) {
580         g_signal_emit(G_OBJECT(path), signals[REACHED_WAYPOINT], 0, NULL);
581         path->announced_waypoint=path->next_way;
582 }
583 }
584
585 /******************************************************************************/
586
587 gdouble
588 path_get_distance_to(Path *path, Point *point, gdouble lat, gdouble lon)
589 {
590 gdouble lat1, lon1, lat2, lon2;
591 gdouble sum=0.0;
592
593 g_return_val_if_fail(path, 0.0);
594
595 /* If point is NULL, use the next waypoint. */
596 if (point == NULL && path->next_way)
597         point = path->next_way->point;
598
599 /* If point is still NULL, return an error. */
600 if (point==NULL)
601         return FALSE;
602
603 lat1=lat;
604 lon1=lon;
605
606 if (point > path->near_point) {
607         Point *curr;
608         /* Skip _near_point in case we have already passed it. */
609         for (curr = path->near_point + 1; curr <= point; ++curr) {
610                 if (curr->unity) {
611                         unit2latlon(curr->unitx, curr->unity, lat2, lon2);
612                         sum += calculate_distance(lat1, lon1, lat2, lon2);
613                         lat1 = lat2;
614                         lon1 = lon2;
615                 }
616         }
617 } else if (point < path->near_point) {
618         Point *curr;
619         /* Skip near_point in case we have already passed it. */
620         for (curr = path->near_point - 1; curr >= point; --curr) {
621                 if (curr->unity) {
622                         unit2latlon(curr->unitx, curr->unity, lat2, lon2);
623                         sum += calculate_distance(lat1, lon1, lat2, lon2);
624                         lat1 = lat2;
625                         lon1 = lon2;
626                 }
627         }
628 } else {
629         /* Waypoint _is_ the nearest point. */
630         unit2latlon(path->near_point->unitx, path->near_point->unity, lat2, lon2);
631         sum += calculate_distance(lat1, lon1, lat2, lon2);
632 }
633 return sum;
634 }
635
636 /******************************************************************************/
637
638 gboolean
639 path_load(Path *path, const gchar *config_dir, const gchar *file)
640 {
641 gchar *pfile;
642 gchar *bytes;
643 gint size;
644
645 g_return_val_if_fail(path, FALSE);
646 g_return_val_if_fail(config_dir, FALSE);
647 g_return_val_if_fail(file, FALSE);
648
649 pfile = gnome_vfs_uri_make_full_from_relative(config_dir, file);
650 if (gnome_vfs_read_entire_file(pfile, &size, &bytes)==GNOME_VFS_OK)
651         gpx_parse(path, bytes, size, GPX_PATH_NEW);
652 g_free(pfile);
653 return TRUE;
654 }
655
656 gboolean 
657 path_save(Path *path, const gchar *config_dir, const gchar *file)
658 {
659 GnomeVFSHandle *handle;
660 gchar *tfile;
661
662 g_return_val_if_fail(path, FALSE);
663 g_return_val_if_fail(config_dir, FALSE);
664 g_return_val_if_fail(file, FALSE);
665
666 tfile=gnome_vfs_uri_make_full_from_relative(config_dir, file);
667 if (gnome_vfs_create(&handle, tfile, GNOME_VFS_OPEN_WRITE, FALSE, 0600)==GNOME_VFS_OK) {
668         gpx_write(path, handle);
669         gnome_vfs_close(handle);
670 }
671 g_free(tfile);
672 return TRUE;
673 }
674
675 /******************************************************************************/
676
677 gboolean
678 path_set_destination_from_last(Path *path, Position *pos)
679 {
680 Point *p;
681 gdouble lat,lon;
682
683 g_return_val_if_fail(path, FALSE);
684 g_return_val_if_fail(pos, FALSE);
685
686 if (path->head==path->tail) {
687         position_set(pos, FALSE, NAN, NAN, NAN);
688         return FALSE;
689 }
690
691 p=path_find_last_point(path);
692 if (p) {
693         unit2latlon(p->unitx, p->unity, &lat, &lon);
694         position_set(pos, TRUE, lat, lon, 0);
695 } else {
696         position_set(pos, FALSE, NAN, NAN, NAN);
697         return FALSE;
698 }
699 return TRUE;
700 }
701
702 /**
703  * path_get_waypoint_latlon:
704  * @way
705  * @lat
706  * @lon
707  *
708  * Get the real latitude and longitude of given waypoint
709  *
710  * Returns: TRUE if waypoint was valid, FALSE otherwise.
711  */
712 gboolean
713 path_get_waypoint_latlon(WayPoint *way, gdouble *lat, gdouble *lon)
714 {
715 gdouble tlat, tlon;
716
717 g_return_val_if_fail(way, FALSE);
718 g_return_val_if_fail(way->point, FALSE);
719 g_return_val_if_fail(lat, FALSE);
720 g_return_val_if_fail(lon, FALSE);
721
722 unit2latlon(way->point->unitx, way->point->unity, tlat, tlon);
723
724 *lat=tlat;
725 *lon=tlon;
726
727 return TRUE;
728 }
729
730 /**
731  * path_insert_mark_text:
732  * @path
733  * @text
734  *
735  * Add a new waypoint to path with given text. 
736  *
737  */
738 void 
739 path_insert_mark_text(Path *path, gchar *text)
740 {
741 g_return_if_fail(path);
742 MACRO_PATH_INCREMENT_WTAIL(*path);
743 path->wtail->point=path->tail;
744 if (text) {
745         path->wtail->desc=text;
746 } else {
747         path->wpcnt++;
748         path->wtail->desc=g_strdup_printf("WPT:#%u", path->wpcnt);
749 }
750 g_signal_emit(G_OBJECT(path), signals[NEW_WAYPOINT], 0, NULL);
751 }
752
753 /**
754  * path_insert_mark_autonumber:
755  * @path
756  *
757  * Add autonumbered waypoint to given path
758  *
759  */
760 void
761 path_insert_mark_autonumber(Path *path)
762 {
763 path_insert_mark_text(path, NULL);
764 }
765
766 /******************************************************************************/
767 #if 0
768 static void
769 path_store_append_waypoint(GtkListStore *, WayPoint *w)
770 {
771 gchar tmp1[16], tmp2[16];
772 gdouble lat2, lon2;
773
774 unit2latlon(wcurr->point->unitx, wcurr->point->unity, lat2, lon2);
775 lat_format(_degformat, lat2, tmp1);
776 lon_format(_degformat, lon2, tmp2);
777
778 g_snprintf(buffer1, sizeof(buffer1), "%s,%s", tmp1, tmp2);
779 sum += calculate_distance(lat1, lon1, lat2, lon2);
780 g_snprintf(buffer2, sizeof(buffer2), "%.02f %s", sum * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
781
782 gtk_list_store_append(store, &iter);
783 gtk_list_store_set(store, &iter,
784         PATH_LATLON, buffer1,
785         PATH_DISTANCE, buffer2,
786         PATH_WAYPOINT, wcurr->desc,
787         PATH_LAT, lat2,
788         PATH_LON, lon2,
789         -1);
790
791 lat1=lat2;
792 lon1=lon2;
793 }
794 #endif
795
796 /**
797  * Generate a GtkListStore with information about path waypoints (location, distance)
798  */
799 GtkListStore *
800 path_get_waypoints_store(Path *path)
801 {
802 WayPoint *wcurr;
803 GtkTreeIter iter;
804 GtkListStore *store;
805 gchar buffer1[80];
806 gchar buffer2[32];
807 gchar tmp1[16], tmp2[16];
808 gdouble lat1, lon1, lat2, lon2;
809 gdouble sum=0.0;
810
811 g_return_val_if_fail(path!=NULL, NULL);
812
813 wcurr=path->whead;
814
815 g_return_val_if_fail(wcurr!=NULL, NULL);
816 g_return_val_if_fail(wcurr->point!=NULL, NULL);
817 if (!path_has_waypoints(path))
818         return NULL;
819
820 store=gtk_list_store_new(PATH_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
821
822 unit2latlon(wcurr->point->unitx, wcurr->point->unity, lat1, lon1);
823
824 while (wcurr!=path->wtail) {
825         if (!wcurr)
826                 break;
827
828         if (!wcurr->point) {
829                 g_debug("PSTORE: No point for waypoint (%s) skipping", wcurr->desc);
830                 wcurr++;
831                 continue;
832         }
833
834         unit2latlon(wcurr->point->unitx, wcurr->point->unity, lat2, lon2);
835         lat_format(_degformat, lat2, tmp1);
836         lon_format(_degformat, lon2, tmp2);
837
838         g_snprintf(buffer1, sizeof(buffer1), "%s,%s", tmp1, tmp2);
839         sum += calculate_distance(lat1, lon1, lat2, lon2);
840         g_snprintf(buffer2, sizeof(buffer2), "%.02f %s", sum * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
841
842         gtk_list_store_append(store, &iter);
843         gtk_list_store_set(store, &iter,
844                 PATH_LATLON, buffer1,
845                 PATH_DISTANCE, buffer2,
846                 PATH_WAYPOINT, wcurr->desc,
847                 PATH_LAT, lat2,
848                 PATH_LON, lon2,
849                 -1);
850
851         lat1=lat2;
852         lon1=lon2;
853
854         wcurr++;
855 }
856
857 return store;
858 }