RTree.c 最新源代码

RTree.c 最新源代码

cheungmine

(现在这个是线程安全的!)

一、什么是RTree

“R树是B树向多维空间发展的另一种形式,它将空间对象按范围划分,每个结点都对应一个区域和一个磁盘页,非叶结点的磁盘页中存储其所有子结点的区域范围,非叶结点的所有子结点的区域都落在它的区域范围之内;叶结点的磁盘页中存储其区域范围之内的所有空间对象的外接矩形。每个结点所能拥有的子结点数目有上、下限,下限保证对磁盘空间的有效利用,上限保证每个结点对应一个磁盘页,当插入新的结点导致某结点要求的空间大于一个磁盘页时,该结点一分为二。R树是一种动态索引结构,即:它的查询可与插入或删除同时进行,而且不需要定期地对树结构进行重新组织。当更新一个关系并且在这个关系上正在做扫描时,如果更新影响到了扫描操作的任何一个页,我们需要检查扫描并且修复它。”

其实上面的话,你也不用多做研究。理解RTree是范围树,适合做空间索引(快速查找)。更多的关于RTree的知识我也没时间写在这里,我只知道原理,然后提供了下面的代码(经过我修改,看起来更顺眼些)。一定要用它。感谢算法的原作者和发明算法的人。“帝国大厦的建立,人才更在资本之上”啊!

 二、RTree的实现代码

本文的代码来源于GRASS,我根据自己的习惯,作了适当的修改,把原来多个文件合成了2个文件(rtree.h和rtree.c)。本文提供了完整的rtree实现代码和一个简单的测试代码(test.c)。如果你发现什么问题,请及时提交评论,以利改正。

RTree.h文件:

/****************************************************************************
* RTree.H
*
* MODULE:       R-Tree library
*             
* AUTHOR(S):    Antonin Guttman - original code
*               Daniel Green (green@superliminal.com) - major clean-up
*                               and implementation of bounding spheres
*              
* PURPOSE:      Multi Dimensional 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.
*
* LAST MODIFY: 
*    2007-11:   Initially created by ZhangLiang (cheungmine@gmail.com)
*    2008-5:    Multiple threads safe supports
*****************************************************************************/
#ifndef  RTREE_H_INCLUDED
#define  RTREE_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

/* PAGE_SIZE is normally the natural page size of the machine */
#define  PAGE_SIZE    512
#define  DIMS_NUMB    3       /* number of dimensions */
#define  SIDES_NUMB   2*DIMS_NUMB

/* typedef float REALTYPE; */
typedef double REALTYPE;


#ifndef  TRUE
#define  TRUE  1
#define  FALSE  0
#endif


typedef struct _RTREEMBR
{
 REALTYPE bound[SIDES_NUMB]; /* xmin,ymin,...,xmax,ymax,... */
}RTREEMBR;

typedef struct _RTREEBRANCH
{  
 RTREEMBR mbr;
 struct _RTREENODE *child; /* mbr id */
}RTREEBRANCH;

/* max branching factor of a node */
#define MAXCARD (int)((PAGE_SIZE-(2*sizeof(int))) / sizeof(RTREEBRANCH))

typedef struct _RTREENODE*  HRTREENODE;
typedef struct _RTREEROOT*  HRTREEROOT;

/*
* If passed to a tree search, this callback function will be called
* with the ID of each data mbr that overlaps the search mbr
* 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 (*PFNRTreeSearchCallback)(void* data_id, void* pfnParam);


/**
* Initialize a rectangle to have all 0 coordinates.
*/
void RTreeInitRect( RTREEMBR *mbr);

/**
* Return a mbr whose first low side is higher than its opposite side -
* interpreted as an undefined mbr.
*/
RTREEMBR RTreeNullRect(void);


/**
* Print out the data for a rectangle.
*/
void RTreePrintRect( RTREEMBR *mbr, int depth );

/**
* Calculate the 2-dimensional area of a rectangle
*/
REALTYPE RTreeRectArea( RTREEMBR *mbr );

/**
* Calculate the n-dimensional volume of a rectangle
*/
REALTYPE RTreeRectVolume( RTREEMBR *mbr );


/**
* Calculate the n-dimensional volume of the bounding sphere of a rectangle
* The exact volume of the bounding sphere for the given RTREEMBR.
*/
REALTYPE RTreeRectSphericalVolume( RTREEMBR *mbr );


/**
* Calculate the n-dimensional surface area of a rectangle
*/
REALTYPE RTreeRectSurfaceArea( RTREEMBR *mbr );


/**
* Combine two rectangles, make one that includes both.
*/
RTREEMBR RTreeCombineRect( RTREEMBR *rc1, RTREEMBR *rc2 );


/**
* Decide whether two rectangles overlap.
*/
int RTreeOverlap( RTREEMBR *rc1, RTREEMBR *rc2);


/**
* Decide whether rectangle r is contained in rectangle s.
*/
int RTreeContained( RTREEMBR *r, RTREEMBR *s);

/**
* Split a node.
* Divides the nodes branches and the extra one between two nodes.
* Old node is one of the new ones, and one really new one is created.
* Tries more than one method for choosing a partition, uses best result.
*/
void RTreeSplitNode(HRTREEROOT root, HRTREENODE node, RTREEBRANCH *br, HRTREENODE *new_node);

/**
* Initialize a RTREENODE structure.
*/
void RTreeInitNode( HRTREENODE node );

