[GRASS-SVN] r44857 - grass/trunk/lib/vector/diglib

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Jan 4 05:09:36 EST 2011


Author: mmetz
Date: 2011-01-04 02:09:36 -0800 (Tue, 04 Jan 2011)
New Revision: 44857

Modified:
   grass/trunk/lib/vector/diglib/spindex.c
   grass/trunk/lib/vector/diglib/spindex_rw.c
Log:
new spatial index

Modified: grass/trunk/lib/vector/diglib/spindex.c
===================================================================
--- grass/trunk/lib/vector/diglib/spindex.c	2011-01-04 10:08:04 UTC (rev 44856)
+++ grass/trunk/lib/vector/diglib/spindex.c	2011-01-04 10:09:36 UTC (rev 44857)
@@ -15,9 +15,11 @@
    \author Update to GRASS 7 Markus Metz
  */
 
-#include <grass/config.h>
 #include <stdlib.h>
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <string.h>
 #include <grass/gis.h>
 #include <grass/vector.h>
@@ -37,15 +39,45 @@
 
     ndims = (Plus->with_z != 0) ? 3 : 2;
     Plus->spidx_with_z = (Plus->with_z != 0);
+    
+    if (Plus->Spidx_file) {
+	int fd;
+	char *filename;
+	
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Node_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
 
-    Plus->Node_spidx = RTreeNewIndex(ndims);
-    Plus->Line_spidx = RTreeNewIndex(ndims);
-    Plus->Area_spidx = RTreeNewIndex(ndims);
-    Plus->Isle_spidx = RTreeNewIndex(ndims);
-    Plus->Face_spidx = NULL;
-    Plus->Volume_spidx = NULL;
-    Plus->Hole_spidx = NULL;
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Line_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
 
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Area_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Isle_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+
+	Plus->Face_spidx = NULL;
+	Plus->Volume_spidx = NULL;
+	Plus->Hole_spidx = NULL;
+    }
+    else {
+	Plus->Node_spidx = RTreeNewIndex(-1, 0, ndims);
+	Plus->Line_spidx = RTreeNewIndex(-1, 0, ndims);
+	Plus->Area_spidx = RTreeNewIndex(-1, 0, ndims);
+	Plus->Isle_spidx = RTreeNewIndex(-1, 0, ndims);
+	Plus->Face_spidx = NULL;
+	Plus->Volume_spidx = NULL;
+	Plus->Hole_spidx = NULL;
+    }
+
     Plus->Node_spidx_offset = 0L;
     Plus->Line_spidx_offset = 0L;
     Plus->Area_spidx_offset = 0L;
@@ -71,8 +103,21 @@
     ndims = Plus->with_z ? 3 : 2;
 
     /* Node spidx */
-    RTreeFreeIndex(Plus->Node_spidx);
-    Plus->Node_spidx = RTreeNewIndex(ndims);
+    if (Plus->Node_spidx->fd > -1) {
+	int fd;
+	char *filename;
+	
+	close(Plus->Node_spidx->fd);
+	RTreeFreeIndex(Plus->Node_spidx);
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Node_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+    }
+    else {
+	RTreeFreeIndex(Plus->Node_spidx);
+	Plus->Node_spidx = RTreeNewIndex(-1, 0, ndims);
+    }
 }
 
 /*! 
@@ -87,8 +132,21 @@
     ndims = Plus->with_z ? 3 : 2;
 
     /* Line spidx */
-    RTreeFreeIndex(Plus->Line_spidx);
-    Plus->Line_spidx = RTreeNewIndex(ndims);
+    if (Plus->Line_spidx->fd > -1) {
+	int fd;
+	char *filename;
+	
+	close(Plus->Line_spidx->fd);
+	RTreeFreeIndex(Plus->Line_spidx);
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Line_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+    }
+    else {
+	RTreeFreeIndex(Plus->Line_spidx);
+	Plus->Line_spidx = RTreeNewIndex(-1, 0, ndims);
+    }
 }
 
 /*! 
@@ -103,8 +161,21 @@
     ndims = Plus->with_z ? 3 : 2;
 
     /* Area spidx */
-    RTreeFreeIndex(Plus->Area_spidx);
-    Plus->Area_spidx = RTreeNewIndex(ndims);
+    if (Plus->Area_spidx->fd > -1) {
+	int fd;
+	char *filename;
+	
+	close(Plus->Area_spidx->fd);
+	RTreeFreeIndex(Plus->Area_spidx);
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Area_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+    }
+    else {
+	RTreeFreeIndex(Plus->Area_spidx);
+	Plus->Area_spidx = RTreeNewIndex(-1, 0, ndims);
+    }
 }
 
 /*! 
@@ -119,8 +190,21 @@
     ndims = Plus->with_z ? 3 : 2;
 
     /* Isle spidx */
