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 destination_distance; /**< Distance to the destination at which the destination is considered "reached" */
190 int speedlist[route_item_last-route_item_first+1]; /**< The speedlist for this route */
194 * @brief A complete route graph
196 * This structure describes a whole routing graph
199 struct route_graph_point *route_points; /**< Pointer to the first route_graph_point in the linked list of all points */
200 struct route_graph_segment *route_segments; /**< Pointer to the first route_graph_segment in the linked list of all segments */
201 #define HASH_SIZE 8192
202 struct route_graph_point *hash[HASH_SIZE]; /**< A hashtable containing all route_graph_points in this graph */
205 #define HASHCOORD(c) ((((c)->x +(c)->y) * 2654435761UL) & (HASH_SIZE-1))
207 static struct route_info * route_find_nearest_street(struct mapset *ms, struct pcoord *c);
208 static struct route_graph_point *route_graph_get_point(struct route_graph *this, struct coord *c);
209 static void route_graph_update(struct route *this);
210 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);
211 static void route_process_street_graph(struct route_graph *this, struct item *item);
212 static void route_graph_destroy(struct route_graph *this);
213 static void route_path_update(struct route *this);
216 * @brief Returns the projection used for this route
218 * @param route The route to return the projection for
219 * @return The projection used for this route
221 static enum projection route_projection(struct route *route)
223 struct street_data *street;
224 street = route->pos ? route->pos->street : route->dst->street;
225 return map_projection(street->item.map);
229 * @brief Destroys a route_path
231 * @param this The route_path to be destroyed
234 route_path_destroy(struct route_path *this)
236 struct route_path_segment *c,*n;
239 if (this->path_hash) {
240 item_hash_destroy(this->path_hash);
241 this->path_hash=NULL;
247 attr_list_free(c->attrs);
256 * @brief Creates a completely new route structure
258 * @param attrs Not used
259 * @return The newly created route
262 route_new(struct attr **attrs)
264 struct route *this=g_new0(struct route, 1);
265 struct attr dest_attr;
268 printf("%s:Out of memory\n", __FUNCTION__);
272 if (attr_generic_get_attr(attrs, NULL, attr_destination_distance, &dest_attr, NULL)) {
273 this->destination_distance = dest_attr.u.num;
275 this->destination_distance = 50; // Default value
282 * @brief Sets the mapset of the route passwd
284 * @param this The route to set the mapset for
285 * @param ms The mapset to set for this route
288 route_set_mapset(struct route *this, struct mapset *ms)
294 * @brief Returns the mapset of the route passed
296 * @param this The route to get the mapset of
297 * @return The mapset of the route passed
300 route_get_mapset(struct route *this)
306 * @brief Returns the current position within the route passed
308 * @param this The route to get the position for
309 * @return The position within the route passed
312 route_get_pos(struct route *this)
318 * @brief Returns the destination of the route passed
320 * @param this The route to get the destination for
321 * @return The destination of the route passed
324 route_get_dst(struct route *this)
330 * @brief Returns the speedlist of the route passed
332 * @param this The route to get the speedlist for
333 * @return The speedlist of the route passed
336 route_get_speedlist(struct route *this)
338 return this->speedlist;
342 * @brief Checks if the path is calculated for the route passed
344 * @param this The route to check
345 * @return True if the path is calculated, false if not
348 route_get_path_set(struct route *this)
350 return this->path2 != NULL;
354 * @brief Sets the driving speed for a certain itemtype
356 * @param this The route to set the speed for
357 * @param type The itemtype to set the speed for
358 * @param value The speed that should be set
359 * @return True on success, false if the itemtype does not exist
362 route_set_speed(struct route *this, enum item_type type, int value)
364 if (type < route_item_first || type > route_item_last) {
365 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
368 this->speedlist[type-route_item_first]=value;
373 * @brief Checks if the route passed contains a certain item within the route path
375 * This function checks if a certain items exists in the path that navit will guide
376 * the user to his destination. It does *not* check if this item exists in the route
379 * @param this The route to check for this item
380 * @param item The item to search for
381 * @return True if the item was found, false if the item was not found or the route was not calculated
384 route_contains(struct route *this, struct item *item)
386 if (! this->path2 || !this->path2->path_hash)
388 return (int)item_hash_lookup(this->path2->path_hash, item);
392 * @brief Checks if the current position in a route is a certain item
394 * @param this The route to check for this item
395 * @param item The item to search for
396 * @return True if the current position is this item, false otherwise
399 route_pos_contains(struct route *this, struct item *item)
403 return item_is_equal(this->pos->street->item, *item);
407 * @brief Checks if a route has reached its destination
409 * @param this The route to be checked
410 * @return True if the destination is "reached", false otherwise.
413 route_destination_reached(struct route *this)
415 struct street_data *sd = this->pos->street;
421 if (! item_is_equal(this->pos->street->item, this->dst->street->item)) {
425 if ((sd->flags & AF_ONEWAY) && (this->pos->lenneg >= this->dst->lenneg)) { // We would have to drive against the one-way road
428 if ((sd->flags & AF_ONEWAYREV) && (this->pos->lenpos >= this->dst->lenpos)) {
432 if (transform_distance(projection_mg, &this->pos->c, &this->dst->lp) > this->destination_distance) {
440 * @brief Updates the route graph and the route path if something changed with the route
442 * This will update the route graph and the route path of the route if some of the
443 * route's settings (destination, position) have changed.
445 * @attention For this to work the route graph has to be destroyed if the route's
446 * @attention destination is changed somewhere!
448 * @param this The route to update
451 route_path_update(struct route *this)
453 struct route_path *oldpath = NULL;
454 if (! this->pos || ! this->dst) {
455 route_path_destroy(this->path2);
459 /* the graph is destroyed when setting the destination */
460 if (this->graph && this->pos && this->dst && this->path2) {
461 // we can try to update
462 oldpath = this->path2;
465 if (! this->graph || !(this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist))) {
467 route_graph_update(this);
468 this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist);
469 profile(1,"route_path_new");
474 /* Destroy what's left */
475 route_path_destroy(oldpath);
480 * @brief This will calculate all the distances stored in a route_info
482 * @param ri The route_info to calculate the distances for
483 * @param pro The projection used for this route
486 route_info_distances(struct route_info *ri, enum projection pro)
489 struct street_data *sd=ri->street;
490 /* 0 1 2 X 3 4 5 6 pos=2 npos=3 count=7 0,1,2 3,4,5,6*/
491 ri->lenextra=transform_distance(pro, &ri->lp, &ri->c);
492 ri->lenneg=transform_polyline_length(pro, sd->c, npos)+transform_distance(pro, &sd->c[ri->pos], &ri->lp);
493 ri->lenpos=transform_polyline_length(pro, sd->c+npos, sd->count-npos)+transform_distance(pro, &sd->c[npos], &ri->lp);
497 * @brief This sets the current position of the route passed
499 * This will set the current position of the route passed to the street that is nearest to the
500 * passed coordinates. It also automatically updates the route.
502 * @param this The route to set the position of
503 * @param pos Coordinates to set as position
506 route_set_position(struct route *this, struct pcoord *pos)
509 route_info_free(this->pos);
511 this->pos=route_find_nearest_street(this->ms, pos);
512 dbg(1,"this->pos=%p\n", this->pos);
515 route_info_distances(this->pos, pos->pro);
517 route_path_update(this);
521 * @brief Sets a route's current position based on coordinates from tracking
523 * @param this The route to set the current position of
524 * @param tracking The tracking to get the coordinates from
527 route_set_position_from_tracking(struct route *this, struct tracking *tracking)
530 struct route_info *ret;
533 c=tracking_get_pos(tracking);
534 ret=g_new0(struct route_info, 1);
536 printf("%s:Out of memory\n", __FUNCTION__);
540 route_info_free(this->pos);
544 ret->pos=tracking_get_segment_pos(tracking);
545 ret->street=street_data_dup(tracking_get_street_data(tracking));
546 route_info_distances(ret, projection_mg);
547 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);
548 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);
551 route_path_update(this);
555 /* Used for debuging of route_rect, what routing sees */
556 struct map_selection *route_selection;
559 * @brief Returns a single map selection
561 struct map_selection *
562 route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs)
564 int dx,dy,sx=1,sy=1,d,m;
565 struct map_selection *sel=g_new(struct map_selection, 1);
567 printf("%s:Out of memory\n", __FUNCTION__);
570 sel->order[layer_town]=0;
571 sel->order[layer_poly]=0;
572 sel->order[layer_street]=order;
573 dbg(1,"%p %p\n", c1, c2);
578 sel->u.c_rect.lu.x=c1->x;
579 sel->u.c_rect.rl.x=c2->x;
581 sel->u.c_rect.lu.x=c2->x;
582 sel->u.c_rect.rl.x=c1->x;
586 sel->u.c_rect.lu.y=c2->y;
587 sel->u.c_rect.rl.y=c1->y;
589 sel->u.c_rect.lu.y=c1->y;
590 sel->u.c_rect.rl.y=c2->y;
597 sel->u.c_rect.lu.x-=m;
598 sel->u.c_rect.rl.x+=m;
599 sel->u.c_rect.lu.y+=m;
600 sel->u.c_rect.rl.y-=m;
606 * @brief Returns a list of map selections useable to create a route graph
608 * Returns a list of map selections useable to get a map rect from which items can be
609 * retrieved to build a route graph. The selections are a rectangle with
610 * c1 and c2 as two corners.
612 * @param c1 Corner 1 of the rectangle
613 * @param c2 Corder 2 of the rectangle
615 static struct map_selection *
616 route_calc_selection(struct coord *c1, struct coord *c2)
618 struct map_selection *ret,*sel;
619 sel=route_rect(4, c1, c2, 25, 0);
621 sel->next=route_rect(8, c1, c1, 0, 40000);
623 sel->next=route_rect(18, c1, c1, 0, 10000);
625 sel->next=route_rect(8, c2, c2, 0, 40000);
627 sel->next=route_rect(18, c2, c2, 0, 10000);
628 /* route_selection=ret; */
633 * @brief Destroys a list of map selections
635 * @param sel Start of the list to be destroyed
638 route_free_selection(struct map_selection *sel)
640 struct map_selection *next;
650 * @brief Sets the destination of a route
652 * This sets the destination of a route to the street nearest to the coordinates passed
653 * and updates the route.
655 * @param this The route to set the destination for
656 * @param dst Coordinates to set as destination
659 route_set_destination(struct route *this, struct pcoord *dst)
663 route_info_free(this->dst);
666 this->dst=route_find_nearest_street(this->ms, dst);
667 route_info_distances(this->dst, dst->pro);
669 profile(1,"find_nearest_street");
671 /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
672 route_graph_destroy(this->graph);
674 route_path_update(this);
679 * @brief Gets the route_graph_point with the specified coordinates
681 * @param this The route in which to search
682 * @param c Coordinates to search for
683 * @return The point at the specified coordinates or NULL if not found
685 static struct route_graph_point *
686 route_graph_get_point(struct route_graph *this, struct coord *c)
688 struct route_graph_point *p;
689 int hashval=HASHCOORD(c);
690 p=this->hash[hashval];
692 if (p->c.x == c->x && p->c.y == c->y)
700 * @brief Inserts a point into the route graph at the specified coordinates
702 * This will insert a point into the route graph at the coordinates passed in f.
703 * Note that the point is not yet linked to any segments.
705 * @param this The route to insert the point into
706 * @param f The coordinates at which the point should be inserted
707 * @return The point inserted or NULL on failure
709 static struct route_graph_point *
710 route_graph_add_point(struct route_graph *this, struct coord *f)
713 struct route_graph_point *p;
715 p=route_graph_get_point(this,f);
717 hashval=HASHCOORD(f);
719 printf("p (0x%x,0x%x)\n", f->x, f->y);
720 p=g_new(struct route_graph_point,1);
722 printf("%s:Out of memory\n", __FUNCTION__);
725 p->hash_next=this->hash[hashval];
726 this->hash[hashval]=p;
727 p->next=this->route_points;
734 this->route_points=p;
740 * @brief Frees all the memory used for points in the route graph passed
742 * @param this The route graph to delete all points from
745 route_graph_free_points(struct route_graph *this)
747 struct route_graph_point *curr,*next;
748 curr=this->route_points;
754 this->route_points=NULL;
755 memset(this->hash, 0, sizeof(this->hash));
759 * @brief Inserts a new segment into the route graph
761 * This function performs a check if a segment for the item specified already exists, and inserts
762 * a new segment representing this item if it does not.
764 * @param this The route graph to insert the segment into
765 * @param start The graph point which should be connected to the start of this segment
766 * @param end The graph point which should be connected to the end of this segment
767 * @param len The length of this segment
768 * @param item The item that is represented by this segment
769 * @param flags Flags for this segment
770 * @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
773 route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
774 struct route_graph_point *end, int len, struct item *item,
775 int flags, int offset)
777 struct route_graph_segment *s;
780 if (item_is_equal(*item, s->item))
784 s = g_new0(struct route_graph_segment, 1);
786 printf("%s:Out of memory\n", __FUNCTION__);
790 s->start_next=start->start;
793 s->end_next=end->end;
795 dbg_assert(len >= 0);
800 s->next=this->route_segments;
801 this->route_segments=s;
803 printf("l (0x%x,0x%x)-(0x%x,0x%x)\n", start->c.x, start->c.y, end->c.x, end->c.y);
807 * @brief Gets all the coordinates of an item
809 * This will get all the coordinates of the item i and return them in c,
810 * up to max coordinates. Additionally it is possible to limit the coordinates
811 * returned to all the coordinates of the item between the two coordinates
814 * @important Make shure that whatever c points to has enough memory allocated
815 * @important to hold max coordinates!
817 * @param i The item to get the coordinates of
818 * @param c Pointer to memory allocated for holding the coordinates
819 * @param max Maximum number of coordinates to return
820 * @param start First coordinate to get
821 * @param end Last coordinate to get
823 static int get_item_seg_coords(struct item *i, struct coord *c, int max,
824 struct coord *start, struct coord *end)
830 mr=map_rect_new(i->map, NULL);
833 item = map_rect_get_item_byid(mr, i->id_hi, i->id_lo);
835 rc = item_coord_get(item, &c1, 1);
836 while (rc && (c1.x != start->x || c1.y != start->y)) {
837 rc = item_coord_get(item, &c1, 1);
839 while (rc && p < max) {
841 if (c1.x == end->x && c1.y == end->y)
843 rc = item_coord_get(item, &c1, 1);
846 map_rect_destroy(mr);
851 * @brief Returns and removes one segment from a path
853 * @param path The path to take the segment from
854 * @param item The item whose segment to remove
855 * @param offset Offset of the segment within the item to remove. If the item is not segmented this should be 1.
856 * @return The segment removed
858 static struct route_path_segment *
859 route_extract_segment_from_path(struct route_path *path, struct item *item,
862 struct route_path_segment *sp = NULL, *s;
865 if (s->offset == offset && item_is_equal(s->item,*item)) {
870 path->path = s->next;
878 item_hash_remove(path->path_hash, item);
883 * @brief Adds a segment and the end of a path
885 * @param this The path to add the segment to
886 * @param segment The segment to add
889 route_path_add_segment(struct route_path *this, struct route_path_segment *segment)
894 this->path_last->next=segment;
895 this->path_last=segment;
899 * @brief Adds a new item to a path
901 * This adds a new item to a path, creating a new segment for it. Please note that this function does not check
902 * if the item passed is segmented - it will create exactly one segment.
904 * @param this The path to add the item to
905 * @param item The item to add
906 * @param len The length of the item
907 * @param first (Optional) coordinate to add to the start of the item. If none should be added, make this NULL.
908 * @param c Pointer to count coordinates of the item.
909 * @param cound Number of coordinates in c
910 * @param last (Optional) coordinate to add to the end of the item. If none should be added, make this NULL.
911 * @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"
914 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)
916 int i,idx=0,ccount=count + (first ? 1:0) + (last ? 1:0);
917 struct route_path_segment *segment;
919 segment=g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccount);
920 segment->ncoords=ccount;
921 segment->direction=dir;
923 segment->c[idx++]=*first;
925 for (i = 0 ; i < count ; i++)
926 segment->c[idx++]=c[i];
928 for (i = 0 ; i < count ; i++)
929 segment->c[idx++]=c[count-i-1];
932 segment->c[idx++]=*last;
936 route_path_add_segment(this, segment);
940 * @brief Inserts a new item into the path
942 * This function does almost the same as "route_apth_add_item()", but identifies
943 * the item to add by a segment from the route graph. Another difference is that it "copies" the
944 * segment from the route graph, i.e. if the item is segmented, only the segment passed in rgs will
945 * be added to the route path, not all segments of the item.
947 * The function can be sped up by passing an old path already containing this segment in oldpath -
948 * the segment will then be extracted from this old path. Please note that in this case the direction
949 * parameter has no effect.
951 * @param this The path to add the item to
952 * @param oldpath Old path containing the segment to be added. Speeds up the function, but can be NULL.
953 * @param rgs Segment of the route graph that should be "copied" to the route path
954 * @param len Length of the item to be added
955 * @param offset Offset of rgs within the item it represents
956 * @param dir Order in which to add the coordinates. See route_path_add_item()
957 * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
960 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
961 struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
963 struct route_path_segment *segment;
965 struct coord ca[2048];
966 struct attr straight_attr;
969 ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
971 segment = route_extract_segment_from_path(oldpath,
979 ccnt = get_item_seg_coords(&rgs->item, ca, 2047, &rgs->start->c, &rgs->end->c);
980 segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt);
982 printf("%s:Out of memory\n", __FUNCTION__);
985 segment->direction=dir;
987 for (i = 0 ; i < ccnt ; i++)
990 for (i = 0 ; i < ccnt ; i++)
991 segment->c[i]=ca[ccnt-i-1];
993 segment->ncoords = ccnt;
994 segment->item=rgs->item;
995 segment->offset = offset;
999 item_hash_insert(this->path_hash, &rgs->item, (void *)ccnt);
1001 straight_attr.type = attr_route_follow_straight;
1002 straight_attr.u.num = straight;
1004 segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
1006 route_path_add_segment(this, segment);
1010 * @brief Destroys all segments of a route graph
1012 * @param this The graph to destroy all segments from
1015 route_graph_free_segments(struct route_graph *this)
1017 struct route_graph_segment *curr,*next;
1018 curr=this->route_segments;
1024 this->route_segments=NULL;
1028 * @brief Destroys a route graph
1030 * @param this The route graph to be destroyed
1033 route_graph_destroy(struct route_graph *this)
1036 route_graph_free_points(this);
1037 route_graph_free_segments(this);
1043 * @brief Returns the time needed to drive len on item
1045 * @param speedlist The speedlist that should be used
1046 * @param item The item to be driven on
1047 * @param len The length to drive
1048 * @return The time needed to drive len on item
1051 route_time(int *speedlist, struct item *item, int len)
1053 if (item->type < route_item_first || item->type > route_item_last) {
1054 dbg(0,"street type %d out of range [%d,%d]", item->type, route_item_first, route_item_last);
1057 return len*36/speedlist[item->type-route_item_first];
1061 * @brief Returns the "costs" of driving len on item
1063 * @param speedlist The speedlist that should be used
1064 * @param item The item to be driven on
1065 * @param len The length to drive
1066 * @return The "costs" needed to drive len on item
1069 route_value(int *speedlist, struct item *item, int len)
1073 printf("len=%d\n", len);
1075 dbg_assert(len >= 0);
1076 ret=route_time(speedlist, item, len);
1077 dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret);
1082 * @brief Adds an item to the route graph
1084 * This adds an item (e.g. a street) to the route graph, creating as many segments as needed for a
1087 * @param this The route graph to add to
1088 * @param item The item to add
1091 route_process_street_graph(struct route_graph *this, struct item *item)
1098 struct route_graph_point *s_pnt,*e_pnt;
1105 if (item_coord_get(item, &l, 1)) {
1106 if (item_attr_get(item, attr_flags, &attr)) {
1108 if (flags & AF_SEGMENTED)
1111 s_pnt=route_graph_add_point(this,&l);
1113 while (item_coord_get(item, &c, 1)) {
1114 len+=transform_distance(map_projection(item->map), &l, &c);
1117 e_pnt=route_graph_add_point(this,&l);
1118 dbg_assert(len >= 0);
1119 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1124 isseg = item_coord_is_segment(item);
1125 rc = item_coord_get(item, &c, 1);
1127 len+=transform_distance(map_projection(item->map), &l, &c);
1130 e_pnt=route_graph_add_point(this,&l);
1131 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1133 s_pnt=route_graph_add_point(this,&l);
1138 e_pnt=route_graph_add_point(this,&l);
1139 dbg_assert(len >= 0);
1141 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1147 * @brief Compares the costs of reaching the destination from two points on
1149 * @important Do not pass anything other than route_graph_points in v1 and v2!
1153 * @return The additional costs of v1 compared to v2 (may be negative)
1156 compare(void *v1, void *v2)
1158 struct route_graph_point *p1=v1;
1159 struct route_graph_point *p2=v2;
1162 printf("compare %d (%p) vs %d (%p)\n", p1->value,p1,p2->value,p2);
1164 return p1->value-p2->value;
1168 * @brief Calculates the routing costs for each point
1170 * This function is the heart of routing. It assigns each point in the route graph a
1171 * cost at which one can reach the destination from this point on. Additionally it assigns
1172 * each point a segment one should follow from this point on to reach the destination at the
1175 * This function uses Dijkstra's algorithm to do the routing. To understand it you should have a look
1176 * at this algorithm.
1179 route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist)
1181 struct route_graph_point *p_min,*end=NULL;
1182 struct route_graph_segment *s;
1183 int min,new,old,val;
1184 struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
1185 struct street_data *sd=dst->street;
1187 heap = fh_makeheap();
1188 fh_setcmp(heap, compare);
1190 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 */
1191 end=route_graph_get_point(this, &sd->c[0]);
1192 dbg_assert(end != 0);
1193 end->value=route_value(speedlist, &sd->item, dst->lenneg);
1194 end->el=fh_insert(heap, end);
1197 if (! (sd->flags & AF_ONEWAY)) { /* If we may drive against the direction of the coordinates, the last coordinate is another starting point */
1198 end=route_graph_get_point(this, &sd->c[sd->count-1]);
1199 dbg_assert(end != 0);
1200 end->value=route_value(speedlist, &sd->item, dst->lenpos);
1201 end->el=fh_insert(heap, end);
1204 dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y);
1206 p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
1207 if (! p_min) /* There are no more points with temporarily calculated costs, Dijkstra has finished */
1211 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);
1212 p_min->el=NULL; /* This point is permanently calculated now, we've taken it out of the heap */
1214 while (s) { /* Iterating all the segments leading away from our point to update the points at their ends */
1215 val=route_value(speedlist, &s->item, s->len);
1217 val+=val*2*street_route_contained(s->str->segid);
1221 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);
1222 if (new < s->end->value && !(s->flags & AF_ONEWAY)) { /* We've found a less costly way to reach the end of s, update it */
1227 printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
1228 s->end->el=fh_insert(heap, s->end);
1230 printf("el new=%p\n", s->end->el);
1234 printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
1235 fh_replacedata(heap, s->end->el, s->end);
1243 while (s) { /* Doing the same as above with the segments leading towards our point */
1244 val=route_value(speedlist, &s->item, s->len);
1247 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);
1248 if (new < s->start->value && !(s->flags & AF_ONEWAYREV)) {
1249 old=s->start->value;
1250 s->start->value=new;
1252 if (! s->start->el) {
1254 printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
1255 s->start->el=fh_insert(heap, s->start);
1257 printf("el new=%p\n", s->start->el);
1261 printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
1262 fh_replacedata(heap, s->start->el, s->start);
1270 fh_deleteheap(heap);
1274 * @brief Starts an "offroad" path
1276 * This starts a path that is not located on a street. It creates a new route path
1277 * adding only one segment, that leads from pos to dest, and which is not associated with an item.
1279 * @param this Not used
1280 * @param pos The starting position for the new path
1281 * @param dst The destination of the new path
1282 * @param dir Not used
1283 * @return The new path
1285 static struct route_path *
1286 route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1288 struct route_path *ret;
1290 ret=g_new0(struct route_path, 1);
1291 ret->path_hash=item_hash_new();
1292 route_path_add_item(ret, NULL, pos->lenextra+dst->lenextra, &pos->c, NULL, 0, &dst->c, 1);
1298 * @brief Creates a new "trivial" route
1300 * This function creates a new "trivial" route. A trivial route is a route that starts and ends on the same street,
1301 * so there is no routing needed. Depending on pos and dst it can optionally add some "offroad" part to the route.
1303 * @param this The route graph to place the route on
1304 * @param pos The starting position for the new path
1305 * @param dst The destination of the new path
1306 * @param dir Direction of the coordinates to be added
1307 * @return The new path
1309 static struct route_path *
1310 route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1312 struct street_data *sd=pos->street;
1313 struct route_path *ret;
1316 if (pos->lenextra + dst->lenextra + pos->lenneg-dst->lenneg > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1317 return route_path_new_offroad(this, pos, dst, dir);
1319 if (pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1320 return route_path_new_offroad(this, pos, dst, dir);
1322 ret=g_new0(struct route_path, 1);
1323 ret->path_hash=item_hash_new();
1325 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1327 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);
1329 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);
1331 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1336 * @brief Calculates of two coordinates' connection
1338 * This function calculates the angle between coordinates, with north = 0
1341 * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
1343 * @param c1 Coordinate 1
1344 * @param c2 Coordinate 2
1345 * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
1346 * @return The angle of the coordinate's connection
1349 route_road_angle(struct coord *c1, struct coord *c2, int dir)
1351 int ret=transform_get_angle_delta(c1, c2, dir);
1352 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
1357 * @brief Checks if entering one segment from another is a "straight" road
1359 * This checks if one can enter seg_to from seg_from by driving "straight" - i.e.
1360 * if seg_to is the segment you can drive to from seg_from by steering less than
1361 * all to all other segments.
1363 * This function returns true on failure, so we don't create maneuvers on every error.
1365 * @param seg_from Segment we are driving from
1366 * @param seg_to Segment we are driving to
1367 * @return True if driving from seg_from to seg_to is "straight", false otherwise
1370 route_check_straight(struct route_graph_segment *seg_from, struct route_graph_segment *seg_to)
1372 struct route_graph_segment *curr;
1373 struct route_graph_point *conn;
1374 int from_angle, to_angle, curr_angle, angle_diff;
1376 struct coord ca[2048];
1378 if ((seg_from->end == seg_to->start) || (seg_from->end == seg_to->end)) {
1379 ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
1380 from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
1382 conn = seg_from->end;
1383 } else if ((seg_from->start == seg_to->start) || (seg_from->start == seg_to->end)) {
1384 ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
1385 from_angle = route_road_angle(&ca[1], &ca[0],1);
1387 conn = seg_from->start;
1394 if (seg_to->end == conn) {
1395 ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
1396 to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
1398 ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
1399 to_angle = route_road_angle(&ca[0], &ca[1],1);
1403 angle_diff = from_angle - to_angle;
1404 if (angle_diff < 0) {
1410 while (curr != NULL) {
1412 curr = curr->start_next;
1416 ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
1417 curr_angle = route_road_angle(&ca[0], &ca[1], 1);
1419 curr_angle = from_angle - curr_angle;
1421 if (curr_angle < 0) {
1426 if (curr_angle <= angle_diff) {
1430 curr = curr->start_next;
1434 while (curr != NULL) {
1436 curr = curr->end_next;
1440 ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
1441 curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
1443 curr_angle = from_angle - curr_angle;
1445 if (curr_angle < 0) {
1449 if (curr_angle <= angle_diff) {
1453 curr = curr->end_next;
1460 * @brief Creates a new route path
1462 * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
1463 * make shure to run route_graph_flood() after changing the destination before using this function.
1465 * @param this The route graph to create the route from
1466 * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
1467 * @param pos The starting position of the route
1468 * @param dst The destination of the route
1469 * @param speedlist The speedlist to use
1470 * @return The new route path
1472 static struct route_path *
1473 route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist)
1475 struct route_graph_point *start1=NULL,*start2=NULL,*start;
1476 struct route_graph_segment *s=NULL;
1477 struct route_graph_segment *lastseg = NULL;
1482 int time=0,hr,min,sec
1484 unsigned int val1=0xffffffff,val2=0xffffffff;
1485 struct street_data *sd=pos->street;
1486 struct route_path *ret;
1488 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 */
1489 if (!(sd->flags & AF_ONEWAY) && pos->lenneg >= dst->lenneg) {
1490 return route_path_new_trivial(this, pos, dst, -1);
1492 if (!(sd->flags & AF_ONEWAYREV) && pos->lenpos >= dst->lenpos) {
1493 return route_path_new_trivial(this, pos, dst, 1);
1496 if (! (sd->flags & AF_ONEWAY)) { /* Using the start of the current segment as one starting point */
1497 start1=route_graph_get_point(this, &sd->c[0]);
1500 val1=start1->value+route_value(speedlist, &sd->item, pos->lenneg);
1501 dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1);
1503 if (! (sd->flags & AF_ONEWAYREV)) { /* Using the start of the current segment as an alternative starting point */
1504 start2=route_graph_get_point(this, &sd->c[sd->count-1]);
1507 val2=start2->value+route_value(speedlist, &sd->item, pos->lenpos);
1508 dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2);
1510 dbg(1,"val1=%d val2=%d\n", val1, val2);
1512 val1=start1->start->start->value;
1513 val2=start2->end->end->value;
1515 ret=g_new0(struct route_path, 1);
1517 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1518 if (start1 && (val1 < val2)) {
1520 route_path_add_item(ret, &sd->item, pos->lenneg, &pos->lp, sd->c, pos->pos+1, NULL, -1);
1524 route_path_add_item(ret, &sd->item, pos->lenpos, &pos->lp, sd->c+pos->pos+1, sd->count-pos->pos-1, NULL, 1);
1526 printf("no route found, pos blocked\n");
1530 ret->path_hash=item_hash_new();
1531 while ((s=start->seg)) { /* following start->seg, which indicates the least costly way to reach our destination */
1534 printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1540 is_straight = route_check_straight(lastseg,s);
1545 if (s->start == start) {
1546 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
1549 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
1556 dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1557 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);
1558 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 */
1559 route_path_add_item(ret, &sd->item, dst->lenneg, &dst->lp, sd->c, dst->pos+1, NULL, -1);
1560 } else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) {
1561 route_path_add_item(ret, &sd->item, dst->lenpos, &dst->lp, sd->c+dst->pos+1, sd->count-dst->pos-1, NULL, 1);
1563 printf("no route found\n");
1564 route_path_destroy(ret);
1568 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1569 dbg(1, "%d segments\n", segs);
1574 * @brief Builds a new route graph from a mapset
1576 * This function builds a new route graph from a map. Please note that this function does not
1577 * add any routing information to the route graph - this has to be done via the route_graph_flood()
1580 * The function does not create a graph covering the whole map, but only covering the rectangle
1581 * between c1 and c2.
1583 * @param ms The mapset to build the route graph from
1584 * @param c1 Corner 1 of the rectangle to use from the map
1585 * @param c2 Corner 2 of the rectangle to use from the map
1586 * @return The new route graph.
1588 static struct route_graph *
1589 route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
1591 struct route_graph *ret=g_new0(struct route_graph, 1);
1592 struct map_selection *sel;
1593 struct mapset_handle *h;
1594 struct map_rect *mr;
1599 printf("%s:Out of memory\n", __FUNCTION__);
1602 sel=route_calc_selection(c1, c2);
1604 while ((m=mapset_next(h,1))) {
1605 mr=map_rect_new(m, sel);
1608 while ((item=map_rect_get_item(mr))) {
1609 if (item->type >= type_street_0 && item->type <= type_ferry) {
1610 route_process_street_graph(ret, item);
1613 map_rect_destroy(mr);
1616 route_free_selection(sel);
1622 * @brief Updates the route graph
1624 * This updates the route graph after settings in the route have changed. It also
1625 * adds routing information afterwards by calling route_graph_flood().
1627 * @param this The route to update the graph for
1630 route_graph_update(struct route *this)
1632 route_graph_destroy(this->graph);
1633 profile(1,"graph_free");
1634 this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c);
1635 profile(1,"route_graph_build");
1636 route_graph_flood(this->graph, this->dst, this->speedlist);
1637 profile(1,"route_graph_flood");
1642 * @brief Gets street data for an item
1644 * @param item The item to get the data for
1645 * @return Street data for the item
1647 struct street_data *
1648 street_get_data (struct item *item)
1651 struct coord c[maxcount];
1653 struct street_data *ret;
1656 while (count < maxcount) {
1657 if (!item_coord_get(item, &c[count], 1))
1661 if (count >= maxcount) {
1662 dbg(0, "count=%d maxcount=%d id_hi=0x%x id_lo=0x%x\n", count, maxcount, item->id_hi, item->id_lo);
1663 if (item_attr_get(item, attr_debug, &attr))
1664 dbg(0,"debug='%s'\n", attr.u.str);
1666 dbg_assert(count < maxcount);
1667 ret=g_malloc(sizeof(struct street_data)+count*sizeof(struct coord));
1670 if (item_attr_get(item, attr_flags, &attr))
1671 ret->flags=attr.u.num;
1674 memcpy(ret->c, c, count*sizeof(struct coord));
1680 * @brief Copies street data
1682 * @param orig The street data to copy
1683 * @return The copied street data
1685 struct street_data *
1686 street_data_dup(struct street_data *orig)
1688 struct street_data *ret;
1689 int size=sizeof(struct street_data)+orig->count*sizeof(struct coord);
1692 memcpy(ret, orig, size);
1698 * @brief Frees street data
1700 * @param sd Street data to be freed
1703 street_data_free(struct street_data *sd)
1709 * @brief Finds the nearest street to a given coordinate
1711 * @param ms The mapset to search in for the street
1712 * @param pc The coordinate to find a street nearby
1713 * @return The nearest street
1715 static struct route_info *
1716 route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
1718 struct route_info *ret=NULL;
1720 struct map_selection *sel;
1721 int dist,mindist=0,pos;
1722 struct mapset_handle *h;
1724 struct map_rect *mr;
1727 struct street_data *sd;
1734 * This is not correct for two reasons:
1735 * - You may need to go back first
1736 * - Currently we allow mixing of mapsets
1738 sel = route_rect(18, &c, &c, 0, max_dist);
1740 while ((m=mapset_next(h,1))) {
1743 if (map_projection(m) != pc->pro) {
1744 transform_to_geo(pc->pro, &c, &g);
1745 transform_from_geo(map_projection(m), &g, &c);
1747 mr=map_rect_new(m, sel);
1750 while ((item=map_rect_get_item(mr))) {
1751 if (item->type >= type_street_0 && item->type <= type_ferry) {
1752 sd=street_get_data(item);
1753 dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos);
1754 if (!ret || dist < mindist) {
1756 street_data_free(ret->street);
1759 ret=g_new(struct route_info, 1);
1761 printf("%s:Out of memory\n", __FUNCTION__);
1769 dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos);
1771 street_data_free(sd);
1774 map_rect_destroy(mr);
1777 map_selection_destroy(sel);
1783 * @brief Destroys a route_info
1785 * @param info The route info to be destroyed
1788 route_info_free(struct route_info *inf)
1791 street_data_free(inf->street);
1799 * @brief Returns street data for a route info
1801 * @param rinf The route info to return the street data for
1802 * @return Street data for the route info
1804 struct street_data *
1805 route_info_street(struct route_info *rinf)
1807 return rinf->street;
1811 struct route_crossings *
1812 route_crossings_get(struct route *this, struct coord *c)
1814 struct route_point *pnt;
1815 struct route_segment *seg;
1817 struct route_crossings *ret;
1819 pnt=route_graph_get_point(this, c);
1822 printf("start: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1824 seg=seg->start_next;
1828 printf("end: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1832 ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing));
1833 ret->count=crossings;
1839 struct map_rect_priv {
1840 struct route_info_handle *ri;
1841 enum attr_type attr_next;
1843 struct map_priv *mpriv;
1846 unsigned int last_coord;
1847 struct route_path_segment *seg,*seg_next;
1848 struct route_graph_point *point;
1849 struct route_graph_segment *rseg;
1854 rm_coord_rewind(void *priv_data)
1856 struct map_rect_priv *mr = priv_data;
1861 rm_attr_rewind(void *priv_data)
1863 struct map_rect_priv *mr = priv_data;
1864 mr->attr_next = attr_street_item;
1868 rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1870 struct map_rect_priv *mr = priv_data;
1871 struct route_path_segment *seg=mr->seg;
1872 struct route *route=mr->mpriv->route;
1873 attr->type=attr_type;
1874 switch (attr_type) {
1876 while (mr->attr_next != attr_none) {
1877 if (rm_attr_get(priv_data, mr->attr_next, attr))
1881 case attr_street_item:
1882 mr->attr_next=attr_route_follow_straight;
1883 if (seg && seg->item.map)
1884 attr->u.item=&seg->item;
1888 case attr_route_follow_straight:
1889 mr->attr_next=attr_direction;
1891 return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
1894 case attr_direction:
1895 mr->attr_next=attr_length;
1897 attr->u.num=seg->direction;
1903 attr->u.num=seg->length;
1905 attr->u.num=mr->length;
1906 mr->attr_next=attr_time;
1909 mr->attr_next=attr_none;
1911 attr->u.num=route_time(route->speedlist, &seg->item, seg->length);
1916 attr->type=attr_none;
1923 rm_coord_get(void *priv_data, struct coord *c, int count)
1925 struct map_rect_priv *mr = priv_data;
1926 struct route_path_segment *seg = mr->seg;
1930 for (i=0; i < count; i++) {
1931 if (mr->last_coord >= seg->ncoords)
1933 if (i >= seg->ncoords)
1935 c[i] = seg->c[mr->last_coord++];
1938 dbg(1,"return %d\n",rc);
1942 static struct item_methods methods_route_item = {
1950 rp_attr_rewind(void *priv_data)
1952 struct map_rect_priv *mr = priv_data;
1953 mr->attr_next = attr_label;
1957 rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1959 struct map_rect_priv *mr = priv_data;
1960 struct route_graph_point *p = mr->point;
1961 if (mr->item.type != type_rg_point)
1963 switch (attr_type) {
1965 while (mr->attr_next != attr_none) {
1966 if (rm_attr_get(priv_data, mr->attr_next, attr))
1970 attr->type = attr_label;
1973 if (p->value != INT_MAX)
1974 mr->str=g_strdup_printf("%d", p->value);
1976 mr->str=g_strdup("-");
1977 attr->u.str = mr->str;
1978 mr->attr_next=attr_none;
1981 attr->type = attr_debug;
1984 mr->str=g_strdup_printf("x=%d y=%d", p->c.x, p->c.y);
1985 attr->u.str = mr->str;
1986 mr->attr_next=attr_none;
1994 rp_coord_get(void *priv_data, struct coord *c, int count)
1996 struct map_rect_priv *mr = priv_data;
1997 struct route_graph_point *p = mr->point;
1998 struct route_graph_segment *seg = mr->rseg;
2000 for (i=0; i < count; i++) {
2001 if (mr->item.type == type_rg_point) {
2002 if (mr->last_coord >= 1)
2006 if (mr->last_coord >= 2)
2009 if (seg->end->seg == seg)
2016 c[i] = seg->start->c;
2024 static struct item_methods methods_point_item = {
2032 rm_destroy(struct map_priv *priv)
2037 static struct map_rect_priv *
2038 rm_rect_new(struct map_priv *priv, struct map_selection *sel)
2040 struct map_rect_priv * mr;
2042 if (! route_get_pos(priv->route))
2044 if (! route_get_dst(priv->route))
2046 if (! priv->route->path2)
2048 mr=g_new0(struct map_rect_priv, 1);
2050 mr->item.priv_data = mr;
2051 mr->item.type = type_street_route;
2052 mr->item.meth = &methods_route_item;
2053 mr->seg_next=priv->route->path2->path;
2057 static struct map_rect_priv *
2058 rp_rect_new(struct map_priv *priv, struct map_selection *sel)
2060 struct map_rect_priv * mr;
2062 if (! priv->route->graph || ! priv->route->graph->route_points)
2064 mr=g_new0(struct map_rect_priv, 1);
2066 mr->item.priv_data = mr;
2067 mr->item.type = type_rg_point;
2068 mr->item.meth = &methods_point_item;
2073 rm_rect_destroy(struct map_rect_priv *mr)
2080 static struct item *
2081 rp_get_item(struct map_rect_priv *mr)
2083 struct route *r = mr->mpriv->route;
2084 struct route_graph_point *p = mr->point;
2085 struct route_graph_segment *seg = mr->rseg;
2087 if (mr->item.type == type_rg_point) {
2089 p = r->graph->route_points;
2095 rm_coord_rewind(mr);
2099 mr->item.type = type_rg_segment;
2102 seg=r->graph->route_segments;
2108 rm_coord_rewind(mr);
2116 static struct item *
2117 rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2119 struct item *ret=NULL;
2121 ret=rp_get_item(mr);
2126 static struct item *
2127 rm_get_item(struct map_rect_priv *mr)
2129 struct route *r = mr->mpriv->route;
2130 struct route_path_segment *seg = mr->seg;
2131 dbg(1,"enter\n", mr->pos);
2133 mr->seg=mr->seg_next;
2136 mr->seg_next=mr->seg->next;
2143 static struct item *
2144 rm_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2146 struct item *ret=NULL;
2148 ret=rm_get_item(mr);
2152 static struct map_methods route_meth = {
2165 static struct map_methods route_graph_meth = {
2179 route_toggle_routegraph_display(struct route *route)
2181 if (route->flags & RF_SHOWGRAPH) {
2182 route->flags &= ~RF_SHOWGRAPH;
2184 route->flags |= RF_SHOWGRAPH;
2188 static struct map_priv *
2189 route_map_new_helper(struct map_methods *meth, struct attr **attrs, int graph)
2191 struct map_priv *ret;
2192 struct attr *route_attr;
2194 route_attr=attr_search(attrs, NULL, attr_route);
2197 ret=g_new0(struct map_priv, 1);
2199 *meth=route_graph_meth;
2202 ret->route=route_attr->u.route;
2207 static struct map_priv *
2208 route_map_new(struct map_methods *meth, struct attr **attrs)
2210 return route_map_new_helper(meth, attrs, 0);
2213 static struct map_priv *
2214 route_graph_map_new(struct map_methods *meth, struct attr **attrs)
2216 return route_map_new_helper(meth, attrs, 1);
2220 route_get_map_helper(struct route *this_, struct map **map, char *type, char *description)
2223 *map=map_new((struct attr*[]){
2224 &(struct attr){attr_type,{type}},
2225 &(struct attr){attr_route,.u.route=this_},
2226 &(struct attr){attr_data,{""}},
2227 &(struct attr){attr_description,{description}},
2233 route_get_map(struct route *this_)
2235 return route_get_map_helper(this_, &this_->map, "route","Route");
2240 route_get_graph_map(struct route *this_)
2242 return route_get_map_helper(this_, &this_->graph_map, "route_graph","Route Graph");
2246 route_set_projection(struct route *this_, enum projection pro)
2253 plugin_register_map_type("route", route_map_new);
2254 plugin_register_map_type("route_graph", route_graph_map_new);