/**
* Make a new node and initialize to have all branch cells empty.
*/
HRTREENODE RTreeNewNode(void);

void RTreeFreeNode( HRTREENODE node );


/**
* Print out the data in a node.
*/
void RTreePrintNode( HRTREENODE node, int depth );


/**
* Find the smallest rectangle that includes all rectangles in branches of a node.
*/
RTREEMBR RTreeNodeCover( HRTREENODE node );


/**
* Pick a branch.  Pick the one that will need the smallest increase
* in area to accomodate the new rectangle.  This will result in the
* least total area for the covering rectangles in the current node.
* In case of a tie, pick the one which was smaller before, to get
* the best resolution when searching.
*/
int RTreePickBranch( RTREEMBR *mbr, HRTREENODE node);


/**
* Add a branch to a node.  Split the node if necessary.
* 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.
*/
int RTreeAddBranch(HRTREEROOT root, RTREEBRANCH *br, HRTREENODE node, HRTREENODE *new_node);


/**
* Disconnect a dependent node.
*/
void RTreeDisconnectBranch( HRTREENODE node, int i );


/**
* Destroy (free) node recursively.
*/
void RTreeDestroyNode ( HRTREENODE node );


/**
* Create a new rtree index, empty. Consists of a single node.
*/
HRTREEROOT RTreeCreate(PFNRTreeSearchCallback  pfnSearchCallback);


/**
* Destroy a rtree root must be a root of rtree. Free all memory.
*/
void RTreeDestroy(HRTREEROOT root);


/**
* Search in an index tree for all data rectangles that overlap the argument rectangle.
* Return the number of qualifying data rects.
*/
int RTreeSearch(HRTREEROOT root, RTREEMBR *mbr, void* pfnSearchCallbackParam);

/**
* Insert a data rectangle into an index structure.
* RTreeInsertRect 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.
* _RTreeInsertRect does the recursion.
*/
int RTreeInsert(HRTREEROOT root, RTREEMBR *data_mbr, void* data_id, int level);

/**
* Delete a data rectangle from an index structure.
* Pass in a pointer to a RTREEMBR, the tid of the record, ptr to ptr to root node.
* Returns 1 if record not found, 0 if success.
* RTreeDeleteRect provides for eliminating the root.
*/
int RTreeDelete(HRTREEROOT root, RTREEMBR *data_mbr, void* data_id);

#ifdef __cplusplus
}
#endif

#endif /* RTREE_H_INCLUDED */

RTree.C文件:

/****************************************************************************
* RTree.C
*
* MODULE:       R-Tree library
*             
* AUTHOR(S):    Antonin Guttman - original code
*               Daniel Green (green@superliminal.com) - major clean-up
*                               and implementation of bounding spheres
*              
* PURPOSE:      Multi Dimensional 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.
*
* LAST MODIFY:         ZhangLiang (cheungmine@gmail.com) - 2007-11
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#include <math.h>

#include "rtree.h"

#define  METHODS  1

/* variables for finding a partition */
typedef struct _RTREEPARTITION
{
 int   partition[MAXCARD+1];
 int   total;
 int   minfill;
 int   taken[MAXCARD+1];
 int   count[2];
 RTREEMBR cover[2];
 REALTYPE area[2];
} RTREEPARTITION;

typedef struct _RTREENODE
{
 int count;
 int level; /* 0 is leaf, others positive */
 RTREEBRANCH  branch[MAXCARD];
}RTREENODE;

typedef struct _RTREELISTNODE
{
     struct _RTREELISTNODE *next;
     RTREENODE  *node;
}RTREELISTNODE;

typedef struct _RTREEROOT
{
 RTREENODE*  root_node;
 
 RTREEBRANCH  BranchBuf[MAXCARD+1];
 int    BranchCount;
 RTREEMBR  CoverSplit;
 REALTYPE  CoverSplitArea;
 RTREEPARTITION Partitions[METHODS];

 PFNRTreeSearchCallback  pfnCallback;
} RTREEROOT;


#define BIG_NUM (FLT_MAX/4.0)

#define INVALID_RECT(x) ((x)->bound[0] > (x)->bound[DIMS_NUMB])

#ifndef MIN
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

int NODECARD = MAXCARD;
int LEAFCARD = MAXCARD;

/* balance criteria for node splitting */
/* NOTE: can be changed if needed. */
#define MINNODEFILL (NODECARD / 2)
#define MINLEAFFILL (LEAFCARD / 2)

#define MAXKIDS(n) ((n)->level > 0 ? NODECARD : LEAFCARD)
#define MINFILL(n) ((n)->level > 0 ? MINNODEFILL : MINLEAFFILL)

/**
 * Methods below not used at all!
 */
static int set_max(int *which, int new_max){
 if(2 > new_max || new_max > MAXCARD)
  return 0;
 *which = new_max;
 return 1;
}
static int RTreeSetNodeMax(int new_max) { return set_max(&NODECARD, new_max); }
static int RTreeSetLeafMax(int new_max) { return set_max(&LEAFCARD, new_max); }
static int RTreeGetNodeMax(void) { return NODECARD; }
static int RTreeGetLeafMax(void) { return LEAFCARD; }


/**
 * Load branch buffer with branches from full node plus the extra branch.
 */
