[GRASS-SVN] r44066 -
grass/branches/releasebranch_6_4/lib/vector/dglib
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Oct 28 07:10:21 EDT 2010
Author: mmetz
Date: 2010-10-28 04:10:21 -0700 (Thu, 28 Oct 2010)
New Revision: 44066
Modified:
grass/branches/releasebranch_6_4/lib/vector/dglib/sp-template.c
Log:
fix for dglib cache BUG1 and BUG2, backport from trunk r43857, r43874, r43881
Modified: grass/branches/releasebranch_6_4/lib/vector/dglib/sp-template.c
===================================================================
--- grass/branches/releasebranch_6_4/lib/vector/dglib/sp-template.c 2010-10-28 07:29:17 UTC (rev 44065)
+++ grass/branches/releasebranch_6_4/lib/vector/dglib/sp-template.c 2010-10-28 11:10:21 UTC (rev 44066)
@@ -23,7 +23,22 @@
/*
* SHORTEST PATH CACHE
+ *
+ * components:
+ * - start node id
+ * - visited network: a node is marked as visited when its departing
+ * edges have been added to the cache
+ * - predist network: node distances from start node
+ * - NodeHeap: holds unvisited nodes, the next node extracted is the
+ * unvisited node closest to SP start
+ *
+ * not all nodes in the predist network have been visited, SP from start
+ * is known only for visited nodes
+ * unvisited nodes can be reached, but not necessarily on the shortest
+ * possible path
+ * important for DGL_SP_CACHE_DISTANCE_FUNC and DGL_SP_CACHE_REPORT_FUNC
*/
+
#if !defined(DGL_DEFINE_TREE_PROCS) && !defined(DGL_DEFINE_FLAT_PROCS)
int DGL_SP_CACHE_INITIALIZE_FUNC(dglGraph_s * pgraph, dglSPCache_s * pCache,
@@ -60,7 +75,7 @@
dglInt32_t nStart,
dglInt32_t nDestination)
{
- dglTreeTouchI32_s *pVisitedItem, VisitedItem;
+ dglTreeTouchI32_s VisitedItem;
dglTreePredist_s *pPredistItem, PredistItem;
if (pCache->nStartNode != nStart) {
@@ -69,7 +84,7 @@
}
VisitedItem.nKey = nDestination;
- if ((pVisitedItem = avl_find(pCache->pvPredist, &VisitedItem)) == NULL) {
+ if (avl_find(pCache->pvVisited, &VisitedItem) == NULL) {
pgraph->iErrno = DGL_ERR_TailNodeNotFound;
return -pgraph->iErrno;
}
@@ -106,12 +121,17 @@
}
VisitedItem.nKey = nDestination;
-
if (avl_find(pCache->pvVisited, &VisitedItem) == NULL) {
pgraph->iErrno = DGL_ERR_TailNodeNotFound;
return NULL;
}
+ PredistItem.nKey = nDestination;
+ if (avl_find(pCache->pvPredist, &PredistItem) == NULL) {
+ pgraph->iErrno = DGL_ERR_UnexpectedNullPointer;
+ return NULL;
+ }
+
for (PredistItem.nKey = nDestination,
pPredistItem = avl_find(pCache->pvPredist, &PredistItem);
pPredistItem;
@@ -312,6 +332,7 @@
dglEdgesetTraverser_s laT;
dglSPCache_s spCache;
+ int new_cache = 0;
/*
* shortest path distance temporary min heap
@@ -346,6 +367,7 @@
if (pCache == NULL) {
pCache = &spCache;
DGL_SP_CACHE_INITIALIZE_FUNC(pgraph, pCache, nStart);
+ new_cache = 1;
}
else {
if (ppReport) {
@@ -364,6 +386,7 @@
if (pgraph->iErrno == DGL_ERR_HeadNodeNotFound) {
DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
DGL_SP_CACHE_INITIALIZE_FUNC(pgraph, pCache, nStart);
+ new_cache = 1;
}
else if (pgraph->iErrno != DGL_ERR_TailNodeNotFound) {
goto sp_error;
@@ -398,44 +421,47 @@
goto sp_error;
}
- /*
- * now we inspect all edges departing from the start node
- * - at each loop 'pedge' points to the edge in the edge buffer
- * - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
- * - we insert a item in the predist network to set actual predecessor and distance
- * (there is no precedecessor at this stage) and actual distance from the starting node
- * (at this stage it equals the edge's cost)
- * - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
- * edge in the edge buffer.
- * In the case of undirected graph (version 3) we inspect input edges as well.
- */
- pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
- if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
- goto sp_error;
- }
- for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
- pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
- ) {
- __EDGELOOP_BODY_1(0);
- }
- DGL_EDGESET_T_RELEASE_FUNC(&laT);
-
- if (pgraph->Version == 3) {
- pEdgeset = _DGL_INEDGESET(pgraph, pStart);
+ /* if we do not need a new cache, we just continue with the unvisited
+ * nodes in the cache */
+ if (new_cache) {
+ /*
+ * now we inspect all edges departing from the start node
+ * - at each loop 'pedge' points to the edge in the edge buffer
+ * - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
+ * - we insert a item in the predist network to set actual predecessor and distance
+ * (there is no precedecessor at this stage) and actual distance from the starting node
+ * (at this stage it equals the edge's cost)
+ * - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
+ * edge in the edge buffer.
+ * In the case of undirected graph (version 3) we inspect input edges as well.
+ */
+ pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
goto sp_error;
}
for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
) {
- if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
- continue;
- __EDGELOOP_BODY_1(1);
+ __EDGELOOP_BODY_1(0);
}
DGL_EDGESET_T_RELEASE_FUNC(&laT);
+
+ if (pgraph->Version == 3) {
+ pEdgeset = _DGL_INEDGESET(pgraph, pStart);
+ if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
+ goto sp_error;
+ }
+ for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
+ pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
+ ) {
+ if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
+ continue;
+ __EDGELOOP_BODY_1(1);
+ }
+ DGL_EDGESET_T_RELEASE_FUNC(&laT);
+ }
}
-
/*
* Now we begin extracting nodes from the min-heap. Each node extracted is
* the one that is actually closest to the SP start.
@@ -459,7 +485,6 @@
pStart = _DGL_EDGE_HEADNODE(pgraph, pEdge); /* reversed head/tail */
}
-
/*
* We do not want to explore twice the same node as a relative starting point,
* that's the meaning of 'visited'. We mark actual start node as 'visited' by
@@ -477,20 +502,16 @@
}
/*
- * Dijkstra algorithm ends when the destination node is extracted from
- * the min distance heap, that means: no other path exist in the network giving
- * a shortest output.
- * If this happens we jump to the epilogue in order to build a path report and return.
- */
- if (DGL_NODE_ID(pStart) == nDestination) {
- goto destination_found;
- }
-
- /*
* Give up with visited nodes now
*/
if (pVisitedItem) {
- continue;
+ if (DGL_NODE_ID(pStart) == nDestination) {
+ /* should not happen but does not harm
+ * this case should have been handled above */
+ goto destination_found;
+ }
+ else
+ continue;
}
/*
@@ -498,8 +519,13 @@
* blind alley. Just give up this direction and continue looping.
* This only applies to v1 and v2 (digraphs)
*/
- if (!(DGL_NODE_STATUS(pStart) & DGL_NS_HEAD) && pgraph->Version < 3)
- continue;
+ if (!(DGL_NODE_STATUS(pStart) & DGL_NS_HEAD) && pgraph->Version < 3) {
+ if (DGL_NODE_ID(pStart) == nDestination) {
+ goto destination_found;
+ }
+ else
+ continue;
+ }
/*
* save actual edge for later clip()
@@ -523,6 +549,10 @@
* Scan the edgeset and loads pedge at each iteration with next-edge.
* iWay == DGL_EDGESET_T_WAY_OUT then pedge is a out arc (departing from node) else ot is a in arc.
* V1 has no in-degree support so iWay is always OUT, V2/3 have in-degree support.
+ *
+ * This loop needs to be done also when destination is found, otherwise
+ * the node is marked as visited but its departing edges are not added to the cache
+ * --> loose end, we might need these edges later on
*/
pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
@@ -549,13 +579,23 @@
}
DGL_EDGESET_T_RELEASE_FUNC(&laT);
}
+
+ /*
+ * Dijkstra algorithm ends when the destination node is extracted from
+ * the min distance heap, that means: no other path exist in the network giving
+ * a shortest output.
+ * If this happens we jump to the epilogue in order to build a path report and return.
+ */
+ if (DGL_NODE_ID(pStart) == nDestination) {
+ goto destination_found;
+ }
}
sp_error:
if (pCache == &spCache) {
DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
}
- return -pgraph->iErrno; /* ==0 path not found */
+ return -pgraph->iErrno; /* == 0 path not found */
destination_found: /* path found - build a shortest path report or report the distance only */
More information about the grass-commit
mailing list