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"
69 #define DISABLE_STRAIGHT 1 /* Slows down incremental routing by factor of 10 */
78 * @brief A point in the route graph
80 * This represents a point in the route graph. A point usually connects two or more segments,
81 * but there are also points which don't do that (e.g. at the end of a dead-end).
83 struct route_graph_point {
84 struct route_graph_point *next; /**< Linked-list pointer to a list of all route_graph_points */
85 struct route_graph_point *hash_next; /**< Pointer to a chained hashlist of all route_graph_points with this hash */
86 struct route_graph_segment *start; /**< Pointer to a list of segments of which this point is the start. The links
87 * of this linked-list are in route_graph_segment->start_next.*/
88 struct route_graph_segment *end; /**< Pointer to a list of segments of which this pointer is the end. The links
89 * of this linked-list are in route_graph_segment->end_next. */
90 struct route_graph_segment *seg; /**< Pointer to the segment one should use to reach the destination at
92 struct fibheap_el *el; /**< When this point is put on a Fibonacci heap, this is a pointer
93 * to this point's heap-element */
94 int value; /**< The cost at which one can reach the destination from this point on */
95 struct coord c; /**< Coordinates of this point */
99 * @brief A segment in the route graph
101 * This is a segment in the route graph. A segment represents a driveable way.
103 struct route_graph_segment {
104 struct route_graph_segment *next; /**< Linked-list pointer to a list of all route_graph_segments */
105 struct route_graph_segment *start_next; /**< Pointer to the next element in the list of segments that start at the
106 * same point. Start of this list is in route_graph_point->start. */
107 struct route_graph_segment *end_next; /**< Pointer to the next element in the list of segments that end at the
108 * same point. Start of this list is in route_graph_point->end. */
109 struct route_graph_point *start; /**< Pointer to the point this segment starts at. */
110 struct route_graph_point *end; /**< Pointer to the point this segment ends at. */
111 struct item item; /**< The item (e.g. street) that this segment represents. */
113 int len; /**< Length of this segment */
114 int offset; /**< If the item represented by this segment is "segmented" (i.e.
115 * is represented by several segments instead of just one), this
116 * indicates the position of this segment in the item - for items
117 * that are not segmented this should always be 1 */
121 * @brief A segment in the route path
123 * This is a segment in the route path.
125 struct route_path_segment {
126 struct route_path_segment *next; /**< Pointer to the next segment in the path */
127 struct item item; /**< The item (e.g. street) this segment represents */
128 int length; /**< Length of the segment */
129 int offset; /**< Same as in route_graph_segment->offset */
130 int direction; /**< Order in which the coordinates are ordered. >0 means "First
131 * coordinate of the segment is the first coordinate of the item", <=0
133 unsigned ncoords; /**< How many coordinates does this segment have? */
134 #ifndef DISABLE_STRAIGHT
135 struct attr **attrs; /**< Attributes of this route path segment */
137 struct coord c[0]; /**< Pointer to the ncoords coordinates of this segment */
138 /* WARNING: There will be coordinates following here, so do not create new fields after c! */
142 * @brief Usually represents a destination or position
144 * This struct usually represents a destination or position
147 struct coord c; /**< The actual destination / position */
148 struct coord lp; /**< The nearest point on a street to c */
149 int pos; /**< The position of lp within the coords of the street */
150 int lenpos; /**< Distance between lp and the end of the street */
151 int lenneg; /**< Distance between lp and the start of the street */
152 int lenextra; /**< Distance between lp and c */
154 struct street_data *street; /**< The street lp is on */
158 * @brief A complete route path
160 * This structure describes a whole routing path
163 struct route_path_segment *path; /**< The first segment in the path, i.e. the segment one should
165 struct route_path_segment *path_last; /**< The last segment in the path */
166 /* XXX: path_hash is not necessery now */
167 struct item_hash *path_hash; /**< A hashtable of all the items represented by this route's segements */
170 #define RF_FASTEST (1<<0)
171 #define RF_SHORTEST (1<<1)
172 #define RF_AVOIDHW (1<<2)
173 #define RF_AVOIDPAID (1<<3)
174 #define RF_LOCKONROAD (1<<4)
175 #define RF_SHOWGRAPH (1<<5)
178 * @brief A complete route
180 * This struct holds all information about a route.
183 int version; /**< Counts how many times this route got updated */
184 struct mapset *ms; /**< The mapset this route is built upon */
186 struct route_info *pos; /**< Current position within this route */
187 struct route_info *dst; /**< Destination of the route */
189 struct route_graph *graph; /**< Pointer to the route graph */
190 struct route_path *path2; /**< Pointer to the route path */
192 struct map *graph_map;
193 int destination_distance; /**< Distance to the destination at which the destination is considered "reached" */
194 int speedlist[route_item_last-route_item_first+1]; /**< The speedlist for this route */
198 * @brief A complete route graph
200 * This structure describes a whole routing graph
203 struct route_graph_point *route_points; /**< Pointer to the first route_graph_point in the linked list of all points */
204 struct route_graph_segment *route_segments; /**< Pointer to the first route_graph_segment in the linked list of all segments */
205 #define HASH_SIZE 8192
206 struct route_graph_point *hash[HASH_SIZE]; /**< A hashtable containing all route_graph_points in this graph */
209 #define HASHCOORD(c) ((((c)->x +(c)->y) * 2654435761UL) & (HASH_SIZE-1))
211 static struct route_info * route_find_nearest_street(struct mapset *ms, struct pcoord *c);
212 static struct route_graph_point *route_graph_get_point(struct route_graph *this, struct coord *c);
213 static void route_graph_update(struct route *this);
214 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);
215 static void route_process_street_graph(struct route_graph *this, struct item *item);
216 static void route_graph_destroy(struct route_graph *this);
217 static void route_path_update(struct route *this);
220 * @brief Returns the projection used for this route
222 * @param route The route to return the projection for
223 * @return The projection used for this route
225 static enum projection route_projection(struct route *route)
227 struct street_data *street;
228 street = route->pos ? route->pos->street : route->dst->street;
229 return map_projection(street->item.map);
233 * @brief Destroys a route_path
235 * @param this The route_path to be destroyed
238 route_path_destroy(struct route_path *this)
240 struct route_path_segment *c,*n;
243 if (this->path_hash) {
244 item_hash_destroy(this->path_hash);
245 this->path_hash=NULL;
250 #ifndef DISABLE_STRAIGHT
252 attr_list_free(c->attrs);
262 * @brief Creates a completely new route structure
264 * @param attrs Not used
265 * @return The newly created route
268 route_new(struct attr *parent, struct attr **attrs)
270 struct route *this=g_new0(struct route, 1);
271 struct attr dest_attr;
274 printf("%s:Out of memory\n", __FUNCTION__);
278 if (attr_generic_get_attr(attrs, NULL, attr_destination_distance, &dest_attr, NULL)) {
279 this->destination_distance = dest_attr.u.num;
281 this->destination_distance = 50; // Default value
288 * @brief Sets the mapset of the route passwd
290 * @param this The route to set the mapset for
291 * @param ms The mapset to set for this route
294 route_set_mapset(struct route *this, struct mapset *ms)
300 * @brief Returns the mapset of the route passed
302 * @param this The route to get the mapset of
303 * @return The mapset of the route passed
306 route_get_mapset(struct route *this)
312 * @brief Returns the current position within the route passed
314 * @param this The route to get the position for
315 * @return The position within the route passed
318 route_get_pos(struct route *this)
324 * @brief Returns the destination of the route passed
326 * @param this The route to get the destination for
327 * @return The destination of the route passed
330 route_get_dst(struct route *this)
336 * @brief Returns the speedlist of the route passed
338 * @param this The route to get the speedlist for
339 * @return The speedlist of the route passed
342 route_get_speedlist(struct route *this)
344 return this->speedlist;
348 * @brief Checks if the path is calculated for the route passed
350 * @param this The route to check
351 * @return True if the path is calculated, false if not
354 route_get_path_set(struct route *this)
356 return this->path2 != NULL;
360 * @brief Sets the driving speed for a certain itemtype
362 * @param this The route to set the speed for
363 * @param type The itemtype to set the speed for
364 * @param value The speed that should be set
365 * @return True on success, false if the itemtype does not exist
368 route_set_speed(struct route *this, enum item_type type, int value)
370 if (type < route_item_first || type > route_item_last) {
371 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
374 this->speedlist[type-route_item_first]=value;
379 * @brief Checks if the route passed contains a certain item within the route path
381 * This function checks if a certain items exists in the path that navit will guide
382 * the user to his destination. It does *not* check if this item exists in the route
385 * @param this The route to check for this item
386 * @param item The item to search for
387 * @return True if the item was found, false if the item was not found or the route was not calculated
390 route_contains(struct route *this, struct item *item)
392 if (! this->path2 || !this->path2->path_hash)
394 return (int)item_hash_lookup(this->path2->path_hash, item);
398 * @brief Checks if the current position in a route is a certain item
400 * @param this The route to check for this item
401 * @param item The item to search for
402 * @return True if the current position is this item, false otherwise
405 route_pos_contains(struct route *this, struct item *item)
409 return item_is_equal(this->pos->street->item, *item);
413 * @brief Checks if a route has reached its destination
415 * @param this The route to be checked
416 * @return True if the destination is "reached", false otherwise.
419 route_destination_reached(struct route *this)
421 struct street_data *sd = NULL;
426 sd = this->pos->street;
432 if (!item_is_equal(this->pos->street->item, this->dst->street->item)) {
436 if ((sd->flags & AF_ONEWAY) && (this->pos->lenneg >= this->dst->lenneg)) { // We would have to drive against the one-way road
439 if ((sd->flags & AF_ONEWAYREV) && (this->pos->lenpos >= this->dst->lenpos)) {
443 if (transform_distance(route_projection(this), &this->pos->c, &this->dst->lp) > this->destination_distance) {
451 * @brief Updates the route graph and the route path if something changed with the route
453 * This will update the route graph and the route path of the route if some of the
454 * route's settings (destination, position) have changed.
456 * @attention For this to work the route graph has to be destroyed if the route's
457 * @attention destination is changed somewhere!
459 * @param this The route to update
462 route_path_update(struct route *this)
464 struct route_path *oldpath = NULL;
465 if (! this->pos || ! this->dst) {
466 route_path_destroy(this->path2);
470 /* the graph is destroyed when setting the destination */
471 if (this->graph && this->pos && this->dst && this->path2) {
472 // we can try to update
473 oldpath = this->path2;
476 if (! this->graph || !(this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist))) {
478 route_graph_update(this);
479 this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist);
480 profile(1,"route_path_new");
485 /* Destroy what's left */
486 route_path_destroy(oldpath);
491 * @brief This will calculate all the distances stored in a route_info
493 * @param ri The route_info to calculate the distances for
494 * @param pro The projection used for this route
497 route_info_distances(struct route_info *ri, enum projection pro)
500 struct street_data *sd=ri->street;
501 /* 0 1 2 X 3 4 5 6 pos=2 npos=3 count=7 0,1,2 3,4,5,6*/
502 ri->lenextra=transform_distance(pro, &ri->lp, &ri->c);
503 ri->lenneg=transform_polyline_length(pro, sd->c, npos)+transform_distance(pro, &sd->c[ri->pos], &ri->lp);
504 ri->lenpos=transform_polyline_length(pro, sd->c+npos, sd->count-npos)+transform_distance(pro, &sd->c[npos], &ri->lp);
508 * @brief This sets the current position of the route passed
510 * This will set the current position of the route passed to the street that is nearest to the
511 * passed coordinates. It also automatically updates the route.
513 * @param this The route to set the position of
514 * @param pos Coordinates to set as position
517 route_set_position(struct route *this, struct pcoord *pos)
520 route_info_free(this->pos);
522 this->pos=route_find_nearest_street(this->ms, pos);
523 dbg(1,"this->pos=%p\n", this->pos);
526 route_info_distances(this->pos, pos->pro);
528 route_path_update(this);
532 * @brief Sets a route's current position based on coordinates from tracking
534 * @param this The route to set the current position of
535 * @param tracking The tracking to get the coordinates from
538 route_set_position_from_tracking(struct route *this, struct tracking *tracking)
541 struct route_info *ret;
544 c=tracking_get_pos(tracking);
545 ret=g_new0(struct route_info, 1);
547 printf("%s:Out of memory\n", __FUNCTION__);
551 route_info_free(this->pos);
557 ret->pos=tracking_get_segment_pos(tracking);
558 ret->street=street_data_dup(tracking_get_street_data(tracking));
559 route_info_distances(ret, c->pro);
560 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);
561 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);
564 route_path_update(this);
568 /* Used for debuging of route_rect, what routing sees */
569 struct map_selection *route_selection;
572 * @brief Returns a single map selection
574 struct map_selection *
575 route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs)
577 int dx,dy,sx=1,sy=1,d,m;
578 struct map_selection *sel=g_new(struct map_selection, 1);
580 printf("%s:Out of memory\n", __FUNCTION__);
583 sel->order[layer_town]=0;
584 sel->order[layer_poly]=0;
585 sel->order[layer_street]=order;
586 dbg(1,"%p %p\n", c1, c2);
591 sel->u.c_rect.lu.x=c1->x;
592 sel->u.c_rect.rl.x=c2->x;
594 sel->u.c_rect.lu.x=c2->x;
595 sel->u.c_rect.rl.x=c1->x;
599 sel->u.c_rect.lu.y=c2->y;
600 sel->u.c_rect.rl.y=c1->y;
602 sel->u.c_rect.lu.y=c1->y;
603 sel->u.c_rect.rl.y=c2->y;
610 sel->u.c_rect.lu.x-=m;
611 sel->u.c_rect.rl.x+=m;
612 sel->u.c_rect.lu.y+=m;
613 sel->u.c_rect.rl.y-=m;
619 * @brief Returns a list of map selections useable to create a route graph
621 * Returns a list of map selections useable to get a map rect from which items can be
622 * retrieved to build a route graph. The selections are a rectangle with
623 * c1 and c2 as two corners.
625 * @param c1 Corner 1 of the rectangle
626 * @param c2 Corder 2 of the rectangle
628 static struct map_selection *
629 route_calc_selection(struct coord *c1, struct coord *c2)
631 struct map_selection *ret,*sel;
632 sel=route_rect(4, c1, c2, 25, 0);
634 sel->next=route_rect(8, c1, c1, 0, 40000);
636 sel->next=route_rect(18, c1, c1, 0, 10000);
638 sel->next=route_rect(8, c2, c2, 0, 40000);
640 sel->next=route_rect(18, c2, c2, 0, 10000);
641 /* route_selection=ret; */
646 * @brief Destroys a list of map selections
648 * @param sel Start of the list to be destroyed
651 route_free_selection(struct map_selection *sel)
653 struct map_selection *next;
663 * @brief Sets the destination of a route
665 * This sets the destination of a route to the street nearest to the coordinates passed
666 * and updates the route.
668 * @param this The route to set the destination for
669 * @param dst Coordinates to set as destination
672 route_set_destination(struct route *this, struct pcoord *dst)
676 route_info_free(this->dst);
679 this->dst=route_find_nearest_street(this->ms, dst);
681 route_info_distances(this->dst, dst->pro);
683 profile(1,"find_nearest_street");
685 /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
686 route_graph_destroy(this->graph);
688 route_path_update(this);
693 * @brief Gets the route_graph_point with the specified coordinates
695 * @param this The route in which to search
696 * @param c Coordinates to search for
697 * @return The point at the specified coordinates or NULL if not found
699 static struct route_graph_point *
700 route_graph_get_point(struct route_graph *this, struct coord *c)
702 struct route_graph_point *p;
703 int hashval=HASHCOORD(c);
704 p=this->hash[hashval];
706 if (p->c.x == c->x && p->c.y == c->y)
714 * @brief Inserts a point into the route graph at the specified coordinates
716 * This will insert a point into the route graph at the coordinates passed in f.
717 * Note that the point is not yet linked to any segments.
719 * @param this The route to insert the point into
720 * @param f The coordinates at which the point should be inserted
721 * @return The point inserted or NULL on failure
723 static struct route_graph_point *
724 route_graph_add_point(struct route_graph *this, struct coord *f)
727 struct route_graph_point *p;
729 p=route_graph_get_point(this,f);
731 hashval=HASHCOORD(f);
733 printf("p (0x%x,0x%x)\n", f->x, f->y);
734 p=g_new(struct route_graph_point,1);
736 printf("%s:Out of memory\n", __FUNCTION__);
739 p->hash_next=this->hash[hashval];
740 this->hash[hashval]=p;
741 p->next=this->route_points;
748 this->route_points=p;
754 * @brief Frees all the memory used for points in the route graph passed
756 * @param this The route graph to delete all points from
759 route_graph_free_points(struct route_graph *this)
761 struct route_graph_point *curr,*next;
762 curr=this->route_points;
768 this->route_points=NULL;
769 memset(this->hash, 0, sizeof(this->hash));
773 * @brief Inserts a new segment into the route graph
775 * This function performs a check if a segment for the item specified already exists, and inserts
776 * a new segment representing this item if it does not.
778 * @param this The route graph to insert the segment into
779 * @param start The graph point which should be connected to the start of this segment
780 * @param end The graph point which should be connected to the end of this segment
781 * @param len The length of this segment
782 * @param item The item that is represented by this segment
783 * @param flags Flags for this segment
784 * @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
787 route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
788 struct route_graph_point *end, int len, struct item *item,
789 int flags, int offset)
791 struct route_graph_segment *s;
793 FIXME: commented out becouse
794 it is possible to have one item with two different
798 if (item_is_equal(*item, s->item))
803 s = g_new0(struct route_graph_segment, 1);
805 printf("%s:Out of memory\n", __FUNCTION__);
809 s->start_next=start->start;
812 s->end_next=end->end;
814 dbg_assert(len >= 0);
819 s->next=this->route_segments;
820 this->route_segments=s;
822 printf("l (0x%x,0x%x)-(0x%x,0x%x)\n", start->c.x, start->c.y, end->c.x, end->c.y);
826 * @brief Gets all the coordinates of an item
828 * This will get all the coordinates of the item i and return them in c,
829 * up to max coordinates. Additionally it is possible to limit the coordinates
830 * returned to all the coordinates of the item between the two coordinates
833 * @important Make shure that whatever c points to has enough memory allocated
834 * @important to hold max coordinates!
836 * @param i The item to get the coordinates of
837 * @param c Pointer to memory allocated for holding the coordinates
838 * @param max Maximum number of coordinates to return
839 * @param start First coordinate to get
840 * @param end Last coordinate to get
841 * @return The number of coordinates returned
843 static int get_item_seg_coords(struct item *i, struct coord *c, int max,
844 struct coord *start, struct coord *end)
850 mr=map_rect_new(i->map, NULL);
853 item = map_rect_get_item_byid(mr, i->id_hi, i->id_lo);
855 rc = item_coord_get(item, &c1, 1);
856 while (rc && (c1.x != start->x || c1.y != start->y)) {
857 rc = item_coord_get(item, &c1, 1);
859 while (rc && p < max) {
861 if (c1.x == end->x && c1.y == end->y)
863 rc = item_coord_get(item, &c1, 1);
866 map_rect_destroy(mr);
871 * @brief Returns and removes one segment from a path
873 * @param path The path to take the segment from
874 * @param item The item whose segment to remove
875 * @param offset Offset of the segment within the item to remove. If the item is not segmented this should be 1.
876 * @return The segment removed
878 static struct route_path_segment *
879 route_extract_segment_from_path(struct route_path *path, struct item *item,
882 struct route_path_segment *sp = NULL, *s;
885 if (s->offset == offset && item_is_equal(s->item,*item)) {
890 path->path = s->next;
898 item_hash_remove(path->path_hash, item);
903 * @brief Adds a segment and the end of a path
905 * @param this The path to add the segment to
906 * @param segment The segment to add
909 route_path_add_segment(struct route_path *this, struct route_path_segment *segment)
914 this->path_last->next=segment;
915 this->path_last=segment;
919 * @brief Adds a new item to a path
921 * This adds a new item to a path, creating a new segment for it. Please note that this function does not check
922 * if the item passed is segmented - it will create exactly one segment.
924 * @param this The path to add the item to
925 * @param item The item to add
926 * @param len The length of the item
927 * @param first (Optional) coordinate to add to the start of the item. If none should be added, make this NULL.
928 * @param c Pointer to count coordinates of the item.
929 * @param cound Number of coordinates in c
930 * @param last (Optional) coordinate to add to the end of the item. If none should be added, make this NULL.
931 * @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"
934 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)
936 int i,idx=0,ccount=count + (first ? 1:0) + (last ? 1:0);
937 struct route_path_segment *segment;
939 segment=g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccount);
940 segment->ncoords=ccount;
941 segment->direction=dir;
943 segment->c[idx++]=*first;
945 for (i = 0 ; i < count ; i++)
946 segment->c[idx++]=c[i];
948 for (i = 0 ; i < count ; i++)
949 segment->c[idx++]=c[count-i-1];
952 segment->c[idx++]=*last;
956 route_path_add_segment(this, segment);
960 * @brief Inserts a new item into the path
962 * This function does almost the same as "route_apth_add_item()", but identifies
963 * the item to add by a segment from the route graph. Another difference is that it "copies" the
964 * segment from the route graph, i.e. if the item is segmented, only the segment passed in rgs will
965 * be added to the route path, not all segments of the item.
967 * The function can be sped up by passing an old path already containing this segment in oldpath -
968 * the segment will then be extracted from this old path. Please note that in this case the direction
969 * parameter has no effect.
971 * @param this The path to add the item to
972 * @param oldpath Old path containing the segment to be added. Speeds up the function, but can be NULL.
973 * @param rgs Segment of the route graph that should be "copied" to the route path
974 * @param len Length of the item to be added
975 * @param offset Offset of rgs within the item it represents
976 * @param dir Order in which to add the coordinates. See route_path_add_item()
977 * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
980 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
981 struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
983 struct route_path_segment *segment;
985 struct coord ca[2048];
986 #ifndef DISABLE_STRAIGHT
987 struct attr straight_attr;
991 ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
993 segment = route_extract_segment_from_path(oldpath,
1001 ccnt = get_item_seg_coords(&rgs->item, ca, 2047, &rgs->start->c, &rgs->end->c);
1002 segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt);
1004 printf("%s:Out of memory\n", __FUNCTION__);
1007 segment->direction=dir;
1009 for (i = 0 ; i < ccnt ; i++)
1010 segment->c[i]=ca[i];
1012 for (i = 0 ; i < ccnt ; i++)
1013 segment->c[i]=ca[ccnt-i-1];
1015 segment->ncoords = ccnt;
1016 segment->item=rgs->item;
1017 segment->offset = offset;
1019 segment->length=len;
1021 item_hash_insert(this->path_hash, &rgs->item, (void *)ccnt);
1023 #ifndef DISABLE_STRAIGHT
1024 straight_attr.type = attr_route_follow_straight;
1025 straight_attr.u.num = straight;
1027 segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
1030 route_path_add_segment(this, segment);
1034 * @brief Destroys all segments of a route graph
1036 * @param this The graph to destroy all segments from
1039 route_graph_free_segments(struct route_graph *this)
1041 struct route_graph_segment *curr,*next;
1042 curr=this->route_segments;
1048 this->route_segments=NULL;
1052 * @brief Destroys a route graph
1054 * @param this The route graph to be destroyed
1057 route_graph_destroy(struct route_graph *this)
1060 route_graph_free_points(this);
1061 route_graph_free_segments(this);
1067 * @brief Returns the time needed to drive len on item
1069 * @param speedlist The speedlist that should be used
1070 * @param item The item to be driven on
1071 * @param len The length to drive
1072 * @return The time needed to drive len on item
1075 route_time(int *speedlist, struct item *item, int len)
1077 if (item->type < route_item_first || item->type > route_item_last) {
1078 dbg(0,"street type %d out of range [%d,%d]\n", item->type, route_item_first, route_item_last);
1081 if (!speedlist[item->type-route_item_first]) {
1082 dbg(0,"street type %d speed is zero\n", item->type);
1085 return len*36/speedlist[item->type-route_item_first];
1089 * @brief Returns the "costs" of driving len on item
1091 * @param speedlist The speedlist that should be used
1092 * @param item The item to be driven on
1093 * @param len The length to drive
1094 * @return The "costs" needed to drive len on item
1097 route_value(int *speedlist, struct item *item, int len)
1101 printf("len=%d\n", len);
1103 dbg_assert(len >= 0);
1104 ret=route_time(speedlist, item, len);
1105 dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret);
1110 * @brief Adds an item to the route graph
1112 * This adds an item (e.g. a street) to the route graph, creating as many segments as needed for a
1115 * @param this The route graph to add to
1116 * @param item The item to add
1119 route_process_street_graph(struct route_graph *this, struct item *item)
1126 struct route_graph_point *s_pnt,*e_pnt;
1133 if (item_coord_get(item, &l, 1)) {
1134 if (item_attr_get(item, attr_flags, &attr)) {
1136 if (flags & AF_SEGMENTED)
1139 s_pnt=route_graph_add_point(this,&l);
1141 while (item_coord_get(item, &c, 1)) {
1142 len+=transform_distance(map_projection(item->map), &l, &c);
1145 e_pnt=route_graph_add_point(this,&l);
1146 dbg_assert(len >= 0);
1147 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1152 isseg = item_coord_is_node(item);
1153 rc = item_coord_get(item, &c, 1);
1155 len+=transform_distance(map_projection(item->map), &l, &c);
1158 e_pnt=route_graph_add_point(this,&l);
1159 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1161 s_pnt=route_graph_add_point(this,&l);
1166 e_pnt=route_graph_add_point(this,&l);
1167 dbg_assert(len >= 0);
1169 route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
1175 * @brief Compares the costs of reaching the destination from two points on
1177 * @important Do not pass anything other than route_graph_points in v1 and v2!
1181 * @return The additional costs of v1 compared to v2 (may be negative)
1184 compare(void *v1, void *v2)
1186 struct route_graph_point *p1=v1;
1187 struct route_graph_point *p2=v2;
1190 printf("compare %d (%p) vs %d (%p)\n", p1->value,p1,p2->value,p2);
1192 return p1->value-p2->value;
1196 * @brief Calculates the routing costs for each point
1198 * This function is the heart of routing. It assigns each point in the route graph a
1199 * cost at which one can reach the destination from this point on. Additionally it assigns
1200 * each point a segment one should follow from this point on to reach the destination at the
1203 * This function uses Dijkstra's algorithm to do the routing. To understand it you should have a look
1204 * at this algorithm.
1207 route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist)
1209 struct route_graph_point *p_min,*end=NULL;
1210 struct route_graph_segment *s;
1211 int min,new,old,val;
1212 struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
1213 struct street_data *sd=dst->street;
1215 heap = fh_makeheap();
1216 fh_setcmp(heap, compare);
1218 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 */
1219 end=route_graph_get_point(this, &sd->c[0]);
1220 dbg_assert(end != 0);
1221 end->value=route_value(speedlist, &sd->item, dst->lenneg);
1222 end->el=fh_insert(heap, end);
1225 if (! (sd->flags & AF_ONEWAY)) { /* If we may drive against the direction of the coordinates, the last coordinate is another starting point */
1226 end=route_graph_get_point(this, &sd->c[sd->count-1]);
1227 dbg_assert(end != 0);
1228 end->value=route_value(speedlist, &sd->item, dst->lenpos);
1229 end->el=fh_insert(heap, end);
1232 dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y);
1234 p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
1235 if (! p_min) /* There are no more points with temporarily calculated costs, Dijkstra has finished */
1239 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);
1240 p_min->el=NULL; /* This point is permanently calculated now, we've taken it out of the heap */
1242 while (s) { /* Iterating all the segments leading away from our point to update the points at their ends */
1243 val=route_value(speedlist, &s->item, s->len);
1245 val+=val*2*street_route_contained(s->str->segid);
1249 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);
1250 if (new < s->end->value && !(s->flags & AF_ONEWAY)) { /* We've found a less costly way to reach the end of s, update it */
1255 printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
1256 s->end->el=fh_insert(heap, s->end);
1258 printf("el new=%p\n", s->end->el);
1262 printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
1263 fh_replacedata(heap, s->end->el, s->end);
1271 while (s) { /* Doing the same as above with the segments leading towards our point */
1272 val=route_value(speedlist, &s->item, s->len);
1275 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);
1276 if (new < s->start->value && !(s->flags & AF_ONEWAYREV)) {
1277 old=s->start->value;
1278 s->start->value=new;
1280 if (! s->start->el) {
1282 printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
1283 s->start->el=fh_insert(heap, s->start);
1285 printf("el new=%p\n", s->start->el);
1289 printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
1290 fh_replacedata(heap, s->start->el, s->start);
1298 fh_deleteheap(heap);
1302 * @brief Starts an "offroad" path
1304 * This starts a path that is not located on a street. It creates a new route path
1305 * adding only one segment, that leads from pos to dest, and which is not associated with an item.
1307 * @param this Not used
1308 * @param pos The starting position for the new path
1309 * @param dst The destination of the new path
1310 * @param dir Not used
1311 * @return The new path
1313 static struct route_path *
1314 route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1316 struct route_path *ret;
1318 ret=g_new0(struct route_path, 1);
1319 ret->path_hash=item_hash_new();
1320 route_path_add_item(ret, NULL, pos->lenextra+dst->lenextra, &pos->c, NULL, 0, &dst->c, 1);
1326 * @brief Creates a new "trivial" route
1328 * This function creates a new "trivial" route. A trivial route is a route that starts and ends on the same street,
1329 * so there is no routing needed. Depending on pos and dst it can optionally add some "offroad" part to the route.
1331 * @param this The route graph to place the route on
1332 * @param pos The starting position for the new path
1333 * @param dst The destination of the new path
1334 * @param dir Direction of the coordinates to be added
1335 * @return The new path
1337 static struct route_path *
1338 route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
1340 struct street_data *sd=pos->street;
1341 struct route_path *ret;
1344 if (pos->lenextra + dst->lenextra + pos->lenneg-dst->lenneg > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1345 return route_path_new_offroad(this, pos, dst, dir);
1347 if (pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
1348 return route_path_new_offroad(this, pos, dst, dir);
1350 ret=g_new0(struct route_path, 1);
1351 ret->path_hash=item_hash_new();
1353 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1355 route_path_add_item(ret, &sd->item, pos->lenpos-dst->lenpos, &pos->lp, sd->c+pos->pos+1, dst->pos+pos->pos, &dst->lp, 1);
1357 route_path_add_item(ret, &sd->item, pos->lenneg-dst->lenneg, &pos->lp, sd->c+dst->pos+1, pos->pos-dst->pos, &dst->lp, -1);
1359 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1363 #ifndef DISABLE_STRAIGHT
1365 * @brief Calculates of two coordinates' connection
1367 * This function calculates the angle between coordinates, with north = 0
1370 * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
1372 * @param c1 Coordinate 1
1373 * @param c2 Coordinate 2
1374 * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
1375 * @return The angle of the coordinate's connection
1378 route_road_angle(struct coord *c1, struct coord *c2, int dir)
1380 int ret=transform_get_angle_delta(c1, c2, dir);
1381 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
1386 * @brief Checks if entering one segment from another is a "straight" road
1388 * This checks if one can enter seg_to from seg_from by driving "straight" - i.e.
1389 * if seg_to is the segment you can drive to from seg_from by steering less than
1390 * all to all other segments.
1392 * This function returns true on failure, so we don't create maneuvers on every error.
1394 * @param seg_from Segment we are driving from
1395 * @param seg_to Segment we are driving to
1396 * @return True if driving from seg_from to seg_to is "straight", false otherwise
1399 route_check_straight(struct route_graph_segment *seg_from, struct route_graph_segment *seg_to)
1401 struct route_graph_segment *curr;
1402 struct route_graph_point *conn;
1403 int from_angle, to_angle, curr_angle, angle_diff;
1405 struct coord ca[2048];
1407 if ((seg_from->end == seg_to->start) || (seg_from->end == seg_to->end)) {
1408 ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
1409 from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
1411 conn = seg_from->end;
1412 } else if ((seg_from->start == seg_to->start) || (seg_from->start == seg_to->end)) {
1413 ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
1414 from_angle = route_road_angle(&ca[1], &ca[0],1);
1416 conn = seg_from->start;
1423 if (seg_to->end == conn) {
1424 ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
1425 to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
1427 ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
1428 to_angle = route_road_angle(&ca[0], &ca[1],1);
1432 angle_diff = from_angle - to_angle;
1433 if (angle_diff < 0) {
1439 while (curr != NULL) {
1441 curr = curr->start_next;
1445 ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
1446 curr_angle = route_road_angle(&ca[0], &ca[1], 1);
1448 curr_angle = from_angle - curr_angle;
1450 if (curr_angle < 0) {
1455 if (curr_angle < angle_diff) {
1459 curr = curr->start_next;
1463 while (curr != NULL) {
1465 curr = curr->end_next;
1469 ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
1470 curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
1472 curr_angle = from_angle - curr_angle;
1474 if (curr_angle < 0) {
1478 if (curr_angle < angle_diff) {
1482 curr = curr->end_next;
1490 * @brief Creates a new route path
1492 * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
1493 * make shure to run route_graph_flood() after changing the destination before using this function.
1495 * @param this The route graph to create the route from
1496 * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
1497 * @param pos The starting position of the route
1498 * @param dst The destination of the route
1499 * @param speedlist The speedlist to use
1500 * @return The new route path
1502 static struct route_path *
1503 route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist)
1505 struct route_graph_point *start1=NULL,*start2=NULL,*start;
1506 struct route_graph_segment *s=NULL;
1507 struct route_graph_segment *lastseg = NULL;
1512 int time=0,hr,min,sec
1514 unsigned int val1=0xffffffff,val2=0xffffffff;
1515 struct street_data *sd=pos->street;
1516 struct route_path *ret;
1518 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 */
1519 if (!(sd->flags & AF_ONEWAY) && pos->lenneg >= dst->lenneg) {
1520 return route_path_new_trivial(this, pos, dst, -1);
1522 if (!(sd->flags & AF_ONEWAYREV) && pos->lenpos >= dst->lenpos) {
1523 return route_path_new_trivial(this, pos, dst, 1);
1526 if (! (sd->flags & AF_ONEWAY)) { /* Using the start of the current segment as one starting point */
1527 start1=route_graph_get_point(this, &sd->c[0]);
1530 val1=start1->value+route_value(speedlist, &sd->item, pos->lenneg);
1531 dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1);
1533 if (! (sd->flags & AF_ONEWAYREV)) { /* Using the start of the current segment as an alternative starting point */
1534 start2=route_graph_get_point(this, &sd->c[sd->count-1]);
1537 val2=start2->value+route_value(speedlist, &sd->item, pos->lenpos);
1538 dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2);
1540 dbg(1,"val1=%d val2=%d\n", val1, val2);
1542 val1=start1->start->start->value;
1543 val2=start2->end->end->value;
1545 ret=g_new0(struct route_path, 1);
1547 route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
1548 if (start1 && (val1 < val2)) {
1550 route_path_add_item(ret, &sd->item, pos->lenneg, &pos->lp, sd->c, pos->pos+1, NULL, -1);
1554 route_path_add_item(ret, &sd->item, pos->lenpos, &pos->lp, sd->c+pos->pos+1, sd->count-pos->pos-1, NULL, 1);
1556 printf("no route found, pos blocked\n");
1560 ret->path_hash=item_hash_new();
1561 while ((s=start->seg)) { /* following start->seg, which indicates the least costly way to reach our destination */
1564 printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1569 #ifndef DISABLE_STRAIGHT
1571 is_straight = route_check_straight(lastseg,s);
1577 if (s->start == start) {
1578 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
1581 route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
1588 dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
1589 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);
1590 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 */
1591 route_path_add_item(ret, &sd->item, dst->lenneg, NULL, sd->c, dst->pos+1, &dst->lp, 1);
1592 } else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) {
1593 route_path_add_item(ret, &sd->item, dst->lenpos, NULL, sd->c+dst->pos+1, sd->count-dst->pos-1, &dst->lp, -1);
1595 printf("no route found\n");
1596 route_path_destroy(ret);
1600 route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
1601 dbg(1, "%d segments\n", segs);
1606 * @brief Builds a new route graph from a mapset
1608 * This function builds a new route graph from a map. Please note that this function does not
1609 * add any routing information to the route graph - this has to be done via the route_graph_flood()
1612 * The function does not create a graph covering the whole map, but only covering the rectangle
1613 * between c1 and c2.
1615 * @param ms The mapset to build the route graph from
1616 * @param c1 Corner 1 of the rectangle to use from the map
1617 * @param c2 Corner 2 of the rectangle to use from the map
1618 * @return The new route graph.
1620 static struct route_graph *
1621 route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
1623 struct route_graph *ret=g_new0(struct route_graph, 1);
1624 struct map_selection *sel;
1625 struct mapset_handle *h;
1626 struct map_rect *mr;
1631 printf("%s:Out of memory\n", __FUNCTION__);
1634 sel=route_calc_selection(c1, c2);
1636 while ((m=mapset_next(h,1))) {
1637 mr=map_rect_new(m, sel);
1640 while ((item=map_rect_get_item(mr))) {
1641 if (item->type >= type_street_0 && item->type <= type_ferry) {
1642 route_process_street_graph(ret, item);
1645 map_rect_destroy(mr);
1648 route_free_selection(sel);
1654 * @brief Updates the route graph
1656 * This updates the route graph after settings in the route have changed. It also
1657 * adds routing information afterwards by calling route_graph_flood().
1659 * @param this The route to update the graph for
1662 route_graph_update(struct route *this)
1664 route_graph_destroy(this->graph);
1665 profile(1,"graph_free");
1666 this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c);
1667 profile(1,"route_graph_build");
1668 route_graph_flood(this->graph, this->dst, this->speedlist);
1669 profile(1,"route_graph_flood");
1674 * @brief Gets street data for an item
1676 * @param item The item to get the data for
1677 * @return Street data for the item
1679 struct street_data *
1680 street_get_data (struct item *item)
1683 struct street_data *ret = NULL, *ret1;
1685 const int step = 128;
1689 ret1=g_realloc(ret, sizeof(struct street_data)+(count+step)*sizeof(struct coord));
1696 c = item_coord_get(item, &ret->c[count], step);
1698 } while (c && c == step);
1700 ret1=g_realloc(ret, sizeof(struct street_data)+count*sizeof(struct coord));
1705 if (item_attr_get(item, attr_flags, &attr))
1706 ret->flags=attr.u.num;
1714 * @brief Copies street data
1716 * @param orig The street data to copy
1717 * @return The copied street data
1719 struct street_data *
1720 street_data_dup(struct street_data *orig)
1722 struct street_data *ret;
1723 int size=sizeof(struct street_data)+orig->count*sizeof(struct coord);
1726 memcpy(ret, orig, size);
1732 * @brief Frees street data
1734 * @param sd Street data to be freed
1737 street_data_free(struct street_data *sd)
1743 * @brief Finds the nearest street to a given coordinate
1745 * @param ms The mapset to search in for the street
1746 * @param pc The coordinate to find a street nearby
1747 * @return The nearest street
1749 static struct route_info *
1750 route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
1752 struct route_info *ret=NULL;
1754 struct map_selection *sel;
1755 int dist,mindist=0,pos;
1756 struct mapset_handle *h;
1758 struct map_rect *mr;
1761 struct street_data *sd;
1765 ret=g_new0(struct route_info, 1);
1767 dbg(0,"Out of memory\n");
1773 while ((m=mapset_next(h,1))) {
1776 if (map_projection(m) != pc->pro) {
1777 transform_to_geo(pc->pro, &c, &g);
1778 transform_from_geo(map_projection(m), &g, &c);
1780 sel = route_rect(18, &c, &c, 0, max_dist);
1783 mr=map_rect_new(m, sel);
1785 map_selection_destroy(sel);
1788 while ((item=map_rect_get_item(mr))) {
1789 if (item->type >= type_street_0 && item->type <= type_ferry) {
1790 sd=street_get_data(item);
1793 dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos);
1794 if (dist < mindist) {
1797 street_data_free(ret->street);
1803 dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos);
1805 street_data_free(sd);
1809 map_selection_destroy(sel);
1810 map_rect_destroy(mr);
1814 if (!ret->street || mindist > max_dist*max_dist) {
1816 street_data_free(ret->street);
1817 dbg(1,"Much too far %d > %d\n", mindist, max_dist);
1827 * @brief Destroys a route_info
1829 * @param info The route info to be destroyed
1832 route_info_free(struct route_info *inf)
1835 street_data_free(inf->street);
1843 * @brief Returns street data for a route info
1845 * @param rinf The route info to return the street data for
1846 * @return Street data for the route info
1848 struct street_data *
1849 route_info_street(struct route_info *rinf)
1851 return rinf->street;
1855 struct route_crossings *
1856 route_crossings_get(struct route *this, struct coord *c)
1858 struct route_point *pnt;
1859 struct route_segment *seg;
1861 struct route_crossings *ret;
1863 pnt=route_graph_get_point(this, c);
1866 printf("start: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1868 seg=seg->start_next;
1872 printf("end: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo);
1876 ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing));
1877 ret->count=crossings;
1883 struct map_rect_priv {
1884 struct route_info_handle *ri;
1885 enum attr_type attr_next;
1887 struct map_priv *mpriv;
1890 unsigned int last_coord;
1891 struct route_path_segment *seg,*seg_next;
1892 struct route_graph_point *point;
1893 struct route_graph_segment *rseg;
1898 rm_coord_rewind(void *priv_data)
1900 struct map_rect_priv *mr = priv_data;
1905 rm_attr_rewind(void *priv_data)
1907 struct map_rect_priv *mr = priv_data;
1908 mr->attr_next = attr_street_item;
1912 rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1914 struct map_rect_priv *mr = priv_data;
1915 struct route_path_segment *seg=mr->seg;
1916 struct route *route=mr->mpriv->route;
1917 attr->type=attr_type;
1918 switch (attr_type) {
1920 while (mr->attr_next != attr_none) {
1921 if (rm_attr_get(priv_data, mr->attr_next, attr))
1925 case attr_street_item:
1926 #ifndef DISABLE_STRAIGHT
1927 mr->attr_next=attr_route_follow_straight;
1929 mr->attr_next=attr_direction;
1931 if (seg && seg->item.map)
1932 attr->u.item=&seg->item;
1936 #ifndef DISABLE_STRAIGHT
1937 case attr_route_follow_straight:
1938 mr->attr_next=attr_direction;
1940 return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
1944 case attr_direction:
1945 mr->attr_next=attr_length;
1947 attr->u.num=seg->direction;
1953 attr->u.num=seg->length;
1955 attr->u.num=mr->length;
1956 mr->attr_next=attr_time;
1959 mr->attr_next=attr_none;
1961 attr->u.num=route_time(route->speedlist, &seg->item, seg->length);
1966 mr->attr_next=attr_none;
1969 mr->attr_next=attr_none;
1970 attr->type=attr_none;
1977 rm_coord_get(void *priv_data, struct coord *c, int count)
1979 struct map_rect_priv *mr = priv_data;
1980 struct route_path_segment *seg = mr->seg;
1982 struct route *r = mr->mpriv->route;
1983 enum projection pro = route_projection(r);
1987 for (i=0; i < count; i++) {
1988 if (mr->last_coord >= seg->ncoords)
1990 if (i >= seg->ncoords)
1992 if (pro != projection_mg)
1993 transform_from_to(&seg->c[mr->last_coord++], pro,
1994 &c[i],projection_mg);
1996 c[i] = seg->c[mr->last_coord++];
1999 dbg(1,"return %d\n",rc);
2003 static struct item_methods methods_route_item = {
2011 rp_attr_rewind(void *priv_data)
2013 struct map_rect_priv *mr = priv_data;
2014 mr->attr_next = attr_label;
2018 rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
2020 struct map_rect_priv *mr = priv_data;
2021 struct route_graph_point *p = mr->point;
2022 if (mr->item.type != type_rg_point)
2024 switch (attr_type) {
2026 while (mr->attr_next != attr_none) {
2027 if (rp_attr_get(priv_data, mr->attr_next, attr))
2032 attr->type = attr_label;
2035 if (p->value != INT_MAX)
2036 mr->str=g_strdup_printf("%d", p->value);
2038 mr->str=g_strdup("-");
2039 attr->u.str = mr->str;
2040 mr->attr_next=attr_none;
2043 attr->type = attr_debug;
2046 mr->str=g_strdup_printf("x=%d y=%d", p->c.x, p->c.y);
2047 attr->u.str = mr->str;
2048 mr->attr_next=attr_none;
2051 mr->attr_next=attr_none;
2052 attr->type=attr_none;
2058 rp_coord_get(void *priv_data, struct coord *c, int count)
2060 struct map_rect_priv *mr = priv_data;
2061 struct route_graph_point *p = mr->point;
2062 struct route_graph_segment *seg = mr->rseg;
2064 struct route *r = mr->mpriv->route;
2065 enum projection pro = route_projection(r);
2067 for (i=0; i < count; i++) {
2068 if (mr->item.type == type_rg_point) {
2069 if (mr->last_coord >= 1)
2071 if (pro != projection_mg)
2072 transform_from_to(&p->c, pro,
2073 &c[i],projection_mg);
2077 if (mr->last_coord >= 2)
2080 if (seg->end->seg == seg)
2085 if (pro != projection_mg)
2086 transform_from_to(&seg->end->c, pro,
2087 &c[i],projection_mg);
2091 if (pro != projection_mg)
2092 transform_from_to(&seg->start->c, pro,
2093 &c[i],projection_mg);
2095 c[i] = seg->start->c;
2104 static struct item_methods methods_point_item = {
2112 rm_destroy(struct map_priv *priv)
2117 static struct map_rect_priv *
2118 rm_rect_new(struct map_priv *priv, struct map_selection *sel)
2120 struct map_rect_priv * mr;
2122 if (! route_get_pos(priv->route))
2124 if (! route_get_dst(priv->route))
2126 if (! priv->route->path2)
2128 mr=g_new0(struct map_rect_priv, 1);
2130 mr->item.priv_data = mr;
2131 mr->item.type = type_street_route;
2132 mr->item.meth = &methods_route_item;
2133 mr->seg_next=priv->route->path2->path;
2137 static struct map_rect_priv *
2138 rp_rect_new(struct map_priv *priv, struct map_selection *sel)
2140 struct map_rect_priv * mr;
2142 if (! priv->route->graph || ! priv->route->graph->route_points)
2144 mr=g_new0(struct map_rect_priv, 1);
2146 mr->item.priv_data = mr;
2147 mr->item.type = type_rg_point;
2148 mr->item.meth = &methods_point_item;
2153 rm_rect_destroy(struct map_rect_priv *mr)
2160 static struct item *
2161 rp_get_item(struct map_rect_priv *mr)
2163 struct route *r = mr->mpriv->route;
2164 struct route_graph_point *p = mr->point;
2165 struct route_graph_segment *seg = mr->rseg;
2167 if (mr->item.type == type_rg_point) {
2169 p = r->graph->route_points;
2175 rm_coord_rewind(mr);
2179 mr->item.type = type_rg_segment;
2182 seg=r->graph->route_segments;
2188 rm_coord_rewind(mr);
2196 static struct item *
2197 rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2199 struct item *ret=NULL;
2201 ret=rp_get_item(mr);
2206 static struct item *
2207 rm_get_item(struct map_rect_priv *mr)
2209 dbg(1,"enter\n", mr->pos);
2211 mr->seg=mr->seg_next;
2214 mr->seg_next=mr->seg->next;
2221 static struct item *
2222 rm_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
2224 struct item *ret=NULL;
2226 ret=rm_get_item(mr);
2230 static struct map_methods route_meth = {
2243 static struct map_methods route_graph_meth = {
2257 route_toggle_routegraph_display(struct route *route)
2259 if (route->flags & RF_SHOWGRAPH) {
2260 route->flags &= ~RF_SHOWGRAPH;
2262 route->flags |= RF_SHOWGRAPH;
2266 static struct map_priv *
2267 route_map_new_helper(struct map_methods *meth, struct attr **attrs, int graph)
2269 struct map_priv *ret;
2270 struct attr *route_attr;
2272 route_attr=attr_search(attrs, NULL, attr_route);
2275 ret=g_new0(struct map_priv, 1);
2277 *meth=route_graph_meth;
2280 ret->route=route_attr->u.route;
2285 static struct map_priv *
2286 route_map_new(struct map_methods *meth, struct attr **attrs)
2288 return route_map_new_helper(meth, attrs, 0);
2291 static struct map_priv *
2292 route_graph_map_new(struct map_methods *meth, struct attr **attrs)
2294 return route_map_new_helper(meth, attrs, 1);
2298 route_get_map_helper(struct route *this_, struct map **map, char *type, char *description)
2301 *map=map_new(NULL, (struct attr*[]){
2302 &(struct attr){attr_type,{type}},
2303 &(struct attr){attr_route,.u.route=this_},
2304 &(struct attr){attr_data,{""}},
2305 &(struct attr){attr_description,{description}},
2311 route_get_map(struct route *this_)
2313 return route_get_map_helper(this_, &this_->map, "route","Route");
2318 route_get_graph_map(struct route *this_)
2320 return route_get_map_helper(this_, &this_->graph_map, "route_graph","Route Graph");
2324 route_set_projection(struct route *this_, enum projection pro)
2331 plugin_register_map_type("route", route_map_new);
2332 plugin_register_map_type("route_graph", route_graph_map_new);