static void _RTreeGetBranches(HRTREEROOT root, RTREENODE *node, RTREEBRANCH *br)
{
 int i;

 assert(node && br);
 
 /* load the branch buffer */
 for (i=0; i<MAXKIDS(node); i++)
 {
  assert(node->branch[i].child); /* n should have every entry full */
  root->BranchBuf[i] = node->branch[i];
 }

 root->BranchBuf[MAXKIDS(node)] = *br;
 root->BranchCount = MAXKIDS(node) + 1;

 /* calculate mbr containing all in the set */
 root->CoverSplit = root->BranchBuf[0].mbr;

 for (i=1; i<MAXKIDS(node)+1; i++)
 {
  root->CoverSplit = RTreeCombineRect(&root->CoverSplit, &root->BranchBuf[i].mbr);
 }

 root->CoverSplitArea = RTreeRectSphericalVolume(&root->CoverSplit);
 RTreeInitNode(node);
}

 

/**
 * Put a branch in one of the groups.
 */
static void _RTreeClassify(HRTREEROOT root, int i, int group, RTREEPARTITION *p)
{
 assert(p);
 assert(!p->taken[i]);

 p->partition[i] = group;
 p->taken[i] = TRUE;

 if (p->count[group] == 0)
  p->cover[group] = root->BranchBuf[i].mbr;
 else
  p->cover[group] = RTreeCombineRect(&root->BranchBuf[i].mbr, &p->cover[group]);
 
 p->area[group] = RTreeRectSphericalVolume(&p->cover[group]);
 p->count[group]++;
}

/**
 * Pick two rects from set to be the first elements of the two groups.
 * Pick the two that waste the most area if covered by a single rectangle.
 */
static void _RTreePickSeeds(HRTREEROOT root, RTREEPARTITION *p)
{
 int i, j, seed0=0, seed1=0;
 REALTYPE worst, waste, area[MAXCARD+1];

 for (i=0; i<p->total; i++)
  area[i] = RTreeRectSphericalVolume(&root->BranchBuf[i].mbr);
 
 worst = -root->CoverSplitArea - 1;
 
 for (i=0; i<p->total-1; i++)
 {
  for (j=i+1; j<p->total; j++)
  {
   RTREEMBR one_rect;
   one_rect = RTreeCombineRect(&root->BranchBuf[i].mbr, &root->BranchBuf[j].mbr);
   waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j];
   if (waste > worst)
   {
    worst = waste;
    seed0 = i;
    seed1 = j;
   }
  }
 }
 _RTreeClassify(root, seed0, 0, p);
 _RTreeClassify(root, seed1, 1, p);
}


/**
 * Copy branches from the buffer into two nodes according to the partition.
 */
static void _RTreeLoadNodes(HRTREEROOT root, RTREENODE *n, RTREENODE *q, RTREEPARTITION *p)
{
 int i;
 assert(n && q && p);

 for (i=0; i<p->total; i++)
 {
  assert(p->partition[i] == 0 || p->partition[i] == 1);
  if (p->partition[i] == 0)
   RTreeAddBranch(root, &root->BranchBuf[i], n, NULL);
  else if (p->partition[i] == 1)
   RTreeAddBranch(root, &root->BranchBuf[i], q, NULL);
 }
}

/**
 * Initialize a RTREEPARTITION structure.
 */
static void _RTreeInitPart( RTREEPARTITION *p, int maxrects, int minfill)
{
 int i;
 assert(p);

 p->count[0] = p->count[1] = 0;
 p->cover[0] = p->cover[1] = RTreeNullRect();
 p->area[0] = p->area[1] = (REALTYPE)0;
 p->total = maxrects;
 p->minfill = minfill;
 for (i=0; i<maxrects; i++)
 {
  p->taken[i] = FALSE;
  p->partition[i] = -1;
 }
}


/**
 * Print out data for a partition from RTREEPARTITION struct.
 */
static void _RTreePrintPart(HRTREEROOT root, RTREEPARTITION *p)
{
 int i;
 assert(p);
 
 fprintf (stdout, "/npartition:/n");
 for (i=0; i<p->total; i++)
 {
  fprintf (stdout, "%3d/t", i);
 }
 fprintf (stdout, "/n");
 for (i=0; i<p->total; i++)
 {
  if (p->taken[i])
   fprintf (stdout, "  t/t");
  else
   fprintf (stdout, "/t");
 }
 fprintf (stdout, "/n");
 for (i=0; i<p->total; i++)
 {
  fprintf (stdout, "%3d/t", p->partition[i]);
 }
 fprintf (stdout, "/n");

 fprintf (stdout, "count[0] = %d  area = %f/n", p->count[0], p->area[0]);
 fprintf (stdout, "count[1] = %d  area = %f/n", p->count[1], p->area[1]);
 if (p->area[0] + p->area[1] > 0)
 {
  fprintf (stdout, "total area = %f  effectiveness = %3.2f/n",
   p->area[0] + p->area[1], (float)root->CoverSplitArea / (p->area[0] + p->area[1]));
 }
 fprintf (stdout, "cover[0]:/n");
 RTreePrintRect(&p->cover[0], 0);

 fprintf (stdout, "cover[1]:/n");
 RTreePrintRect(&p->cover[1], 0);
}


/**
 * Method #0 for choosing a partition:
 * As the seeds for the two groups, pick the two rects that would waste the
 * most area if covered by a single rectangle, i.e. evidently the worst pair
 * to have in the same group.
 * Of the remaining, one at a time is chosen to be put in one of the two groups.
 * The one chosen is the one with the greatest difference in area expansion
 * depending on which group - the mbr most strongly attracted to one group
 * and repelled from the other.
 * If one group gets too full (more would force other group to violate min
 * fill requirement) then other group gets the rest.
 * These last are the ones that can go in either group most easily.
 */
