[GRASS-SVN] r44855 - grass/trunk/lib/vector/rtree
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Jan 4 05:01:42 EST 2011
Author: mmetz
Date: 2011-01-04 02:01:42 -0800 (Tue, 04 Jan 2011)
New Revision: 44855
Added:
grass/trunk/lib/vector/rtree/indexf.c
grass/trunk/lib/vector/rtree/indexm.c
grass/trunk/lib/vector/rtree/io.c
Modified:
grass/trunk/lib/vector/rtree/card.c
grass/trunk/lib/vector/rtree/card.h
grass/trunk/lib/vector/rtree/gammavol.c
grass/trunk/lib/vector/rtree/index.c
grass/trunk/lib/vector/rtree/index.h
grass/trunk/lib/vector/rtree/node.c
grass/trunk/lib/vector/rtree/rect.c
grass/trunk/lib/vector/rtree/rtree.h
grass/trunk/lib/vector/rtree/split.c
grass/trunk/lib/vector/rtree/split.h
Log:
optionally file-based spatial index
Modified: grass/trunk/lib/vector/rtree/card.c
===================================================================
--- grass/trunk/lib/vector/rtree/card.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/card.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
Modified: grass/trunk/lib/vector/rtree/card.h
===================================================================
--- grass/trunk/lib/vector/rtree/card.h 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/card.h 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -23,11 +23,13 @@
extern int LEAFCARD;
/* balance criteria for node splitting */
-/* NOTE: can be changed if needed. */
-#define MinNodeFill (NODECARD / 2)
-#define MinLeafFill (LEAFCARD / 2)
+/* NOTE: can be changed if needed but
+ * must be >= 2 and <= (t)->[nodecard|leafcard] / 2 */
+#define MinNodeFill(t) ((t)->minfill_node_split)
+#define MinLeafFill(t) ((t)->minfill_leaf_split)
-#define MAXKIDS(n) ((n)->level > 0 ? NODECARD : LEAFCARD)
-#define MINFILL(n) ((n)->level > 0 ? MinNodeFill : MinLeafFill)
+#define MAXKIDS(level, t) ((level) > 0 ? (t)->nodecard : (t)->leafcard)
+#define MINFILL(level, t) ((level) > 0 ? (t)->minfill_node_split : (t)->minfill_leaf_split)
+//#define MINFILL(level, t) ((level) > 0 ? (t)->nodecard * 0.4 : (t)->leafcard * 0.4)
#endif
Modified: grass/trunk/lib/vector/rtree/gammavol.c
===================================================================
--- grass/trunk/lib/vector/rtree/gammavol.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/gammavol.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
Modified: grass/trunk/lib/vector/rtree/index.c
===================================================================
--- grass/trunk/lib/vector/rtree/index.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/index.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -17,47 +17,97 @@
*****************************************************************************/
#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <assert.h>
+#include <grass/gis.h>
#include "index.h"
#include "card.h"
-/* stack used for non-recursive insertion/deletion */
-struct stack
-{
- struct Node *sn; /* stack node */
- int branch_id; /* branch no to follow down */
-};
-
/*
* Make a new index, empty.
+ * fp pointer to file holding index, file must be opened as w+
+ * rootpos postion of rootnode (past any header info)
* ndims number of dimensions
* returns pointer to RTree structure
*/
-struct RTree *RTreeNewIndex(int ndims)
+struct RTree *RTreeNewIndex(int fd, off_t rootpos, int ndims)
{
struct RTree *new_rtree;
struct Node *n;
-
+ int i;
+
new_rtree = (struct RTree *)malloc(sizeof(struct RTree));
+ new_rtree->fd = fd;
+ new_rtree->rootpos = rootpos;
new_rtree->ndims = ndims;
new_rtree->nsides = 2 * ndims;
+
+ new_rtree->rectsize = sizeof(struct Rect);
+ /* init free nodes */
+ new_rtree->free_nodes.avail = 0;
+ new_rtree->free_nodes.alloc = 0;
+ new_rtree->free_nodes.pos = NULL;
+
new_rtree->nodesize = sizeof(struct Node);
new_rtree->branchsize = sizeof(struct Branch);
- new_rtree->rectsize = sizeof(struct Rect);
+
+ /* create empty root node */
+ n = RTreeNewNode(new_rtree, 0);
+ new_rtree->rootlevel = n->level = 0; /* leaf */
+ new_rtree->root = NULL;
- /* nodecard and leafcard can be adjusted, must NOT be larger than MAXCARD */
- new_rtree->nodecard = MAXCARD;
- new_rtree->leafcard = MAXCARD;
- /* NOTE: min fill can be changed if needed. */
- new_rtree->min_node_fill = (new_rtree->nodecard - 1) / 2;
- new_rtree->min_leaf_fill = (new_rtree->leafcard - 1) / 2;
+ if (fd > -1) { /* file based */
+ /* nodecard and leafcard can be adjusted, must NOT be larger than MAXCARD */
+ new_rtree->nodecard = MAXCARD;
+ new_rtree->leafcard = MAXCARD;
- n = RTreeNewNode(new_rtree, 0);
- new_rtree->n_levels = n->level = 0; /* leaf */
- new_rtree->root = n;
+ /* initialize node buffer */
+ for (i = 0; i < MAXLEVEL; i++) {
+ new_rtree->nb[i][0].dirty = 0;
+ new_rtree->nb[i][1].dirty = 0;
+ new_rtree->nb[i][0].pos = -1;
+ new_rtree->nb[i][1].pos = -1;
+ new_rtree->mru[i] = 0;
+ }
+ /* write empty root node */
+ lseek(new_rtree->fd, rootpos, SEEK_SET);
+ RTreeWriteNode(n, new_rtree);
+ new_rtree->nb[0][0].n = *n;
+ new_rtree->nb[0][0].pos = rootpos;
+ new_rtree->mru[0] = 0;
+ RTreeFreeNode(n);
+
+ new_rtree->insert_rect = RTreeInsertRectF;
+ new_rtree->delete_rect = RTreeDeleteRectF;
+ new_rtree->search_rect = RTreeSearchF;
+ new_rtree->valid_child = RTreeValidChildF;
+
+ }
+ else { /* memory based */
+ new_rtree->nodecard = MAXCARD;
+ new_rtree->leafcard = MAXCARD;
+
+ new_rtree->insert_rect = RTreeInsertRectM;
+ new_rtree->delete_rect = RTreeDeleteRectM;
+ new_rtree->search_rect = RTreeSearchM;
+ new_rtree->valid_child = RTreeValidChildM;
+
+ new_rtree->root = n;
+ }
+
+ /* minimum number of remaining children for RTreeDeleteRect */
+ /* NOTE: min fill can be changed if needed, must be < nodecard and leafcard. */
+ new_rtree->min_node_fill = (new_rtree->nodecard - 2) / 2;
+ new_rtree->min_leaf_fill = (new_rtree->leafcard - 2) / 2;
+
+ /* balance criteria for node splitting */
+ new_rtree->minfill_node_split = (new_rtree->nodecard - 1) / 2;
+ new_rtree->minfill_leaf_split = (new_rtree->leafcard - 1) / 2;
+
new_rtree->n_nodes = 1;
new_rtree->n_leafs = 0;
@@ -68,8 +118,12 @@
{
assert(t);
- if (t->root)
- RTreeDestroyNode(t->root, t->nodecard);
+ if (t->fd > -1) {
+ if (t->free_nodes.alloc)
+ free(t->free_nodes.pos);
+ }
+ else if (t->root)
+ RTreeDestroyNode(t->root, t->root->level ? t->nodecard : t->leafcard);
free(t);
}
@@ -79,252 +133,15 @@
* overlap the argument rectangle.
* Return the number of qualifying data rects.
*/
-int RTreeSearch(struct RTree *t, struct Rect *r, SearchHitCallback shcb,
+int RTreeSearch(struct RTree *t, struct Rect *r, SearchHitCallback *shcb,
void *cbarg)
{
- struct Node *n;
- int hitCount = 0, found;
- int i;
- struct stack s[MAXLEVEL];
- int top = 0;
+ assert(r && t);
- assert(r);
- assert(t);
-
- /* stack size of t->n_levels + 1 is enough because of depth first search */
- /* only one node per level on stack at any given time */
-
- /* add root node position to stack */
- s[top].sn = t->root;
- s[top].branch_id = i = 0;
- n = s[top].sn;
-
- while (top >= 0) {
- n = s[top].sn;
- 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.ptr &&
- RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) {
- s[top++].branch_id = i + 1;
- /* add next node to stack */
- s[top].sn = n->branch[i].child.ptr;
- s[top].branch_id = 0;
- found = 0;
- break;
- }
- }
- if (found) {
- /* nothing else found, go back up */
- s[top].branch_id = t->nodecard;
- top--;
- }
- }
- else { /* this is a leaf node */
- for (i = 0; i < t->leafcard; i++) {
- 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(s[top].sn->branch[i].child.id, cbarg)) {
- /* callback wants to terminate search early */
- return hitCount;
- }
- }
- }
- }
- top--;
- }
- }
-
- return hitCount;
+ return t->search_rect(t, r, shcb, cbarg);
}
/*
- * Free ListBranch
- */
-static void RTreeFreeListBranch(struct ListBranch *p)
-{
- free(p);
-}
-
-/*
- * Inserts a new data rectangle into the index structure.
- * Non-recursively descends tree.
- * Returns 0 if node was not split and nothing was removed.
- * Returns 1 if root node was split. Old node updated to become one of two.
- * Returns 2 if branches need to be reinserted.
- * The level argument specifies the number of steps up from the leaf
- * level to insert; e.g. a data rectangle goes in at level = 0.
- */
-static int RTreeInsertRect2(struct Rect *r, union Child child, int level,
- struct Node **newnode, struct RTree *t,
- struct ListBranch **ee, int *overflow)
-{
- int i;
- struct Branch b;
- struct Node *n, *n2;
- struct Rect *cover;
- struct stack s[MAXLEVEL];
- int top = 0, down = 0;
- int result;
-
- assert(r && newnode && t);
-
- /* add root node to stack */
- s[top].sn = t->root;
-
- /* go down to level of insertion */
- while (s[top].sn->level > level) {
- n = s[top].sn;
- i = RTreePickBranch(r, n, t);
- s[top++].branch_id = i;
- /* add next node to stack */
- s[top].sn = n->branch[i].child.ptr;
- }
-
- /* Have reached level for insertion. Remove p rectangles or split */
- if (s[top].sn->level == level) {
- b.rect = *r;
- /* child field of leaves contains tid of data record */
- b.child = child;
- /* add branch, may split node or remove branches */
- if (top)
- cover = &(s[top - 1].sn->branch[s[top - 1].branch_id].rect);
- else
- cover = NULL;
- result = RTreeAddBranch(&b, s[top].sn, &n2, ee, cover, overflow, t);
- /* update node count */
- if (result == 1) {
- t->n_nodes++;
- }
- }
- else {
- /* Not supposed to happen */
- assert(FALSE);
- return 0;
- }
-
- /* go back up */
- while (top) {
- down = top--;
- i = s[top].branch_id;
- if (result == 0) { /* branch was added */
- s[top].sn->branch[i].rect =
- RTreeCombineRect(r, &(s[top].sn->branch[i].rect), t);
- }
- else if (result == 2) { /* branches were removed */
- /* get node cover of previous node */
- s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
- }
- else if (result == 1) { /* node was split */
- /* get node cover of previous node */
- s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
- /* add new branch for new node previously added by RTreeAddBranch() */
- b.child.ptr = n2;
- b.rect = RTreeNodeCover(b.child.ptr, t);
-
- /* add branch, may split node or remove branches */
- if (top)
- cover = &(s[top - 1].sn->branch[s[top - 1].branch_id].rect);
- else
- cover = NULL;
- result =
- RTreeAddBranch(&b, s[top].sn, &n2, ee, cover, overflow, t);
-
- /* update node count */
- if (result == 1) {
- t->n_nodes++;
- }
- }
- }
-
- *newnode = n2;
-
- return result;
-}
-
-/*
- * Insert a data rectangle into an index structure.
- * RTreeInsertRect1 provides for splitting the root;
- * returns 1 if root was split, 0 if it was not.
- * The level argument specifies the number of steps up from the leaf
- * level to insert; e.g. a data rectangle goes in at level = 0.
- * RTreeInsertRect2 does the actual insertion.
- */
-static int RTreeInsertRect1(struct Rect *r, union Child child, int level,
- struct RTree *t)
-{
- struct Node *newnode;
- struct Node *newroot;
- struct Branch b;
- struct ListBranch *reInsertList = NULL;
- struct ListBranch *e;
- int result;
- int i, overflow[MAXLEVEL];
-
- /* R*-tree forced reinsertion: for each level only once */
- for (i = 0; i < MAXLEVEL; i++)
- overflow[i] = 1;
-
- result =
- RTreeInsertRect2(r, child, level, &newnode, t, &reInsertList,
- overflow);
-
- if (result == 1) { /* root split */
- /* grow a new root, & tree taller */
- t->n_levels++;
- newroot = RTreeNewNode(t, t->n_levels);
- newroot->level = t->n_levels;
- /* branch for old root */
- b.rect = RTreeNodeCover(t->root, t);
- b.child.ptr = t->root;
- RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
- /* branch for new node created by RTreeInsertRect2() */
- b.rect = RTreeNodeCover(newnode, t);
- b.child.ptr = newnode;
- RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
- /* set new root node */
- t->root = newroot;
- t->n_nodes++;
- }
- else if (result == 2) { /* branches were removed */
- while (reInsertList) {
- /* get next branch in list */
- b = reInsertList->b;
- level = reInsertList->level;
- e = reInsertList;
- reInsertList = reInsertList->next;
- RTreeFreeListBranch(e);
- /* reinsert branches */
- result =
- RTreeInsertRect2(&(b.rect), b.child, level, &newnode, t,
- &reInsertList, overflow);
-
- if (result == 1) { /* root split */
- /* grow a new root, & tree taller */
- t->n_levels++;
- newroot = RTreeNewNode(t, t->n_levels);
- newroot->level = t->n_levels;
- /* branch for old root */
- b.rect = RTreeNodeCover(t->root, t);
- b.child.ptr = t->root;
- RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
- /* branch for new node created by RTreeInsertRect2() */
- b.rect = RTreeNodeCover(newnode, t);
- b.child.ptr = newnode;
- RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
- /* set new root node */
- t->root = newroot;
- t->n_nodes++;
- }
- }
- }
-
- return result;
-}
-
-/*
* Insert a data rectangle into an RTree index structure.
* r pointer to rectangle
* tid data id stored with rectangle, must be > 0
@@ -333,26 +150,48 @@
int RTreeInsertRect(struct Rect *r, int tid, struct RTree *t)
{
union Child newchild;
- assert(r && t);
+ assert(r && t && tid > 0);
+
t->n_leafs++;
-
newchild.id = tid;
+
+ return t->insert_rect(r, newchild, 0, t);
+}
- return RTreeInsertRect1(r, newchild, 0, t);
+/*
+ * Delete a data rectangle from an index structure.
+ * Pass in a pointer to a Rect, the tid of the record, ptr RTree.
+ * Returns 1 if record not found, 0 if success.
+ * RTreeDeleteRect1 provides for eliminating the root.
+ *
+ * RTreeDeleteRect() should be called by external functions instead of
+ * RTreeDeleteRect1()
+ * wrapper for RTreeDeleteRect1 not really needed, but restricts
+ * compile warnings to rtree lib
+ * this way it's easier to fix if necessary?
+ */
+int RTreeDeleteRect(struct Rect *r, int tid, struct RTree *t)
+{
+ union Child child;
+
+ assert(r && t && tid > 0);
+
+ child.id = tid;
+
+ return t->delete_rect(r, child, t);
}
/*
- * Allocate space for a node in the list used in DeletRect to
+ * Allocate space for a node in the list used in DeleteRect to
* store Nodes that are too empty.
*/
-static struct ListNode *RTreeNewListNode(void)
+struct ListNode *RTreeNewListNode(void)
{
return (struct ListNode *)malloc(sizeof(struct ListNode));
- /* return new ListNode; */
}
-static void RTreeFreeListNode(struct ListNode *p)
+void RTreeFreeListNode(struct ListNode *p)
{
free(p);
}
@@ -361,187 +200,22 @@
* Add a node to the reinsertion list. All its branches will later
* be reinserted into the index structure.
*/
-static void RTreeReInsertNode(struct Node *n, struct ListNode **ee)
+void RTreeReInsertNode(struct Node *n, struct ListNode **ee)
{
- register struct ListNode *l;
+ struct ListNode *l = RTreeNewListNode();
- l = RTreeNewListNode();
l->node = n;
l->next = *ee;
*ee = l;
}
-/*
- * Delete a rectangle from non-root part of an index structure.
- * Called by RTreeDeleteRect. Descends tree non-recursively,
- * merges branches on the way back up.
- * Returns 1 if record not found, 0 if success.
+/*
+ * Free ListBranch
*/
-static int
-RTreeDeleteRect2(struct Rect *r, union Child child, struct RTree *t,
- struct ListNode **ee)
+void RTreeFreeListBranch(struct ListBranch *p)
{
- int i, notfound = 1;
- struct Node *n;
- struct stack s[MAXLEVEL];
- int top = 0, down = 0;
- int minfill;
-
- assert(r && ee && t);
-
- /* add root node position to stack */
- s[top].sn = t->root;
- s[top].branch_id = 0;
- n = s[top].sn;
-
- while (notfound) {
- /* go down to level 0, remember path */
- if (s[top].sn->level > 0) {
- n = s[top].sn;
- for (i = s[top].branch_id; i < t->nodecard; i++) {
- if (n->branch[i].child.ptr &&
- RTreeOverlap(r, &(n->branch[i].rect), t)) {
- s[top++].branch_id = i + 1;
- /* add next node to stack */
- s[top].sn = n->branch[i].child.ptr;
- s[top].branch_id = 0;
-
- notfound = 0;
- break;
- }
- }
- if (notfound) {
- /* nothing else found, go back up */
- s[top].branch_id = t->nodecard;
- top--;
- }
- else /* found a way down but not yet the item */
- notfound = 1;
- }
- else {
- for (i = 0; i < t->leafcard; i++) {
- if (s[top].sn->branch[i].child.id && s[top].sn->branch[i].child.id == child.id) { /* found item */
- RTreeDisconnectBranch(s[top].sn, i, t);
- t->n_leafs--;
- notfound = 0;
- break;
- }
- }
- if (notfound) /* continue searching */
- top--;
- }
- }
-
- if (notfound) {
- return notfound;
- }
-
- /* go back up */
- while (top) {
- down = top;
- top--;
- n = s[top].sn;
- i = s[top].branch_id - 1;
- assert(s[down].sn->level == s[top].sn->level - 1);
-
- minfill = (s[down].sn->level ? t->min_node_fill : t->min_leaf_fill);
- if (s[down].sn->count >= minfill) {
- /* just update node cover */
- s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
- }
- else {
- /* not enough entries in child, eliminate child node */
- RTreeReInsertNode(s[top].sn->branch[i].child.ptr, ee);
- RTreeDisconnectBranch(s[top].sn, i, t);
- }
- }
-
- return notfound;
+ free(p);
}
-/*
- * should be called by RTreeDeleteRect() only
- *
- * Delete a data rectangle from an index structure.
- * Pass in a pointer to a Rect, the tid of the record, ptr RTree.
- * Returns 1 if record not found, 0 if success.
- * RTreeDeleteRect1 provides for eliminating the root.
- */
-static int RTreeDeleteRect1(struct Rect *r, union Child child,
- struct RTree *t)
-{
- int i, maxkids;
- struct Node *n;
- struct ListNode *reInsertList = NULL;
- struct ListNode *e;
- assert(r);
- assert(t);
- if (!RTreeDeleteRect2(r, child, t, &reInsertList)) {
- /* found and deleted a data item */
-
- /* reinsert any branches from eliminated nodes */
- while (reInsertList) {
- t->n_nodes--;
- n = reInsertList->node;
- maxkids = (n->level > 0 ? t->nodecard : t->leafcard);
- for (i = 0; i < maxkids; i++) {
- if (n->level > 0) { /* reinsert node branches */
- if (n->branch[i].child.ptr) {
- RTreeInsertRect1(&(n->branch[i].rect),
- n->branch[i].child, n->level, t);
- }
- }
- else { /* reinsert leaf branches */
- if (n->branch[i].child.id) {
- RTreeInsertRect1(&(n->branch[i].rect),
- n->branch[i].child, n->level, t);
- }
- }
- }
- e = reInsertList;
- reInsertList = reInsertList->next;
- RTreeFreeNode(e->node);
- RTreeFreeListNode(e);
- }
-
- /* check for redundant root (not leaf, 1 child) and eliminate */
- n = t->root;
-
- if (n->count == 1 && n->level > 0) {
- for (i = 0; i < t->nodecard; i++) {
- if (n->branch[i].child.ptr)
- break;
- }
- t->root = n->branch[i].child.ptr;
- RTreeFreeNode(n);
- t->n_levels--;
- }
- return 0;
- }
- else {
- return 1;
- }
-}
-
-/*
- * Delete a data rectangle from an index structure.
- * Pass in a pointer to a Rect, the tid of the record, ptr RTree.
- * Returns 1 if record not found, 0 if success.
- * RTreeDeleteRect1 provides for eliminating the root.
- *
- * RTreeDeleteRect() should be called by external functions instead of
- * RTreeDeleteRect1()
- * wrapper for RTreeDeleteRect1 not really needed, but restricts
- * compile warnings to rtree lib
- * this way it's easier to fix if necessary?
- */
-int RTreeDeleteRect(struct Rect *r, int tid, struct RTree *t)
-{
- union Child child;
-
- child.id = tid;
-
- return RTreeDeleteRect1(r, child, t);
-}
Modified: grass/trunk/lib/vector/rtree/index.h
===================================================================
--- grass/trunk/lib/vector/rtree/index.h 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/index.h 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -18,13 +18,13 @@
#ifndef _INDEX_
#define _INDEX_
+#include <stdio.h>
#include <sys/types.h>
/* PGSIZE is normally the natural page size of the machine */
#define PGSIZE 512
#define NUMDIMS 3 /* maximum number of dimensions */
-/* typedef float RectReal; */
typedef double RectReal;
/*-----------------------------------------------------------------------------
@@ -45,43 +45,64 @@
* this is LFS dependent, not good
* on 32 bit without LFS this is 9.69
* on 32 bit with LFS and on 64 bit this is 9 */
-#define MAXCARD 9
+#define MAXCARD 18
/* R*-tree: number of branches to be force-reinserted when adding a branch */
#define FORCECARD 2
/* maximum no of levels = tree depth */
-#define MAXLEVEL 20 /* 4^MAXLEVEL items are guaranteed to fit into the tree */
+#define MAXLEVEL 20 /* 8^MAXLEVEL items are guaranteed to fit into the tree */
+#define NODETYPE(l, fd) ((l) == 0 ? 0 : ((fd) < 0 ? 1 : 2))
+
struct Rect
{
RectReal boundary[NUMSIDES]; /* xmin,ymin,...,xmax,ymax,... */
};
-struct Node; /* node for memory based index */
+struct Node; /* node for spatial index */
union Child
{
int id; /* child id */
struct Node *ptr; /* pointer to child node */
+ off_t pos; /* position of child node in file */
};
-struct Branch /* branch for memory based index */
+struct Branch /* branch for spatial index */
{
struct Rect rect;
union Child child;
};
-struct Node /* node for memory based index */
+struct Node /* node for spatial index */
{
int count; /* number of branches */
- int level; /* 0 is leaf, others positive */
+ int level; /* 0 is leaf, others positive */
struct Branch branch[MAXCARD];
};
+/*
+ * If passed to a tree search, this callback function will be called
+ * with the ID of each data rect that overlaps the search rect
+ * plus whatever user specific pointer was passed to the search.
+ * It can terminate the search early by returning 0 in which case
+ * the search will return the number of hits found up to that point.
+ */
+typedef int SearchHitCallback(int id, void *arg);
+
+struct RTree;
+
+typedef int rt_search_fn(struct RTree *, struct Rect *,
+ SearchHitCallback *, void *);
+typedef int rt_insert_fn(struct Rect *, union Child, int, struct RTree *);
+typedef int rt_delete_fn(struct Rect *, union Child, struct RTree *);
+typedef int rt_valid_child_fn(union Child *);
+
struct RTree
{
/* RTree setup info */
+ int fd; /* file descriptor */
unsigned char ndims; /* number of dimensions */
unsigned char nsides; /* number of sides = 2 * ndims */
int nodesize; /* node size in bytes */
@@ -89,18 +110,44 @@
int rectsize; /* rectangle size in bytes */
/* RTree info, useful to calculate space requirements */
- unsigned int n_nodes; /* number of nodes */
- unsigned int n_leafs; /* number of data items (level 0 leafs) */
- int n_levels; /* n levels = root level */
+ int n_nodes; /* number of nodes */
+ int n_leafs; /* number of data items (level 0 leafs) */
+ int rootlevel; /* root level = tree depth */
/* settings for RTree building */
int nodecard; /* max number of childs in node */
int leafcard; /* max number of childs in leaf */
- int min_node_fill; /* balance criteria for node splitting */
- int min_leaf_fill; /* balance criteria for leaf splitting */
+ int min_node_fill; /* balance criteria for node removal */
+ int min_leaf_fill; /* balance criteria for leaf removal */
+ int minfill_node_split; /* balance criteria for splitting */
+ int minfill_leaf_split; /* balance criteria for splitting */
- struct Node *root; /* pointer to root node */
+ /* free node positions for recycling */
+ struct _recycle {
+ int avail; /* number of available positions */
+ int alloc; /* number of allcoated positions in *pos */
+ off_t *pos; /* array of available positions */
+ } free_nodes;
+ /* node buffer for file-based index, two nodes per level
+ * more than two nodes per level would require too complex cache management:
+ * lru or pseudo-lru replacement, searching for buffered nodes */
+ struct NodeBuffer
+ {
+ struct Node n; /* buffered node */
+ off_t pos; /* file position of buffered node */
+ char dirty; /* node in buffer was modified */
+ } nb[MAXLEVEL][2];
+ char mru[MAXLEVEL]; /* most recently used buffered node per level */
+
+ /* insert, delete, search */
+ rt_insert_fn *insert_rect;
+ rt_delete_fn *delete_rect;
+ rt_search_fn *search_rect;
+ rt_valid_child_fn *valid_child;
+
+ struct Node *root; /* pointer to root node */
+
off_t rootpos; /* root node position in file */
};
@@ -110,6 +157,12 @@
struct Node *node;
};
+struct ListFNode
+{
+ struct ListFNode *next;
+ off_t node_pos;
+};
+
struct ListBranch
{
struct ListBranch *next;
@@ -117,22 +170,29 @@
int level;
};
-/*
- * If passed to a tree search, this callback function will be called
- * with the ID of each data rect that overlaps the search rect
- * plus whatever user specific pointer was passed to the search.
- * It can terminate the search early by returning 0 in which case
- * the search will return the number of hits found up to that point.
- */
-typedef int (*SearchHitCallback) (int id, void *arg);
-
/* index.c */
-extern int RTreeSearch(struct RTree *, struct Rect *, SearchHitCallback,
+extern int RTreeSearch(struct RTree *, struct Rect *, SearchHitCallback *,
void *);
-extern int RTreeInsertRect(struct Rect *, int, struct RTree *t);
-extern int RTreeDeleteRect(struct Rect *, int, struct RTree *t);
-extern struct RTree *RTreeNewIndex(int);
-void RTreeFreeIndex(struct RTree *);
+extern int RTreeInsertRect(struct Rect *, int, struct RTree *);
+extern int RTreeDeleteRect(struct Rect *, int, struct RTree *);
+extern struct RTree *RTreeNewIndex(int, off_t, int);
+extern void RTreeFreeIndex(struct RTree *);
+extern struct ListNode *RTreeNewListNode(void);
+extern void RTreeFreeListNode(struct ListNode *);
+extern void RTreeReInsertNode(struct Node *, struct ListNode **);
+extern void RTreeFreeListBranch(struct ListBranch *);
+/* indexm.c */
+extern int RTreeSearchM(struct RTree *, struct Rect *, SearchHitCallback *,
+ void *);
+extern int RTreeInsertRectM(struct Rect *, union Child, int, struct RTree *);
+extern int RTreeDeleteRectM(struct Rect *, union Child, struct RTree *);
+extern int RTreeValidChildM(union Child *child);
+/* indexf.c */
+extern int RTreeSearchF(struct RTree *, struct Rect *, SearchHitCallback *,
+ void *);
+extern int RTreeInsertRectF(struct Rect *, union Child, int, struct RTree *);
+extern int RTreeDeleteRectF(struct Rect *, union Child, struct RTree *);
+extern int RTreeValidChildF(union Child *child);
/* node.c */
extern struct Node *RTreeNewNode(struct RTree *, int);
extern void RTreeInitNode(struct Node *, int);
@@ -153,6 +213,7 @@
extern RectReal RTreeRectVolume(struct Rect *, struct RTree *);
extern RectReal RTreeRectMargin(struct Rect *, struct RTree *);
extern struct Rect RTreeCombineRect(struct Rect *, struct Rect *, struct RTree *);
+extern int RTreeCompareRect(struct Rect *, struct Rect *, struct RTree *);
extern int RTreeOverlap(struct Rect *, struct Rect *, struct RTree *);
extern void RTreePrintRect(struct Rect *, int);
/* split.c */
@@ -162,5 +223,15 @@
extern int RTreeSetLeafMax(int, struct RTree *);
extern int RTreeGetNodeMax(struct RTree *);
extern int RTreeGetLeafMax(struct RTree *);
+/* fileio.c */
+extern void RTreeGetNode(struct Node *, off_t, int, struct RTree *);
+extern size_t RTreeReadNode(struct Node *, off_t, struct RTree *);
+extern void RTreePutNode(struct Node *, off_t, struct RTree *);
+extern size_t RTreeWriteNode(struct Node *, struct RTree *);
+extern size_t RTreeRewriteNode(struct Node *, off_t, struct RTree *);
+extern void RTreeUpdateRect(struct Rect *, struct Node *, off_t, int, struct RTree *);
+extern void RTreeAddNodePos(off_t, int, struct RTree *);
+extern off_t RTreeGetNodePos(struct RTree *);
+extern void RTreeFlushBuffer(struct RTree *);
#endif /* _INDEX_ */
Added: grass/trunk/lib/vector/rtree/indexf.c
===================================================================
--- grass/trunk/lib/vector/rtree/indexf.c (rev 0)
+++ grass/trunk/lib/vector/rtree/indexf.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -0,0 +1,472 @@
+
+/****************************************************************************
+* MODULE: R-Tree library
+*
+* AUTHOR(S): Antonin Guttman - original code
+* Daniel Green (green at superliminal.com) - major clean-up
+* and implementation of bounding spheres
+* Markus Metz - file-based and memory-based R*-tree
+*
+* PURPOSE: Multidimensional index
+*
+* COPYRIGHT: (C) 2001 by 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.
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <grass/config.h>
+#include <grass/gis.h>
+#include "index.h"
+#include "card.h"
+
+/* stack used for non-recursive insertion/deletion */
+struct fstack
+{
+ struct Node sn; /* stack node */
+ int branch_id; /* branch no to follow down */
+ off_t pos; /* file position of stack node */
+};
+
+int RTreeValidChildF(union Child *child)
+{
+ return (child->pos > -1);
+}
+
+/*
+ * Search in an index tree for all data retangles that
+ * overlap the argument rectangle.
+ * Return the number of qualifying data rects.
+ */
+int RTreeSearchF(struct RTree *t, struct Rect *r,
+ SearchHitCallback *shcb, void *cbarg)
+{
+ struct Node *n;
+ int hitCount = 0, found, currlevel;
+ int i;
+ struct fstack s[MAXLEVEL];
+ int top = 0;
+
+ /* stack size of t->rootlevel + 1 is enough because of depth first search */
+ /* only one node per level on stack at any given time */
+
+ /* add root node position to stack */
+ currlevel = t->rootlevel;
+ s[top].pos = t->rootpos;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+ s[top].branch_id = i = 0;
+
+ while (top >= 0) {
+ if (s[top].sn.level > 0) { /* this is an internal node in the tree */
+ n = &(s[top].sn);
+ found = 1;
+ currlevel = s[top].sn.level - 1;
+ for (i = s[top].branch_id; i < t->nodecard; i++) {
+ if (s[top].sn.branch[i].child.pos > -1 &&
+ RTreeOverlap(r, &(s[top].sn.branch[i].rect), t)) {
+ s[top++].branch_id = i + 1;
+ /* add next node to stack */
+ s[top].pos = n->branch[i].child.pos;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+ s[top].branch_id = 0;
+ found = 0;
+ break;
+ }
+ }
+ if (found) {
+ /* nothing else found, go back up */
+ s[top].branch_id = t->nodecard;
+ top--;
+ }
+ }
+ else { /* this is a leaf node */
+ for (i = 0; i < t->leafcard; i++) {
+ 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(s[top].sn.branch[i].child.id, cbarg)) {
+ /* callback wants to terminate search early */
+ return hitCount;
+ }
+ }
+ }
+ }
+ top--;
+ }
+ }
+
+ return hitCount;
+}
+
+/*
+ * Inserts a new data rectangle into the index structure.
+ * Non-recursively descends tree, propagates splits back up.
+ * Returns 0 if node was not split. Old node updated.
+ * If node was split, returns 1 and sets the pointer pointed to by
+ * new_node to point to the new node. Old node updated to become one of two.
+ * The level argument specifies the number of steps up from the leaf
+ * level to insert; e.g. a data rectangle goes in at level = 0.
+ */
+static int RTreeInsertRect2F(struct Rect *r, union Child child, int level,
+ struct Node *newnode, off_t *newnode_pos,
+ struct RTree *t,
+ struct ListBranch **ee, int *overflow)
+{
+ int i, currlevel;
+ struct Branch b;
+ struct Rect nr, *cover;
+ struct Node *n, *n2, nn;
+ struct fstack s[MAXLEVEL];
+ int top = 0, down = 0;
+ int result;
+
+ n2 = &nn;
+
+ /* add root node position to stack */
+ currlevel = t->rootlevel;
+ s[top].pos = t->rootpos;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+
+ /* go down to level of insertion */
+ while (s[top].sn.level > level) {
+ n = &(s[top].sn);
+ i = RTreePickBranch(r, n, t);
+ s[top++].branch_id = i;
+ /* add next node to stack */
+ s[top].pos = n->branch[i].child.pos;
+ currlevel--;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+ assert(s[top].sn.level == currlevel);
+ }
+
+ /* Have reached level for insertion. Add rect, split if necessary */
+ if (s[top].sn.level == level) {
+ b.rect = *r;
+ /* child field of leaves contains tid of data record */
+ b.child = child;
+ /* add branch, may split node or remove branches */
+ if (top)
+ cover = &(s[top - 1].sn.branch[s[top - 1].branch_id].rect);
+ else
+ cover = NULL;
+ result = RTreeAddBranch(&b, &(s[top].sn), &n2, ee, cover, overflow, t);
+ /* write out new node if node was split */
+ if (result == 1) {
+ *newnode_pos = RTreeGetNodePos(t);
+ RTreeWriteNode(n2, t);
+ t->n_nodes++;
+ }
+ /* update node */
+ RTreePutNode(&(s[top].sn), s[top].pos, t);
+ }
+ else {
+ /* Not supposed to happen */
+ assert(s[top].sn.level == level);
+ return 0;
+ }
+
+ /* go back up */
+ while (top) {
+ down = top--;
+ i = s[top].branch_id;
+ if (result == 0) { /* branch was added */
+ nr = RTreeCombineRect(r, &(s[top].sn.branch[i].rect), t);
+ /* rewrite rect */
+ if (!RTreeCompareRect(&nr, &(s[top].sn.branch[i].rect), t)) {
+ RTreeUpdateRect(&nr, &(s[top].sn), s[top].pos, i, t);
+ }
+ }
+ else if (result == 2) { /* branches were removed */
+ /* get node cover of previous node */
+ nr = RTreeNodeCover(&(s[down].sn), t);
+ /* rewrite rect */
+ if (!RTreeCompareRect(&nr, &(s[top].sn.branch[i].rect), t)) {
+ RTreeUpdateRect(&nr, &(s[top].sn), s[top].pos, i, t);
+ }
+ }
+ else if (result == 1) { /* node was split */
+ /* get node cover of previous node */
+ s[top].sn.branch[i].rect = RTreeNodeCover(&(s[down].sn), t);
+ /* add new branch for new node previously added by RTreeAddBranch() */
+ b.child.pos = *newnode_pos;
+ b.rect = RTreeNodeCover(n2, t);
+
+ /* add branch, may split node or remove branches */
+ if (top)
+ cover = &(s[top - 1].sn.branch[s[top - 1].branch_id].rect);
+ else
+ cover = NULL;
+ result = RTreeAddBranch(&b, &(s[top].sn), &n2, ee, cover, overflow, t);
+
+ /* write out new node if node was split */
+ if (result == 1) {
+ *newnode_pos = RTreeGetNodePos(t);
+ RTreeWriteNode(n2, t);
+ t->n_nodes++;
+ }
+ /* update node */
+ RTreePutNode(&(s[top].sn), s[top].pos, t);
+ }
+ }
+
+ *newnode = *n2;
+
+ return result;
+}
+
+/*
+ * Insert a data rectangle into an index structure.
+ * RTreeInsertRect1 provides for splitting the root;
+ * returns 1 if root was split, 0 if it was not.
+ * The level argument specifies the number of steps up from the leaf
+ * level to insert; e.g. a data rectangle goes in at level = 0.
+ * RTreeInsertRect2 does the actual insertion.
+ */
+int RTreeInsertRectF(struct Rect *r, union Child child, int level,
+ struct RTree *t)
+{
+ struct Node oldroot, newroot, newnode;
+ struct Branch b;
+ struct ListBranch *e, *reInsertList = NULL;
+ int result;
+ int i, overflow[MAXLEVEL];
+ off_t newnode_pos = -1;
+
+ /* R*-tree forced reinsertion: for each level only once */
+ for (i = 0; i < MAXLEVEL; i++)
+ overflow[i] = 1;
+
+ /* no R*-tree like forced reinsertion for file-based index ? */
+ result =
+ RTreeInsertRect2F(r, child, level, &newnode, &newnode_pos, t,
+ &reInsertList, overflow);
+
+ if (result == 1) { /* root split */
+ RTreeGetNode(&oldroot, t->rootpos, t->rootlevel, t);
+ /* grow a new root, & tree taller */
+ t->rootlevel++;
+ RTreeInitNode(&newroot, NODETYPE(t->rootlevel, t->fd));
+ newroot.level = t->rootlevel;
+ /* branch for old root */
+ b.rect = RTreeNodeCover(&oldroot, t);
+ b.child.pos = t->rootpos;
+ RTreeAddBranch(&b, &newroot, NULL, NULL, NULL, NULL, t);
+ /* branch for new node created by RTreeInsertRect2F */
+ b.rect = RTreeNodeCover(&newnode, t);
+ b.child.pos = newnode_pos; /* offset to new node as returned by RTreeInsertRect2F */
+ RTreeAddBranch(&b, &newroot, NULL, NULL, NULL, NULL, t);
+ /* write new root node */
+ t->rootpos = RTreeGetNodePos(t);
+ RTreeWriteNode(&newroot, t);
+ t->n_nodes++;
+ }
+ else if (result == 2) { /* branches were removed */
+ while (reInsertList) {
+ /* get next branch in list */
+ b = reInsertList->b;
+ level = reInsertList->level;
+ e = reInsertList;
+ reInsertList = reInsertList->next;
+ RTreeFreeListBranch(e);
+ /* reinsert branches */
+ result =
+ RTreeInsertRect2F(&(b.rect), b.child, level, &newnode, &newnode_pos, t,
+ &reInsertList, overflow);
+
+ if (result == 1) { /* root split */
+ RTreeGetNode(&oldroot, t->rootpos, t->rootlevel, t);
+ /* grow a new root, & tree taller */
+ t->rootlevel++;
+ RTreeInitNode(&newroot, NODETYPE(t->rootlevel, t->fd));
+ newroot.level = t->rootlevel;
+ /* branch for old root */
+ b.rect = RTreeNodeCover(&oldroot, t);
+ b.child.pos = t->rootpos;
+ RTreeAddBranch(&b, &newroot, NULL, NULL, NULL, NULL, t);
+ /* branch for new node created by RTreeFInsertRect2() */
+ b.rect = RTreeNodeCover(&newnode, t);
+ b.child.pos = newnode_pos;
+ RTreeAddBranch(&b, &newroot, NULL, NULL, NULL, NULL, t);
+ /* write new root node */
+ t->rootpos = RTreeGetNodePos(t);
+ RTreeWriteNode(&newroot, t);
+ t->n_nodes++;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Delete a rectangle from non-root part of an index structure.
+ * Called by RTreeDeleteRect. Descends tree non-recursively,
+ * merges branches on the way back up.
+ * Returns 1 if record not found, 0 if success.
+ */
+static int
+RTreeDeleteRect2F(struct Rect *r, union Child child, struct RTree *t,
+ struct ListNode **ee)
+{
+ int i, notfound = 1, currlevel;
+ struct Node *n;
+ struct Rect nr;
+ struct fstack s[MAXLEVEL];
+ int top = 0, down = 0;
+ int minfill;
+
+ assert(ee);
+
+ /* add root node position to stack */
+ currlevel = t->rootlevel;
+ s[top].pos = t->rootpos;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+ s[top].branch_id = 0;
+
+ while (notfound) {
+ /* go down to level 0, remember path */
+ if (s[top].sn.level > 0) {
+ n = &(s[top].sn);
+ currlevel = s[top].sn.level - 1;
+ for (i = s[top].branch_id; i < t->nodecard; i++) {
+ if (n->branch[i].child.pos > -1 && RTreeOverlap(r, &(n->branch[i].rect), t)) {
+ s[top++].branch_id = i + 1;
+ /* add next node to stack */
+ s[top].pos = n->branch[i].child.pos;
+ RTreeGetNode(&(s[top].sn), s[top].pos, currlevel, t);
+ s[top].branch_id = 0;
+
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) {
+ /* nothing else found, go back up */
+ s[top].branch_id = t->nodecard;
+ top--;
+ }
+ else /* found a way down but not yet the item */
+ notfound = 1;
+ }
+ else {
+ for (i = 0; i < t->leafcard; i++) {
+ if (s[top].sn.branch[i].child.id &&
+ s[top].sn.branch[i].child.id == child.id) { /* found item */
+ RTreeDisconnectBranch(&(s[top].sn), i, t);
+ RTreePutNode(&(s[top].sn), s[top].pos, t);
+ t->n_leafs--;
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) /* continue searching */
+ top--;
+ }
+ }
+
+ if (notfound) {
+ return notfound;
+ }
+
+ /* go back up */
+ while (top) {
+ down = top--;
+ i = s[top].branch_id - 1;
+ assert(s[down].sn.level == s[top].sn.level - 1);
+
+ minfill = (s[down].sn.level ? t->min_node_fill : t->min_leaf_fill);
+ if (s[down].sn.count >= minfill) {
+ /* just update node cover */
+ nr = RTreeNodeCover(&(s[down].sn), t);
+ /* rewrite rect */
+ if (!RTreeCompareRect(&nr, &(s[top].sn.branch[i].rect), t)) {
+ //s[top].sn.branch[i].rect = nr;
+ //RTreeRewriteRect(&nr, s[top].pos, i, t);
+ RTreeUpdateRect(&nr, &(s[top].sn), s[top].pos, i, t);
+ }
+ }
+ else {
+ /* not enough entries in child, eliminate child node */
+ assert(s[top].sn.branch[i].child.pos == s[down].pos);
+ n = RTreeNewNode(t, s[down].sn.level);
+ memcpy(n, &(s[down].sn), t->nodesize);
+ RTreeAddNodePos(s[top].sn.branch[i].child.pos, s[down].sn.level, t);
+ RTreeReInsertNode(n, ee);
+ RTreeDisconnectBranch(&(s[top].sn), i, t);
+
+ RTreePutNode(&(s[top].sn), s[top].pos, t);
+ }
+ }
+
+ return notfound;
+}
+
+/*
+ * should be called by RTreeDeleteRect() only
+ *
+ * Delete a data rectangle from an index structure.
+ * Pass in a pointer to a Rect, the tid of the record, ptr RTree.
+ * Returns 1 if record not found, 0 if success.
+ * RTreeDeleteRect1 provides for eliminating the root.
+ */
+int RTreeDeleteRectF(struct Rect *r, union Child child, struct RTree *t)
+{
+ int i;
+ struct Node *n, rn;
+ struct ListNode *e, *reInsertList = NULL;
+
+ if (!RTreeDeleteRect2F(r, child, t, &reInsertList)) {
+ /* found and deleted a data item */
+
+ /* reinsert any branches from eliminated nodes */
+ while (reInsertList) {
+ t->n_nodes--;
+ n = reInsertList->node;
+ if (n->level > 0) { /* reinsert node branches */
+ for (i = 0; i < t->nodecard; i++) {
+ if (n->branch[i].child.pos > -1) {
+ RTreeInsertRectF(&(n->branch[i].rect),
+ n->branch[i].child, n->level, t);
+ }
+ }
+ }
+ else { /* reinsert leaf branches */
+ for (i = 0; i < t->leafcard; i++) {
+ if (n->branch[i].child.id) {
+ RTreeInsertRectF(&(n->branch[i].rect),
+ n->branch[i].child, n->level, t);
+ }
+ }
+ }
+ e = reInsertList;
+ reInsertList = reInsertList->next;
+ RTreeFreeNode(e->node);
+ RTreeFreeListNode(e);
+ }
+
+ /* check for redundant root (not leaf, 1 child) and eliminate */
+ RTreeGetNode(&rn, t->rootpos, t->rootlevel, t);
+
+ if (rn.count == 1 && rn.level > 0) {
+ for (i = 0; i < t->nodecard; i++) {
+ if (rn.branch[i].child.pos > -1)
+ break;
+ }
+ RTreeAddNodePos(t->rootpos, t->rootlevel, t);
+ t->rootpos = rn.branch[i].child.pos;
+ t->rootlevel--;
+ }
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
Property changes on: grass/trunk/lib/vector/rtree/indexf.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/lib/vector/rtree/indexm.c
===================================================================
--- grass/trunk/lib/vector/rtree/indexm.c (rev 0)
+++ grass/trunk/lib/vector/rtree/indexm.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -0,0 +1,424 @@
+
+/****************************************************************************
+* MODULE: R-Tree library
+*
+* AUTHOR(S): Antonin Guttman - original code
+* Daniel Green (green at superliminal.com) - major clean-up
+* and implementation of bounding spheres
+* Markus Metz - file-based and memory-based R*-tree
+*
+* PURPOSE: Multidimensional index
+*
+* COPYRIGHT: (C) 2010 by 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.
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <grass/gis.h>
+#include "index.h"
+#include "card.h"
+
+/* stack used for non-recursive insertion/deletion */
+struct stack
+{
+ struct Node *sn; /* stack node */
+ int branch_id; /* branch no to follow down */
+};
+
+int RTreeValidChildM(union Child *child)
+{
+ return (child->ptr != NULL);
+}
+
+/*
+ * Search in an index tree for all data retangles that
+ * overlap the argument rectangle.
+ * Return the number of qualifying data rects.
+ */
+int RTreeSearchM(struct RTree *t, struct Rect *r,
+ SearchHitCallback *shcb, void *cbarg)
+{
+ struct Node *n;
+ int hitCount = 0, found;
+ int i;
+ struct stack s[MAXLEVEL];
+ int top = 0;
+
+ /* stack size of t->rootlevel + 1 is enough because of depth first search */
+ /* only one node per level on stack at any given time */
+
+ /* add root node position to stack */
+ s[top].sn = t->root;
+ s[top].branch_id = i = 0;
+ n = s[top].sn;
+
+ while (top >= 0) {
+ n = s[top].sn;
+ 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.ptr &&
+ RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) {
+ s[top++].branch_id = i + 1;
+ /* add next node to stack */
+ s[top].sn = n->branch[i].child.ptr;
+ s[top].branch_id = 0;
+ found = 0;
+ break;
+ }
+ }
+ if (found) {
+ /* nothing else found, go back up */
+ s[top].branch_id = t->nodecard;
+ top--;
+ }
+ }
+ else { /* this is a leaf node */
+ for (i = 0; i < t->leafcard; i++) {
+ 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(s[top].sn->branch[i].child.id, cbarg)) {
+ /* callback wants to terminate search early */
+ return hitCount;
+ }
+ }
+ }
+ }
+ top--;
+ }
+ }
+
+ return hitCount;
+}
+
+/*
+ * Inserts a new data rectangle into the index structure.
+ * Non-recursively descends tree.
+ * Returns 0 if node was not split and nothing was removed.
+ * Returns 1 if root node was split. Old node updated to become one of two.
+ * Returns 2 if branches need to be reinserted.
+ * The level argument specifies the number of steps up from the leaf
+ * level to insert; e.g. a data rectangle goes in at level = 0.
+ */
+static int RTreeInsertRect2M(struct Rect *r, union Child child, int level,
+ struct Node **newnode,
+ struct RTree *t,
+ struct ListBranch **ee, int *overflow)
+{
+ int i;
+ struct Branch b;
+ struct Node *n, *n2;
+ struct Rect *cover;
+ struct stack s[MAXLEVEL];
+ int top = 0, down = 0;
+ int result;
+
+ /* add root node to stack */
+ s[top].sn = t->root;
+
+ /* go down to level of insertion */
+ while (s[top].sn->level > level) {
+ n = s[top].sn;
+ i = RTreePickBranch(r, n, t);
+ s[top++].branch_id = i;
+ /* add next node to stack */
+ s[top].sn = n->branch[i].child.ptr;
+ }
+
+ /* Have reached level for insertion. Remove p rectangles or split */
+ if (s[top].sn->level == level) {
+ b.rect = *r;
+ /* child field of leaves contains tid of data record */
+ b.child = child;
+ /* add branch, may split node or remove branches */
+ if (top)
+ cover = &(s[top - 1].sn->branch[s[top - 1].branch_id].rect);
+ else
+ cover = NULL;
+ result = RTreeAddBranch(&b, s[top].sn, &n2, ee, cover, overflow, t);
+ /* update node count */
+ if (result == 1) {
+ t->n_nodes++;
+ }
+ }
+ else {
+ /* Not supposed to happen */
+ assert(0);
+ return 0;
+ }
+
+ /* go back up */
+ while (top) {
+ down = top--;
+ i = s[top].branch_id;
+ if (result == 0) { /* branch was added */
+ s[top].sn->branch[i].rect =
+ RTreeCombineRect(r, &(s[top].sn->branch[i].rect), t);
+ }
+ else if (result == 2) { /* branches were removed */
+ /* get node cover of previous node */
+ s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
+ }
+ else if (result == 1) { /* node was split */
+ /* get node cover of previous node */
+ s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
+ /* add new branch for new node previously added by RTreeAddBranch() */
+ b.child.ptr = n2;
+ b.rect = RTreeNodeCover(b.child.ptr, t);
+
+ /* add branch, may split node or remove branches */
+ if (top)
+ cover = &(s[top - 1].sn->branch[s[top - 1].branch_id].rect);
+ else
+ cover = NULL;
+ result =
+ RTreeAddBranch(&b, s[top].sn, &n2, ee, cover, overflow, t);
+
+ /* update node count */
+ if (result == 1) {
+ t->n_nodes++;
+ }
+ }
+ }
+
+ *newnode = n2;
+
+ return result;
+}
+
+/*
+ * Insert a data rectangle into an index structure.
+ * RTreeInsertRectM provides for splitting the root;
+ * returns 1 if root was split, 0 if it was not.
+ * The level argument specifies the number of steps up from the leaf
+ * level to insert; e.g. a data rectangle goes in at level = 0.
+ * RTreeInsertRect2 does the actual insertion.
+ */
+int RTreeInsertRectM(struct Rect *r, union Child child, int level,
+ struct RTree *t)
+{
+ struct Node *newnode;
+ struct Node *newroot;
+ struct Branch b;
+ struct ListBranch *reInsertList = NULL;
+ struct ListBranch *e;
+ int result;
+ int i, overflow[MAXLEVEL];
+
+ /* R*-tree forced reinsertion: for each level only once */
+ for (i = 0; i < MAXLEVEL; i++)
+ overflow[i] = 1;
+
+ result =
+ RTreeInsertRect2M(r, child, level, &newnode, t, &reInsertList,
+ overflow);
+
+ if (result == 1) { /* root split */
+ /* grow a new root, & tree taller */
+ t->rootlevel++;
+ newroot = RTreeNewNode(t, t->rootlevel);
+ newroot->level = t->rootlevel;
+ /* branch for old root */
+ b.rect = RTreeNodeCover(t->root, t);
+ b.child.ptr = t->root;
+ RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
+ /* branch for new node created by RTreeInsertRect2() */
+ b.rect = RTreeNodeCover(newnode, t);
+ b.child.ptr = newnode;
+ RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
+ /* set new root node */
+ t->root = newroot;
+ t->n_nodes++;
+ }
+ else if (result == 2) { /* branches were removed */
+ while (reInsertList) {
+ /* get next branch in list */
+ b = reInsertList->b;
+ level = reInsertList->level;
+ e = reInsertList;
+ reInsertList = reInsertList->next;
+ RTreeFreeListBranch(e);
+ /* reinsert branches */
+ result =
+ RTreeInsertRect2M(&(b.rect), b.child, level, &newnode, t,
+ &reInsertList, overflow);
+
+ if (result == 1) { /* root split */
+ /* grow a new root, & tree taller */
+ t->rootlevel++;
+ newroot = RTreeNewNode(t, t->rootlevel);
+ newroot->level = t->rootlevel;
+ /* branch for old root */
+ b.rect = RTreeNodeCover(t->root, t);
+ b.child.ptr = t->root;
+ RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
+ /* branch for new node created by RTreeInsertRect2() */
+ b.rect = RTreeNodeCover(newnode, t);
+ b.child.ptr = newnode;
+ RTreeAddBranch(&b, newroot, NULL, NULL, NULL, NULL, t);
+ /* set new root node */
+ t->root = newroot;
+ t->n_nodes++;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Delete a rectangle from non-root part of an index structure.
+ * Called by RTreeDeleteRect. Descends tree non-recursively,
+ * merges branches on the way back up.
+ * Returns 1 if record not found, 0 if success.
+ */
+static int
+RTreeDeleteRect2M(struct Rect *r, union Child child, struct RTree *t,
+ struct ListNode **ee)
+{
+ int i, notfound = 1;
+ struct Node *n;
+ struct stack s[MAXLEVEL];
+ int top = 0, down = 0;
+ int minfill;
+
+ assert(ee);
+
+ /* add root node position to stack */
+ s[top].sn = t->root;
+ s[top].branch_id = 0;
+ n = s[top].sn;
+
+ while (notfound) {
+ /* go down to level 0, remember path */
+ if (s[top].sn->level > 0) {
+ n = s[top].sn;
+ for (i = s[top].branch_id; i < t->nodecard; i++) {
+ if (n->branch[i].child.ptr &&
+ RTreeOverlap(r, &(n->branch[i].rect), t)) {
+ s[top++].branch_id = i + 1;
+ /* add next node to stack */
+ s[top].sn = n->branch[i].child.ptr;
+ s[top].branch_id = 0;
+
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) {
+ /* nothing else found, go back up */
+ s[top].branch_id = t->nodecard;
+ top--;
+ }
+ else /* found a way down but not yet the item */
+ notfound = 1;
+ }
+ else {
+ for (i = 0; i < t->leafcard; i++) {
+ if (s[top].sn->branch[i].child.id &&
+ s[top].sn->branch[i].child.id == child.id) { /* found item */
+ RTreeDisconnectBranch(s[top].sn, i, t);
+ t->n_leafs--;
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) /* continue searching */
+ top--;
+ }
+ }
+
+ if (notfound) {
+ return notfound;
+ }
+
+ /* go back up */
+ while (top) {
+ down = top;
+ top--;
+ i = s[top].branch_id - 1;
+ assert(s[down].sn->level == s[top].sn->level - 1);
+
+ minfill = (s[down].sn->level ? t->min_node_fill : t->min_leaf_fill);
+ if (s[down].sn->count >= minfill) {
+ /* just update node cover */
+ s[top].sn->branch[i].rect = RTreeNodeCover(s[down].sn, t);
+ }
+ else {
+ /* not enough entries in child, eliminate child node */
+ RTreeReInsertNode(s[top].sn->branch[i].child.ptr, ee);
+ RTreeDisconnectBranch(s[top].sn, i, t);
+ }
+ }
+
+ return notfound;
+}
+
+/*
+ * should be called by RTreeDeleteRect() only
+ *
+ * Delete a data rectangle from an index structure.
+ * Pass in a pointer to a Rect, the tid of the record, ptr RTree.
+ * Returns 1 if record not found, 0 if success.
+ * RTreeDeleteRect1 provides for eliminating the root.
+ */
+int RTreeDeleteRectM(struct Rect *r, union Child child, struct RTree *t)
+{
+ int i;
+ struct Node *n;
+ struct ListNode *reInsertList = NULL;
+ struct ListNode *e;
+
+ if (!RTreeDeleteRect2M(r, child, t, &reInsertList)) {
+ /* found and deleted a data item */
+
+ /* reinsert any branches from eliminated nodes */
+ while (reInsertList) {
+ t->n_nodes--;
+ n = reInsertList->node;
+ if (n->level > 0) { /* reinsert node branches */
+ for (i = 0; i < t->nodecard; i++) {
+ if (n->branch[i].child.ptr) {
+ RTreeInsertRectM(&(n->branch[i].rect),
+ n->branch[i].child, n->level, t);
+ }
+ }
+ }
+ else { /* reinsert leaf branches */
+ for (i = 0; i < t->leafcard; i++) {
+ if (n->branch[i].child.id) {
+ RTreeInsertRectM(&(n->branch[i].rect),
+ n->branch[i].child, n->level, t);
+ }
+ }
+ }
+ e = reInsertList;
+ reInsertList = reInsertList->next;
+ RTreeFreeNode(e->node);
+ RTreeFreeListNode(e);
+ }
+
+ /* check for redundant root (not leaf, 1 child) and eliminate */
+ n = t->root;
+
+ if (n->count == 1 && n->level > 0) {
+ for (i = 0; i < t->nodecard; i++) {
+ if (n->branch[i].child.ptr)
+ break;
+ }
+ t->root = n->branch[i].child.ptr;
+ RTreeFreeNode(n);
+ t->rootlevel--;
+ }
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
Property changes on: grass/trunk/lib/vector/rtree/indexm.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/lib/vector/rtree/io.c
===================================================================
--- grass/trunk/lib/vector/rtree/io.c (rev 0)
+++ grass/trunk/lib/vector/rtree/io.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -0,0 +1,134 @@
+
+/****************************************************************************
+* MODULE: R-Tree library
+*
+* AUTHOR(S): Antonin Guttman - original code
+* Daniel Green (green at superliminal.com) - major clean-up
+* and implementation of bounding spheres
+* Markus Metz - file-based and memory-based R*-tree
+*
+* PURPOSE: Multidimensional index
+*
+* COPYRIGHT: (C) 2001 by 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.
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <grass/config.h>
+#include "index.h"
+
+/* add new free node position for recycling */
+void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
+{
+ int which;
+
+ if (t->free_nodes.avail >= t->free_nodes.alloc) {
+ size_t size;
+
+ t->free_nodes.alloc += 100;
+ size = t->free_nodes.alloc * sizeof(off_t);
+ t->free_nodes.pos = (off_t *)realloc((void *)t->free_nodes.pos, size);
+ assert(t->free_nodes.pos);
+ }
+ t->free_nodes.pos[t->free_nodes.avail++] = pos;
+
+ which = pos == t->nb[level][1].pos;
+ t->nb[level][which].pos = -1;
+ t->nb[level][which].dirty = 0;
+ t->mru[level] = which == 0;
+}
+
+/* looks for free node position, sets file pointer, returns position */
+off_t RTreeGetNodePos(struct RTree *t)
+{
+ if (t->free_nodes.avail > 0) {
+ t->free_nodes.avail--;
+ return lseek(t->fd, t->free_nodes.pos[t->free_nodes.avail], SEEK_SET);
+ }
+ else {
+ return lseek(t->fd, 0, SEEK_END);
+ }
+}
+
+/* read node from file */
+size_t RTreeReadNode(struct Node *n, off_t nodepos, struct RTree *t)
+{
+ lseek(t->fd, nodepos, SEEK_SET);
+ return read(t->fd, n, t->nodesize);
+}
+
+/* get node from buffer or file */
+void RTreeGetNode(struct Node *n, off_t nodepos, int level, struct RTree *t)
+{
+ int which = nodepos == t->nb[level][1].pos;
+
+ if (t->nb[level][which].pos != nodepos) {
+ /* which is 0 */
+ /* replace least recently used */
+ /* least recently used is faster than most recently used */
+ if (t->nb[level][which].pos != -1)
+ which = t->mru[level] == 0;
+ /* rewrite node in buffer */
+ if (t->nb[level][which].dirty) {
+ RTreeRewriteNode(&(t->nb[level][which].n), t->nb[level][which].pos, t);
+ t->nb[level][which].dirty = 0;
+ }
+ RTreeReadNode(&(t->nb[level][which].n), nodepos, t);
+ t->nb[level][which].pos = nodepos;
+ }
+ t->mru[level] = which;
+ *n = t->nb[level][which].n;
+}
+
+/* write new node to file */
+size_t RTreeWriteNode(struct Node *n, struct RTree *t)
+{
+ /* file position must be set first with RTreeGetFNodePos() */
+ return write(t->fd, n, t->nodesize);
+}
+
+/* rewrite updated node to file */
+size_t RTreeRewriteNode(struct Node *n, off_t nodepos, struct RTree *t)
+{
+ lseek(t->fd, nodepos, SEEK_SET);
+ return write(t->fd, n, t->nodesize);
+}
+
+/* update node in buffer */
+void RTreePutNode(struct Node *n, off_t nodepos, struct RTree *t)
+{
+ int which = nodepos == t->nb[n->level][1].pos;
+
+ t->nb[n->level][which].n = *n;
+ t->nb[n->level][which].dirty = 1;
+ t->mru[n->level] = which;
+}
+
+/* update rectangle */
+void RTreeUpdateRect(struct Rect *r, struct Node *n, off_t nodepos, int b, struct RTree *t)
+{
+ int which = nodepos == t->nb[n->level][1].pos;
+
+ t->nb[n->level][which].n.branch[b].rect = n->branch[b].rect = *r;
+ t->nb[n->level][which].dirty = 1;
+ t->mru[n->level] = which;
+}
+
+void RTreeFlushBuffer(struct RTree *t)
+{
+ int i;
+
+ for (i = 0; i <= t->rootlevel; i++) {
+ if (t->nb[i][0].dirty)
+ RTreeRewriteNode(&(t->nb[i][0].n), t->nb[i][0].pos, t);
+ if (t->nb[i][1].dirty)
+ RTreeRewriteNode(&(t->nb[i][1].n), t->nb[i][1].pos, t);
+ }
+}
Property changes on: grass/trunk/lib/vector/rtree/io.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Modified: grass/trunk/lib/vector/rtree/node.c
===================================================================
--- grass/trunk/lib/vector/rtree/node.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/node.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <grass/gis.h>
#include "index.h"
#include "card.h"
@@ -30,11 +31,17 @@
};
/* Initialize one branch cell in an internal node. */
-static void RTreeInitNodeBranch(struct Branch *b)
+static void RTreeInitNodeBranchM(struct Branch *b)
{
RTreeInitRect(&(b->rect));
b->child.ptr = NULL;
+}
+/* Initialize one branch cell in an internal node. */
+static void RTreeInitNodeBranchF(struct Branch *b)
+{
+ RTreeInitRect(&(b->rect));
+ b->child.pos = -1;
}
/* Initialize one branch cell in a leaf node. */
@@ -42,28 +49,23 @@
{
RTreeInitRect(&(b->rect));
b->child.id = 0;
-
}
-static void (*RTreeInitBranch[2]) () = {
- RTreeInitLeafBranch, RTreeInitNodeBranch
+static void (*RTreeInitBranch[3]) () = {
+ RTreeInitLeafBranch, RTreeInitNodeBranchM, RTreeInitNodeBranchF
};
/* Initialize a Node structure. */
-void RTreeInitNode(struct Node *n, int level)
+/* type = 1: leaf, type = 2: internal, memory, type = 3: internal, file */
+void RTreeInitNode(struct Node *n, int type)
{
int i;
n->count = 0;
n->level = -1;
- if (level > 0) {
- for (i = 0; i < MAXCARD; i++)
- RTreeInitNodeBranch(&(n->branch[i]));
- }
- else {
- for (i = 0; i < MAXCARD; i++)
- RTreeInitLeafBranch(&(n->branch[i]));
- }
+
+ for (i = 0; i < MAXCARD; i++)
+ RTreeInitBranch[type](&(n->branch[i]));
}
/* Make a new node and initialize to have all branch cells empty. */
@@ -73,7 +75,7 @@
n = (struct Node *)malloc((size_t) t->nodesize);
assert(n);
- RTreeInitNode(n, level);
+ RTreeInitNode(n, NODETYPE(level, t->fd));
return n;
}
@@ -92,12 +94,10 @@
int i, first_time = 1;
struct Rect r;
- assert(n);
-
RTreeInitRect(&r);
if ((n)->level > 0) { /* internal node */
for (i = 0; i < t->nodecard; i++) {
- if (n->branch[i].child.ptr) {
+ if (t->valid_child(&(n->branch[i].child))) {
if (first_time) {
r = n->branch[i].rect;
first_time = 0;
@@ -134,23 +134,21 @@
* to get the best resolution when searching.
*/
-static int RTreePickBranch1(struct Rect *r, struct Node *n, struct RTree *t)
+static int RTreePickLeafBranch(struct Rect *r, struct Node *n, struct RTree *t)
{
struct Rect *rr;
int i, j;
- RectReal increase, bestIncr = (RectReal) - 1, area, bestArea = 0;
+ RectReal increase, bestIncr = -1, area, bestArea = 0;
int best = 0, bestoverlap;
struct Rect tmp_rect;
int overlap;
- assert(r && n && t);
-
bestoverlap = t->nodecard + 1;
/* get the branch that will overlap with the smallest number of
* sibling branches when including the new rectangle */
for (i = 0; i < t->nodecard; i++) {
- if (n->branch[i].child.ptr) {
+ if (t->valid_child(&(n->branch[i].child))) {
rr = &n->branch[i].rect;
tmp_rect = RTreeCombineRect(r, rr, t);
area = RTreeRectSphericalVolume(rr, t);
@@ -199,18 +197,17 @@
{
struct Rect *rr;
int i, first_time = 1;
- RectReal increase, bestIncr = (RectReal) - 1, area, bestArea = 0;
+ RectReal increase, bestIncr = (RectReal) -1, area, bestArea = 0;
int best = 0;
struct Rect tmp_rect;
- assert(r && n && t);
assert((n)->level > 0); /* must not be called on leaf node */
if ((n)->level == 1)
- return RTreePickBranch1(r, n, t);
+ return RTreePickLeafBranch(r, n, t);
for (i = 0; i < t->nodecard; i++) {
- if (n->branch[i].child.ptr) {
+ if (t->valid_child(&(n->branch[i].child))) {
rr = &n->branch[i].rect;
area = RTreeRectSphericalVolume(rr, t);
tmp_rect = RTreeCombineRect(r, rr, t);
@@ -235,8 +232,11 @@
{
if ((n)->level > 0) {
assert(n && i >= 0 && i < t->nodecard);
- assert(n->branch[i].child.ptr);
- RTreeInitNodeBranch(&(n->branch[i]));
+ assert(t->valid_child(&(n->branch[i].child)));
+ if (t->fd < 0)
+ RTreeInitNodeBranchM(&(n->branch[i]));
+ else
+ RTreeInitNodeBranchF(&(n->branch[i]));
}
else {
assert(n && i >= 0 && i < t->leafcard);
@@ -265,11 +265,11 @@
RTreeFreeNode(n);
}
-/**********************************************************************
- * *
- * R*-tree: force remove p (currently 3) branches for reinsertion *
- * *
- **********************************************************************/
+/****************************************************************
+ * *
+ * R*-tree: force remove FORCECARD branches for reinsertion *
+ * *
+ ****************************************************************/
/*
* swap dist structs
@@ -399,15 +399,8 @@
static struct ListBranch *RTreeNewListBranch(void)
{
return (struct ListBranch *)malloc(sizeof(struct ListBranch));
- /* return new ListBranch; */
}
-/*
- * Remove branches from a node. Select the 3 branches whose rectangle
- * center is farthest away from node cover center.
- * Old node updated.
- */
-
/*
* Add a branch to the reinsertion list. It will later
* be reinserted into the index structure.
@@ -424,11 +417,16 @@
*ee = l;
}
+/*
+ * Remove branches from a node. Select the 2 branches whose rectangle
+ * center is farthest away from node cover center.
+ * Old node updated.
+ */
static void RTreeRemoveBranches(struct Node *n, struct Branch *b,
struct ListBranch **ee, struct Rect *cover,
struct RTree *t)
{
- int i, j, maxkids, is_node;
+ int i, j, maxkids, type;
RectReal center_n[NUMDIMS], center_r, delta;
struct Branch branchbuf[MAXCARD + 1];
struct dist rdist[MAXCARD + 1];
@@ -436,15 +434,9 @@
assert(cover);
- if ((n)->level > 0) {
- maxkids = t->nodecard;
- is_node = 1;
- }
- else {
- maxkids = t->leafcard;
- is_node = 0;
- }
-
+ maxkids = MAXKIDS((n)->level, t);
+ type = NODETYPE((n)->level, t->fd);
+
assert(n->count == maxkids); /* must be full */
new_cover = RTreeCombineRect(cover, &(b->rect), t);
@@ -467,7 +459,7 @@
rdist[i].distance += delta * delta;
}
- RTreeInitBranch[is_node](&(n->branch[i]));
+ RTreeInitBranch[type](&(n->branch[i]));
}
/* new branch */
@@ -501,23 +493,20 @@
* Returns 0 if node not split. Old node updated.
* Returns 1 if node split, sets *new_node to address of new node.
* Old node updated, becomes one of two.
- * Returns 2 if branches wereremoved for forced reinsertion
+ * Returns 2 if branches were removed for forced reinsertion
*/
int RTreeAddBranch(struct Branch *b, struct Node *n,
- struct Node **new_node, struct ListBranch **ee,
+ struct Node **newnode, struct ListBranch **ee,
struct Rect *cover, int *overflow, struct RTree *t)
{
int i, maxkids;
- assert(b);
- assert(n);
+ maxkids = MAXKIDS((n)->level, t);
- maxkids = ((n)->level > 0 ? t->nodecard : t->leafcard);
-
if (n->count < maxkids) { /* split won't be necessary */
if ((n)->level > 0) { /* internal node */
- for (i = 0; i < t->nodecard; i++) { /* find empty branch */
- if (n->branch[i].child.ptr == NULL) {
+ for (i = 0; i < maxkids; i++) { /* find empty branch */
+ if (!t->valid_child(&(n->branch[i].child))) {
n->branch[i] = *b;
n->count++;
break;
@@ -526,7 +515,7 @@
return 0;
}
else if ((n)->level == 0) { /* leaf */
- for (i = 0; i < t->leafcard; i++) { /* find empty branch */
+ for (i = 0; i < maxkids; i++) { /* find empty branch */
if (n->branch[i].child.id == 0) {
n->branch[i] = *b;
n->count++;
@@ -537,15 +526,18 @@
}
}
else {
- if (n->level < t->n_levels && overflow[n->level]) {
+ if (n->level < t->rootlevel && overflow[n->level]) {
/* R*-tree forced reinsert */
RTreeRemoveBranches(n, b, ee, cover, t);
overflow[n->level] = 0;
return 2;
}
else {
- *new_node = RTreeNewNode(t, (n)->level);
- RTreeSplitNode(n, b, *new_node, t);
+ if (t->fd > -1)
+ RTreeInitNode(*newnode, NODETYPE(n->level, t->fd));
+ else
+ *newnode = RTreeNewNode(t, (n)->level);
+ RTreeSplitNode(n, b, *newnode, t);
return 1;
}
}
@@ -580,7 +572,6 @@
RTreeTabIn(depth);
-
maxkids = (n->level > 0 ? t->nodecard : t->leafcard);
fprintf(stdout, "node");
@@ -606,3 +597,4 @@
}
}
}
+
Modified: grass/trunk/lib/vector/rtree/rect.c
===================================================================
--- grass/trunk/lib/vector/rtree/rect.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/rect.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -251,7 +251,7 @@
/*
* The exact volume of the bounding sphere for the given Rect.
*/
-RectReal RTreeRectSphericalVolume(struct Rect * r, struct RTree * t)
+RectReal RTreeRectSphericalVolume(struct Rect *r, struct RTree *t)
{
int i;
double sum_of_squares = 0, radius, half_extent;
@@ -272,7 +272,7 @@
/*-----------------------------------------------------------------------------
| Calculate the n-dimensional surface area of a rectangle
-----------------------------------------------------------------------------*/
-RectReal RTreeRectSurfaceArea(struct Rect * r, struct RTree * t)
+RectReal RTreeRectSurfaceArea(struct Rect *r, struct RTree *t)
{
int i, j;
RectReal j_extent, sum = (RectReal) 0;
@@ -301,7 +301,7 @@
| Calculate the n-dimensional margin of a rectangle
| the margin is the sum of the lengths of the edges
-----------------------------------------------------------------------------*/
-RectReal RTreeRectMargin(struct Rect * r, struct RTree * t)
+RectReal RTreeRectMargin(struct Rect *r, struct RTree *t)
{
int i;
RectReal margin = 0.0;
@@ -342,6 +342,26 @@
/*-----------------------------------------------------------------------------
+| Decide whether two rectangles are identical.
+-----------------------------------------------------------------------------*/
+int RTreeCompareRect(struct Rect *r, struct Rect *s, struct RTree *t)
+{
+ register int i, j;
+
+ assert(r && s);
+
+ for (i = 0; i < t->ndims; i++) {
+ j = i + NUMDIMS; /* index for high sides */
+ if (r->boundary[i] != s->boundary[i] ||
+ r->boundary[j] != s->boundary[j]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*-----------------------------------------------------------------------------
| Decide whether two rectangles overlap.
-----------------------------------------------------------------------------*/
int RTreeOverlap(struct Rect *r, struct Rect *s, struct RTree *t)
@@ -368,7 +388,7 @@
{
register int i, j, result;
- assert(r && s); /* same as in RTreeOverlap() */
+ assert(r && s);
/* undefined rect is contained in any other */
if (Undefined(r))
Modified: grass/trunk/lib/vector/rtree/rtree.h
===================================================================
--- grass/trunk/lib/vector/rtree/rtree.h 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/rtree.h 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
Modified: grass/trunk/lib/vector/rtree/split.c
===================================================================
--- grass/trunk/lib/vector/rtree/split.c 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/split.c 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2001 by the GRASS Development Team
*
* This program is free software under the GNU General
* Public License (>=v2). Read the file COPYING that comes
@@ -34,7 +34,7 @@
RectReal CoverSplitArea;
/* variables for finding a partition */
-struct PartitionVars Partitions[METHODS];
+struct PartitionVars Partitions[1];
/*----------------------------------------------------------------------
| Load branch buffer with branches from full node plus the extra branch.
@@ -44,14 +44,11 @@
{
int i, maxkids = 0;
- assert(n);
- assert(b);
-
if ((n)->level > 0) {
maxkids = t->nodecard;
/* load the branch buffer */
for (i = 0; i < maxkids; i++) {
- assert(n->branch[i].child.ptr); /* n should have every entry full */
+ assert(t->valid_child(&(n->branch[i].child))); /* n should have every entry full */
BranchBuf[i] = n->branch[i];
}
}
@@ -67,14 +64,16 @@
BranchBuf[maxkids] = *b;
BranchCount = maxkids + 1;
- /* calculate rect containing all in the set */
- CoverSplit = BranchBuf[0].rect;
- for (i = 1; i < maxkids + 1; i++) {
- CoverSplit = RTreeCombineRect(&CoverSplit, &BranchBuf[i].rect, t);
+ if (METHOD == 0) { /* quadratic split */
+ /* calculate rect containing all in the set */
+ CoverSplit = BranchBuf[0].rect;
+ for (i = 1; i < maxkids + 1; i++) {
+ CoverSplit = RTreeCombineRect(&CoverSplit, &BranchBuf[i].rect, t);
+ }
+ CoverSplitArea = RTreeRectSphericalVolume(&CoverSplit, t);
}
- CoverSplitArea = RTreeRectSphericalVolume(&CoverSplit, t);
- RTreeInitNode(n, n->level);
+ RTreeInitNode(n, NODETYPE(n->level, t->fd));
}
/*----------------------------------------------------------------------
@@ -83,26 +82,27 @@
static void RTreeClassify(int i, int group, struct PartitionVars *p,
struct RTree *t)
{
- assert(p);
assert(!p->taken[i]);
p->partition[i] = group;
p->taken[i] = TRUE;
- if (p->count[group] == 0)
- p->cover[group] = BranchBuf[i].rect;
- else
- p->cover[group] =
- RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group], t);
- p->area[group] = RTreeRectSphericalVolume(&p->cover[group], t);
+ if (METHOD == 0) {
+ if (p->count[group] == 0)
+ p->cover[group] = BranchBuf[i].rect;
+ else
+ p->cover[group] =
+ RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group], t);
+ p->area[group] = RTreeRectSphericalVolume(&p->cover[group], t);
+ }
p->count[group]++;
}
-/**********************************************************************
- * *
- * Toni Guttman's quadratic splitting method *
- * *
- **********************************************************************/
+/***************************************************
+ * *
+ * Toni Guttman's quadratic splitting method *
+ * *
+ ***************************************************/
/*----------------------------------------------------------------------
| Pick two rects from set to be the first elements of the two groups.
@@ -146,11 +146,6 @@
{
int i;
- assert(n);
- assert(q);
- assert(p);
- assert(t);
-
for (i = 0; i < p->total; i++) {
assert(p->partition[i] == 0 || p->partition[i] == 1);
if (p->partition[i] == 0)
@@ -167,8 +162,6 @@
{
int i;
- assert(p);
-
p->count[0] = p->count[1] = 0;
p->cover[0] = p->cover[1] = RTreeNullRect();
p->area[0] = p->area[1] = (RectReal) 0;
@@ -188,8 +181,6 @@
{
int i;
- assert(p);
-
fprintf(stdout, "\npartition:\n");
for (i = 0; i < p->total; i++) {
fprintf(stdout, "%3d\t", i);
@@ -242,8 +233,6 @@
RectReal biggestDiff;
int group, chosen = 0, betterGroup = 0;
- assert(p);
-
RTreeInitPVars(p, BranchCount, minfill);
RTreePickSeeds(p, t);
@@ -367,9 +356,9 @@
return last;
}
- /* Larger of two */
- if (RTreeCompareBranches(&(BranchBuf[first]), &(BranchBuf[mid]), side) ==
- 1) {
+ /* larger of two */
+ if (RTreeCompareBranches(&(BranchBuf[first]), &(BranchBuf[mid]), side)
+ == 1) {
larger = pivot = first;
smaller = mid;
}
@@ -462,9 +451,9 @@
| These last are the ones that can go in either group most easily.
----------------------------------------------------------------------*/
static void RTreeMethodOne(struct PartitionVars *p, int minfill,
- struct RTree *t)
+ int maxkids, struct RTree *t)
{
- int i, j, k, l, s, maxkids;
+ int i, j, k, l, s;
int axis = 0, best_axis = 0, side = 0, best_side[NUMDIMS];
int best_cut[NUMDIMS];
RectReal margin, smallest_margin = 0;
@@ -472,12 +461,8 @@
int minfill1 = minfill - 1;
RectReal overlap, vol, smallest_overlap = -1, smallest_vol = -1;
- assert(p);
-
RTreeInitPVars(p, BranchCount, minfill);
- maxkids = (minfill == t->min_leaf_fill ? t->leafcard : t->nodecard);
-
margin = DBL_MAX;
/* choose split axis */
@@ -523,8 +508,8 @@
/* the margin is the sum of the lengths of the edges of a rectangle */
margin =
- RTreeRectMargin(&testrect1,
- t) + RTreeRectMargin(&testrect2, t);
+ RTreeRectMargin(&testrect1, t) +
+ RTreeRectMargin(&testrect2, t);
/* remember best axis */
if (margin <= smallest_margin) {
@@ -539,10 +524,8 @@
for (k = 0; k < t->ndims; k++) {
/* no overlap */
- if (testrect1.boundary[k] >
- testrect2.boundary[k + NUMDIMS] ||
- testrect1.boundary[k + NUMDIMS] <
- testrect2.boundary[k]) {
+ if (testrect1.boundary[k] > testrect2.boundary[k + NUMDIMS] ||
+ testrect1.boundary[k + NUMDIMS] < testrect2.boundary[k]) {
overlap = 0;
break;
}
@@ -564,8 +547,8 @@
overlap = RTreeRectVolume(&orect, t);
vol =
- RTreeRectVolume(&testrect1,
- t) + RTreeRectVolume(&testrect2, t);
+ RTreeRectVolume(&testrect1, t) +
+ RTreeRectVolume(&testrect2, t);
/* get best cut for this axis */
if (overlap <= smallest_overlap) {
@@ -582,9 +565,9 @@
best_side[i] = s;
}
}
- } /* end of distribution check */
- } /* end of side check */
- } /* end of axis check */
+ } /* end of distribution check */
+ } /* end of side check */
+ } /* end of axis check */
/* Use best distribution to classify branches */
if (best_axis != axis || best_side[best_axis] != side)
@@ -614,18 +597,17 @@
struct PartitionVars *p;
int level;
- assert(n);
- assert(b);
-
/* load all the branches into a buffer, initialize old node */
level = n->level;
RTreeGetBranches(n, b, t);
/* find partition */
p = &Partitions[0];
- /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */
- /* RTreeMethodZero(p, level > 0 ? t->min_node_fill : t->min_leaf_fill, t); */
- RTreeMethodOne(p, level > 0 ? t->min_node_fill : t->min_leaf_fill, t);
+
+ if (METHOD == 1) /* R* split */
+ RTreeMethodOne(p, MINFILL(level, t), MAXKIDS(level, t), t);
+ else
+ RTreeMethodZero(p, MINFILL(level, t), t);
/*
* put branches from buffer into 2 nodes
Modified: grass/trunk/lib/vector/rtree/split.h
===================================================================
--- grass/trunk/lib/vector/rtree/split.h 2011-01-04 09:59:59 UTC (rev 44854)
+++ grass/trunk/lib/vector/rtree/split.h 2011-01-04 10:01:42 UTC (rev 44855)
@@ -5,11 +5,11 @@
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green (green at superliminal.com) - major clean-up
* and implementation of bounding spheres
-* Markus Metz - R*-tree
+* Markus Metz - file-based and memory-based R*-tree
*
* PURPOSE: Multidimensional index
*
-* COPYRIGHT: (C) 2009 by the GRASS Development Team
+* COPYRIGHT: (C) 2010 by the GRASS Development Team
*
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
@@ -20,7 +20,9 @@
| Definitions and global variables.
-----------------------------------------------------------------------------*/
-#define METHODS 1
+/* METHOD 0: R-Tree, quadratic split */
+/* METHOD 1: R*-Tree split */
+#define METHOD 1
struct PartitionVars {
int partition[MAXCARD + 1];
@@ -37,5 +39,6 @@
extern RectReal CoverSplitArea;
/* variables for finding a partition */
-extern struct PartitionVars Partitions[METHODS];
+extern struct PartitionVars Partitions[1];
+extern void RTreeInitPVars(struct PartitionVars *, int, int);
More information about the grass-commit
mailing list