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-Treelibrary
*
*AUTHOR(S):AntoninGuttman-originalcode
*DanielGreen(green@superliminal.com)-majorclean-up
*andimplementationofboundingspheres
*
*PURPOSE:MultiDimensionalIndex
*
*COPYRIGHT:(C)2001bytheGRASSDevelopmentTeam
*
*ThisprogramisfreesoftwareundertheGNUGeneralPublic
*License(>=v2).ReadthefileCOPYINGthatcomeswithGRASS
*fordetails.
*
*LASTMODIFY:ZhangLiang(cheungmine@gmail.com)-2007-11
****************************************************************************
*/
#ifndefRTREE_H_INCLUDED
#define RTREE_H_INCLUDED

/* PAGE_SIZEisnormallythenaturalpagesizeofthemachine */
#define PAGE_SIZE512
#define DIMS_NUMB3/*numberofdimensions*/
#define SIDES_NUMB2*DIMS_NUMB

/* typedeffloatREALTYPE; */
typedef
double REALTYPE;


#ifndefTRUE
#define TRUE1
#define FALSE0
#endif


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

typedef
struct _RTREEBRANCH
{
RTREEMBRmbr;
struct _RTREENODE * child; /* mbrid */
}RTREEBRANCH;

/* maxbranchingfactorofanode */
#define MAXCARD(int)((PAGE_SIZE-(2*sizeof(int)))/sizeof(RTREEBRANCH))

typedef
struct _RTREENODE
{
int count;
int level; /* 0isleaf,otherspositive */
RTREEBRANCHbranch[MAXCARD];
}RTREENODE;

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

/*
*Ifpassedtoatreesearch,thiscallbackfunctionwillbecalled
*withtheIDofeachdatambrthatoverlapsthesearchmbr
*pluswhateveruserspecificpointerwaspassedtothesearch.
*Itcanterminatethesearchearlybyreturning0inwhichcase
*thesearchwillreturnthenumberofhitsfounduptothatpoint.
*/
typedef
int ( * pfnSearchHitCallback)( int id, void * pfnParam);


int RTreeSetNodeMax( int new_max);

int RTreeSetLeafMax( int new_max);

int RTreeGetNodeMax( void );

int RTreeGetLeafMax( void );

/* *
*Initializearectangletohaveall0coordinates.
*/
void RTreeInitRect(RTREEMBR * rc);

/* *
*Returnambrwhosefirstlowsideishigherthanitsoppositeside-
*interpretedasanundefinedmbr.
*/
RTREEMBRRTreeNullRect(
void );


/* *
*Printoutthedataforarectangle.
*/
void RTreePrintRect(RTREEMBR * rc, int depth);

/* *
*Calculatethe2-dimensionalareaofarectangle
*/
REALTYPERTreeRectArea(RTREEMBR
* rc);

/* *
*Calculatethen-dimensionalvolumeofarectangle
*/
REALTYPERTreeRectVolume(RTREEMBR
* rc);


/* *
*Calculatethen-dimensionalvolumeoftheboundingsphereofarectangle
*TheexactvolumeoftheboundingsphereforthegivenRTREEMBR.
*/
REALTYPERTreeRectSphericalVolume(RTREEMBR
* rc);


/* *
*Calculatethen-dimensionalsurfaceareaofarectangle
*/
REALTYPERTreeRectSurfaceArea(RTREEMBR
* rc);


/* *
*Combinetworectangles,makeonethatincludesboth.
*/
RTREEMBRRTreeCombineRect(RTREEMBR
* rc1,RTREEMBR * rc2);


/* *
*Decidewhethertworectanglesoverlap.
*/
int RTreeOverlap(RTREEMBR * rc1,RTREEMBR * rc2);


/* *
*Decidewhetherrectangleriscontainedinrectangles.
*/
int RTreeContained(RTREEMBR * r,RTREEMBR * s);

/* *
*Splitanode.
*Dividesthenodesbranchesandtheextraonebetweentwonodes.
*Oldnodeisoneofthenewones,andonereallynewoneiscreated.
*Triesmorethanonemethodforchoosingapartition,usesbestresult.
*/
void RTreeSplitNode(RTREENODE * node,RTREEBRANCH * br,RTREENODE ** new_node);