static void _RTreeMethodZero(HRTREEROOT root, RTREEPARTITION *p, int minfill )
{
 int i;
 REALTYPE biggestDiff;
 int group, chosen=0, betterGroup=0;
 assert(p);

 _RTreeInitPart(p, root->BranchCount, minfill);
 _RTreePickSeeds(root, p);

 while (p->count[0] + p->count[1] < p->total &&
  p->count[0] < p->total - p->minfill &&
  p->count[1] < p->total - p->minfill)
 {
  biggestDiff = (REALTYPE)-1.;
  for (i=0; i<p->total; i++)
  {
   if (!p->taken[i])
   {
    RTREEMBR *r, rect_0, rect_1;
    REALTYPE growth0, growth1, diff;
    
    r = &root->BranchBuf[i].mbr;
    rect_0 = RTreeCombineRect(r, &p->cover[0]);
    rect_1 = RTreeCombineRect(r, &p->cover[1]);
    growth0 = RTreeRectSphericalVolume(&rect_0) - p->area[0];
    growth1 = RTreeRectSphericalVolume(&rect_1) - p->area[1];
    diff = growth1 - growth0;
    if (diff >= 0)
     group = 0;
    else
    {
     group = 1;
     diff = -diff;
    }
    if (diff > biggestDiff)
    {
     biggestDiff = diff;
     chosen = i;
     betterGroup = group;
    }
    else if (diff==biggestDiff && p->count[group]<p->count[betterGroup])
    {
     chosen = i;
     betterGroup = group;
    }
   }
  }
  _RTreeClassify(root, chosen, betterGroup, p);
 }
 
 /* if one group too full, put remaining rects in the other */
 if (p->count[0] + p->count[1] < p->total)
 {
  if (p->count[0] >= p->total - p->minfill)
   group = 1;
  else
   group = 0;
  
  for (i=0; i<p->total; i++)
  {
   if (!p->taken[i])
    _RTreeClassify(root, i, group, p);
  }
 }
 
 assert(p->count[0] + p->count[1] == p->total);
 assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill);
}


/**
 * Initialize one branch cell in a node.
 */
static void _RTreeInitBranch( RTREEBRANCH *br )
{
 RTreeInitRect(&(br->mbr));
 br->child = NULL;
}


static void _RTreePrintBranch( RTREEBRANCH *br, int depth )
{
 RTreePrintRect(&(br->mbr), depth);
 RTreePrintNode(br->child, depth);
}


/**
 * Inserts a new data rectangle into the index structure.
 * 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 _RTreeInsertRect(HRTREEROOT root, RTREEMBR *mbr, void* tid,  RTREENODE *node, RTREENODE **new_node, int level)
{
 int i;
 RTREEBRANCH b;
 RTREENODE *n2;

 assert(mbr && node && new_node);
 assert(level >= 0 && level <= node->level);

 /* Still above level for insertion, go down tree recursively */
 if (node->level > level)
 {
  i = RTreePickBranch(mbr, node);
  if (!_RTreeInsertRect(root, mbr, tid, node->branch[i].child, &n2, level))
  {
   /* child was not split */
   node->branch[i].mbr = RTreeCombineRect(mbr, &(node->branch[i].mbr));
   return 0;
  }
  
  /* child was split */
  node->branch[i].mbr = RTreeNodeCover(node->branch[i].child);
  b.child = n2;
  b.mbr = RTreeNodeCover(n2);

  return RTreeAddBranch(root, &b, node, new_node);
 } 
 else if (node->level == level) /* Have reached level for insertion. Add mbr, split if necessary */
 {
  b.mbr = *mbr;

#pragma warning(push) /* C4312 */
#pragma warning( disable : 4312 )
  b.child = ( RTREENODE *) tid;
#pragma warning(pop)

  /* child field of leaves contains tid of data record */
  return RTreeAddBranch(root, &b, node, new_node);
 }
 
 /* Not supposed to happen */
 assert (FALSE);
 return 0;
}


/**
 * Allocate space for a node in the list used in DeletRect to
 * store Nodes that are too empty.
 */
static RTREELISTNODE * _RTreeNewListNode(void)
{
 return (RTREELISTNODE *) malloc(sizeof(RTREELISTNODE));
}

static void _RTreeFreeListNode(RTREELISTNODE *p)
{
 free(p);
}

/**
 * Add a node to the reinsertion list.  All its branches will later
 * be reinserted into the index structure.
 */
static void _RTreeReInsert(RTREENODE *node, RTREELISTNODE **ne)
{
 RTREELISTNODE *ln = _RTreeNewListNode();
 ln->node = node;
 ln->next = *ne;
 *ne = ln;
}

/**
 * Delete a rectangle from non-root part of an index structure.
 * Called by RTreeDeleteRect.  Descends tree recursively,
 * merges branches on the way back up.
 * Returns 1 if record not found, 0 if success.
 */
