[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