/* *
*InitializeaRTREENODEstructure.
*/
void RTreeInitNode(RTREENODE * node);

/* *
*Makeanewnodeandinitializetohaveallbranchcellsempty.
*/
RTREENODE
* RTreeNewNode( void );

void RTreeFreeNode(RTREENODE * node);


/* *
*Printoutthedatainanode.
*/
void RTreePrintNode(RTREENODE * node, int depth);


/* *
*Findthesmallestrectanglethatincludesallrectanglesinbranchesofanode.
*/
RTREEMBRRTreeNodeCover(RTREENODE
* node);


/* *
*Pickabranch.Picktheonethatwillneedthesmallestincrease
*inareatoaccomodatethenewrectangle.Thiswillresultinthe
*leasttotalareaforthecoveringrectanglesinthecurrentnode.
*Incaseofatie,picktheonewhichwassmallerbefore,toget
*thebestresolutionwhensearching.
*/
int RTreePickBranch(RTREEMBR * rc,RTREENODE * node);


/* *
*Addabranchtoanode.Splitthenodeifnecessary.
*Returns0ifnodenotsplit.Oldnodeupdated.
*Returns1ifnodesplit,sets*new_nodetoaddressofnewnode.
*Oldnodeupdated,becomesoneoftwo.
*/
int RTreeAddBranch(RTREEBRANCH * br,RTREENODE * node,RTREENODE ** new_node);


/* *
*Disconnectadependentnode.
*/
void RTreeDisconnectBranch(RTREENODE * node, int i);


/* *
*Destroy(free)noderecursively.
*/
void RTreeDestroyNode(RTREENODE * node);


/* *
*Createanewrtreeindex,empty.Consistsofasinglenode.
*/
RTREENODE
* RTreeCreate( void );


/* *
*Destroyartreerootmustbearootofrtree.Freeallmemory.
*/
void RTreeDestroy(RTREENODE * root);


/* *
*Searchinanindextreeorsubtreeforalldatarectanglesthatoverlaptheargumentrectangle.
*Returnthenumberofqualifyingdatarects.
*/
int RTreeSearch(RTREENODE * node,RTREEMBR * rc,pfnSearchHitCallbackpfnSHCB, void * pfnParam);

/* *
*Insertadatarectangleintoanindexstructure.
*RTreeInsertRectprovidesforsplittingtheroot;
*returns1ifrootwassplit,0ifitwasnot.
*Thelevelargumentspecifiesthenumberofstepsupfromtheleaf
*leveltoinsert;e.g.adatarectanglegoesinatlevel=0.
*_RTreeInsertRectdoestherecursion.
*/
int RTreeInsertRect(RTREEMBR * rc, int tid,RTREENODE ** root, int level);

/* *
*Deleteadatarectanglefromanindexstructure.
*PassinapointertoaRTREEMBR,thetidoftherecord,ptrtoptrtorootnode.
*Returns1ifrecordnotfound,0ifsuccess.
*RTreeDeleteRectprovidesforeliminatingtheroot.
*/
int RTreeDeleteRect(RTREEMBR * rc, int tid,RTREENODE ** root);

#endif /*RTREE_H_INCLUDED*/

RTree.C文件:

/* ***************************************************************************
*RTree.C
*
*MODULE:R-Treelibrary
*
*AUTHOR(S):AntoninGuttman-originalcode
*DanielGreen(green@superliminal.com)-majorclean-up
*andimplementationofboundingspheres
*
*PURPOSE:MultiDimensionalIndex
*
*COPYRIGHT:(C)2001bytheGRASSDevelopmentTeam
*
*ThisprogramisfreesoftwareundertheGNUGeneralPublic
*License(>=v2).ReadthefileCOPYINGthatcomeswithGRASS
*fordetails.
*
*LASTMODIFY: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 METHODS1

/* variablesforfindingapartition */
typedef
struct _RTREEPARTITION
{
int partition[MAXCARD + 1 ];
int total;
int minfill;
int taken[MAXCARD + 1 ];
int count[ 2 ];
RTREEMBRcover[
2 ];
REALTYPEarea[
2 ];
}RTREEPARTITION;

RTREEBRANCHBranchBuf[MAXCARD
+ 1 ];
int BranchCount;
RTREEMBRCoverSplit;
REALTYPECoverSplitArea;
RTREEPARTITIONPartitions[METHODS];