static int _RTreeDeleteRect( RTREEMBR *mbr, void* tid, RTREENODE *node, RTREELISTNODE **ee)
{
 int i;

 assert(mbr && node && ee);
 assert(node->level >= 0);

 if (node->level > 0)  /* not a leaf node */
 {
  for (i = 0; i < NODECARD; i++)
  {
   if (node->branch[i].child && RTreeOverlap( mbr, &(node->branch[i].mbr )))
   {
    if (!_RTreeDeleteRect( mbr, tid, node->branch[i].child, ee ))
    {
     if (node->branch[i].child->count >= MINNODEFILL)
      node->branch[i].mbr = RTreeNodeCover( node->branch[i].child );
     else{ /* not enough entries in child, eliminate child node */
      _RTreeReInsert(node->branch[i].child, ee);
      RTreeDisconnectBranch(node, i);
     }
     return 0;
    }
   }
  }
  return 1;
 }

#pragma warning(push) /* C4312 */
#pragma warning( disable : 4312 )

 /* a leaf node */
 for (i = 0; i < LEAFCARD; i++)
 {
  if ( node->branch[i].child && node->branch[i].child == (RTREENODE *) tid )
  {
   RTreeDisconnectBranch( node, i );
   return 0;
  }

 }
#pragma warning(pop)

 return 1;
}

static void _RTreeTabIn(int depth)
{
 int i;
 for(i=0; i<depth; i++)
  putchar(&apos;/t&apos;);
}


/**
 * Search in an index tree or subtree for all data rectangles that overlap the argument rectangle.
 * Return the number of qualifying data rects.
 */
static int _RTreeSearchRect( RTREENODE *node, RTREEMBR *mbr, PFNRTreeSearchCallback pfnSHCB, void* pfnParam)
{
 /* Fix not yet tested. */
 int hitCount = 0;
 int i;

 assert(node && mbr);
 assert(node->level >= 0);
 
 if (node->level > 0) /* this is an internal node in the tree */
 {
  for (i=0; i<NODECARD; i++){
   if (node->branch[i].child && RTreeOverlap(mbr, &node->branch[i].mbr))
    hitCount += _RTreeSearchRect(node->branch[i].child, mbr, pfnSHCB, pfnParam);
  }
 }
 else /* this is a leaf node */
 {
#pragma warning(push) /* C4311 */
#pragma warning( disable : 4311 )
  for (i=0; i<LEAFCARD; i++)
  {
   if (node->branch[i].child && RTreeOverlap(mbr, &node->branch[i].mbr))
   {
    hitCount++;

    /* call the user-provided callback and return if callback wants to terminate search early */
    if(pfnSHCB && ! pfnSHCB((void*)node->branch[i].child, pfnParam) )
     return hitCount;

   }
  }
#pragma warning(pop)
 }
 return hitCount;
}

/*=============================================================================
        Public functions:
 =============================================================================*/
/**
 * Initialize a rectangle to have all 0 coordinates.
 */
 void RTreeInitRect( RTREEMBR *mbr)
{
 int i;
 for (i=0; i<SIDES_NUMB; i++)
  mbr->bound[i] = (REALTYPE) 0;
}


/**
 * Return a mbr whose first low side is higher than its opposite side -
 * interpreted as an undefined mbr.
 */
 RTREEMBR RTreeNullRect(void)
{
 RTREEMBR mbr;
 int i;

 mbr.bound[0] = (REALTYPE) 1;
 mbr.bound[DIMS_NUMB] = (REALTYPE)-1;
 for (i=1; i<DIMS_NUMB; i++)
  mbr.bound[i] = mbr.bound[i+DIMS_NUMB] = (REALTYPE) 0;
 return mbr;
}

/**
 * Print out the data for a rectangle.
 */
 void RTreePrintRect( RTREEMBR *mbr, int depth)
{
 int i;
 
 _RTreeTabIn(depth);
 fprintf (stdout, "mbr:/n");
 for (i = 0; i < DIMS_NUMB; i++)
 {
  _RTreeTabIn(depth+1);
  fprintf (stdout, "%f/t%f/n", mbr->bound[i], mbr->bound[i + DIMS_NUMB]);
 }
}

/**
 * Calculate the 2-dimensional area of a rectangle
 */
 REALTYPE RTreeRectArea( RTREEMBR *mbr )
{
 if (INVALID_RECT(mbr))
  return (REALTYPE) 0;

 return (mbr->bound[DIMS_NUMB] - mbr->bound[0]) * (mbr->bound[DIMS_NUMB+1] - mbr->bound[1]);
}


/**
 * Calculate the n-dimensional volume of a rectangle
 */
 REALTYPE RTreeRectVolume( RTREEMBR *mbr )
{
 int i;
 REALTYPE vol = (REALTYPE) 1;

 if (INVALID_RECT(mbr))
  return (REALTYPE) 0;

 for(i=0; i<DIMS_NUMB; i++)
  vol *= (mbr->bound[i+DIMS_NUMB] - mbr->bound[i]);
 assert(vol >= 0.0);
 return vol;
}


/**
 * Precomputed volumes of the unit spheres for the first few dimensions
 */
const double UnitSphereVolumes[] = {
 0.000000,  /* dimension   0 */
 2.000000,  /* dimension   1 */
 3.141593,  /* dimension   2 */
 4.188790,  /* dimension   3 */
 4.934802,  /* dimension   4 */
 5.263789,  /* dimension   5 */
 5.167713,  /* dimension   6 */
 4.724766,  /* dimension   7 */
 4.058712,  /* dimension   8 */
 3.298509,  /* dimension   9 */
 2.550164,  /* dimension  10 */
 1.884104,  /* dimension  11 */
 1.335263,  /* dimension  12 */
 0.910629,  /* dimension  13 */
 0.599265,  /* dimension  14 */
 0.381443,  /* dimension  15 */
 0.235331,  /* dimension  16 */
 0.140981,  /* dimension  17 */
 0.082146,  /* dimension  18 */
 0.046622,  /* dimension  19 */
 0.025807,  /* dimension  20 */
};

