2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 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.
21 * @brief Contains code related to finding a route from a position to a destination
23 * Routing uses segments, points and items. Items are items from the map: Streets, highways, etc.
24 * Segments represent such items, or parts of it. Generally, a segment is a driveable path. An item
25 * can be represented by more than one segment - in that case it is "segmented". Each segment has an
26 * "offset" associated, that indicates at which position in a segmented item this segment is - a
27 * segment representing a not-segmented item always has the offset 1.
28 * A point is located at the end of segments, often connecting several segments.
30 * The code in this file will make navit find a route between a position and a destination.
31 * It accomplishes this by first building a "route graph". This graph contains segments and
34 * After building this graph in route_graph_build(), the function route_graph_flood() assigns every
35 * point and segment a "value" which represents the "costs" of traveling from this point to the
36 * destination. This is done by Dijkstra's algorithm.
38 * When the graph is built a "route path" is created, which is a path in this graph from a given
39 * position to the destination determined at time of building the graph.
56 #include "projection.h"
64 #include "transform.h"
76 * @brief A point in the route graph
78 * This represents a point in the route graph. A point usually connects two or more segments,
79 * but there are also points which don't do that (e.g. at the end of a dead-end).
81 struct route_graph_point {
82 struct route_graph_point *next; /**< Linked-list pointer to a list of all route_graph_points */
83 struct route_graph_point *hash_next; /**< Pointer to a chained hashlist of all route_graph_points with this hash */
84 struct route_graph_segment *start; /**< Pointer to a list of segments of which this point is the start. The links
85 * of this linked-list are in route_graph_segment->start_next.*/
86 struct route_graph_segment *end; /**< Pointer to a list of segments of which this pointer is the end. The links
87 * of this linked-list are in route_graph_segment->end_next. */
88 struct route_graph_segment *seg; /**< Pointer to the segment one should use to reach the destination at
90 struct fibheap_el *el; /**< When this point is put on a Fibonacci heap, this is a pointer
91 * to this point's heap-element */
92 int value; /**< The cost at which one can reach the destination from this point on */
93 struct coord c; /**< Coordinates of this point */
97 * @brief A segment in the route graph
99 * This is a segment in the route graph. A segment represents a driveable way.
101 struct route_graph_segment {
102 struct route_graph_segment *next; /**< Linked-list pointer to a list of all route_graph_segments */
103 struct route_graph_segment *start_next; /**< Pointer to the next element in the list of segments that start at the
104 * same point. Start of this list is in route_graph_point->start. */
105 struct route_graph_segment *end_next; /**< Pointer to the next element in the list of segments that end at the
106 * same point. Start of this list is in route_graph_point->end. */
107 struct route_graph_point *start; /**< Pointer to the point this segment starts at. */
108 struct route_graph_point *end; /**< Pointer to the point this segment ends at. */
109 struct item item; /**< The item (e.g. street) that this segment represents. */
111 int len; /**< Length of this segment */
112 int offset; /**< If the item represented by this segment is "segmented" (i.e.
113 * is represented by several segments instead of just one), this
114 * indicates the position of this segment in the item - for items
115 * that are not segmented this should always be 1 */
119 * @brief A segment in the route path
121 * This is a segment in the route path.
123 struct route_path_segment {
124 struct route_path_segment *next; /**< Pointer to the next segment in the path */
125 struct item item; /**< The item (e.g. street) this segment represents */
126 int length; /**< Length of the segment */
127 int offset; /**< Same as in route_graph_segment->offset */
128 int direction; /**< Order in which the coordinates are ordered. >0 means "First
129 * coordinate of the segment is the first coordinate of the item", <=0
131 unsigned ncoords; /**< How many coordinates does this segment have? */
132 struct attr **attrs; /**< Attributes of this route path segment */
133 struct coord c[0]; /**< Pointer to the ncoords coordinates of this segment */
134 /* WARNING: There will be coordinates following here, so do not create new fields after c! */
138 * @brief Usually represents a destination or position
140 * This struct usually represents a destination or position
143 struct coord c; /**< The actual destination / position */
144 struct coord lp; /**< The nearest point on a street to c */
145 int pos; /**< The position of lp within the coords of the street */
146 int lenpos; /**< Distance between lp and the end of the street */
147 int lenneg; /**< Distance between lp and the start of the street */
148 int lenextra; /**< Distance between lp and c */
150 struct street_data *street; /**< The street lp is on */
154 * @brief A complete route path
156 * This structure describes a whole routing path
159 struct route_path_segment *path; /**< The first segment in the path, i.e. the segment one should
161 struct route_path_segment *path_last; /**< The last segment in the path */
162 /* XXX: path_hash is not necessery now */
163 struct item_hash *path_hash; /**< A hashtable of all the items represented by this route's segements */
166 #define RF_FASTEST (1<<0)
167 #define RF_SHORTEST (1<<1)
168 #define RF_AVOIDHW (1<<2)
169 #define RF_AVOIDPAID (1<<3)
170 #define RF_LOCKONROAD (1<<4)
171 #define RF_SHOWGRAPH (1<<5)
174 * @brief A complete route
176 * This struct holds all information about a route.
179 int version; /**< Counts how many times this route got updated */
180 struct mapset *ms; /**< The mapset this route is built upon */
182 struct route_info *pos; /**< Current position within this route */
183 struct route_info *dst; /**< Destination of the route */
185 struct route_graph *graph; /**< Pointer to the route graph */
186 struct route_path *path2; /**< Pointer to the route path */
188 struct map *graph_map;
189 int speedlist[route_item_last-route_item_first+1]; /**< The speedlist for this route */
193 * @brief A complete route graph
195 * This structure describes a whole routing graph
198 struct route_graph_point *route_points; /**< Pointer to the first route_graph_point in the linked list of all points */
199 struct route_graph_segment *route_segments; /**< Pointer to the first route_graph_segment in the linked list of all segments */
200 #define HASH_SIZE 8192
201 struct route_graph_point *hash[HASH_SIZE]; /**< A hashtable containing all route_graph_points in this graph */
204 #define HASHCOORD(c) ((((c)->x +(c)->y) * 2654435761UL) & (HASH_SIZE-1))
206 static struct route_info * route_find_nearest_street(struct mapset *ms, struct pcoord *c);
207 static struct route_graph_point *route_graph_get_point(struct route_graph *this, struct coord *c);
208 static void route_graph_update(struct route *this);
209 static struct route_path *route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist);
210 static void route_process_street_graph(struct route_graph *this, struct item *item);
211 static void route_graph_destroy(struct route_graph *this);
212 static void route_path_update(struct route *this);
215 * @brief Returns the projection used for this route
217 * @param route The route to return the projection for
218 * @return The projection used for this route
220 static enum projection route_projection(struct route *route)
222 struct street_data *street;
223 street = route->pos ? route->pos->street : route->dst->street;
224 return map_projection(street->item.map);
228 * @brief Destroys a route_path
230 * @param this The route_path to be destroyed
233 route_path_destroy(struct route_path *this)
235 struct route_path_segment *c,*n;
238 if (this->path_hash) {
239 item_hash_destroy(this->path_hash);
240 this->path_hash=NULL;
252 * @brief Creates a completely new route structure
254 * @param attrs Not used
255 * @return The newly created route
258 route_new(struct attr **attrs)
260 struct route *this=g_new0(struct route, 1);
262 printf("%s:Out of memory\n", __FUNCTION__);
269 * @brief Sets the mapset of the route passwd
271 * @param this The route to set the mapset for
272 * @param ms The mapset to set for this route
275 route_set_mapset(struct route *this, struct mapset *ms)
281 * @brief Returns the mapset of the route passed
283 * @param this The route to get the mapset of
284 * @return The mapset of the route passed
287 route_get_mapset(struct route *this)
293 * @brief Returns the current position within the route passed
295 * @param this The route to get the position for
296 * @return The position within the route passed
299 route_get_pos(struct route *this)
305 * @brief Returns the destination of the route passed
307 * @param this The route to get the destination for
308 * @return The destination of the route passed
311 route_get_dst(struct route *this)
317 * @brief Returns the speedlist of the route passed
319 * @param this The route to get the speedlist for
320 * @return The speedlist of the route passed
323 route_get_speedlist(struct route *this)
325 return this->speedlist;
329 * @brief Checks if the path is calculated for the route passed
331 * @param this The route to check
332 * @return True if the path is calculated, false if not
335 route_get_path_set(struct route *this)
337 return this->path2 != NULL;
341 * @brief Sets the driving speed for a certain itemtype
343 * @param this The route to set the speed for
344 * @param type The itemtype to set the speed for
345 * @param value The speed that should be set
346 * @return True on success, false if the itemtype does not exist
349 route_set_speed(struct route *this, enum item_type type, int value)
351 if (type < route_item_first || type > route_item_last) {
352 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
355 this->speedlist[type-route_item_first]=value;
360 * @brief Checks if the route passed contains a certain item within the route path
362 * This function checks if a certain items exists in the path that navit will guide
363 * the user to his destination. It does *not* check if this item exists in the route
366 * @param this The route to check for this item
367 * @param item The item to search for
368 * @return True if the item was found, false if the item was not found or the route was not calculated
371 route_contains(struct route *this, struct item *item)
373 if (! this->path2 || !this->path2->path_hash)
375 return (int)item_hash_lookup(this->path2->path_hash, item);
379 * @brief Checks if the current position in a route is a certain item
381 * @param this The route to check for this item
382 * @param item The item to search for
383 * @return True if the current position is this item, false otherwise
386 route_pos_contains(struct route *this, struct item *item)
390 return item_is_equal(this->pos->street->item, *item);
394 * @brief Updates the route graph and the route path if something changed with the route
396 * This will update the route graph and the route path of the route if some of the
397 * route's settings (destination, position) have changed.
399 * @attention For this to work the route graph has to be destroyed if the route's
400 * @attention destination is changed somewhere!
402 * @param this The route to update
405 route_path_update(struct route *this)
407 struct route_path *oldpath = NULL;
408 if (! this->pos || ! this->dst) {
409 route_path_destroy(this->path2);
413 /* the graph is destroyed when setting the destination */
414 if (this->graph && this->pos && this->dst && this->path2) {
415 // we can try to update
416 oldpath = this->path2;
419 if (! this->graph || !(this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist))) {
421 route_graph_update(this);
422 this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist);
423 profile(1,"route_path_new");
427 /* Destroy what's left */
428 route_path_destroy(oldpath);
433 * @brief This will calculate all the distances stored in a route_info
435 * @param ri The route_info to calculate the distances for
436 * @param pro The projection used for this route
439 route_info_distances(struct route_info *ri, enum projection pro)
442 struct street_data *sd=ri->street;
443 /* 0 1 2 X 3 4 5 6 pos=2 npos=3 count=7 0,1,2 3,4,5,6*/
444 ri->lenextra=transform_distance(pro, &ri->lp, &ri->c);
445 ri->lenneg=transform_polyline_length(pro, sd->c, npos)+transform_distance(pro, &sd->c[ri->pos], &ri->lp);
446 ri->lenpos=transform_polyline_length(pro, sd->c+npos, sd->count-npos)+transform_distance(pro, &sd->c[npos], &ri->lp);
450 * @brief This sets the current position of the route passed
452 * This will set the current position of the route passed to the street that is nearest to the
453 * passed coordinates. It also automatically updates the route.
455 * @param this The route to set the position of
456 * @param pos Coordinates to set as position
459 route_set_position(struct route *this, struct pcoord *pos)
462 route_info_free(this->pos);
464 this->pos=route_find_nearest_street(this->ms, pos);
465 dbg(1,"this->pos=%p\n", this->pos);
468 route_info_distances(this->pos, pos->pro);
470 route_path_update(this);
474 * @brief Sets a route's current position based on coordinates from tracking
476 * @param this The route to set the current position of
477 * @param tracking The tracking to get the coordinates from
480 route_set_position_from_tracking(struct route *this, struct tracking *tracking)
483 struct route_info *ret;
486 c=tracking_get_pos(tracking);
487 ret=g_new0(struct route_info, 1);
489 printf("%s:Out of memory\n", __FUNCTION__);
493 route_info_free(this->pos);
497 ret->pos=tracking_get_segment_pos(tracking);
498 ret->street=street_data_dup(tracking_get_street_data(tracking));
499 route_info_distances(ret, projection_mg);
500 dbg(3,"c->x=0x%x, c->y=0x%x pos=%d item=(0x%x,0x%x)\n", c->x, c->y, ret->pos, ret->street->item.id_hi, ret->street->item.id_lo);
501 dbg(3,"street 0=(0x%x,0x%x) %d=(0x%x,0x%x)\n", ret->street->c[0].x, ret->street->c[0].y, ret->street->count-1, ret->street->c[ret->street->count-1].x, ret->street->c[ret->street->count-1].y);
504 route_path_update(this);
508 /* Used for debuging of route_rect, what routing sees */
509 struct map_selection *route_selection;
512 * @brief Returns a single map selection
514 struct map_selection *
515 route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs)
517 int dx,dy,sx=1,sy=1,d,m;
518 struct map_selection *sel=g_new(struct map_selection, 1);
520 printf("%s:Out of memory\n", __FUNCTION__);
523 sel->order[layer_town]=0;
524 sel->order[layer_poly]=0;
525 sel->order[layer_street]=order;
526 dbg(1,"%p %p\n", c1, c2);
531 sel->u.c_rect.lu.x=c1->x;
532 sel->u.c_rect.rl.x=c2->x;
534 sel->u.c_rect.lu.x=c2->x;
535 sel->u.c_rect.rl.x=c1->x;
539 sel->u.c_rect.lu.y=c2->y;
540 sel->u.c_rect.rl.y=c1->y;
542 sel->u.c_rect.lu.y=c1->y;
543 sel->u.c_rect.rl.y=c2->y;
550 sel->u.c_rect.lu.x-=m;
551 sel->u.c_rect.rl.x+=m;
552 sel->u.c_rect.lu.y+=m;
553 sel->u.c_rect.rl.y-=m;
559 * @brief Returns a list of map selections useable to create a route graph
561 * Returns a list of map selections useable to get a map rect from which items can be
562 * retrieved to build a route graph. The selections are a rectangle with
563 * c1 and c2 as two corners.
565 * @param c1 Corner 1 of the rectangle
566 * @param c2 Corder 2 of the rectangle
568 static struct map_selection *
569 route_calc_selection(struct coord *c1, struct coord *c2)
571 struct map_selection *ret,*sel;
572 sel=route_rect(4, c1, c2, 25, 0);
574 sel->next=route_rect(8, c1, c1, 0, 40000);
576 sel->next=route_rect(18, c1, c1, 0, 10000);
578 sel->next=route_rect(8, c2, c2, 0, 40000);
580 sel->next=route_rect(18, c2, c2, 0, 10000);
581 /* route_selection=ret; */
586 * @brief Destroys a list of map selections
588 * @param sel Start of the list to be destroyed
591 route_free_selection(struct map_selection *sel)
593 struct map_selection *next;
603 * @brief Sets the destination of a route
605 * This sets the destination of a route to the street nearest to the coordinates passed
606 * and updates the route.
608 * @param this The route to set the destination for
609 * @param dst Coordinates to set as destination
612 route_set_destination(struct route *this, struct pcoord *dst)
616 route_info_free(this->dst);
619 this->dst=route_find_nearest_street(this->ms, dst);
620 route_info_distances(this->dst, dst->pro);
621 profile(1,"find_nearest_street");
623 /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
624 route_graph_destroy(this->graph);
626 route_path_update(this);
631 * @brief Gets the route_graph_point with the specified coordinates
633 * @param this The route in which to search
634 * @param c Coordinates to search for
635 * @return The point at the specified coordinates or NULL if not found
637 static struct route_graph_point *
638 route_graph_get_point(struct route_graph *this, struct coord *c)
640 struct route_graph_point *p;
641 int hashval=HASHCOORD(c);
642 p=this->hash[hashval];
644 if (p->c.x == c->x && p->c.y == c->y)
652 * @brief Inserts a point into the route graph at the specified coordinates
654 * This will insert a point into the route graph at the coordinates passed in f.
655 * Note that the point is not yet linked to any segments.
657 * @param this The route to insert the point into
658 * @param f The coordinates at which the point should be inserted
659 * @return The point inserted or NULL on failure
661 static struct route_graph_point *
662 route_graph_add_point(struct route_graph *this, struct coord *f)
665 struct route_graph_point *p;
667 p=route_graph_get_point(this,f);
669 hashval=HASHCOORD(f);
671 printf("p (0x%x,0x%x)\n", f->x, f->y);
672 p=g_new(struct route_graph_point,1);
674 printf("%s:Out of memory\n", __FUNCTION__);
677 p->hash_next=this->hash[hashval];
678 this->hash[hashval]=p;
679 p->next=this->route_points;
686 this->route_points=p;
692 * @brief Frees all the memory used for points in the route graph passed
694 * @param this The route graph to delete all points from
697 route_graph_free_points(struct route_graph *this)
699 struct route_graph_point *curr,*next;
700 curr=this->route_points;
706 this->route_points=NULL;
707 memset(this->hash, 0, sizeof(this->hash));
711 * @brief Inserts a new segment into the route graph
713 * This function performs a check if a segment for the item specified already exists, and inserts
714 * a new segment representing this item if it does not.
716 * @param this The route graph to insert the segment into
717 * @param start The graph point which should be connected to the start of this segment
718 * @param end The graph point which should be connected to the end of this segment
719 * @param len The length of this segment
720 * @param item The item that is represented by this segment
721 * @param flags Flags for this segment
722 * @param offset If the item passed in "item" is segmented (i.e. divided into several segments), this indicates the position of this segment within the item
725 route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
726 struct route_graph_point *end, int len, struct item *item,
727 int flags, int offset)
729 struct route_graph_segment *s;
732 if (item_is_equal(*item, s->item))
736 s = g_new0(struct route_graph_segment, 1);
738 printf("%s:Out of memory\n", __FUNCTION__);
742 s->start_next=start->start;
745 s->end_next=end->end;
752 s->next=this->route_segments;
753 this->route_segments=s;
755 printf("l (0x%x,0x%x)-(0x%x,0x%x)\n", start->c.x, start->c.y, end->c.x, end->c.y);
759 * @brief Gets all the coordinates of an item
761 * This will get all the coordinates of the item i and return them in c,
762 * up to max coordinates. Additionally it is possible to limit the coordinates
763 * returned to all the coordinates of the item between the two coordinates
766 * @important Make shure that whatever c points to has enough memory allocated
767 * @important to hold max coordinates!
769 * @param i The item to get the coordinates of
770 * @param c Pointer to memory allocated for holding the coordinates
771 * @param max Maximum number of coordinates to return
772 * @param start First coordinate to get
773 * @param end Last coordinate to get
775 static int get_item_seg_coords(struct item *i, struct coord *c, int max,
776 struct coord *start, struct coord *end)
782 mr=map_rect_new(i->map, NULL);
785 item = map_rect_get_item_byid(mr, i->id_hi, i->id_lo);
787 rc = item_coord_get(item, &c1, 1);
788 while (rc && (c1.x != start->x || c1.y != start->y)) {
789 rc = item_coord_get(item, &c1, 1);
791 while (rc && p < max) {
793 if (c1.x == end->x && c1.y == end->y)
795 rc = item_coord_get(item, &c1, 1);
798 map_rect_destroy(mr);
803 * @brief Returns and removes one segment from a path
805 * @param path The path to take the segment from
806 * @param item The item whose segment to remove
807 * @param offset Offset of the segment within the item to remove. If the item is not segmented this should be 1.
808 * @return The segment removed
810 static struct route_path_segment *
811 route_extract_segment_from_path(struct route_path *path, struct item *item,
814 struct route_path_segment *sp = NULL, *s;
817 if (s->offset == offset && item_is_equal(s->item,*item)) {
822 path->path = s->next;
830 item_hash_remove(path->path_hash, item);
835 * @brief Adds a segment and the end of a path
837 * @param this The path to add the segment to
838 * @param segment The segment to add
841 route_path_add_segment(struct route_path *this, struct route_path_segment *segment)
846 this->path_last->next=segment;
847 this->path_last=segment;
851 * @brief Adds a new item to a path
853 * This adds a new item to a path, creating a new segment for it. Please note that this function does not check
854 * if the item passed is segmented - it will create exactly one segment.
856 * @param this The path to add the item to
857 * @param item The item to add
858 * @param len The length of the item
859 * @param first (Optional) coordinate to add to the start of the item. If none should be added, make this NULL.
860 * @param c Pointer to count coordinates of the item.
861 * @param cound Number of coordinates in c
862 * @param last (Optional) coordinate to add to the end of the item. If none should be added, make this NULL.
863 * @param dir Direction to add the coordinates in. Greater than zero means "start with the first coordinate in c", all other values mean "start with the last coordinate in c"
866 route_path_add_item(struct route_path *this, struct item *item, int len, struct coord *first, struct coord *c, int count, struct coord *last, int dir)
868 int i,idx=0,ccount=count + (first ? 1:0) + (last ? 1:0);
869 struct route_path_segment *segment;
871 segment=g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccount);
872 segment->ncoords=ccount;
873 segment->direction=dir;
875 segment->c[idx++]=*first;
877 for (i = 0 ; i < count ; i++)
878 segment->c[idx++]=c[i];
880 for (i = 0 ; i < count ; i++)
881 segment->c[idx++]=c[count-i-1];
884 segment->c[idx++]=*last;
888 route_path_add_segment(this, segment);
892 * @brief Inserts a new item into the path
894 * This function does almost the same as "route_apth_add_item()", but identifies
895 * the item to add by a segment from the route graph. Another difference is that it "copies" the
896 * segment from the route graph, i.e. if the item is segmented, only the segment passed in rgs will
897 * be added to the route path, not all segments of the item.
899 * The function can be sped up by passing an old path already containing this segment in oldpath -
900 * the segment will then be extracted from this old path. Please note that in this case the direction
901 * parameter has no effect.
903 * @param this The path to add the item to
904 * @param oldpath Old path containing the segment to be added. Speeds up the function, but can be NULL.
905 * @param rgs Segment of the route graph that should be "copied" to the route path
906 * @param len Length of the item to be added
907 * @param offset Offset of rgs within the item it represents
908 * @param dir Order in which to add the coordinates. See route_path_add_item()
909 * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
912 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
913 struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
915 struct route_path_segment *segment;
917 struct coord ca[2048];
918 struct attr straight_attr;
921 ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
923 segment = route_extract_segment_from_path(oldpath,
931 ccnt = get_item_seg_coords(&rgs->item, ca, 2047, &rgs->start->c, &rgs->end->c);
932 segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt);
934 printf("%s:Out of memory\n", __FUNCTION__);
937 segment->direction=dir;
939 for (i = 0 ; i < ccnt ; i++)
942 for (i = 0 ; i < ccnt ; i++)
943 segment->c[i]=ca[ccnt-i-1];
945 segment->ncoords = ccnt;
946 segment->item=rgs->item;
947 segment->offset = offset;
951 item_hash_insert(this->path_hash, &rgs->item, (void *)ccnt);
953 straight_attr.type = attr_route_follow_straight;
954 straight_attr.u.num = straight;
956 segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
958 route_path_add_segment(this, segment);
962 * @brief Destroys all segments of a route graph
964 * @param this The graph to destroy all segments from
967 route_graph_free_segments(struct route_graph *this)
969 struct route_graph_segment *curr,*next;
970 curr=this->route_segments;
976 this->route_segments=NULL;
980 * @brief Destroys a route graph
982 * @param this The route graph to be destroyed
985 route_graph_destroy(struct route_graph *this)
988 route_graph_free_points(this);
989 route_graph_free_segments(this);
995 * @brief Returns the time needed to drive len on item
997 * @param speedlist The speedlist that should be used
998 * @param item The item to be driven on
999 * @param len The length to drive
1000 * @return The time needed to drive len on item
1003 route_time(int *speedlist, struct item *item, int len)
1005 if (item->type < route_item_first || item->type > route_item_last) {
1006 dbg(0,"street type %d out of range [%d,%d]", item->type, route_item_first, route_item_last);
1009 return len*36/speedlist[item->type-route_item_first];
1013 * @brief Returns the "costs" of driving len on item
1015 * @param speedlist The speedlist that should be used
1016 * @param item The item to be driven on
1017 * @param len The length to drive
1018 * @return The "costs" needed to drive len on item
1021 route_value(int *speedlist, struct item *item, int len)
1025 printf("len=%d\n", len);
1028 ret=route_time(speedlist, item, len);
1029 dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret);
1034 * @brief Adds an item to the route graph
1036 * This adds an item (e.g. a street) to the route graph, creating as many segments as needed for a
1039 * @param this The route graph to add to
1040 * @param item The item to add
1043 route_process_street_graph(struct route_graph *this, struct item *item)
1050 struct route_graph_point *s_pnt,*e_pnt;
1057 if (item_coord_get(item, &l, 1)) {
1058 if (item_attr_get(item, attr_flags, &attr)) {
1060 if (flags & AF_SEGMENTED)
1063 s_pnt=route_graph_add_point(this,&l);
1065 while (item_coord_get(item, &c, 1)) {
1066 len+=transform_distance(map_projection(item->map), &l, &c);
1069 e_pnt=route_graph_add_point(this,&l);
1071 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1076 isseg = item_coord_is_segment(item);
1077 rc = item_coord_get(item, &c, 1);
1079 len+=transform_distance(map_projection(item->map), &l, &c);
1082 e_pnt=route_graph_add_point(this,&l);
1083 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1085 s_pnt=route_graph_add_point(this,&l);
1090 e_pnt=route_graph_add_point(this,&l);
1093 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1099 * @brief Compares the costs of reaching the destination from two points on
1101 * @important Do not pass anything other than route_graph_points in v1 and v2!
1105 * @return The additional costs of v1 compared to v2 (may be negative)
1108 compare(void *v1, void *v2)
1110 struct route_graph_point *p1=v1;
1111 struct route_graph_point *p2=v2;
1114 printf("compare %d (%p) vs %d (%p)\n", p1->value,p1,p2->value,p2);
1116 return p1->value-p2->value;
1120 * @brief Calculates the routing costs for each point
1122 * This function is the heart of routing. It assigns each point in the route graph a
1123 * cost at which one can reach the destination from this point on. Additionally it assigns
1124 * each point a segment one should follow from this point on to reach the destination at the
1127 * This function uses Dijkstra's algorithm to do the routing. To understand it you should have a look
1128 * at this algorithm.
1131 route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist)
1133 struct route_graph_point *p_min,*end=NULL;
1134 struct route_graph_segment *s;
1135 int min,new,old,val;
1136 struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
1137 struct street_data *sd=dst->street;
1139 heap = fh_makeheap();
1140 fh_setcmp(heap, compare);
1142 if (! (sd->flags & AF_ONEWAYREV)) { /* If we may drive in the direction of the coordinates of the item, the first coordinate is one starting point */
1143 end=route_graph_get_point(this, &sd->c[0]);
1145 end->value=route_value(speedlist, &sd->item, dst->lenneg);
1146 end->el=fh_insert(heap, end);
1149 if (! (sd->flags & AF_ONEWAY)) { /* If we may drive against the direction of the coordinates, the last coordinate is another starting point */
1150 end=route_graph_get_point(this, &sd->c[sd->count-1]);
1152 end->value=route_value(speedlist, &sd->item, dst->lenpos);
1153 end->el=fh_insert(heap, end);
1156 dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y);
1158 p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
1159 if (! p_min) /* There are no more points with temporarily calculated costs, Dijkstra has finished */
1163 printf("extract p=%p free el=%p min=%d, 0x%x, 0x%x\n", p_min, p_min->el, min, p_min->c.x, p_min->c.y);
1164 p_min->el=NULL; /* This point is permanently calculated now, we've taken it out of the heap */
1166 while (s) { /* Iterating all the segments leading away from our point to update the points at their ends */
1167 val=route_value(speedlist, &s->item, s->len);
1169 val+=val*2*street_route_contained(s->str->segid);
1173 printf("begin %d len %d vs %d (0x%x,0x%x)\n",new,val,s->end->value, s->end->c.x, s->end->c.y);
1174 if (new < s->end->value && !(s->flags & AF_ONEWAY)) { /* We've found a less costly way to reach the end of s, update it */
1179 printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
1180 s->end->el=fh_insert(heap, s->end);
1182 printf("el new=%p\n", s->end->el);
1186 printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
1187 fh_replacedata(heap, s->end->el, s->end);
1195 while (s) { /* Doing the same as above with the segments leading towards our point */
1196 val=route_value(speedlist, &s->item, s->len);
1199 printf("end %d len %d vs %d (0x%x,0x%x)\n",new,val,s->start->value,s->start->c.x, s->start->c.y);
1200 if (new < s->start->value && !(s->flags & AF_ONEWAYREV)) {
1201 old=s->start->value;
1202 s->start->value=new;
1204 if (! s->start->el) {
1206 printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
1207 s->start->el=fh_insert(heap, s->start);
1209 printf("el new=%p\n", s->start->el);
1213 printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
1214 fh_replacedata(heap, s->start->el, s->start);
1222 fh_deleteheap(heap);
1226 * @brief Starts an "offroad" path
1228 * This starts a path that is not located on a street. It creates a new route path
1229 * adding only one segment, that leads from pos to dest, and which is not associated with an item.
1231 * @param this Not used
1232 * @param pos The starting position for the new path
1233 * @param dst The destination of the new path
1234 * @param dir Not used
1235 * @return The new path
1237 static struct route_path *
1238 route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1240 struct route_path *ret;
1242 ret=g_new0(struct route_path, 1);
1243 ret->path_hash=item_hash_new();
1244 route_path_add_item(ret, NULL, pos->lenextra+dst->lenextra, &pos->c, NULL, 0, &dst->c, 1);
1250 * @brief Creates a new "trivial" route
1252 * This function creates a new "trivial" route. A trivial route is a route that starts and ends on the same street,
1253 * so there is no routing needed. Depending on pos and dst it can optionally add some "offroad" part to the route.
1255 * @param this The route graph to place the route on
1256 * @param pos The starting position for the new path
1257 * @param dst The destination of the new path
1258 * @param dir Direction of the coordinates to be added
1259 * @return The new path
1261 static struct route_path *
1262 route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1264 struct street_data *sd=pos->street;
1265 struct route_path *ret;
1268 if (pos->lenextra + dst->lenextra + pos->lenneg-dst->lenneg > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1269 return route_path_new_offroad(this, pos, dst, dir);
1271 if (pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1272 return route_path_new_offroad(this, pos, dst, dir);
1274 ret=g_new0(struct route_path, 1);
1275 ret->path_hash=item_hash_new();
1277 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1279 route_path_add_item(ret, &sd->item, pos->lenneg-dst->lenneg, &pos->lp, sd->c+pos->pos+1, dst->pos+pos->pos, &dst->lp, 1);
1281 route_path_add_item(ret, &sd->item, pos->lenpos-dst->lenpos, &pos->lp, sd->c+dst->pos+1, pos->pos-dst->pos, &dst->lp, -1);
1283 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1288 * @brief Calculates of two coordinates' connection
1290 * This function calculates the angle between coordinates, with north = 0
1293 * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
1295 * @param c1 Coordinate 1
1296 * @param c2 Coordinate 2
1297 * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
1298 * @return The angle of the coordinate's connection
1301 route_road_angle(struct coord *c1, struct coord *c2, int dir)
1303 int ret=transform_get_angle_delta(c1, c2, dir);
1304 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
1309 * @brief Checks if entering one segment from another is a "straight" road
1311 * This checks if one can enter seg_to from seg_from by driving "straight" - i.e.
1312 * if seg_to is the segment you can drive to from seg_from by steering less than
1313 * all to all other segments.
1315 * This function returns true on failure, so we don't create maneuvers on every error.
1317 * @param seg_from Segment we are driving from
1318 * @param seg_to Segment we are driving to
1319 * @param dir Set to true to indicate that seg_from is left throught its "start" instead through its "end"
1320 * @return True if driving from seg_from to seg_to is "straight", false otherwise
1323 route_check_straight(struct route_graph_segment *seg_from, struct route_graph_segment *seg_to, int dir)
1325 struct route_graph_segment *curr;
1326 struct route_graph_point *conn;
1327 int from_angle, to_angle, curr_angle, angle_diff;
1329 struct coord ca[2048];
1332 if ((seg_from->end != seg_to->start) && (seg_from->end != seg_to->end)) {
1337 ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
1338 from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
1340 conn = seg_from->end;
1342 if ((seg_from->start != seg_to->start) && (seg_from->start != seg_to->end)) {
1347 ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
1348 from_angle = route_road_angle(&ca[1], &ca[0],1);
1350 conn = seg_from->start;
1353 if (seg_to->end == conn) {
1354 ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
1355 to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
1357 ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
1358 to_angle = route_road_angle(&ca[0], &ca[1],1);
1362 angle_diff = from_angle - to_angle;
1363 if (angle_diff < 0) {
1369 while (curr != NULL) {
1371 curr = curr->start_next;
1375 ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
1376 curr_angle = route_road_angle(&ca[0], &ca[1], 1);
1378 curr_angle = from_angle - curr_angle;
1380 if (curr_angle < 0) {
1385 if (curr_angle <= angle_diff) {
1389 curr = curr->start_next;
1393 while (curr != NULL) {
1395 curr = curr->end_next;
1399 ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
1400 curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
1402 curr_angle = from_angle - curr_angle;
1404 if (curr_angle < 0) {
1408 if (curr_angle <= angle_diff) {
1412 curr = curr->end_next;
1419 * @brief Creates a new route path
1421 * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
1422 * make shure to run route_graph_flood() after changing the destination before using this function.
1424 * @param this The route graph to create the route from
1425 * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
1426 * @param pos The starting position of the route
1427 * @param dst The destination of the route
1428 * @param speedlist The speedlist to use
1429 * @return The new route path
1431 static struct route_path *
1432 route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist)
1434 struct route_graph_point *start1=NULL,*start2=NULL,*start;
1435 struct route_graph_segment *s=NULL;
1436 struct route_graph_segment *lastseg = NULL;
1441 int time=0,hr,min,sec
1443 unsigned int val1=0xffffffff,val2=0xffffffff;
1444 struct street_data *sd=pos->street;
1445 struct route_path *ret;
1447 if (item_is_equal(pos->street->item, dst->street->item)) { /* We probably don't have to leave this street and can use a trivial route */
1448 if (!(sd->flags & AF_ONEWAY) && pos->lenneg >= dst->lenneg) {
1449 return route_path_new_trivial(this, pos, dst, -1);
1451 if (!(sd->flags & AF_ONEWAYREV) && pos->lenpos >= dst->lenpos) {
1452 return route_path_new_trivial(this, pos, dst, 1);
1455 if (! (sd->flags & AF_ONEWAY)) { /* Using the start of the current segment as one starting point */
1456 start1=route_graph_get_point(this, &sd->c[0]);
1459 val1=start1->value+route_value(speedlist, &sd->item, pos->lenneg);
1460 dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1);
1462 if (! (sd->flags & AF_ONEWAYREV)) { /* Using the start of the current segment as an alternative starting point */
1463 start2=route_graph_get_point(this, &sd->c[sd->count-1]);
1466 val2=start2->value+route_value(speedlist, &sd->item, pos->lenpos);
1467 dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2);
1469 dbg(1,"val1=%d val2=%d\n", val1, val2);
1471 val1=start1->start->start->value;
1472 val2=start2->end->end->value;
1474 ret=g_new0(struct route_path, 1);
1476 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1477 if (start1 && (val1 < val2)) {
1479 route_path_add_item(ret, &sd->item, pos->lenneg, &pos->lp, sd->c, pos->pos+1, NULL, -1);
1483 route_path_add_item(ret, &sd->item, pos->lenpos, &pos->lp, sd->c+pos->pos+1, sd->count-pos->pos-1, NULL, 1);
1485 printf("no route found, pos blocked\n");
1489 ret->path_hash=item_hash_new();
1490 while ((s=start->seg)) { /* following start->seg, which indicates the least costly way to reach our destination */
1493 printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1499 is_straight = route_check_straight(lastseg,s,(s->end == start));
1504 if (s->start == start) {
1505 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
1508 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
1515 dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1516 dbg(1,"dst sd->flags=%d sd->c[0]=0x%x,0x%x sd->c[sd->count-1]=0x%x,0x%x\n", sd->flags, sd->c[0].x,sd->c[0].y, sd->c[sd->count-1].x, sd->c[sd->count-1].y);
1517 if (start->c.x == sd->c[0].x && start->c.y == sd->c[0].y) { /* Adding a final segment to reach the destination within the destination street */
1518 route_path_add_item(ret, &sd->item, dst->lenneg, &dst->lp, sd->c, dst->pos+1, NULL, -1);
1519 } else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) {
1520 route_path_add_item(ret, &sd->item, dst->lenpos, &dst->lp, sd->c+dst->pos+1, sd->count-dst->pos-1, NULL, 1);
1522 printf("no route found\n");
1523 route_path_destroy(ret);
1527 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1528 dbg(1, "%d segments\n", segs);
1533 * @brief Builds a new route graph from a mapset
1535 * This function builds a new route graph from a map. Please note that this function does not
1536 * add any routing information to the route graph - this has to be done via the route_graph_flood()
1539 * The function does not create a graph covering the whole map, but only covering the rectangle
1540 * between c1 and c2.
1542 * @param ms The mapset to build the route graph from
1543 * @param c1 Corner 1 of the rectangle to use from the map
1544 * @param c2 Corner 2 of the rectangle to use from the map
1545 * @return The new route graph.
1547 static struct route_graph *
1548 route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
1550 struct route_graph *ret=g_new0(struct route_graph, 1);
1551 struct map_selection *sel;
1552 struct mapset_handle *h;
1553 struct map_rect *mr;
1558 printf("%s:Out of memory\n", __FUNCTION__);
1561 sel=route_calc_selection(c1, c2);
1563 while ((m=mapset_next(h,1))) {
1564 mr=map_rect_new(m, sel);
1567 while ((item=map_rect_get_item(mr))) {
1568 if (item->type >= type_street_0 && item->type <= type_ferry) {
1569 route_process_street_graph(ret, item);
1572 map_rect_destroy(mr);
1575 route_free_selection(sel);
1581 * @brief Updates the route graph
1583 * This updates the route graph after settings in the route have changed. It also
1584 * adds routing information afterwards by calling route_graph_flood().
1586 * @param this The route to update the graph for
1589 route_graph_update(struct route *this)
1591 route_graph_destroy(this->graph);
1592 profile(1,"graph_free");
1593 this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c);
1594 profile(1,"route_graph_build");
1595 route_graph_flood(this->graph, this->dst, this->speedlist);
1596 profile(1,"route_graph_flood");
1601 * @brief Gets street data for an item
1603 * @param item The item to get the data for
1604 * @return Street data for the item
1606 struct street_data *
1607 street_get_data (struct item *item)
1610 struct coord c[maxcount];
1612 struct street_data *ret;
1615 while (count < maxcount) {
1616 if (!item_coord_get(item, &c[count], 1))
1620 if (count >= maxcount) {
1621 dbg(0, "count=%d maxcount=%d id_hi=0x%x id_lo=0x%x\n", count, maxcount, item->id_hi, item->id_lo);
1622 if (item_attr_get(item, attr_debug, &attr))
1623 dbg(0,"debug='%s'\n", attr.u.str);
1625 g_assert(count < maxcount);
1626 ret=g_malloc(sizeof(struct street_data)+count*sizeof(struct coord));
1629 if (item_attr_get(item, attr_flags, &attr))
1630 ret->flags=attr.u.num;
1633 memcpy(ret->c, c, count*sizeof(struct coord));
1639 * @brief Copies street data
1641 * @param orig The street data to copy
1642 * @return The copied street data
1644 struct street_data *
1645 street_data_dup(struct street_data *orig)
1647 struct street_data *ret;
1648 int size=sizeof(struct street_data)+orig->count*sizeof(struct coord);
1651 memcpy(ret, orig, size);
1657 * @brief Frees street data
1659 * @param sd Street data to be freed
1662 street_data_free(struct street_data *sd)
1668 * @brief Finds the nearest street to a given coordinate
1670 * @param ms The mapset to search in for the street
1671 * @param pc The coordinate to find a street nearby
1672 * @return The nearest street
1674 static struct route_info *
1675 route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
1677 struct route_info *ret=NULL;
1679 struct map_selection *sel;
1680 int dist,mindist=0,pos;
1681 struct mapset_handle *h;
1683 struct map_rect *mr;
1686 struct street_data *sd;
1693 * This is not correct for two reasons:
1694 * - You may need to go back first
1695 * - Currently we allow mixing of mapsets
1697 sel = route_rect(18, &c, &c, 0, max_dist);
1699 while ((m=mapset_next(h,1))) {
1702 if (map_projection(m) != pc->pro) {
1703 transform_to_geo(pc->pro, &c, &g);
1704 transform_from_geo(map_projection(m), &g, &c);
1706 mr=map_rect_new(m, sel);
1709 while ((item=map_rect_get_item(mr))) {
1710 if (item->type >= type_street_0 && item->type <= type_ferry) {
1711 sd=street_get_data(item);
1712 dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos);
1713 if (!ret || dist < mindist) {
1715 street_data_free(ret->street);
1718 ret=g_new(struct route_info, 1);
1720 printf("%s:Out of memory\n", __FUNCTION__);
1728 dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos);
1730 street_data_free(sd);
1733 map_rect_destroy(mr);
1736 map_selection_destroy(sel);
1742 * @brief Destroys a route_info
1744 * @param info The route info to be destroyed
1747 route_info_free(struct route_info *inf)
1750 street_data_free(inf->street);
1758 * @brief Returns street data for a route info
1760 * @param rinf The route info to return the street data for
1761 * @return Street data for the route info
1763 struct street_data *
1764 route_info_street(struct route_info *rinf)
1766 return rinf->street;
1770 struct route_crossings *
1771 route_crossings_get(struct route *this, struct coord *c)
1773 struct route_point *pnt;
1774 struct route_segment *seg;
1776 struct route_crossings *ret;
1778 pnt=route_graph_get_point(this, c);
1781 printf("start: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1783 seg=seg->start_next;
1787 printf("end: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1791 ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing));
1792 ret->count=crossings;
1798 struct map_rect_priv {
1799 struct route_info_handle *ri;
1800 enum attr_type attr_next;
1802 struct map_priv *mpriv;
1805 unsigned int last_coord;
1806 struct route_path_segment *seg,*seg_next;
1807 struct route_graph_point *point;
1808 struct route_graph_segment *rseg;
1813 rm_coord_rewind(void *priv_data)
1815 struct map_rect_priv *mr = priv_data;
1820 rm_attr_rewind(void *priv_data)
1822 struct map_rect_priv *mr = priv_data;
1823 mr->attr_next = attr_street_item;
1827 rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1829 struct map_rect_priv *mr = priv_data;
1830 struct route_path_segment *seg=mr->seg;
1831 struct route *route=mr->mpriv->route;
1832 attr->type=attr_type;
1833 switch (attr_type) {
1835 while (mr->attr_next != attr_none) {
1836 if (rm_attr_get(priv_data, mr->attr_next, attr))
1840 case attr_street_item:
1841 mr->attr_next=attr_route_follow_straight;
1842 if (seg && seg->item.map)
1843 attr->u.item=&seg->item;
1847 case attr_route_follow_straight:
1848 mr->attr_next=attr_direction;
1850 return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
1853 case attr_direction:
1854 mr->attr_next=attr_length;
1856 attr->u.num=seg->direction;
1862 attr->u.num=seg->length;
1864 attr->u.num=mr->length;
1865 mr->attr_next=attr_time;
1868 mr->attr_next=attr_none;
1870 attr->u.num=route_time(route->speedlist, &seg->item, seg->length);
1875 attr->type=attr_none;
1882 rm_coord_get(void *priv_data, struct coord *c, int count)
1884 struct map_rect_priv *mr = priv_data;
1885 struct route_path_segment *seg = mr->seg;
1889 for (i=0; i < count; i++) {
1890 if (mr->last_coord >= seg->ncoords)
1892 if (i >= seg->ncoords)
1894 c[i] = seg->c[mr->last_coord++];
1897 dbg(1,"return %d\n",rc);
1901 static struct item_methods methods_route_item = {
1909 rp_attr_rewind(void *priv_data)
1911 struct map_rect_priv *mr = priv_data;
1912 mr->attr_next = attr_label;
1916 rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1918 struct map_rect_priv *mr = priv_data;
1919 struct route_graph_point *p = mr->point;
1920 if (mr->item.type != type_rg_point)
1922 switch (attr_type) {
1924 while (mr->attr_next != attr_none) {
1925 if (rm_attr_get(priv_data, mr->attr_next, attr))
1929 attr->type = attr_label;
1932 if (p->value != INT_MAX)
1933 mr->str=g_strdup_printf("%d", p->value);
1935 mr->str=g_strdup("-");
1936 attr->u.str = mr->str;
1937 mr->attr_next=attr_none;
1940 attr->type = attr_debug;
1943 mr->str=g_strdup_printf("x=%d y=%d", p->c.x, p->c.y);
1944 attr->u.str = mr->str;
1945 mr->attr_next=attr_none;
1953 rp_coord_get(void *priv_data, struct coord *c, int count)
1955 struct map_rect_priv *mr = priv_data;
1956 struct route_graph_point *p = mr->point;
1957 struct route_graph_segment *seg = mr->rseg;
1959 for (i=0; i < count; i++) {
1960 if (mr->item.type == type_rg_point) {
1961 if (mr->last_coord >= 1)
1965 if (mr->last_coord >= 2)
1968 if (seg->end->seg == seg)
1975 c[i] = seg->start->c;
1983 static struct item_methods methods_point_item = {
1991 rm_destroy(struct map_priv *priv)
1996 static struct map_rect_priv *
1997 rm_rect_new(struct map_priv *priv, struct map_selection *sel)
1999 struct map_rect_priv * mr;
2001 if (! route_get_pos(priv->route))
2003 if (! route_get_dst(priv->route))
2005 if (! priv->route->path2)
2007 mr=g_new0(struct map_rect_priv, 1);
2009 mr->item.priv_data = mr;
2010 mr->item.type = type_street_route;
2011 mr->item.meth = &methods_route_item;
2012 mr->seg_next=priv->route->path2->path;
2016 static struct map_rect_priv *
2017 rp_rect_new(struct map_priv *priv, struct map_selection *sel)
2019 struct map_rect_priv * mr;
2021 if (! priv->route->graph || ! priv->route->graph->route_points)
2023 mr=g_new0(struct map_rect_priv, 1);
2025 mr->item.priv_data = mr;
2026 mr->item.type = type_rg_point;
2027 mr->item.meth = &methods_point_item;
2032 rm_rect_destroy(struct map_rect_priv *mr)
2039 static struct item *
2040 rp_get_item(struct map_rect_priv *mr)
2042 struct route *r = mr->mpriv->route;
2043 struct route_graph_point *p = mr->point;
2044 struct route_graph_segment *seg = mr->rseg;
2046 if (mr->item.type == type_rg_point) {
2048 p = r->graph->route_points;
2054 rm_coord_rewind(mr);
2058 mr->item.type = type_rg_segment;
2061 seg=r->graph->route_segments;
2067 rm_coord_rewind(mr);
2075 static struct item *
2076 rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2078 struct item *ret=NULL;
2080 ret=rp_get_item(mr);
2085 static struct item *
2086 rm_get_item(struct map_rect_priv *mr)
2088 struct route *r = mr->mpriv->route;
2089 struct route_path_segment *seg = mr->seg;
2090 dbg(1,"enter\n", mr->pos);
2092 mr->seg=mr->seg_next;
2095 mr->seg_next=mr->seg->next;
2102 static struct item *
2103 rm_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2105 struct item *ret=NULL;
2107 ret=rm_get_item(mr);
2111 static struct map_methods route_meth = {
2124 static struct map_methods route_graph_meth = {
2138 route_toggle_routegraph_display(struct route *route)
2140 if (route->flags & RF_SHOWGRAPH) {
2141 route->flags &= ~RF_SHOWGRAPH;
2143 route->flags |= RF_SHOWGRAPH;
2147 static struct map_priv *
2148 route_map_new_helper(struct map_methods *meth, struct attr **attrs, int graph)
2150 struct map_priv *ret;
2151 struct attr *route_attr;
2153 route_attr=attr_search(attrs, NULL, attr_route);
2156 ret=g_new0(struct map_priv, 1);
2158 *meth=route_graph_meth;
2161 ret->route=route_attr->u.route;
2166 static struct map_priv *
2167 route_map_new(struct map_methods *meth, struct attr **attrs)
2169 return route_map_new_helper(meth, attrs, 0);
2172 static struct map_priv *
2173 route_graph_map_new(struct map_methods *meth, struct attr **attrs)
2175 return route_map_new_helper(meth, attrs, 1);
2179 route_get_map_helper(struct route *this_, struct map **map, char *type, char *description)
2182 *map=map_new((struct attr*[]){
2183 &(struct attr){attr_type,{type}},
2184 &(struct attr){attr_route,.u.route=this_},
2185 &(struct attr){attr_data,{""}},
2186 &(struct attr){attr_description,{description}},
2192 route_get_map(struct route *this_)
2194 return route_get_map_helper(this_, &this_->map, "route","Route");
2199 route_get_graph_map(struct route *this_)
2201 return route_get_map_helper(this_, &this_->graph_map, "route_graph","Route Graph");
2205 route_set_projection(struct route *this_, enum projection pro)
2212 plugin_register_map_type("route", route_map_new);
2213 plugin_register_map_type("route_graph", route_graph_map_new);