#define BIG_NUM(FLT_MAX/4.0)

#define INVALID_RECT(x)((x)->bound[0]>(x)->bound[DIMS_NUMB])
#define MIN(a,b)((a)<(b)?(a):(b))
#define MAX(a,b)((a)>(b)?(a):(b))

int NODECARD = MAXCARD;
int LEAFCARD = MAXCARD;

/* balancecriteriafornodesplitting */
/* NOTE:canbechangedifneeded. */
#define MINNODEFILL(NODECARD/2)
#define MINLEAFFILL(LEAFCARD/2)

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

static int set_max( int * which, int new_max)
{
if ( 2 > new_max || new_max > MAXCARD)
return 0 ;
* which = new_max;
return 1 ;
}


/* *
*Loadbranchbufferwithbranchesfromfullnodeplustheextrabranch.
*/
static void _RTreeGetBranches(RTREENODE * node,RTREEBRANCH * br)
{
int i;

assert(node
&& br);

/* loadthebranchbuffer */
for (i = 0 ;i < MAXKIDS(node);i ++ )
{
assert(node
-> branch[i].child); /* nshouldhaveeveryentryfull */
BranchBuf[i]
= node -> branch[i];
}

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

/* calculatembrcontainingallintheset */
CoverSplit
= BranchBuf[ 0 ].mbr;

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

CoverSplitArea
= RTreeRectSphericalVolume( & CoverSplit);
RTreeInitNode(node);
}



/* *
*Putabranchinoneofthegroups.
*/
static void _RTreeClassify( 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] = BranchBuf[i].mbr;
else
p
-> cover[group] = RTreeCombineRect( & BranchBuf[i].mbr, & p -> cover[group]);

p
-> area[group] = RTreeRectSphericalVolume( & p -> cover[group]);
p
-> count[group] ++ ;
}

/* *
*Picktworectsfromsettobethefirstelementsofthetwogroups.
*Pickthetwothatwastethemostareaifcoveredbyasinglerectangle.
*/
static void _RTreePickSeeds(RTREEPARTITION * p)
{
int i,j,seed0 = 0 ,seed1 = 0 ;
REALTYPEworst,waste,area[MAXCARD
+ 1 ];

for (i = 0 ;i < p -> total;i ++ )
area[i]
= RTreeRectSphericalVolume( & BranchBuf[i].mbr);

worst
= - CoverSplitArea - 1 ;

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


/* *
*Copybranchesfromthebufferintotwonodesaccordingtothepartition.
*/
static void _RTreeLoadNodes(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(
& BranchBuf[i],n,NULL);
else if (p -> partition[i] == 1 )
RTreeAddBranch(
& BranchBuf[i],q,NULL);
}
}

/* *
*InitializeaRTREEPARTITIONstructure.
*/
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 ;
}
}


/* *
*PrintoutdataforapartitionfromRTREEPARTITIONstruct.
*/
static void _RTreePrintPart(RTREEPARTITION * p)
{
int i;
assert(p);

fprintf(stdout,
" partition: " );
for (i = 0 ;i < p -> total;i ++ )
{
fprintf(stdout,
" %3d " ,i);
}
fprintf(stdout,
" " );
for (i = 0 ;i < p -> total;i ++ )
{
if (p -> taken[i])
fprintf(stdout,
" t " );
else
fprintf(stdout,
" " );
}
fprintf(stdout,
" " );
for (i = 0 ;i < p -> total;i ++ )
{
fprintf(stdout,
" %3d " ,p -> partition[i]);
}
fprintf(stdout,
" " );

fprintf(stdout,
" count[0]=%darea=%f " ,p -> count[ 0 ],p -> area[ 0 ]);
fprintf(stdout,
" count[1]=%darea=%f " ,p -> count[ 1 ],p -> area[ 1 ]);
if (p -> area[ 0 ] + p -> area[ 1 ] > 0 )
{
fprintf(stdout,
" totalarea=%feffectiveness=%3.2f " ,
p
-> area[ 0 ] + p -> area[ 1 ],( float )CoverSplitArea / (p -> area[ 0 ] + p -> area[ 1 ]));
}
fprintf(stdout,
" cover[0]: " );
RTreePrintRect(
& p -> cover[ 0 ], 0 );

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


/* *
*Method#0forchoosingapartition:
*Astheseedsforthetwogroups,pickthetworectsthatwouldwastethe
*mostareaifcoveredbyasinglerectangle,i.e.evidentlytheworstpair
*tohaveinthesamegroup.
*Oftheremaining,oneatatimeischosentobeputinoneofthetwogroups.
*Theonechosenistheonewiththegreatestdifferenceinareaexpansion
*dependingonwhichgroup-thembrmoststronglyattractedtoonegroup
*andrepelledfromtheother.
*Ifonegroupgetstoofull(morewouldforceothergrouptoviolatemin
*fillrequirement)thenothergroupgetstherest.
*Theselastaretheonesthatcangoineithergroupmosteasily.
*/
static void _RTreeMethodZero(RTREEPARTITION * p, int minfill)
{
int i;
REALTYPEbiggestDiff;
int group,chosen = 0 ,betterGroup = 0 ;
assert(p);

_RTreeInitPart(p,BranchCount,minfill);
_RTreePickSeeds(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;
REALTYPEgrowth0,growth1,diff;

r
= & 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(chosen,betterGroup,p);
}

/* ifonegrouptoofull,putremainingrectsintheother */
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(i,group,p);
}
}