-    RTreeFreeIndex(Plus->Isle_spidx);
-    Plus->Isle_spidx = RTreeNewIndex(ndims);
+    if (Plus->Isle_spidx->fd > -1) {
+	int fd;
+	char *filename;
+	
+	close(Plus->Isle_spidx->fd);
+	RTreeFreeIndex(Plus->Isle_spidx);
+	filename = G_tempfile();
+	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+	Plus->Isle_spidx = RTreeNewIndex(fd, 0, ndims);
+	remove(filename);
+    }
+    else {
+	RTreeFreeIndex(Plus->Isle_spidx);
+	Plus->Isle_spidx = RTreeNewIndex(-1, 0, ndims);
+    }
 }
 
 /*! 
@@ -131,16 +215,29 @@
 void dig_spidx_free(struct Plus_head *Plus)
 {
     /* Node spidx */
+    if (Plus->Node_spidx->fd > -1)
+	close(Plus->Node_spidx->fd);
     RTreeFreeIndex(Plus->Node_spidx);
 
     /* Line spidx */
+    if (Plus->Line_spidx->fd > -1)
+	close(Plus->Line_spidx->fd);
     RTreeFreeIndex(Plus->Line_spidx);
 
     /* Area spidx */
+    if (Plus->Area_spidx->fd > -1)
+	close(Plus->Area_spidx->fd);
     RTreeFreeIndex(Plus->Area_spidx);
 
     /* Isle spidx */
+    if (Plus->Isle_spidx->fd > -1)
+	close(Plus->Isle_spidx->fd);
     RTreeFreeIndex(Plus->Isle_spidx);
+
+    /* 3D future : */
+    /* Face spidx */
+    /* Volume spidx */
+    /* Hole spidx */
 }
 
 /*!

Modified: grass/trunk/lib/vector/diglib/spindex_rw.c
===================================================================
--- grass/trunk/lib/vector/diglib/spindex_rw.c	2011-01-04 10:08:04 UTC (rev 44856)
+++ grass/trunk/lib/vector/diglib/spindex_rw.c	2011-01-04 10:09:36 UTC (rev 44857)
@@ -24,21 +24,6 @@
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
-
-struct FBranch			/* branch for file based index */
-{
-    struct Rect rect;
-    off_t child;		/* position of child node in file */
-};
-
-struct FNode			/* node for file based index */
-{
-    int count;			/* number of branches */
-    int level;			/* 0 is leaf, others positive */
-    struct FBranch branch[MAXCARD];
-};
-
-
 /*!
    \brief Write spatial index header to file
 
@@ -115,10 +100,10 @@
     /* identical for all spatial indices: */
     t = ptr->Node_spidx;
     /* byte 12 : n dimensions */
-    if (0 >= dig__fwrite_port_C(&(t->ndims), 1, fp))
+    if (0 >= dig__fwrite_port_C((const char *)&(t->ndims), 1, fp))
 	return (-1);
     /* byte 13 : n sides */
-    if (0 >= dig__fwrite_port_C(&(t->nsides), 1, fp))
+    if (0 >= dig__fwrite_port_C((const char *)&(t->nsides), 1, fp))
 	return (-1);
     /* bytes 14 - 17 : nodesize */
     if (0 >= dig__fwrite_port_I(&(t->nodesize), 1, fp))
@@ -140,13 +125,13 @@
 
     /* Node spatial index */
     /* bytes 34 - 37 : n nodes */