#if DIMS_NUMB > 20
 #error "not enough precomputed sphere volumes"
#endif

#define UnitSphereVolume UnitSphereVolumes[DIMS_NUMB]

/**
 * Calculate the n-dimensional volume of the bounding sphere of a rectangle.
 * The exact volume of the bounding sphere for the given RTREEMBR.
 */
 REALTYPE RTreeRectSphericalVolume( RTREEMBR *mbr )
{
 int i;
 double sum_of_squares=0, radius;

 if (INVALID_RECT(mbr))
  return (REALTYPE) 0;
 
 for (i=0; i<DIMS_NUMB; i++) {
  double half_extent = (mbr->bound[i+DIMS_NUMB] - mbr->bound[i]) / 2;
  sum_of_squares += half_extent * half_extent;
 }
 radius = sqrt(sum_of_squares);
 return (REALTYPE)(pow(radius, DIMS_NUMB) * UnitSphereVolume);
}


/**
 * Calculate the n-dimensional surface area of a rectangle
 */
 REALTYPE RTreeRectSurfaceArea( RTREEMBR *mbr )
{
 int i, j;
 REALTYPE sum = (REALTYPE) 0;

 if (INVALID_RECT(mbr))
  return (REALTYPE) 0;

 for (i=0; i<DIMS_NUMB; i++) {
  REALTYPE face_area = (REALTYPE)1;
  for (j=0; j<DIMS_NUMB; j++)
   /* exclude i extent from product in this dimension */
   if(i != j) {
    REALTYPE j_extent = mbr->bound[j+DIMS_NUMB] - mbr->bound[j];
    face_area *= j_extent;
   }
   sum += face_area;
 }
 return 2 * sum;
}

 

/**
 * Combine two rectangles, make one that includes both.
 */
 RTREEMBR RTreeCombineRect( RTREEMBR *rc1, RTREEMBR *rc2 )
{
 int i, j;
 RTREEMBR new_rect;

 assert(rc1 && rc2);

 if (INVALID_RECT(rc1))
  return *rc2;

 if (INVALID_RECT(rc2))
  return *rc1;

 for (i = 0; i < DIMS_NUMB; i++)
 {
  new_rect.bound[i] = MIN(rc1->bound[i], rc2->bound[i]);
  j = i + DIMS_NUMB;
  new_rect.bound[j] = MAX(rc1->bound[j], rc2->bound[j]);
 }
 return new_rect;
}


/**
 * Decide whether two rectangles overlap.
 */
 int RTreeOverlap( RTREEMBR *rc1, RTREEMBR *rc2)
{
 int i, j;
 assert(rc1 && rc2);

 for (i=0; i<DIMS_NUMB; i++)
 {
  j = i + DIMS_NUMB;  /* index for high sides */

  if (rc1->bound[i] > rc2->bound[j] || rc2->bound[i] > rc1->bound[j])
   return FALSE;
 }
 return TRUE;
}


/**
 * Decide whether rectangle r is contained in rectangle s.
 */
 int RTreeContained( RTREEMBR *r, RTREEMBR *s)
{
 int i, j, result;
 assert(r && s);

 /* undefined mbr is contained in any other */
 if (INVALID_RECT(r))
  return TRUE;

 /* no mbr (except an undefined one) is contained in an undef mbr */
 if (INVALID_RECT(s))
  return FALSE;

 result = TRUE;
 for (i = 0; i < DIMS_NUMB; i++)
 {
  j = i + DIMS_NUMB;  /* index for high sides */
  result = result && r->bound[i] >= s->bound[i] && r->bound[j] <= s->bound[j];
 }
 return result;
}

/**
 * Split a node.
 * Divides the nodes branches and the extra one between two nodes.
 * Old node is one of the new ones, and one really new one is created.
 * Tries more than one method for choosing a partition, uses best result.
 */
void RTreeSplitNode(HRTREEROOT root, RTREENODE *node, RTREEBRANCH *br, RTREENODE **new_node)
{
 RTREEPARTITION *p;
 int level;

 assert(node && br);
 
 /* load all the branches into a buffer, initialize old node */
 level = node->level;
 _RTreeGetBranches(root, node, br);

 /* find partition */
 p = &root->Partitions[0];

 /* Note: can&apos;t use MINFILL(n) below since node was cleared by GetBranches() */
 _RTreeMethodZero(root, p, (level>0 ? MINNODEFILL : MINLEAFFILL));

 /* put branches from buffer into 2 nodes according to chosen partition */
 *new_node = RTreeNewNode();
 (*new_node)->level = node->level = level;
 _RTreeLoadNodes(root, node, *new_node, p);

 assert(node->count+(*new_node)->count == p->total);
}


/**
 * Initialize a RTREENODE structure.
 */
void RTreeInitNode( RTREENODE *node )
{
 int i;
 node->count = 0;
 node->level = -1;
 for (i = 0; i < MAXCARD; i++)
  _RTreeInitBranch(&(node->branch[i]));
}

/**
 * Make a new node and initialize to have all branch cells empty.
 */
RTREENODE *RTreeNewNode(void)
{
 RTREENODE *node = (RTREENODE*) malloc(sizeof(RTREENODE));
 assert(node);
 RTreeInitNode(node);
 return node;
}

void RTreeFreeNode( RTREENODE *node )
{
 assert(node);
 free(node);
}