assert(p
-> count[ 0 ] + p -> count[ 1 ] == p -> total);
assert(p
-> count[ 0 ] >= p -> minfill && p -> count[ 1 ] >= p -> minfill);
}


/* *
*Initializeonebranchcellinanode.
*/
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);
}


/* *
*Insertsanewdatarectangleintotheindexstructure.
*Recursivelydescendstree,propagatessplitsbackup.
*Returns0ifnodewasnotsplit.Oldnodeupdated.
*Ifnodewassplit,returns1andsetsthepointerpointedtoby
*new_nodetopointtothenewnode.Oldnodeupdatedtobecomeoneoftwo.
*Thelevelargumentspecifiesthenumberofstepsupfromtheleaf
*leveltoinsert;e.g.adatarectanglegoesinatlevel=0.
*/
static int _RTreeInsertRect(RTREEMBR * rc, int tid,RTREENODE * node,RTREENODE ** new_node, int level)
{
int i;
RTREEBRANCHb;
RTREENODE
* n2;

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

/* Stillabovelevelforinsertion,godowntreerecursively */
if (node -> level > level)
{
i
= RTreePickBranch(rc,node);
if ( ! _RTreeInsertRect(rc,tid,node -> branch[i].child, & n2,level))
{
/* childwasnotsplit */
node
-> branch[i].mbr = RTreeCombineRect(rc, & (node -> branch[i].mbr));
return 0 ;
}

/* childwassplit */
node
-> branch[i].mbr = RTreeNodeCover(node -> branch[i].child);
b.child
= n2;
b.mbr
= RTreeNodeCover(n2);

return RTreeAddBranch( & b,node,new_node);
}
else if (node -> level == level) /* Havereachedlevelforinsertion.Addmbr,splitifnecessary */
{
b.mbr
= * rc;

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

/* childfieldofleavescontainstidofdatarecord */
return RTreeAddBranch( & b,node,new_node);
}

/* Notsupposedtohappen */
assert(FALSE);
return 0 ;
}


/* *
*AllocatespaceforanodeinthelistusedinDeletRectto
*storeNodesthataretooempty.
*/
static RTREELISTNODE * _RTreeNewListNode( void )
{
return (RTREELISTNODE * )malloc( sizeof (RTREELISTNODE));
}

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

/* *
*Addanodetothereinsertionlist.Allitsbrancheswilllater
*bereinsertedintotheindexstructure.
*/
static void _RTreeReInsert(RTREENODE * node,RTREELISTNODE ** ne)
{
RTREELISTNODE
* ln = _RTreeNewListNode();
ln
-> node = node;
ln
-> next = * ne;
* ne = ln;
}