-    if (0 >= dig__fwrite_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 38 - 41 : n leafs */
-    if (0 >= dig__fwrite_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 42 - 45 : n levels */
-    if (0 >= dig__fwrite_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 46 - 49 (LFS 53) : root node offset */
     if (0 >=
@@ -157,13 +142,13 @@
     /* Line spatial index */
     t = ptr->Line_spidx;
     /* bytes 50 - 53 (LFS 54 - 57) : n nodes */
-    if (0 >= dig__fwrite_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 54 - 57 (LFS 58 - 61) : n leafs */
-    if (0 >= dig__fwrite_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 58 - 61 (LFS 62 - 65) : n levels */
-    if (0 >= dig__fwrite_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 62 - 65 (LFS 66 - 73) : root node offset */
     if (0 >=
@@ -174,13 +159,13 @@
     /* Area spatial index */
     t = ptr->Area_spidx;
     /* bytes 66 - 69 (LFS 74 - 77) : n nodes */
-    if (0 >= dig__fwrite_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 70 - 73 (LFS 78 - 81) : n leafs */
-    if (0 >= dig__fwrite_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 74 - 77 (LFS 82 - 85) : n levels */
-    if (0 >= dig__fwrite_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 78 - 81 (LFS 86 - 93) : root node offset */
     if (0 >=
@@ -191,13 +176,13 @@
     /* Isle spatial index */
     t = ptr->Isle_spidx;
     /* bytes 82 - 85 (LFS 94 - 97) : n nodes */
-    if (0 >= dig__fwrite_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 86 - 89 (LFS 98 - 101) : n leafs */
-    if (0 >= dig__fwrite_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 90 - 93 (LFS 102 - 105) : n levels */
-    if (0 >= dig__fwrite_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 94 - 97 (LFS 106 - 113) : root node offset */
     if (0 >=
@@ -338,14 +323,14 @@
     /* identical for all spatial indices: */
     t = ptr->Node_spidx;
     /* byte 12 : n dimensions */
-    if (0 >= dig__fread_port_C(&(t->ndims), 1, fp))
+    if (0 >= dig__fread_port_C((char *)&(t->ndims), 1, fp))
 	return (-1);
     ptr->Line_spidx->ndims = t->ndims;
     ptr->Area_spidx->ndims = t->ndims;
     ptr->Isle_spidx->ndims = t->ndims;
 
     /* byte 13 : n sides */
-    if (0 >= dig__fread_port_C(&(t->nsides), 1, fp))
+    if (0 >= dig__fread_port_C((char *)&(t->nsides), 1, fp))
 	return (-1);
     ptr->Line_spidx->nsides = t->nsides;
     ptr->Area_spidx->nsides = t->nsides;
@@ -390,13 +375,13 @@
 
     /* Node spatial index */
     /* bytes 34 - 37 : n nodes */
-    if (0 >= dig__fread_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 38 - 41 : n leafs */
-    if (0 >= dig__fread_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 42 - 45 : n levels */
-    if (0 >= dig__fread_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 46 - 49 (LFS 53) : root node offset */
     if (0 >=
@@ -408,13 +393,13 @@
     /* Line spatial index */
     t = ptr->Line_spidx;
     /* bytes 50 - 53 (LFS 54 - 57) : n nodes */
-    if (0 >= dig__fread_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 54 - 57 (LFS 58 - 61) : n leafs */
-    if (0 >= dig__fread_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 58 - 61 (LFS 62 - 65) : n levels */
-    if (0 >= dig__fread_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 62 - 65 (LFS 66 - 73) : root node offset */
     if (0 >=
@@ -426,13 +411,13 @@
     /* Area spatial index */
     t = ptr->Area_spidx;
     /* bytes 66 - 69 (LFS 74 - 77) : n nodes */
-    if (0 >= dig__fread_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 70 - 73 (LFS 78 - 81) : n leafs */
-    if (0 >= dig__fread_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 74 - 77 (LFS 82 - 85) : n levels */
-    if (0 >= dig__fread_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 78 - 81 (LFS 86 - 93) : root node offset */
     if (0 >=
@@ -444,13 +429,13 @@
     /* Isle spatial index */
     t = ptr->Isle_spidx;
     /* bytes 82 - 85 (LFS 94 - 97) : n nodes */
-    if (0 >= dig__fread_port_I(&(t->n_nodes), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
 	return (-1);
     /* bytes 86 - 89 (LFS 98 - 101) : n leafs */
-    if (0 >= dig__fread_port_I(&(t->n_leafs), 1, fp))
+    if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
 	return (-1);
     /* bytes 90 - 93 (LFS 102 - 105) : n levels */
-    if (0 >= dig__fread_port_I(&(t->n_levels), 1, fp))
+    if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
 	return (-1);
     /* bytes 94 - 97 (LFS 106 - 113) : root node offset */
     if (0 >=
@@ -598,13 +583,13 @@
    \return offset to root node on success
  */
 
-static off_t rtree_write_to_sidx(struct gvfile * fp, off_t startpos,
+static off_t rtree_write_from_memory(struct gvfile *fp, off_t startpos,
 				 struct RTree *t, int off_t_size)
 {
     off_t nextfreepos = startpos;
-    int sidx_nodesize;
+    int sidx_nodesize, sidx_leafsize;
     struct Node *n;
-    int i, j, writeout;
+    int i, j, writeout, maxcard;
     struct spidxstack
     {
 	off_t pos[MAXCARD];	/* file position of child node, object ID on level 0 */
@@ -615,9 +600,11 @@
 
     /* should be foolproof */
     sidx_nodesize =
-	(int)(2 * PORT_INT + MAXCARD * (off_t_size + NUMSIDES * PORT_DOUBLE));
+	(int)(2 * PORT_INT + t->nodecard * (off_t_size + NUMSIDES * PORT_DOUBLE));
+    sidx_leafsize =
+	(int)(2 * PORT_INT + t->leafcard * (off_t_size + NUMSIDES * PORT_DOUBLE));
 
-    /* stack size of t->n_levels + 1 would be enough because of
+    /* stack size of t->rootlevel + 1 would be enough because of
      * depth-first post-order traversal:
      * only one node per level on stack at any given time */
 
@@ -661,7 +648,8 @@
 	    /* write with dig__fwrite_port_* fns */
 	    dig__fwrite_port_I(&(s[top].sn->count), 1, fp);
 	    dig__fwrite_port_I(&(s[top].sn->level), 1, fp);
-	    for (j = 0; j < MAXCARD; j++) {
+	    maxcard = s[top].sn->level ? t->nodecard : t->leafcard;
+	    for (j = 0; j < maxcard; j++) {
 		dig__fwrite_port_D(s[top].sn->branch[j].rect.boundary,
 				   NUMSIDES, fp);
 		/* leaf node: vector object IDs are stored in child.id */
@@ -678,7 +666,7 @@
 	     * they hold the position in file of the next nodes down the tree */
 	    if (top >= 0) {
 		s[top].pos[s[top].branch_id - 1] = nextfreepos;
-		nextfreepos += sidx_nodesize;
+		nextfreepos += (s[top + 1].sn->level ? sidx_nodesize : sidx_leafsize);
 	    }
 	}
     }
@@ -688,6 +676,123 @@
 
 
 /*!
+   \brief Write RTree body from temporary file to sidx file
+   Must be called when new or updated vector is closed
+
+   \param[out] fp pointer to struct gvfile
+   \param startpos offset to struct gvfile where to start writing out
+   \param t pointer to RTree
+   \param off_t_size size of off_t used to write struct gvfile
+
+   \return -1 on error
+   \return offset to root node on success
+ */
+
+static off_t rtree_write_from_file(struct gvfile *fp, off_t startpos,
+				 struct RTree *t, int off_t_size)
+{
+    off_t nextfreepos = startpos;
+    int sidx_nodesize, sidx_leafsize;
+    struct Node *n;
+    int i, j, writeout, maxcard;
+    struct spidxstack
+    {
+	off_t pos[MAXCARD];	/* file position of child node, object ID on level 0 */
+	struct Node sn;		/* stack node */
+	int branch_id;		/* branch no to follow down */
+    } s[MAXLEVEL];
+    int top = 0;
+    
+    /* write pending changes to file */
+    RTreeFlushBuffer(t);
+
+    /* should be foolproof */
+    sidx_nodesize =
+	(int)(2 * PORT_INT + t->nodecard * (off_t_size + NUMSIDES * PORT_DOUBLE));
+    sidx_leafsize =
+	(int)(2 * PORT_INT + t->leafcard * (off_t_size + NUMSIDES * PORT_DOUBLE));
+
+    /* stack size of t->rootlevel + 1 would be enough because of
+     * depth-first post-order traversal:
+     * only one node per level on stack at any given time */
+
+    /* add root node position to stack */
+    s[top].branch_id = i = 0;
+    RTreeReadNode(&s[top].sn, t->rootpos, t);
+
+    /* depth-first postorder traversal 
+     * all children of a node are visitied and written out first
+     * when a child is written out, its position in file is stored in pos[] for
+     * the parent node and written out with the parent node */
+    /* root node is written out last and its position returned */
+
+    while (top >= 0) {
+	n = &(s[top].sn);
+	writeout = 1;
+	/* this is an internal node in the RTree
+	 * all its children are processed first,
+	 * before it is written out to the sidx file */
+	if (s[top].sn.level > 0) {
+	    for (i = s[top].branch_id; i < t->nodecard; i++) {
+		s[top].pos[i] = -1;
+		if (n->branch[i].child.pos >= 0) {
+		    s[top++].branch_id = i + 1;
+		    RTreeReadNode(&s[top].sn, n->branch[i].child.pos, t);
+		    s[top].branch_id = 0;
+		    writeout = 0;
+		    break;
+		}
+	    }
+	    if (writeout) {
+		/* nothing else found, ready to write out */
+		s[top].branch_id = t->nodecard;
+	    }
+	}
+	if (writeout) {
+	    /* write node to sidx file */
+	    if (G_ftell(fp->file) != nextfreepos)
+		G_fatal_error(_("Writing sidx: wrong node position in file"));
+
+	    /* write with dig__fwrite_port_* fns */
+	    dig__fwrite_port_I(&(s[top].sn.count), 1, fp);
+	    dig__fwrite_port_I(&(s[top].sn.level), 1, fp);
+	    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+	    for (j = 0; j < maxcard; j++) {
+		dig__fwrite_port_D(s[top].sn.branch[j].rect.boundary,
+				   NUMSIDES, fp);
+		/* leaf node: vector object IDs are stored in child.id */
+		if (s[top].sn.level == 0)
+		    s[top].pos[j] = (off_t) s[top].sn.branch[j].child.id;
+		dig__fwrite_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
+	    }
+
+	    top--;
+	    /* update corresponding child position of parent node
+	     * this node is only updated if its level is > 0, i.e.
+	     * this is an internal node
+	     * children of internal nodes do not have an ID, instead
+	     * they hold the position in file of the next nodes down the tree */
+	    if (top >= 0) {
+		s[top].pos[s[top].branch_id - 1] = nextfreepos;
+		nextfreepos += (s[top + 1].sn.level ? sidx_nodesize : sidx_leafsize);
+	    }
+	}
+    }
+    
+    return nextfreepos;
+}
+
+/* write RTree body to sidx file */
+static off_t rtree_write_to_sidx(struct gvfile *fp, off_t startpos,
+				 struct RTree *t, int off_t_size)
+{
+    if (t->fd > -1)
+	return rtree_write_from_file(fp, startpos, t, off_t_size);
+    else
+	return rtree_write_from_memory(fp, startpos, t, off_t_size);
+}
+
+/*!
    \brief Load RTree body from sidx file to memory
    Must be called when old vector is opened in update mode
 
@@ -699,21 +804,20 @@
    \return pointer to root node on success
  */
 
-struct Node *rtree_load_from_sidx(struct gvfile * fp, off_t rootpos,
+static void rtree_load_to_memory(struct gvfile *fp, off_t rootpos,
 				  struct RTree *t, int off_t_size)
 {
     struct Node *newnode = NULL;
-    int i, j, loadnode;
+    int i, j, loadnode, maxcard;
     struct spidxstack
     {
-	off_t childpos[MAXCARD];
-	off_t pos;		/* file position of child node */
+	off_t pos[MAXCARD];	/* file position of child node, object ID on level 0 */
 	struct Node sn;		/* stack node */
 	int branch_id;		/* branch no to follow down */
     } s[50], *last;
     int top = 0;
 
-    /* stack size of t->n_levels + 1 would be enough because of
+    /* stack size of t->rootlevel + 1 would be enough because of
      * depth-first postorder traversal:
      * only one node per level on stack at any given time */
 
@@ -723,17 +827,13 @@
     /* read with dig__fread_port_* fns */
     dig__fread_port_I(&(s[top].sn.count), 1, fp);
     dig__fread_port_I(&(s[top].sn.level), 1, fp);
-    for (j = 0; j < MAXCARD; j++) {
+    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+    for (j = 0; j < maxcard; j++) {
 	dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, fp);
-	dig__fread_port_O(&(s[top].childpos[j]), 1, fp, off_t_size);
+	dig__fread_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
 	/* leaf node: vector object IDs are stored in child.id */
 	if (s[top].sn.level == 0) {
-	    if (s[top].childpos[j]) {
-	    s[top].sn.branch[j].child.id =
-		(int)s[top].childpos[j];
-	    }
-	    else
-		s[top].sn.branch[j].child.id = 0;
+	    s[top].sn.branch[j].child.id = (int)s[top].pos[j];
 	}
 	else {
 	    s[top].sn.branch[j].child.ptr = NULL;
@@ -753,29 +853,25 @@
 	 * before it is transfered to the RTree in memory */
 	if (s[top].sn.level > 0) {
 	    for (i = s[top].branch_id; i < t->nodecard; i++) {
-		if (s[top].childpos[i] > 0) {
+		if (s[top].pos[i] > 0) {
 		    s[top++].branch_id = i + 1;
-		    s[top].pos = last->childpos[i];
-		    G_fseek(fp->file, s[top].pos, SEEK_SET);
+		    G_fseek(fp->file, last->pos[i], SEEK_SET);
 		    /* read with dig__fread_port_* fns */
 		    dig__fread_port_I(&(s[top].sn.count), 1, fp);
 		    dig__fread_port_I(&(s[top].sn.level), 1, fp);
-		    for (j = 0; j < MAXCARD; j++) {
+		    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+		    for (j = 0; j < maxcard; j++) {
 			dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
 					  NUMSIDES, fp);
-			dig__fread_port_O(&(s[top].childpos[j]), 1, fp,
+			dig__fread_port_O(&(s[top].pos[j]), 1, fp,
 					  off_t_size);
 			/* leaf node
 			 * vector object IDs are stored in file as
 			 * off_t but always fit into an int, see dig_structs.h
 			 * vector object IDs are transfered to child.id */
 			if (s[top].sn.level == 0) {
-			    if (s[top].childpos[j]) {
-				s[top].sn.branch[j].child.id =
-				    (int)s[top].childpos[j];
-			    }
-			    else
-				s[top].sn.branch[j].child.id = 0;
+			    s[top].sn.branch[j].child.id =
+				(int)s[top].pos[j];
 			}
 			else {
 			    s[top].sn.branch[j].child.ptr = NULL;
@@ -785,7 +881,7 @@
 		    loadnode = 0;
 		    break;
 		}
-		else if (last->childpos[i] < 0)
+		else if (last->pos[i] < 0)
 		    G_fatal_error("corrupt spatial index");
 	    }
 	    if (loadnode) {
@@ -800,7 +896,8 @@
 	    /* copy from stack node */
 	    newnode->level = s[top].sn.level;
 	    newnode->count = s[top].sn.count;
-	    for (j = 0; j < MAXCARD; j++) {
+	    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+	    for (j = 0; j < maxcard; j++) {
 		newnode->branch[j].rect = s[top].sn.branch[j].rect;
 		newnode->branch[j].child = s[top].sn.branch[j].child;
 	    }
@@ -816,10 +913,146 @@
 	    }
 	}
     }
+    
+    t->root = newnode;
+}
 
-    return newnode;
+/*!
+   \brief Load RTree body from sidx file to temporary file
+   Must be called when old vector is opened in update mode
+
+   \param fp pointer to struct gvfile
+   \param rootpos position of root node in file
+   \param t pointer to RTree
+   \param off_t_size size of off_t used to read struct gvfile
+
+   \return offset to root node
+ */
+
+static void rtree_load_to_file(struct gvfile *fp, off_t rootpos,
+				  struct RTree *t, int off_t_size)
+{
+    struct Node newnode;
+    off_t newnode_pos = -1;
+    int i, j, loadnode, maxcard;
+    struct spidxstack
+    {
+	off_t pos[MAXCARD];	/* file position of child node, object ID on level 0 */
+	struct Node sn;		/* stack node */
+	int branch_id;		/* branch no to follow down */
+    } s[MAXLEVEL], *last;
+    int top = 0;
+
+    /* stack size of t->rootlevel + 1 would be enough because of
+     * depth-first postorder traversal:
+     * only one node per level on stack at any given time */
+
+    /* add root node position to stack */
+    last = &(s[top]);
+    G_fseek(fp->file, rootpos, SEEK_SET);
+    /* read with dig__fread_port_* fns */
+    dig__fread_port_I(&(s[top].sn.count), 1, fp);
+    dig__fread_port_I(&(s[top].sn.level), 1, fp);
+    maxcard = t->rootlevel ? t->nodecard : t->leafcard;
+    for (j = 0; j < maxcard; j++) {
+	dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, fp);
+	dig__fread_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
+	/* leaf node: vector object IDs are stored in child.id */
+	if (s[top].sn.level == 0) {
+	    s[top].sn.branch[j].child.id = (int)s[top].pos[j];
+	}
+	else {
+	    s[top].sn.branch[j].child.pos = -1;
+	}
+    }
+
+    s[top].branch_id = i = 0;
+
+    /* depth-first postorder traversal */
+    /* root node is loaded last and returned */
+
+    while (top >= 0) {
+	last = &(s[top]);
+	loadnode = 1;
+	/* this is an internal node in the RTree
+	 * all its children are read first,
+	 * before it is transfered to the RTree in memory */
+	if (s[top].sn.level > 0) {
+	    for (i = s[top].branch_id; i < t->nodecard; i++) {
+		if (s[top].pos[i] > 0) {
+		    s[top++].branch_id = i + 1;
+		    G_fseek(fp->file, last->pos[i], SEEK_SET);
+		    /* read with dig__fread_port_* fns */
+		    dig__fread_port_I(&(s[top].sn.count), 1, fp);
+		    dig__fread_port_I(&(s[top].sn.level), 1, fp);
+		    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+		    for (j = 0; j < maxcard; j++) {
+			dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
+					  NUMSIDES, fp);
+			dig__fread_port_O(&(s[top].pos[j]), 1, fp,
+					  off_t_size);
+			/* leaf node
+			 * vector object IDs are stored in file as
+			 * off_t but always fit into an int, see dig_structs.h
+			 * vector object IDs are transfered to child.id */
+			if (s[top].sn.level == 0) {
+			    s[top].sn.branch[j].child.id =
+				    (int)s[top].pos[j];
+			}
+			else {
+			    s[top].sn.branch[j].child.pos = -1;
+			}
+		    }
+		    s[top].branch_id = 0;
+		    loadnode = 0;
+		    break;
+		}
+		else if (last->pos[i] < 0)
+		    G_fatal_error("corrupt spatial index");
+	    }
+	    if (loadnode) {
+		/* nothing else found, ready to load */
+		s[top].branch_id = t->nodecard;
+	    }
+	}
+	if (loadnode) {
+	    /* ready to load node and write to temp file */
+
+	    /* copy from stack node */
+	    newnode.level = s[top].sn.level;
+	    newnode.count = s[top].sn.count;
+	    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+	    for (j = 0; j < maxcard; j++) {
+		newnode.branch[j].rect = s[top].sn.branch[j].rect;
+		newnode.branch[j].child = s[top].sn.branch[j].child;
+	    }
+	    newnode_pos = RTreeGetNodePos(t);
+	    RTreeWriteNode(&newnode, t);
+
+	    top--;
+	    /* update child of parent node
+	     * this node is only updated if its level is > 0, i.e.
+	     * this is an internal node
+	     * children of internal nodes do not have an ID, instead
+	     * they point to the next nodes down the tree */
+	    if (top >= 0) {
+		s[top].sn.branch[s[top].branch_id - 1].child.pos = newnode_pos;
+	    }
+	}
+    }
+    
+    t->rootpos = newnode_pos;
 }
 
+static void rtree_load_from_sidx(struct gvfile *fp, off_t rootpos,
+				  struct RTree *t, int off_t_size)
+{
+    if (t->fd > -1)
+	return rtree_load_to_file(fp, rootpos, t, off_t_size);
+    else
+	return rtree_load_to_memory(fp, rootpos, t, off_t_size);
+}
+
 /*!
    \brief Write spatial index to file
 
@@ -828,7 +1061,7 @@
 
    \return 0
  */
-int dig_Wr_spidx(struct gvfile * fp, struct Plus_head *Plus)
+int dig_Wr_spidx(struct gvfile *fp, struct Plus_head *Plus)
 {
     G_debug(1, "dig_Wr_spidx()");
 
@@ -891,24 +1124,20 @@
     dig_set_cur_port(&(Plus->spidx_port));
 
     /* Nodes */
-    Plus->Node_spidx->root =
-	rtree_load_from_sidx(fp, Plus->Node_spidx_offset,
-			     Plus->Node_spidx, Plus->spidx_port.off_t_size);
+    rtree_load_from_sidx(fp, Plus->Node_spidx_offset,
+			 Plus->Node_spidx, Plus->spidx_port.off_t_size);
 
     /* Lines */
-    Plus->Line_spidx->root =
-	rtree_load_from_sidx(fp, Plus->Line_spidx_offset,
-			     Plus->Line_spidx, Plus->spidx_port.off_t_size);
+    rtree_load_from_sidx(fp, Plus->Line_spidx_offset,
+			 Plus->Line_spidx, Plus->spidx_port.off_t_size);
 
     /* Areas */
-    Plus->Area_spidx->root =
-	rtree_load_from_sidx(fp, Plus->Area_spidx_offset,
-			     Plus->Area_spidx, Plus->spidx_port.off_t_size);
+    rtree_load_from_sidx(fp, Plus->Area_spidx_offset,
+			 Plus->Area_spidx, Plus->spidx_port.off_t_size);
 
     /* Isles */
-    Plus->Isle_spidx->root =
-	rtree_load_from_sidx(fp, Plus->Isle_spidx_offset,
-			     Plus->Isle_spidx, Plus->spidx_port.off_t_size);
+    rtree_load_from_sidx(fp, Plus->Isle_spidx_offset,
+			 Plus->Isle_spidx, Plus->spidx_port.off_t_size);
 
     /* 3D future : */
     /* Faces */
@@ -959,21 +1188,20 @@
 int rtree_search(struct RTree *t, struct Rect *r, SearchHitCallback shcb,
 		 void *cbarg, struct Plus_head *Plus)
 {
-    struct FNode *n;
-    int hitCount = 0, found;
+    int hitCount = 0, found, maxcard;
     int i, j;
     struct spidxstack
     {
-	off_t pos;		/* file position of stack node */
-	struct FNode sn;	/* stack node */
+	off_t pos[MAXCARD];	/* file position of child node, object ID on level 0 */
+	struct Node sn;	        /* stack node */
 	int branch_id;		/* branch no to follow down */
-    } s[50];
+    } s[50], *last;
     int top = 0;
 
     assert(r);
     assert(t);
 
-    /* stack size of t->n_levels + 1 is enough because of depth first search */
+    /* stack size of t->rootlevel + 1 is enough because of depth first search */
     /* only one node per level on stack at any given time */
 
     dig_set_cur_port(&(Plus->spidx_port));
@@ -983,39 +1211,50 @@
     /* read with dig__fread_port_* fns */
     dig__fread_port_I(&(s[top].sn.count), 1, &(Plus->spidx_fp));
     dig__fread_port_I(&(s[top].sn.level), 1, &(Plus->spidx_fp));
-    for (j = 0; j < MAXCARD; j++) {
+    maxcard = t->rootlevel ? t->nodecard : t->leafcard;
+    for (j = 0; j < maxcard; j++) {
 	dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES,
 			  &(Plus->spidx_fp));
-	dig__fread_port_O(&(s[top].sn.branch[j].child), 1, &(Plus->spidx_fp),
+	dig__fread_port_O(&(s[top].pos[j]), 1, &(Plus->spidx_fp),
 			  Plus->spidx_port.off_t_size);
+	/* leaf node: vector object IDs are stored in child.id */
+	if (s[top].sn.level == 0) {
+	    s[top].sn.branch[j].child.id = (int)s[top].pos[j];
+	}
+	else {
+	    s[top].sn.branch[j].child.pos = s[top].pos[j];
+	}
     }
 
-    s[top].pos = t->rootpos;
     s[top].branch_id = i = 0;
-    n = &(s[top].sn);
 
     while (top >= 0) {
-	n = &(s[top].sn);
+	last = &(s[top]);
 	if (s[top].sn.level > 0) {	/* this is an internal node in the tree */
 	    found = 1;
 	    for (i = s[top].branch_id; i < t->nodecard; i++) {
-		if (s[top].sn.branch[i].child &&
+		if (s[top].pos[i] > 0 &&
 		    RTreeOverlap(r, &(s[top].sn.branch[i].rect), t)) {
 		    s[top++].branch_id = i + 1;
-		    s[top].pos = n->branch[i].child;
-
-		    dig_fseek(&(Plus->spidx_fp), s[top].pos, SEEK_SET);
+		    dig_fseek(&(Plus->spidx_fp), last->pos[i], SEEK_SET);
 		    /* read with dig__fread_port_* fns */
 		    dig__fread_port_I(&(s[top].sn.count), 1,
 				      &(Plus->spidx_fp));
 		    dig__fread_port_I(&(s[top].sn.level), 1,
 				      &(Plus->spidx_fp));
-		    for (j = 0; j < MAXCARD; j++) {
+		    maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
+		    for (j = 0; j < maxcard; j++) {
 			dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
 					  NUMSIDES, &(Plus->spidx_fp));
-			dig__fread_port_O(&(s[top].sn.branch[j].child), 1,
+			dig__fread_port_O(&(s[top].pos[j]), 1,
 					  &(Plus->spidx_fp),
 					  Plus->spidx_port.off_t_size);
+			if (s[top].sn.level == 0) {
+			    s[top].sn.branch[j].child.id = (int)s[top].pos[j];
+			}
+			else {
+			    s[top].sn.branch[j].child.pos = s[top].pos[j];
+			}
 		    }
 
 		    s[top].branch_id = 0;
@@ -1031,11 +1270,11 @@
 	}
 	else {			/* this is a leaf node */
 	    for (i = 0; i < t->leafcard; i++) {
-		if (s[top].sn.branch[i].child &&
+		if (s[top].sn.branch[i].child.id &&
 		    RTreeOverlap(r, &(s[top].sn.branch[i].rect), t)) {
 		    hitCount++;
 		    if (shcb) {	/* call the user-provided callback */
-			if (!shcb((int)s[top].sn.branch[i].child, cbarg)) {
+			if (!shcb((int)s[top].sn.branch[i].child.id, cbarg)) {
 			    /* callback wants to terminate search early */
 			    return hitCount;
 			}



More information about the grass-commit mailing list