/**
 * Print out the data in a node.
 */
 void RTreePrintNode( RTREENODE *node, int depth )
{
 int i;
 assert(node);

 _RTreeTabIn(depth);
 fprintf (stdout, "node");

 if (node->level == 0)
  fprintf (stdout, " LEAF");
 else if (node->level > 0)
  fprintf (stdout, " NONLEAF");
 else
  fprintf (stdout, " TYPE=?");

#pragma warning(push) /* C4311 */
#pragma warning( disable : 4311 )
 fprintf (stdout, "  level=%d  count=%d  address=%o/n", node->level, node->count, (unsigned int) node);

 for (i=0; i<node->count; i++)
 {
  if(node->level == 0) {
   /* _RTreeTabIn(depth); */
   fprintf (stdout, "/t%ld: data = %ld/n", i, (unsigned int)node->branch[i].child);
  }
  else {
   _RTreeTabIn(depth);
   fprintf (stdout, "branch %d/n", i);
   _RTreePrintBranch(&node->branch[i], depth+1);
  }
 }
#pragma warning(pop)
}

/**
 * Find the smallest rectangle that includes all rectangles in branches of a node.
 */
 RTREEMBR RTreeNodeCover( RTREENODE *node )
{
 int i, first_time=1;
 RTREEMBR mbr;
 assert(node);

 RTreeInitRect(&mbr);

 for (i = 0; i < MAXKIDS(node); i++)
 {
  if (node->branch[i].child)
  {
   if (first_time)
   {
    mbr = node->branch[i].mbr;
    first_time = 0;
   }
   else
    mbr = RTreeCombineRect(&mbr, &(node->branch[i].mbr));
  }
 }
 return mbr;
}

/**
 * Pick a branch.  Pick the one that will need the smallest increase
 * in area to accomodate the new rectangle.  This will result in the
 * least total area for the covering rectangles in the current node.
 * In case of a tie, pick the one which was smaller before, to get
 * the best resolution when searching.
 */
 int RTreePickBranch( RTREEMBR *mbr, RTREENODE *node)
{
 RTREEMBR *r;
 int i, first_time = 1;
 REALTYPE increase, bestIncr=(REALTYPE)-1, area, bestArea=0;
 int best=0;
 RTREEMBR tmp_rect;
 assert(mbr && node);

 for (i=0; i<MAXKIDS(node); i++)
 {
  if (node->branch[i].child)
  {
   r = &node->branch[i].mbr;
   area = RTreeRectSphericalVolume(r);
   tmp_rect = RTreeCombineRect(mbr, r);
   increase = RTreeRectSphericalVolume(&tmp_rect) - area;
   if (increase < bestIncr || first_time)
   {
    best = i;
    bestArea = area;
    bestIncr = increase;
    first_time = 0;
   }
   else if (increase == bestIncr && area < bestArea)
   {
    best = i;
    bestArea = area;
    bestIncr = increase;
   }
  }
 }
 return best;
}

/**
 * Add a branch to a node.  Split the node if necessary.
 * 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.
 */
 int RTreeAddBranch(HRTREEROOT root, RTREEBRANCH *br, RTREENODE *node, RTREENODE **new_node)
{
 int i;
 assert(br && node);
 
 if (node->count < MAXKIDS(node))  /* split won&apos;t be necessary */
 {
  for (i = 0; i < MAXKIDS(node); i++)  /* find empty branch */
  {
   if (node->branch[i].child == NULL)
   {
    node->branch[i] = *br;
    node->count++;
    break;
   }
  }

  return 0;
 }
 
 assert(new_node);
 RTreeSplitNode(root, node, br, new_node);
 
 return 1;
}

/**
 * Disconnect a dependent node.
 */
 void RTreeDisconnectBranch( RTREENODE *node, int i )
{
 assert(node && i>=0 && i<MAXKIDS(node));
 assert(node->branch[i].child);

 _RTreeInitBranch(&(node->branch[i]));
 node->count--;
}

/**
 * Destroy (free) node recursively.
 */
 void RTreeDestroyNode ( RTREENODE *node )
{
 int i;

 if (node->level > 0)
 {
  /* it is not leaf -> destroy childs */
  for ( i = 0; i < NODECARD; i++)
  {
   if ( node->branch[i].child )
    RTreeDestroyNode ( node->branch[i].child );
  }
 }

 /* Free this node */
 RTreeFreeNode( node );
}


/**
 * Create a new rtree index, empty. Consists of a single node.
 */
HRTREEROOT RTreeCreate(PFNRTreeSearchCallback  pfnSearchCallback)
{
 RTREEROOT * root = (RTREEROOT*) malloc(sizeof(RTREEROOT));
 assert(root);
 root->root_node = RTreeNewNode();
 assert(root->root_node);
 root->root_node->level = 0;  /* leaf */
 root->pfnCallback = pfnSearchCallback;
 return root;
}

/**
 * Destroy a rtree root must be a root of rtree. Free all memory.
 */
void RTreeDestroy(HRTREEROOT root)
{
 RTreeDestroyNode (root->root_node);
 root->root_node = 0;
 free(root);
}

/**
* Search in an index tree for all data rectangles that overlap the argument rectangle.
* Return the number of qualifying data rects.
*/
int RTreeSearch(HRTREEROOT root, RTREEMBR *mbr, void* pfnSearchCallbackParam)
{
 return  _RTreeSearchRect(root->root_node, mbr, root->pfnCallback, pfnSearchCallbackParam);
}