/* *
*Deletearectanglefromnon-rootpartofanindexstructure.
*CalledbyRTreeDeleteRect.Descendstreerecursively,
*mergesbranchesonthewaybackup.
*Returns1ifrecordnotfound,0ifsuccess.
*/
static int _RTreeDeleteRect(RTREEMBR * rc, int tid,RTREENODE * node,RTREELISTNODE ** ee)
{
int i;

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

if (node -> level > 0 ) /* notaleafnode */
{
for (i = 0 ;i < NODECARD;i ++ )
{
if (node -> branch[i].child && RTreeOverlap(rc, & (node -> branch[i].mbr)))
{
if ( ! _RTreeDeleteRect(rc,tid,node -> branch[i].child,ee))
{
if (node -> branch[i].child -> count >= MINNODEFILL)
node
-> branch[i].mbr = RTreeNodeCover(node -> branch[i].child);
else { /* notenoughentriesinchild,eliminatechildnode */
_RTreeReInsert(node
-> branch[i].child,ee);
RTreeDisconnectBranch(node,i);
}
return 0 ;
}
}
}
return 1 ;
}

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

/* aleafnode */
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(
' ' );
}

/* =============================================================================
Publicfunctions:
=============================================================================
*/

int RTreeSetNodeMax( int new_max){ return set_max( & NODECARD,new_max);}
int RTreeSetLeafMax( int new_max){ return set_max( & LEAFCARD,new_max);}
int RTreeGetNodeMax( void ){ return NODECARD;}
int RTreeGetLeafMax( void ){ return LEAFCARD;}

/* *
*Initializearectangletohaveall0coordinates.
*/
void RTreeInitRect(RTREEMBR * rc)
{
int i;
for (i = 0 ;i < SIDES_NUMB;i ++ )
rc
-> bound[i] = (REALTYPE) 0 ;
}


