123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- /*!
- \file vector/neta/path.c
- \brief Network Analysis library - shortest path
- Shortest paths from a set of nodes.
- (C) 2009-2010 by Daniel Bundala, and the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author Daniel Bundala (Google Summer of Code 2009)
- \author Markus Metz
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <grass/gis.h>
- #include <grass/vector.h>
- #include <grass/glocale.h>
- #include <grass/dgl/graph.h>
- #include <grass/neta.h>
- /*!
- \brief Computes shortest paths to every node from nodes in "from".
- Array "dst" contains the cost of the path or -1 if the node is not
- reachable. Prev contains edges from predecessor along the shortest
- path.
- \param graph input graph
- \param from list of 'from' positions
- \param[out] dst array of costs to reach nodes
- \param[out] prev array of edges from predecessor along the shortest path
- \return 0 on success
- \return -1 on failure
- */
- int NetA_distance_from_points(dglGraph_s *graph, struct ilist *from,
- int *dst, dglInt32_t **prev)
- {
- int i, nnodes;
- dglHeap_s heap;
- int have_node_costs;
- dglInt32_t ncost;
- nnodes = dglGet_NodeCount(graph);
- dglEdgesetTraverser_s et;
- /* initialize costs and edge list */
- for (i = 1; i <= nnodes; i++) {
- dst[i] = -1;
- prev[i] = NULL;
- }
- ncost = 0;
- have_node_costs = dglGet_NodeAttrSize(graph);
- dglHeapInit(&heap);
- for (i = 0; i < from->n_values; i++) {
- int v = from->value[i];
- if (dst[v] == 0)
- continue; /* ignore duplicates */
- dst[v] = 0; /* make sure all from nodes are processed first */
- dglHeapData_u heap_data;
- heap_data.ul = v;
- dglHeapInsertMin(&heap, 0, ' ', heap_data);
- }
- while (1) {
- dglInt32_t v, dist;
- dglHeapNode_s heap_node;
- dglHeapData_u heap_data;
- dglInt32_t *edge;
- dglInt32_t *node;
- if (!dglHeapExtractMin(&heap, &heap_node))
- break;
- v = heap_node.value.ul;
- dist = heap_node.key;
- if (dst[v] < dist)
- continue;
- node = dglGetNode(graph, v);
- if (have_node_costs && prev[v]) {
- memcpy(&ncost, dglNodeGet_Attr(graph, node),
- sizeof(ncost));
- if (ncost > 0)
- dist += ncost;
- /* do not go through closed nodes */
- if (ncost < 0)
- continue;
- }
- dglEdgeset_T_Initialize(&et, graph,
- dglNodeGet_OutEdgeset(graph, node));
- for (edge = dglEdgeset_T_First(&et); edge;
- edge = dglEdgeset_T_Next(&et)) {
- dglInt32_t *to = dglEdgeGet_Tail(graph, edge);
- dglInt32_t to_id = dglNodeGet_Id(graph, to);
- dglInt32_t d = dglEdgeGet_Cost(graph, edge);
- if (dst[to_id] < 0 || dst[to_id] > dist + d) {
- dst[to_id] = dist + d;
- prev[to_id] = edge;
- heap_data.ul = to_id;
- dglHeapInsertMin(&heap, dist + d, ' ', heap_data);
- }
- }
- dglEdgeset_T_Release(&et);
- }
- dglHeapFree(&heap, NULL);
- return 0;
- }
- /*!
- \brief Computes shortest paths from every node to nodes in "to".
- Array "dst" contains the cost of the path or -1 if the node is not
- reachable. Nxt contains edges from successor along the shortest
- path. This method does reverse search starting with "to" nodes and
- going backward.
- \param graph input graph
- \param to list of 'to' positions
- \param[out] dst array of costs to reach nodes
- \param[out] nxt array of edges from successor along the shortest path
- \return 0 on success
- \return -1 on failure
- */
- int NetA_distance_to_points(dglGraph_s *graph, struct ilist *to,
- int *dst, dglInt32_t **nxt)
- {
- int i, nnodes;
- dglHeap_s heap;
- dglEdgesetTraverser_s et;
- int have_node_costs;
- dglInt32_t ncost;
- nnodes = dglGet_NodeCount(graph);
- /* initialize costs and edge list */
- for (i = 1; i <= nnodes; i++) {
- dst[i] = -1;
- nxt[i] = NULL;
- }
- if (graph->Version < 2) {
- G_warning("Directed graph must be version 2 or 3 for NetA_distance_to_points()");
- return -1;
- }
- ncost = 0;
- have_node_costs = dglGet_NodeAttrSize(graph);
- dglHeapInit(&heap);
- for (i = 0; i < to->n_values; i++) {
- int v = to->value[i];
- if (dst[v] == 0)
- continue; /* ignore duplicates */
- dst[v] = 0; /* make sure all to nodes are processed first */
- dglHeapData_u heap_data;
- heap_data.ul = v;
- dglHeapInsertMin(&heap, 0, ' ', heap_data);
- }
- while (1) {
- dglInt32_t v, dist;
- dglHeapNode_s heap_node;
- dglHeapData_u heap_data;
- dglInt32_t *edge;
- dglInt32_t *node;
- if (!dglHeapExtractMin(&heap, &heap_node))
- break;
- v = heap_node.value.ul;
- dist = heap_node.key;
- if (dst[v] < dist)
- continue;
- node = dglGetNode(graph, v);
- if (have_node_costs && nxt[v]) {
- memcpy(&ncost, dglNodeGet_Attr(graph, node),
- sizeof(ncost));
- if (ncost > 0)
- dist += ncost;
- /* do not go through closed nodes */
- if (ncost < 0)
- continue;
- }
- dglEdgeset_T_Initialize(&et, graph,
- dglNodeGet_InEdgeset(graph, node));
- for (edge = dglEdgeset_T_First(&et); edge;
- edge = dglEdgeset_T_Next(&et)) {
- dglInt32_t *from = dglEdgeGet_Head(graph, edge);
- dglInt32_t from_id = dglNodeGet_Id(graph, from);
- dglInt32_t d = dglEdgeGet_Cost(graph, edge);
- if (dst[from_id] < 0 || dst[from_id] > dist + d) {
- dst[from_id] = dist + d;
- nxt[from_id] = edge;
- heap_data.ul = from_id;
- dglHeapInsertMin(&heap, dist + d, ' ', heap_data);
- }
- }
- dglEdgeset_T_Release(&et);
- }
- dglHeapFree(&heap, NULL);
- return 0;
- }
- /*!
- \brief Find a path (minimum number of edges) from 'from' to 'to'
- using only edges flagged as valid in 'edges'. Edge costs are not
- considered. Closed nodes are not traversed.
- Precisely, edge with id I is used if edges[abs(i)] == 1. List
- stores the indices of lines on the path. The method returns the
- number of edges or -1 if no path exists.
- \param graph input graph
- \param from 'from' position
- \param to 'to' position
- \param edges array of edges indicating whether an edge should be used
- \param[out] list list of edges
- \return number of edges
- \return -1 on failure
- */
- int NetA_find_path(dglGraph_s * graph, int from, int to, int *edges,
- struct ilist *list)
- {
- dglInt32_t **prev, *queue;
- dglEdgesetTraverser_s et;
- char *vis;
- int begin, end, cur, nnodes;
- int have_node_costs;
- dglInt32_t ncost;
- nnodes = dglGet_NodeCount(graph);
- prev = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
- queue = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t));
- vis = (char *)G_calloc(nnodes + 1, sizeof(char));
- if (!prev || !queue || !vis) {
- G_fatal_error(_("Out of memory"));
- return -1;
- }
- Vect_reset_list(list);
- ncost = 0;
- have_node_costs = dglGet_NodeAttrSize(graph);
- begin = 0;
- end = 1;
- vis[from] = 'y';
- queue[0] = from;
- prev[from] = NULL;
- while (begin != end) {
- dglInt32_t vertex = queue[begin++];
- dglInt32_t *edge, *node;
- if (vertex == to)
- break;
- /* do not go through closed nodes */
- if (have_node_costs && prev[vertex]) {
- memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)),
- sizeof(ncost));
- if (ncost < 0)
- continue;
- }
- node = dglGetNode(graph, vertex);
- dglEdgeset_T_Initialize(&et, graph,
- dglNodeGet_OutEdgeset(graph, node));
- for (edge = dglEdgeset_T_First(&et); edge;
- edge = dglEdgeset_T_Next(&et)) {
- dglInt32_t edge_id = labs(dglEdgeGet_Id(graph, edge));
- dglInt32_t node_id =
- dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge));
- if (edges[edge_id] && !vis[node_id]) {
- vis[node_id] = 'y';
- prev[node_id] = edge;
- queue[end++] = node_id;
- }
- }
- dglEdgeset_T_Release(&et);
- }
- G_free(queue);
- if (!vis[to]) {
- G_free(prev);
- G_free(vis);
- return -1;
- }
- cur = to;
- while (prev[cur] != NULL) {
- Vect_list_append(list, labs(dglEdgeGet_Id(graph, prev[cur])));
- cur = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, prev[cur]));
- }
- G_free(prev);
- G_free(vis);
- return list->n_values;
- }
|