/**
 * Insert a data rectangle into an index structure.
 * RTreeInsertRect 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.
 * _RTreeInsertRect does the recursion.
 */
int RTreeInsert(HRTREEROOT root, RTREEMBR *mbr, void* tid, int level)
{
#ifdef _DEBUG
 int i;
#endif

 RTREENODE *newroot;
 RTREENODE *newnode;
 RTREEBRANCH b;
 
 assert(mbr && root);
 assert(level >= 0 && level <= root->root_node->level);

#ifdef _DEBUG
 for (i=0; i<DIMS_NUMB; i++)
  assert(mbr->bound[i] <= mbr->bound[DIMS_NUMB+i]);
#endif

 /* root split */
 if (_RTreeInsertRect(root, mbr, tid, root->root_node, &newnode, level)) 
 {
  newroot = RTreeNewNode();  /* grow a new root, & tree taller */
  newroot->level = root->root_node->level + 1;
  b.mbr = RTreeNodeCover(root->root_node);
  b.child = root->root_node;
  RTreeAddBranch(root, &b, newroot, NULL);
  b.mbr = RTreeNodeCover(newnode);
  b.child = newnode;
  RTreeAddBranch(root, &b, newroot, NULL);
  root->root_node = newroot;
  
  return 1;
 }

 return 0;
}


/**
 * Delete a data rectangle from an index structure.
 * Pass in a pointer to a RTREEMBR, the tid of the record, ptr to ptr to root node.
 * Returns 1 if record not found, 0 if success.
 * RTreeDeleteRect provides for eliminating the root.
 */
int RTreeDelete(HRTREEROOT root, RTREEMBR *mbr, void* tid)
{
 int  i;
 RTREENODE  *tmp_nptr = NULL;
 RTREELISTNODE *reInsertList = NULL;
 RTREELISTNODE *e;

 assert(mbr && root && root->root_node);
 
 if (!_RTreeDeleteRect(mbr, tid, root->root_node, &reInsertList))
 {
  /* found and deleted a data item */

  /* reinsert any branches from eliminated nodes */
  while (reInsertList)
  {
   tmp_nptr = reInsertList->node;

#pragma warning(push) /* C4311 */
#pragma warning( disable : 4311 )
   for (i = 0; i < MAXKIDS(tmp_nptr); i++)
   {
    if (tmp_nptr->branch[i].child)
    {
     RTreeInsert(root, &(tmp_nptr->branch[i].mbr), (void*)tmp_nptr->branch[i].child, tmp_nptr->level);
    }
   }
#pragma warning(pop)

   e = reInsertList;
   reInsertList = reInsertList->next;
   RTreeFreeNode(e->node);
   _RTreeFreeListNode(e);
  }
  
  /* check for redundant root (not leaf, 1 child) and eliminate */
  if (root->root_node->count == 1 && root->root_node->level > 0)
  {
   for (i = 0; i < NODECARD; i++)
   {
    tmp_nptr = root->root_node->branch[i].child;
    if(tmp_nptr)
     break;
   }
   assert(tmp_nptr);
   RTreeFreeNode(root->root_node);
   root->root_node = tmp_nptr;
  }

  return 0;
 }
 
 return 1;
}

测试文件Test.C

/**
 * rtree lib usage example app. - test.c
 */
#include <stdio.h>
#include "../../rtree.h"

// data id=1,2,3,4
RTREEMBR mbrs[] = {
    { {0, 0, 0, 2, 2, 0} },  /* xmin, ymin, zmin, xmax, ymax, zmax (for 3 dimensional RTree) */
    { {5, 5, 0, 7, 7, 0} },
    { {8, 5, 0, 9, 6, 0} },
    { {7, 1, 0, 9, 2, 0} }
};


int nmbr = sizeof(mbrs) / sizeof(mbrs[0]);
RTREEMBR search_mbr = {
 {6, 4, 0, 10, 6, 0}   /* search will find above mbrs that this one overlaps */
};

int MySearchCallback(int id, void* arg)
{
 /* Note: -1 to make up for the +1 when data was inserted */
 fprintf (stdout, "Searched data id: %d/n", id);
 return 1; /* keep going */
}

int main()

    HRTREEROOT root = RTreeCreate(MySearchCallback);
   
 int i, nhits;
    
 fprintf (stdout, "nmbr = %d/n", nmbr);
   
 /* Insert all the testing data mbrs */
 for(i=0; i<nmbr; i++){
  RTreeInsert(root, &mbrs[i],   /* the mbr being inserted */
      (void*)(i+1),  /* i+1 is mbr ID. ID MUST NEVER BE ZERO */
      0     /* always zero which means to add from the root */
     );
 }

    nhits = RTreeSearch(root, &search_mbr, MySearchCallback);
 fprintf (stdout, "Search resulted is %d hits before delete 1/n", nhits);
   
 /* delete first shape: 1 */
 fprintf (stdout, "delete id=2 from tree/n");
 i = RTreeDelete(root, &mbrs[1], (void*)2);

 nhits = RTreeSearch(root, &search_mbr, MySearchCallback);
 fprintf (stdout, "Search resulted is %d hits after delete 1/n", nhits);

 RTreeDestroy (root);
    return 0;
}

        使用VS2005,新建一个Console项目test,选为空项目。然后把这3个文件加入进来,就可以使用了。

       原文链接(请不要使用下面链接中的代码。务必使用本文的代码!):

http://blog.csdn.net/cheungmine/archive/2007/11/22/1898129.aspx

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车斗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值