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);
622 profile(1,"find_nearest_street");
624 /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
625 route_graph_destroy(this->graph);
627 route_path_update(this);
632 * @brief Gets the route_graph_point with the specified coordinates
634 * @param this The route in which to search
635 * @param c Coordinates to search for
636 * @return The point at the specified coordinates or NULL if not found
638 static struct route_graph_point *
639 route_graph_get_point(struct route_graph *this, struct coord *c)
641 struct route_graph_point *p;
642 int hashval=HASHCOORD(c);
643 p=this->hash[hashval];
645 if (p->c.x == c->x && p->c.y == c->y)
653 * @brief Inserts a point into the route graph at the specified coordinates
655 * This will insert a point into the route graph at the coordinates passed in f.
656 * Note that the point is not yet linked to any segments.
658 * @param this The route to insert the point into
659 * @param f The coordinates at which the point should be inserted
660 * @return The point inserted or NULL on failure
662 static struct route_graph_point *
663 route_graph_add_point(struct route_graph *this, struct coord *f)
666 struct route_graph_point *p;
668 p=route_graph_get_point(this,f);
670 hashval=HASHCOORD(f);
672 printf("p (0x%x,0x%x)\n", f->x, f->y);
673 p=g_new(struct route_graph_point,1);
675 printf("%s:Out of memory\n", __FUNCTION__);
678 p->hash_next=this->hash[hashval];
679 this->hash[hashval]=p;
680 p->next=this->route_points;
687 this->route_points=p;
693 * @brief Frees all the memory used for points in the route graph passed
695 * @param this The route graph to delete all points from
698 route_graph_free_points(struct route_graph *this)
700 struct route_graph_point *curr,*next;
701 curr=this->route_points;
707 this->route_points=NULL;
708 memset(this->hash, 0, sizeof(this->hash));
712 * @brief Inserts a new segment into the route graph
714 * This function performs a check if a segment for the item specified already exists, and inserts
715 * a new segment representing this item if it does not.
717 * @param this The route graph to insert the segment into
718 * @param start The graph point which should be connected to the start of this segment
719 * @param end The graph point which should be connected to the end of this segment
720 * @param len The length of this segment
721 * @param item The item that is represented by this segment
722 * @param flags Flags for this segment
723 * @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
726 route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
727 struct route_graph_point *end, int len, struct item *item,
728 int flags, int offset)
730 struct route_graph_segment *s;
733 if (item_is_equal(*item, s->item))
737 s = g_new0(struct route_graph_segment, 1);
739 printf("%s:Out of memory\n", __FUNCTION__);
743 s->start_next=start->start;
746 s->end_next=end->end;
753 s->next=this->route_segments;
754 this->route_segments=s;
756 printf("l (0x%x,0x%x)-(0x%x,0x%x)\n", start->c.x, start->c.y, end->c.x, end->c.y);
760 * @brief Gets all the coordinates of an item
762 * This will get all the coordinates of the item i and return them in c,
763 * up to max coordinates. Additionally it is possible to limit the coordinates
764 * returned to all the coordinates of the item between the two coordinates
767 * @important Make shure that whatever c points to has enough memory allocated
768 * @important to hold max coordinates!
770 * @param i The item to get the coordinates of
771 * @param c Pointer to memory allocated for holding the coordinates
772 * @param max Maximum number of coordinates to return
773 * @param start First coordinate to get
774 * @param end Last coordinate to get
776 static int get_item_seg_coords(struct item *i, struct coord *c, int max,
777 struct coord *start, struct coord *end)
783 mr=map_rect_new(i->map, NULL);
786 item = map_rect_get_item_byid(mr, i->id_hi, i->id_lo);
788 rc = item_coord_get(item, &c1, 1);
789 while (rc && (c1.x != start->x || c1.y != start->y)) {
790 rc = item_coord_get(item, &c1, 1);
792 while (rc && p < max) {
794 if (c1.x == end->x && c1.y == end->y)
796 rc = item_coord_get(item, &c1, 1);
799 map_rect_destroy(mr);
804 * @brief Returns and removes one segment from a path
806 * @param path The path to take the segment from
807 * @param item The item whose segment to remove
808 * @param offset Offset of the segment within the item to remove. If the item is not segmented this should be 1.
809 * @return The segment removed
811 static struct route_path_segment *
812 route_extract_segment_from_path(struct route_path *path, struct item *item,
815 struct route_path_segment *sp = NULL, *s;
818 if (s->offset == offset && item_is_equal(s->item,*item)) {
823 path->path = s->next;
831 item_hash_remove(path->path_hash, item);
836 * @brief Adds a segment and the end of a path
838 * @param this The path to add the segment to
839 * @param segment The segment to add
842 route_path_add_segment(struct route_path *this, struct route_path_segment *segment)
847 this->path_last->next=segment;
848 this->path_last=segment;
852 * @brief Adds a new item to a path
854 * This adds a new item to a path, creating a new segment for it. Please note that this function does not check
855 * if the item passed is segmented - it will create exactly one segment.
857 * @param this The path to add the item to
858 * @param item The item to add
859 * @param len The length of the item
860 * @param first (Optional) coordinate to add to the start of the item. If none should be added, make this NULL.
861 * @param c Pointer to count coordinates of the item.
862 * @param cound Number of coordinates in c
863 * @param last (Optional) coordinate to add to the end of the item. If none should be added, make this NULL.
864 * @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"
867 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)
869 int i,idx=0,ccount=count + (first ? 1:0) + (last ? 1:0);
870 struct route_path_segment *segment;
872 segment=g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccount);
873 segment->ncoords=ccount;
874 segment->direction=dir;
876 segment->c[idx++]=*first;
878 for (i = 0 ; i < count ; i++)
879 segment->c[idx++]=c[i];
881 for (i = 0 ; i < count ; i++)
882 segment->c[idx++]=c[count-i-1];
885 segment->c[idx++]=*last;
889 route_path_add_segment(this, segment);
893 * @brief Inserts a new item into the path
895 * This function does almost the same as "route_apth_add_item()", but identifies
896 * the item to add by a segment from the route graph. Another difference is that it "copies" the
897 * segment from the route graph, i.e. if the item is segmented, only the segment passed in rgs will
898 * be added to the route path, not all segments of the item.
900 * The function can be sped up by passing an old path already containing this segment in oldpath -
901 * the segment will then be extracted from this old path. Please note that in this case the direction
902 * parameter has no effect.
904 * @param this The path to add the item to
905 * @param oldpath Old path containing the segment to be added. Speeds up the function, but can be NULL.
906 * @param rgs Segment of the route graph that should be "copied" to the route path
907 * @param len Length of the item to be added
908 * @param offset Offset of rgs within the item it represents
909 * @param dir Order in which to add the coordinates. See route_path_add_item()
910 * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
913 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
914 struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
916 struct route_path_segment *segment;
918 struct coord ca[2048];
919 struct attr straight_attr;
922 ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
924 segment = route_extract_segment_from_path(oldpath,
932 ccnt = get_item_seg_coords(&rgs->item, ca, 2047, &rgs->start->c, &rgs->end->c);
933 segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt);
935 printf("%s:Out of memory\n", __FUNCTION__);
938 segment->direction=dir;
940 for (i = 0 ; i < ccnt ; i++)
943 for (i = 0 ; i < ccnt ; i++)
944 segment->c[i]=ca[ccnt-i-1];
946 segment->ncoords = ccnt;
947 segment->item=rgs->item;
948 segment->offset = offset;
952 item_hash_insert(this->path_hash, &rgs->item, (void *)ccnt);
954 straight_attr.type = attr_route_follow_straight;
955 straight_attr.u.num = straight;
957 segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
959 route_path_add_segment(this, segment);
963 * @brief Destroys all segments of a route graph
965 * @param this The graph to destroy all segments from
968 route_graph_free_segments(struct route_graph *this)
970 struct route_graph_segment *curr,*next;
971 curr=this->route_segments;
977 this->route_segments=NULL;
981 * @brief Destroys a route graph
983 * @param this The route graph to be destroyed
986 route_graph_destroy(struct route_graph *this)
989 route_graph_free_points(this);
990 route_graph_free_segments(this);
996 * @brief Returns the time needed to drive len on item
998 * @param speedlist The speedlist that should be used
999 * @param item The item to be driven on
1000 * @param len The length to drive
1001 * @return The time needed to drive len on item
1004 route_time(int *speedlist, struct item *item, int len)
1006 if (item->type < route_item_first || item->type > route_item_last) {
1007 dbg(0,"street type %d out of range [%d,%d]", item->type, route_item_first, route_item_last);
1010 return len*36/speedlist[item->type-route_item_first];
1014 * @brief Returns the "costs" of driving len on item
1016 * @param speedlist The speedlist that should be used
1017 * @param item The item to be driven on
1018 * @param len The length to drive
1019 * @return The "costs" needed to drive len on item
1022 route_value(int *speedlist, struct item *item, int len)
1026 printf("len=%d\n", len);
1029 ret=route_time(speedlist, item, len);
1030 dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret);
1035 * @brief Adds an item to the route graph
1037 * This adds an item (e.g. a street) to the route graph, creating as many segments as needed for a
1040 * @param this The route graph to add to
1041 * @param item The item to add
1044 route_process_street_graph(struct route_graph *this, struct item *item)
1051 struct route_graph_point *s_pnt,*e_pnt;
1058 if (item_coord_get(item, &l, 1)) {
1059 if (item_attr_get(item, attr_flags, &attr)) {
1061 if (flags & AF_SEGMENTED)
1064 s_pnt=route_graph_add_point(this,&l);
1066 while (item_coord_get(item, &c, 1)) {
1067 len+=transform_distance(map_projection(item->map), &l, &c);
1070 e_pnt=route_graph_add_point(this,&l);
1072 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1077 isseg = item_coord_is_segment(item);
1078 rc = item_coord_get(item, &c, 1);
1080 len+=transform_distance(map_projection(item->map), &l, &c);
1083 e_pnt=route_graph_add_point(this,&l);
1084 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1086 s_pnt=route_graph_add_point(this,&l);
1091 e_pnt=route_graph_add_point(this,&l);
1094 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1100 * @brief Compares the costs of reaching the destination from two points on
1102 * @important Do not pass anything other than route_graph_points in v1 and v2!
1106 * @return The additional costs of v1 compared to v2 (may be negative)
1109 compare(void *v1, void *v2)
1111 struct route_graph_point *p1=v1;
1112 struct route_graph_point *p2=v2;
1115 printf("compare %d (%p) vs %d (%p)\n", p1->value,p1,p2->value,p2);
1117 return p1->value-p2->value;
1121 * @brief Calculates the routing costs for each point
1123 * This function is the heart of routing. It assigns each point in the route graph a
1124 * cost at which one can reach the destination from this point on. Additionally it assigns
1125 * each point a segment one should follow from this point on to reach the destination at the
1128 * This function uses Dijkstra's algorithm to do the routing. To understand it you should have a look
1129 * at this algorithm.
1132 route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist)
1134 struct route_graph_point *p_min,*end=NULL;
1135 struct route_graph_segment *s;
1136 int min,new,old,val;
1137 struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
1138 struct street_data *sd=dst->street;
1140 heap = fh_makeheap();
1141 fh_setcmp(heap, compare);
1143 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 */
1144 end=route_graph_get_point(this, &sd->c[0]);
1146 end->value=route_value(speedlist, &sd->item, dst->lenneg);
1147 end->el=fh_insert(heap, end);
1150 if (! (sd->flags & AF_ONEWAY)) { /* If we may drive against the direction of the coordinates, the last coordinate is another starting point */
1151 end=route_graph_get_point(this, &sd->c[sd->count-1]);
1153 end->value=route_value(speedlist, &sd->item, dst->lenpos);
1154 end->el=fh_insert(heap, end);
1157 dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y);
1159 p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
1160 if (! p_min) /* There are no more points with temporarily calculated costs, Dijkstra has finished */
1164 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);
1165 p_min->el=NULL; /* This point is permanently calculated now, we've taken it out of the heap */
1167 while (s) { /* Iterating all the segments leading away from our point to update the points at their ends */
1168 val=route_value(speedlist, &s->item, s->len);
1170 val+=val*2*street_route_contained(s->str->segid);
1174 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);
1175 if (new < s->end->value && !(s->flags & AF_ONEWAY)) { /* We've found a less costly way to reach the end of s, update it */
1180 printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
1181 s->end->el=fh_insert(heap, s->end);
1183 printf("el new=%p\n", s->end->el);
1187 printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
1188 fh_replacedata(heap, s->end->el, s->end);
1196 while (s) { /* Doing the same as above with the segments leading towards our point */
1197 val=route_value(speedlist, &s->item, s->len);
1200 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);
1201 if (new < s->start->value && !(s->flags & AF_ONEWAYREV)) {
1202 old=s->start->value;
1203 s->start->value=new;
1205 if (! s->start->el) {
1207 printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
1208 s->start->el=fh_insert(heap, s->start);
1210 printf("el new=%p\n", s->start->el);
1214 printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
1215 fh_replacedata(heap, s->start->el, s->start);
1223 fh_deleteheap(heap);
1227 * @brief Starts an "offroad" path
1229 * This starts a path that is not located on a street. It creates a new route path
1230 * adding only one segment, that leads from pos to dest, and which is not associated with an item.
1232 * @param this Not used
1233 * @param pos The starting position for the new path
1234 * @param dst The destination of the new path
1235 * @param dir Not used
1236 * @return The new path
1238 static struct route_path *
1239 route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1241 struct route_path *ret;
1243 ret=g_new0(struct route_path, 1);
1244 ret->path_hash=item_hash_new();
1245 route_path_add_item(ret, NULL, pos->lenextra+dst->lenextra, &pos->c, NULL, 0, &dst->c, 1);
1251 * @brief Creates a new "trivial" route
1253 * This function creates a new "trivial" route. A trivial route is a route that starts and ends on the same street,
1254 * so there is no routing needed. Depending on pos and dst it can optionally add some "offroad" part to the route.
1256 * @param this The route graph to place the route on
1257 * @param pos The starting position for the new path
1258 * @param dst The destination of the new path
1259 * @param dir Direction of the coordinates to be added
1260 * @return The new path
1262 static struct route_path *
1263 route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1265 struct street_data *sd=pos->street;
1266 struct route_path *ret;
1269 if (pos->lenextra + dst->lenextra + pos->lenneg-dst->lenneg > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1270 return route_path_new_offroad(this, pos, dst, dir);
1272 if (pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1273 return route_path_new_offroad(this, pos, dst, dir);
1275 ret=g_new0(struct route_path, 1);
1276 ret->path_hash=item_hash_new();
1278 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1280 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);
1282 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);
1284 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1289 * @brief Calculates of two coordinates' connection
1291 * This function calculates the angle between coordinates, with north = 0
1294 * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
1296 * @param c1 Coordinate 1
1297 * @param c2 Coordinate 2
1298 * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
1299 * @return The angle of the coordinate's connection
1302 route_road_angle(struct coord *c1, struct coord *c2, int dir)
1304 int ret=transform_get_angle_delta(c1, c2, dir);
1305 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
1310 * @brief Checks if entering one segment from another is a "straight" road
1312 * This checks if one can enter seg_to from seg_from by driving "straight" - i.e.
1313 * if seg_to is the segment you can drive to from seg_from by steering less than
1314 * all to all other segments.
1316 * This function returns true on failure, so we don't create maneuvers on every error.
1318 * @param seg_from Segment we are driving from
1319 * @param seg_to Segment we are driving to
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)
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];
1331 if ((seg_from->end == seg_to->start) || (seg_from->end == seg_to->end)) {
1332 ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
1333 from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
1335 conn = seg_from->end;
1336 } else if ((seg_from->start == seg_to->start) || (seg_from->start == seg_to->end)) {
1337 ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
1338 from_angle = route_road_angle(&ca[1], &ca[0],1);
1340 conn = seg_from->start;
1347 if (seg_to->end == conn) {
1348 ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
1349 to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
1351 ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
1352 to_angle = route_road_angle(&ca[0], &ca[1],1);
1356 angle_diff = from_angle - to_angle;
1357 if (angle_diff < 0) {
1363 while (curr != NULL) {
1365 curr = curr->start_next;
1369 ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
1370 curr_angle = route_road_angle(&ca[0], &ca[1], 1);
1372 curr_angle = from_angle - curr_angle;
1374 if (curr_angle < 0) {
1379 if (curr_angle <= angle_diff) {
1383 curr = curr->start_next;
1387 while (curr != NULL) {
1389 curr = curr->end_next;
1393 ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
1394 curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
1396 curr_angle = from_angle - curr_angle;
1398 if (curr_angle < 0) {
1402 if (curr_angle <= angle_diff) {
1406 curr = curr->end_next;
1413 * @brief Creates a new route path
1415 * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
1416 * make shure to run route_graph_flood() after changing the destination before using this function.
1418 * @param this The route graph to create the route from
1419 * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
1420 * @param pos The starting position of the route
1421 * @param dst The destination of the route
1422 * @param speedlist The speedlist to use
1423 * @return The new route path
1425 static struct route_path *
1426 route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist)
1428 struct route_graph_point *start1=NULL,*start2=NULL,*start;
1429 struct route_graph_segment *s=NULL;
1430 struct route_graph_segment *lastseg = NULL;
1435 int time=0,hr,min,sec
1437 unsigned int val1=0xffffffff,val2=0xffffffff;
1438 struct street_data *sd=pos->street;
1439 struct route_path *ret;
1441 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 */
1442 if (!(sd->flags & AF_ONEWAY) && pos->lenneg >= dst->lenneg) {
1443 return route_path_new_trivial(this, pos, dst, -1);
1445 if (!(sd->flags & AF_ONEWAYREV) && pos->lenpos >= dst->lenpos) {
1446 return route_path_new_trivial(this, pos, dst, 1);
1449 if (! (sd->flags & AF_ONEWAY)) { /* Using the start of the current segment as one starting point */
1450 start1=route_graph_get_point(this, &sd->c[0]);
1453 val1=start1->value+route_value(speedlist, &sd->item, pos->lenneg);
1454 dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1);
1456 if (! (sd->flags & AF_ONEWAYREV)) { /* Using the start of the current segment as an alternative starting point */
1457 start2=route_graph_get_point(this, &sd->c[sd->count-1]);
1460 val2=start2->value+route_value(speedlist, &sd->item, pos->lenpos);
1461 dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2);
1463 dbg(1,"val1=%d val2=%d\n", val1, val2);
1465 val1=start1->start->start->value;
1466 val2=start2->end->end->value;
1468 ret=g_new0(struct route_path, 1);
1470 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1471 if (start1 && (val1 < val2)) {
1473 route_path_add_item(ret, &sd->item, pos->lenneg, &pos->lp, sd->c, pos->pos+1, NULL, -1);
1477 route_path_add_item(ret, &sd->item, pos->lenpos, &pos->lp, sd->c+pos->pos+1, sd->count-pos->pos-1, NULL, 1);
1479 printf("no route found, pos blocked\n");
1483 ret->path_hash=item_hash_new();
1484 while ((s=start->seg)) { /* following start->seg, which indicates the least costly way to reach our destination */
1487 printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1493 is_straight = route_check_straight(lastseg,s);
1498 if (s->start == start) {
1499 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
1502 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
1509 dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1510 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);
1511 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 */
1512 route_path_add_item(ret, &sd->item, dst->lenneg, &dst->lp, sd->c, dst->pos+1, NULL, -1);
1513 } else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) {
1514 route_path_add_item(ret, &sd->item, dst->lenpos, &dst->lp, sd->c+dst->pos+1, sd->count-dst->pos-1, NULL, 1);
1516 printf("no route found\n");
1517 route_path_destroy(ret);
1521 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1522 dbg(1, "%d segments\n", segs);
1527 * @brief Builds a new route graph from a mapset
1529 * This function builds a new route graph from a map. Please note that this function does not
1530 * add any routing information to the route graph - this has to be done via the route_graph_flood()
1533 * The function does not create a graph covering the whole map, but only covering the rectangle
1534 * between c1 and c2.
1536 * @param ms The mapset to build the route graph from
1537 * @param c1 Corner 1 of the rectangle to use from the map
1538 * @param c2 Corner 2 of the rectangle to use from the map
1539 * @return The new route graph.
1541 static struct route_graph *
1542 route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
1544 struct route_graph *ret=g_new0(struct route_graph, 1);
1545 struct map_selection *sel;
1546 struct mapset_handle *h;
1547 struct map_rect *mr;
1552 printf("%s:Out of memory\n", __FUNCTION__);
1555 sel=route_calc_selection(c1, c2);
1557 while ((m=mapset_next(h,1))) {
1558 mr=map_rect_new(m, sel);
1561 while ((item=map_rect_get_item(mr))) {
1562 if (item->type >= type_street_0 && item->type <= type_ferry) {
1563 route_process_street_graph(ret, item);
1566 map_rect_destroy(mr);
1569 route_free_selection(sel);
1575 * @brief Updates the route graph
1577 * This updates the route graph after settings in the route have changed. It also
1578 * adds routing information afterwards by calling route_graph_flood().
1580 * @param this The route to update the graph for
1583 route_graph_update(struct route *this)
1585 route_graph_destroy(this->graph);
1586 profile(1,"graph_free");
1587 this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c);
1588 profile(1,"route_graph_build");
1589 route_graph_flood(this->graph, this->dst, this->speedlist);
1590 profile(1,"route_graph_flood");
1595 * @brief Gets street data for an item
1597 * @param item The item to get the data for
1598 * @return Street data for the item
1600 struct street_data *
1601 street_get_data (struct item *item)
1604 struct coord c[maxcount];
1606 struct street_data *ret;
1609 while (count < maxcount) {
1610 if (!item_coord_get(item, &c[count], 1))
1614 if (count >= maxcount) {
1615 dbg(0, "count=%d maxcount=%d id_hi=0x%x id_lo=0x%x\n", count, maxcount, item->id_hi, item->id_lo);
1616 if (item_attr_get(item, attr_debug, &attr))
1617 dbg(0,"debug='%s'\n", attr.u.str);
1619 g_assert(count < maxcount);
1620 ret=g_malloc(sizeof(struct street_data)+count*sizeof(struct coord));
1623 if (item_attr_get(item, attr_flags, &attr))
1624 ret->flags=attr.u.num;
1627 memcpy(ret->c, c, count*sizeof(struct coord));
1633 * @brief Copies street data
1635 * @param orig The street data to copy
1636 * @return The copied street data
1638 struct street_data *
1639 street_data_dup(struct street_data *orig)
1641 struct street_data *ret;
1642 int size=sizeof(struct street_data)+orig->count*sizeof(struct coord);
1645 memcpy(ret, orig, size);
1651 * @brief Frees street data
1653 * @param sd Street data to be freed
1656 street_data_free(struct street_data *sd)
1662 * @brief Finds the nearest street to a given coordinate
1664 * @param ms The mapset to search in for the street
1665 * @param pc The coordinate to find a street nearby
1666 * @return The nearest street
1668 static struct route_info *
1669 route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
1671 struct route_info *ret=NULL;
1673 struct map_selection *sel;
1674 int dist,mindist=0,pos;
1675 struct mapset_handle *h;
1677 struct map_rect *mr;
1680 struct street_data *sd;
1687 * This is not correct for two reasons:
1688 * - You may need to go back first
1689 * - Currently we allow mixing of mapsets
1691 sel = route_rect(18, &c, &c, 0, max_dist);
1693 while ((m=mapset_next(h,1))) {
1696 if (map_projection(m) != pc->pro) {
1697 transform_to_geo(pc->pro, &c, &g);
1698 transform_from_geo(map_projection(m), &g, &c);
1700 mr=map_rect_new(m, sel);
1703 while ((item=map_rect_get_item(mr))) {
1704 if (item->type >= type_street_0 && item->type <= type_ferry) {
1705 sd=street_get_data(item);
1706 dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos);
1707 if (!ret || dist < mindist) {
1709 street_data_free(ret->street);
1712 ret=g_new(struct route_info, 1);
1714 printf("%s:Out of memory\n", __FUNCTION__);
1722 dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos);
1724 street_data_free(sd);
1727 map_rect_destroy(mr);
1730 map_selection_destroy(sel);
1736 * @brief Destroys a route_info
1738 * @param info The route info to be destroyed
1741 route_info_free(struct route_info *inf)
1744 street_data_free(inf->street);
1752 * @brief Returns street data for a route info
1754 * @param rinf The route info to return the street data for
1755 * @return Street data for the route info
1757 struct street_data *
1758 route_info_street(struct route_info *rinf)
1760 return rinf->street;
1764 struct route_crossings *
1765 route_crossings_get(struct route *this, struct coord *c)
1767 struct route_point *pnt;
1768 struct route_segment *seg;
1770 struct route_crossings *ret;
1772 pnt=route_graph_get_point(this, c);
1775 printf("start: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1777 seg=seg->start_next;
1781 printf("end: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1785 ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing));
1786 ret->count=crossings;
1792 struct map_rect_priv {
1793 struct route_info_handle *ri;
1794 enum attr_type attr_next;
1796 struct map_priv *mpriv;
1799 unsigned int last_coord;
1800 struct route_path_segment *seg,*seg_next;
1801 struct route_graph_point *point;
1802 struct route_graph_segment *rseg;
1807 rm_coord_rewind(void *priv_data)
1809 struct map_rect_priv *mr = priv_data;
1814 rm_attr_rewind(void *priv_data)
1816 struct map_rect_priv *mr = priv_data;
1817 mr->attr_next = attr_street_item;
1821 rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1823 struct map_rect_priv *mr = priv_data;
1824 struct route_path_segment *seg=mr->seg;
1825 struct route *route=mr->mpriv->route;
1826 attr->type=attr_type;
1827 switch (attr_type) {
1829 while (mr->attr_next != attr_none) {
1830 if (rm_attr_get(priv_data, mr->attr_next, attr))
1834 case attr_street_item:
1835 mr->attr_next=attr_route_follow_straight;
1836 if (seg && seg->item.map)
1837 attr->u.item=&seg->item;
1841 case attr_route_follow_straight:
1842 mr->attr_next=attr_direction;
1844 return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
1847 case attr_direction:
1848 mr->attr_next=attr_length;
1850 attr->u.num=seg->direction;
1856 attr->u.num=seg->length;
1858 attr->u.num=mr->length;
1859 mr->attr_next=attr_time;
1862 mr->attr_next=attr_none;
1864 attr->u.num=route_time(route->speedlist, &seg->item, seg->length);
1869 attr->type=attr_none;
1876 rm_coord_get(void *priv_data, struct coord *c, int count)
1878 struct map_rect_priv *mr = priv_data;
1879 struct route_path_segment *seg = mr->seg;
1883 for (i=0; i < count; i++) {
1884 if (mr->last_coord >= seg->ncoords)
1886 if (i >= seg->ncoords)
1888 c[i] = seg->c[mr->last_coord++];
1891 dbg(1,"return %d\n",rc);
1895 static struct item_methods methods_route_item = {
1903 rp_attr_rewind(void *priv_data)
1905 struct map_rect_priv *mr = priv_data;
1906 mr->attr_next = attr_label;
1910 rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1912 struct map_rect_priv *mr = priv_data;
1913 struct route_graph_point *p = mr->point;
1914 if (mr->item.type != type_rg_point)
1916 switch (attr_type) {
1918 while (mr->attr_next != attr_none) {
1919 if (rm_attr_get(priv_data, mr->attr_next, attr))
1923 attr->type = attr_label;
1926 if (p->value != INT_MAX)
1927 mr->str=g_strdup_printf("%d", p->value);
1929 mr->str=g_strdup("-");
1930 attr->u.str = mr->str;
1931 mr->attr_next=attr_none;
1934 attr->type = attr_debug;
1937 mr->str=g_strdup_printf("x=%d y=%d", p->c.x, p->c.y);
1938 attr->u.str = mr->str;
1939 mr->attr_next=attr_none;
1947 rp_coord_get(void *priv_data, struct coord *c, int count)
1949 struct map_rect_priv *mr = priv_data;
1950 struct route_graph_point *p = mr->point;
1951 struct route_graph_segment *seg = mr->rseg;
1953 for (i=0; i < count; i++) {
1954 if (mr->item.type == type_rg_point) {
1955 if (mr->last_coord >= 1)
1959 if (mr->last_coord >= 2)
1962 if (seg->end->seg == seg)
1969 c[i] = seg->start->c;
1977 static struct item_methods methods_point_item = {
1985 rm_destroy(struct map_priv *priv)
1990 static struct map_rect_priv *
1991 rm_rect_new(struct map_priv *priv, struct map_selection *sel)
1993 struct map_rect_priv * mr;
1995 if (! route_get_pos(priv->route))
1997 if (! route_get_dst(priv->route))
1999 if (! priv->route->path2)
2001 mr=g_new0(struct map_rect_priv, 1);
2003 mr->item.priv_data = mr;
2004 mr->item.type = type_street_route;
2005 mr->item.meth = &methods_route_item;
2006 mr->seg_next=priv->route->path2->path;
2010 static struct map_rect_priv *
2011 rp_rect_new(struct map_priv *priv, struct map_selection *sel)
2013 struct map_rect_priv * mr;
2015 if (! priv->route->graph || ! priv->route->graph->route_points)
2017 mr=g_new0(struct map_rect_priv, 1);
2019 mr->item.priv_data = mr;
2020 mr->item.type = type_rg_point;
2021 mr->item.meth = &methods_point_item;
2026 rm_rect_destroy(struct map_rect_priv *mr)
2033 static struct item *
2034 rp_get_item(struct map_rect_priv *mr)
2036 struct route *r = mr->mpriv->route;
2037 struct route_graph_point *p = mr->point;
2038 struct route_graph_segment *seg = mr->rseg;
2040 if (mr->item.type == type_rg_point) {
2042 p = r->graph->route_points;
2048 rm_coord_rewind(mr);
2052 mr->item.type = type_rg_segment;
2055 seg=r->graph->route_segments;
2061 rm_coord_rewind(mr);
2069 static struct item *
2070 rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2072 struct item *ret=NULL;
2074 ret=rp_get_item(mr);
2079 static struct item *
2080 rm_get_item(struct map_rect_priv *mr)
2082 struct route *r = mr->mpriv->route;
2083 struct route_path_segment *seg = mr->seg;
2084 dbg(1,"enter\n", mr->pos);
2086 mr->seg=mr->seg_next;
2089 mr->seg_next=mr->seg->next;
2096 static struct item *
2097 rm_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2099 struct item *ret=NULL;
2101 ret=rm_get_item(mr);
2105 static struct map_methods route_meth = {
2118 static struct map_methods route_graph_meth = {
2132 route_toggle_routegraph_display(struct route *route)
2134 if (route->flags & RF_SHOWGRAPH) {
2135 route->flags &= ~RF_SHOWGRAPH;
2137 route->flags |= RF_SHOWGRAPH;
2141 static struct map_priv *
2142 route_map_new_helper(struct map_methods *meth, struct attr **attrs, int graph)
2144 struct map_priv *ret;
2145 struct attr *route_attr;
2147 route_attr=attr_search(attrs, NULL, attr_route);
2150 ret=g_new0(struct map_priv, 1);
2152 *meth=route_graph_meth;
2155 ret->route=route_attr->u.route;
2160 static struct map_priv *
2161 route_map_new(struct map_methods *meth, struct attr **attrs)
2163 return route_map_new_helper(meth, attrs, 0);
2166 static struct map_priv *
2167 route_graph_map_new(struct map_methods *meth, struct attr **attrs)
2169 return route_map_new_helper(meth, attrs, 1);
2173 route_get_map_helper(struct route *this_, struct map **map, char *type, char *description)
2176 *map=map_new((struct attr*[]){
2177 &(struct attr){attr_type,{type}},
2178 &(struct attr){attr_route,.u.route=this_},
2179 &(struct attr){attr_data,{""}},
2180 &(struct attr){attr_description,{description}},
2186 route_get_map(struct route *this_)
2188 return route_get_map_helper(this_, &this_->map, "route","Route");
2193 route_get_graph_map(struct route *this_)
2195 return route_get_map_helper(this_, &this_->graph_map, "route_graph","Route Graph");
2199 route_set_projection(struct route *this_, enum projection pro)
2206 plugin_register_map_type("route", route_map_new);
2207 plugin_register_map_type("route_graph", route_graph_map_new);