/* *
*Returnambrwhosefirstlowsideishigherthanitsoppositeside-
*interpretedasanundefinedmbr.
*/
RTREEMBRRTreeNullRect(
void )
{
RTREEMBRrc;
int i;

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

/* *
*Printoutthedataforarectangle.
*/
void RTreePrintRect(RTREEMBR * rc, int depth)
{
int i;

_RTreeTabIn(depth);
fprintf(stdout,
" mbr: " );
for (i = 0 ;i < DIMS_NUMB;i ++ )
{
_RTreeTabIn(depth
+ 1 );
fprintf(stdout,
" %f %f " ,rc -> bound[i],rc -> bound[i + DIMS_NUMB]);
}
}

/* *
*Calculatethe2-dimensionalareaofarectangle
*/
REALTYPERTreeRectArea(RTREEMBR
* rc)
{
if (INVALID_RECT(rc))
return (REALTYPE) 0 ;

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


/* *
*Calculatethen-dimensionalvolumeofarectangle
*/
REALTYPERTreeRectVolume(RTREEMBR
* rc)
{
int i;
REALTYPEvol
= (REALTYPE) 1 ;

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

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


/* *
*Precomputedvolumesoftheunitspheresforthefirstfewdimensions
*/
const double UnitSphereVolumes[] = {
0.000000 , /* dimension0 */
2.000000 , /* dimension1 */
3.141593 , /* dimension2 */
4.188790 , /* dimension3 */
4.934802 , /* dimension4 */
5.263789 , /* dimension5 */
5.167713 , /* dimension6 */
4.724766 , /* dimension7 */
4.058712 , /* dimension8 */
3.298509 , /* dimension9 */
2.550164 , /* dimension10 */
1.884104 , /* dimension11 */
1.335263 , /* dimension12 */
0.910629 , /* dimension13 */
0.599265 , /* dimension14 */
0.381443 , /* dimension15 */
0.235331 , /* dimension16 */
0.140981 , /* dimension17 */
0.082146 , /* dimension18 */
0.046622 , /* dimension19 */
0.025807 , /* dimension20 */
};

#if DIMS_NUMB>20
#error "notenoughprecomputedspherevolumes"
#endif

#define UnitSphereVolumeUnitSphereVolumes[DIMS_NUMB]

/* *
*Calculatethen-dimensionalvolumeoftheboundingsphereofarectangle.
*TheexactvolumeoftheboundingsphereforthegivenRTREEMBR.
*/
REALTYPERTreeRectSphericalVolume(RTREEMBR
* rc)
{
int i;
double sum_of_squares = 0 ,radius;

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

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


/* *
*Calculatethen-dimensionalsurfaceareaofarectangle
*/
REALTYPERTreeRectSurfaceArea(RTREEMBR
* rc)
{
int i,j;
REALTYPEsum
= (REALTYPE) 0 ;

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

for (i = 0 ;i < DIMS_NUMB;i ++ ){
REALTYPEface_area
= (REALTYPE) 1 ;
for (j = 0 ;j < DIMS_NUMB;j ++ )
/* excludeiextentfromproductinthisdimension */
if (i != j){
REALTYPEj_extent
= rc -> bound[j + DIMS_NUMB] - rc -> bound[j];
face_area
*= j_extent;
}
sum
+= face_area;
}
return 2 * sum;
}



/* *
*Combinetworectangles,makeonethatincludesboth.
*/
RTREEMBRRTreeCombineRect(RTREEMBR
* rc1,RTREEMBR * rc2)
{
int i,j;
RTREEMBRnew_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;
}


/* *
*Decidewhethertworectanglesoverlap.
*/
int RTreeOverlap(RTREEMBR * rc1,RTREEMBR * rc2)
{
int i,j;
assert(rc1
&& rc2);

for (i = 0 ;i < DIMS_NUMB;i ++ )
{
j
= i + DIMS_NUMB; /* indexforhighsides */

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


/* *
*Decidewhetherrectangleriscontainedinrectangles.
*/
int RTreeContained(RTREEMBR * r,RTREEMBR * s)
{
int i,j,result;
assert(r
&& s);

/* undefinedmbriscontainedinanyother */
if (INVALID_RECT(r))
return TRUE;

/* nombr(exceptanundefinedone)iscontainedinanundefmbr */
if (INVALID_RECT(s))
return FALSE;

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

/* *
*Splitanode.
*Dividesthenodesbranchesandtheextraonebetweentwonodes.
*Oldnodeisoneofthenewones,andonereallynewoneiscreated.
*Triesmorethanonemethodforchoosingapartition,usesbestresult.
*/
void RTreeSplitNode(RTREENODE * node,RTREEBRANCH * br,RTREENODE ** new_node)
{
RTREEPARTITION
* p;
int level;

assert(node
&& br);

/* loadallthebranchesintoabuffer,initializeoldnode */
level
= node -> level;
_RTreeGetBranches(node,br);

/* findpartition */
p
= & Partitions[ 0 ];

/* Note:can'tuseMINFILL(n)belowsincenodewasclearedbyGetBranches() */
_RTreeMethodZero(p,level
> 0 ? MINNODEFILL:MINLEAFFILL);

/* putbranchesfrombufferinto2nodesaccordingtochosenpartition */
* new_node = RTreeNewNode();
(
* new_node) -> level = node -> level = level;
_RTreeLoadNodes(node,
* new_node,p);

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


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

/* *
*Makeanewnodeandinitializetohaveallbranchcellsempty.
*/
RTREENODE
* RTreeNewNode( void )
{
RTREENODE
* node = (RTREENODE * )malloc( sizeof (RTREENODE));
assert(node);
RTreeInitNode(node);
return node;
}

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


/* *
*Printoutthedatainanode.
*/
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=%dcount=%daddress=%o " ,node -> level,node -> count,(unsigned int )node);
#pragma warning(pop)

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

/* *
*Findthesmallestrectanglethatincludesallrectanglesinbranchesofanode.
*/
RTREEMBRRTreeNodeCover(RTREENODE
* node)
{
int i,first_time = 1 ;
RTREEMBRrc;
assert(node);

RTreeInitRect(
& rc);

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

/* *
*Pickabranch.Picktheonethatwillneedthesmallestincrease
*inareatoaccomodatethenewrectangle.Thiswillresultinthe
*leasttotalareaforthecoveringrectanglesinthecurrentnode.
*Incaseofatie,picktheonewhichwassmallerbefore,toget
*thebestresolutionwhensearching.
*/
int RTreePickBranch(RTREEMBR * rc,RTREENODE * node)
{
RTREEMBR
* r;
int i,first_time = 1 ;
REALTYPEincrease,bestIncr
= (REALTYPE) - 1 ,area,bestArea = 0 ;
int best = 0 ;
RTREEMBRtmp_rect;
assert(rc
&& node);

for (i = 0 ;i < MAXKIDS(node);i ++ )
{
if (node -> branch[i].child)
{
r
= & node -> branch[i].mbr;
area
= RTreeRectSphericalVolume(r);
tmp_rect
= RTreeCombineRect(rc,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;
}

/* *
*Addabranchtoanode.Splitthenodeifnecessary.
*Returns0ifnodenotsplit.Oldnodeupdated.
*Returns1ifnodesplit,sets*new_nodetoaddressofnewnode.
*Oldnodeupdated,becomesoneoftwo.
*/
int RTreeAddBranch(RTREEBRANCH * br,RTREENODE * node,RTREENODE ** new_node)
{
int i;
assert(br
&& node);

if (node -> count < MAXKIDS(node)) /* splitwon'tbenecessary */
{
for (i = 0 ;i < MAXKIDS(node);i ++ ) /* findemptybranch */
{
if (node -> branch[i].child == NULL)
{
node
-> branch[i] = * br;
node
-> count ++ ;
break ;
}
}

return 0 ;
}

assert(new_node);
RTreeSplitNode(node,br,new_node);

return 1 ;
}

/* *
*Disconnectadependentnode.
*/
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)noderecursively.
*/
void RTreeDestroyNode(RTREENODE * node)
{
int i;

if (node -> level > 0 )
{
/* itisnotleaf->destroychilds */
for (i = 0 ;i < NODECARD;i ++ )
{
if (node -> branch[i].child)
RTreeDestroyNode(node
-> branch[i].child);
}
}

/* Freethisnode */
RTreeFreeNode(node);
}


/* *
*Createanewrtreeindex,empty.Consistsofasinglenode.
*/
RTREENODE
* RTreeCreate( void )
{
RTREENODE
* root = RTreeNewNode();
root
-> level = 0 ; /* leaf */
return root;
}

/* *
*Destroyartreerootmustbearootofrtree.Freeallmemory.
*/
void RTreeDestroy(RTREENODE * root)
{
RTreeDestroyNode(root);
}

/* *
*Searchinanindextreeorsubtreeforalldatarectanglesthatoverlaptheargumentrectangle.
*Returnthenumberofqualifyingdatarects.
*/
int RTreeSearch(RTREENODE * node,RTREEMBR * rc,pfnSearchHitCallbackpfnSHCB, void * pfnParam)
{
/* Fixnotyettested. */
int hitCount = 0 ;
int i;

assert(node
&& rc);
assert(node
-> level >= 0 );

if (node -> level > 0 ) /* thisisaninternalnodeinthetree */
{
for (i = 0 ;i < NODECARD;i ++ ){
if (node -> branch[i].child && RTreeOverlap(rc, & node -> branch[i].mbr))
hitCount
+= RTreeSearch(node -> branch[i].child,rc,pfnSHCB,pfnParam);
}
}
else /* thisisaleafnode */
{
#pragma warning(push)/*C4311*/
#pragma warning(disable:4311)
for (i = 0 ;i < LEAFCARD;i ++ )
{
if (node -> branch[i].child && RTreeOverlap(rc, & node -> branch[i].mbr))
{
hitCount
++ ;

/* calltheuser-providedcallbackandreturnifcallbackwantstoterminatesearchearly */
if (pfnSHCB && ! pfnSHCB(( int )node -> branch[i].child,pfnParam))
return hitCount;

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

/* *
*Insertadatarectangleintoanindexstructure.
*RTreeInsertRectprovidesforsplittingtheroot;
*returns1ifrootwassplit,0ifitwasnot.
*Thelevelargumentspecifiesthenumberofstepsupfromtheleaf
*leveltoinsert;e.g.adatarectanglegoesinatlevel=0.
*_RTreeInsertRectdoestherecursion.
*/
int RTreeInsertRect(RTREEMBR * rc, int tid,RTREENODE ** root, int level)
{
#ifdef_DEBUG
int i;
#endif

RTREENODE
* newroot;
RTREENODE
* newnode;
RTREEBRANCHb;

assert(rc
&& root);
assert(level
>= 0 && level <= ( * root) -> level);

#ifdef_DEBUG
for (i = 0 ;i < DIMS_NUMB;i ++ )
assert(rc
-> bound[i] <= rc -> bound[DIMS_NUMB + i]);
#endif

/* rootsplit */
if (_RTreeInsertRect(rc,tid, * root, & newnode,level))
{
newroot
= RTreeNewNode(); /* growanewroot,&treetaller */
newroot
-> level = ( * root) -> level + 1 ;
b.mbr
= RTreeNodeCover( * root);
b.child
= * root;
RTreeAddBranch(
& b,newroot,NULL);
b.mbr
= RTreeNodeCover(newnode);
b.child
= newnode;
RTreeAddBranch(
& b,newroot,NULL);
* root = newroot;

return 1 ;
}

return 0 ;
}


/* *
*Deleteadatarectanglefromanindexstructure.
*PassinapointertoaRTREEMBR,thetidoftherecord,ptrtoptrtorootnode.
*Returns1ifrecordnotfound,0ifsuccess.
*RTreeDeleteRectprovidesforeliminatingtheroot.
*/
int RTreeDeleteRect(RTREEMBR * rc, int tid,RTREENODE ** root)
{
int i;
RTREENODE
* tmp_nptr = NULL;
RTREELISTNODE
* reInsertList = NULL;
RTREELISTNODE
* e;

assert(rc
&& root);
assert(
* root);
assert(tid
>= 0 );

if ( ! _RTreeDeleteRect(rc,tid, * root, & reInsertList))
{
/* foundanddeletedadataitem */

/* reinsertanybranchesfromeliminatednodes */
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)
{
RTreeInsertRect(
& (tmp_nptr -> branch[i].mbr),( int )tmp_nptr -> branch[i].child,root,tmp_nptr -> level);
}
}
#pragma warning(pop)

e
= reInsertList;
reInsertList
= reInsertList -> next;
RTreeFreeNode(e
-> node);
_RTreeFreeListNode(e);
}

/* checkforredundantroot(notleaf,1child)andeliminate */
if (( * root) -> count == 1 && ( * root) -> level > 0 )
{
for (i = 0 ;i < NODECARD;i ++ )
{
tmp_nptr
= ( * root) -> branch[i].child;
if (tmp_nptr)
break ;
}
assert(tmp_nptr);
RTreeFreeNode(
* root);
* root = tmp_nptr;
}

return 0 ;
}

return 1 ;
}

测试文件test.c:

/* *
rtreelibusageexampleapp.
*/
#include
< stdio.h >
#include
" rtree.h "

RTREEMBRrects[]
= {
{{
0 , 0 , 0 , 2 , 2 , 0 }}, /* xmin,ymin,zmin,xmax,ymax,zmax(for3dimensionalRTree) */
{{
5 , 5 , 0 , 7 , 7 , 0 }},
{{
8 , 5 , 0 , 9 , 6 , 0 }},
{{
7 , 1 , 0 , 9 , 2 , 0 }}
};


int nrects = sizeof (rects) / sizeof (rects[ 0 ]);
RTREEMBRsearch_rect
= {
{
6 , 4 , 0 , 10 , 6 , 0 } /* searchwillfindaboverectsthatthisoneoverlaps */
};

int MySearchCallback( int id, void * arg)
{
/* Note:-1tomakeupforthe+1whendatawasinserted */
fprintf(stdout,
" Hitdatambr%d " ,id - 1 );
return 1 ; /* keepgoing */
}

int main()
{
RTREENODE
* root = RTreeCreate();

int i,nhits;

fprintf(stdout,
" nrects=%d " ,nrects);

/* Insertallthetestingdatarects */
for (i = 0 ;i < nrects;i ++ ){
RTreeInsertRect(
& rects[i], /* thembrbeinginserted */
i
+ 10 , /* i+1ismbrID.IDMUSTNEVERBEZERO */
& root, /* theaddressofrtree'srootsincerootcanchangeundernieth */
0 /* alwayszerowhichmeanstoaddfromtheroot */
);
}

nhits
= RTreeSearch(root, & search_rect,MySearchCallback, 0 );

fprintf(stdout,
" Searchresultedin%dhits " ,nhits);

RTreeDestroy(root);

return 0 ;
}


使用VS2005,新建一个Console项目test,选为空项目。然后把这3个文件加入进来,就可以使用了。必要的话,把RTree.h和RTree.C建立成连接库,就更方便了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值