首页 > 其他分享 >RTree源代码——C语言实现

RTree源代码——C语言实现

时间:2023-01-27 14:08:43浏览次数:44  
标签:node RTREENODE int RTree C语言 branch rc 源代码 RTREEMBR


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 ([email protected]) - 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 ([email protected]) - 2007-11
****************************************************************************
*/

#ifndef RTREE_H_INCLUDED

#define
RTREE_H_INCLUDED



/*
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
{

int
count;

int
level;
/*
0 is leaf, others positive
*/

RTREEBRANCH branch[MAXCARD];
}RTREENODE;

typedef
struct
_RTREELISTNODE
{

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


/*

* 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
(
*
pfnSearchHitCallback)(
int
id,
void
*
pfnParam);



int
RTreeSetNodeMax(
int
new_max);


int
RTreeSetLeafMax(
int
new_max);


int
RTreeGetNodeMax(
void
);


int
RTreeGetLeafMax(
void
);


/*
*
* Initialize a rectangle to have all 0 coordinates.

*/


void
RTreeInitRect( RTREEMBR
*
rc);


/*
*
* 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
*
rc,
int
depth );


/*
*
* Calculate the 2-dimensional area of a rectangle

*/

REALTYPE RTreeRectArea( RTREEMBR
*
rc );


/*
*
* Calculate the n-dimensional volume of a rectangle

*/

REALTYPE RTreeRectVolume( RTREEMBR
*
rc );



/*
*
* 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
*
rc );



/*
*
* Calculate the n-dimensional surface area of a rectangle

*/

REALTYPE RTreeRectSurfaceArea( RTREEMBR
*
rc );



/*
*
* 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( RTREENODE
*
node, RTREEBRANCH
*
br, RTREENODE
**
new_node);


/*
*
* Initialize a RTREENODE structure.

*/


void
RTreeInitNode( RTREENODE
*
node );


/*
*
* Make a new node and initialize to have all branch cells empty.

*/

RTREENODE
*
RTreeNewNode(
void
);


void
RTreeFreeNode( RTREENODE
*
node );



/*
*
* Print out the data in a node.

*/


void
RTreePrintNode( RTREENODE
*
node,
int
depth );



/*
*
* Find the smallest rectangle that includes all rectangles in branches of a node.

*/

RTREEMBR RTreeNodeCover( RTREENODE
*
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
*
rc, RTREENODE
*
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( RTREEBRANCH
*
br, RTREENODE
*
node, RTREENODE
**
new_node);



/*
*
* Disconnect a dependent node.

*/


void
RTreeDisconnectBranch( RTREENODE
*
node,
int
i );



/*
*
* Destroy (free) node recursively.

*/


void
RTreeDestroyNode ( RTREENODE
*
node );



/*
*
* Create a new rtree index, empty. Consists of a single node.

*/

RTREENODE
*
RTreeCreate(
void
);



/*
*
* Destroy a rtree root must be a root of rtree. Free all memory.

*/


void
RTreeDestroy(RTREENODE
*
root);



/*
*
* Search in an index tree or subtree for all data rectangles that overlap the argument rectangle.
* Return the number of qualifying data rects.

*/


int
RTreeSearch( RTREENODE
*
node, RTREEMBR
*
rc, pfnSearchHitCallback pfnSHCB,
void
*
pfnParam);


/*
*
* 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
RTreeInsertRect( RTREEMBR
*
rc,
int
tid, RTREENODE
**
root,
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
RTreeDeleteRect( RTREEMBR
*
rc,
int
tid, RTREENODE
**
root);


#endif
/* RTREE_H_INCLUDED */

 

RTree.C文件:

/*
***************************************************************************
* RTree.C
*
* MODULE: R-Tree library
*
* AUTHOR(S): Antonin Guttman - original code
* Daniel Green ([email protected]) - 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 ([email protected]) - 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;

RTREEBRANCH BranchBuf[MAXCARD
+
1
];

int
BranchCount;
RTREEMBR CoverSplit;
REALTYPE CoverSplitArea;
RTREEPARTITION Partitions[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;


/*
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)



static

int
set_max(
int

*
which,
int
new_max)
{

if
(
2

>
new_max
||
new_max
>
MAXCARD)

return

0
;

*
which
=
new_max;

return

1
;
}



/*
*
* Load branch buffer with branches from full node plus the extra branch.

*/


static

void
_RTreeGetBranches( 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
*/

BranchBuf[i]
=
node
->
branch[i];
}

BranchBuf[MAXKIDS(node)]
=

*
br;
BranchCount
=
MAXKIDS(node)
+

1
;


/*
calculate mbr containing all in the set
*/

CoverSplit
=
BranchBuf[
0
].mbr;


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

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




/*
*
* Put a branch in one of the groups.

*/


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]
++
;
}


/*
*
* 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(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(
&
BranchBuf[i].mbr);

worst
=

-
CoverSplitArea
-

1
;


for
(i
=
0
; i
<
p
->
total
-
1
; i
++
)
{

for
(j
=
i
+
1
; j
<
p
->
total; j
++
)
{
RTREEMBR one_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);
}



/*
*
* Copy branches from the buffer into two nodes according to the partition.

*/


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);
}
}


/*
*
* 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( 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] = %d area = %f
"
, p
->
count[
0
], p
->
area[
0
]);
fprintf (stdout,
"
count[1] = %d area = %f
"
, p
->
count[
1
], p
->
area[
1
]);

if
(p
->
area[
0
]
+
p
->
area[
1
]
>

0
)
{
fprintf (stdout,
"
total area = %f effectiveness = %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 #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( RTREEPARTITION
*
p,
int
minfill )
{

int
i;
REALTYPE biggestDiff;

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;
REALTYPE growth0, 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);
}


/*
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(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( RTREEMBR
*
rc,
int
tid, RTREENODE
*
node, RTREENODE
**
new_node,
int
level)
{

int
i;
RTREEBRANCH b;
RTREENODE
*
n2;

assert(rc
&&
node
&&
new_node);
assert(level
>=

0

&&
level
<=
node
->
level);


/*
Still above level for insertion, go down tree recursively
*/


if
(node
->
level
>
level)
{
i
=
RTreePickBranch(rc, node);

if
(
!
_RTreeInsertRect(rc, tid, node
->
branch[i].child,
&
n2, level))
{

/*
child was not split
*/

node
->
branch[i].mbr
=
RTreeCombineRect(rc,
&
(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(
&
b, node, new_node);
}

else

if
(node
->
level
==
level)
/*
Have reached level for insertion. Add mbr, split if necessary
*/

{
b.mbr
=

*
rc;


#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(
&
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
*
rc,
int
tid, RTREENODE
*
node, RTREELISTNODE
**
ee)
{

int
i;

assert(rc
&&
node
&&
ee);
assert(tid
>=

0
);
assert(node
->
level
>=

0
);


if
(node
->
level
>

0
)
/*
not a leaf node
*/

{

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
{
/*
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(
'

'
);
}


/*
=============================================================================
Public functions:
=============================================================================
*/



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; }


/*
*
* Initialize a rectangle to have all 0 coordinates.

*/


void
RTreeInitRect( RTREEMBR
*
rc)
{

int
i;

for
(i
=
0
; i
<
SIDES_NUMB; i
++
)
rc
->
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 rc;

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;
}


/*
*
* Print out the data for a rectangle.

*/


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]);
}
}


/*
*
* Calculate the 2-dimensional area of a rectangle

*/

REALTYPE RTreeRectArea( 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
]);
}



/*
*
* Calculate the n-dimensional volume of a rectangle

*/

REALTYPE RTreeRectVolume( RTREEMBR
*
rc )
{

int
i;
REALTYPE vol
=
(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;
}



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



/*
*
* Calculate the n-dimensional surface area of a rectangle

*/

REALTYPE RTreeRectSurfaceArea( RTREEMBR
*
rc )
{

int
i, j;
REALTYPE sum
=
(REALTYPE)
0
;


if
(INVALID_RECT(rc))

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
=
rc
->
bound[j
+
DIMS_NUMB]
-
rc
->
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( 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(node, br);


/*
find partition
*/

p
=

&
Partitions[
0
];


/*
Note: can't use MINFILL(n) below since node was cleared by GetBranches()
*/

_RTreeMethodZero(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(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
"
, 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
);
}
}
}


/*
*
* Find the smallest rectangle that includes all rectangles in branches of a node.

*/

RTREEMBR RTreeNodeCover( RTREENODE
*
node )
{

int
i, first_time
=
1
;
RTREEMBR rc;
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;
}


/*
*
* 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
*
rc, RTREENODE
*
node)
{
RTREEMBR
*
r;

int
i, first_time
=

1
;
REALTYPE increase, bestIncr
=
(REALTYPE)
-
1
, area, bestArea
=
0
;

int
best
=
0
;
RTREEMBR tmp_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;
}


/*
*
* 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( RTREEBRANCH
*
br, RTREENODE
*
node, RTREENODE
**
new_node)
{

int
i;
assert(br
&&
node);


if
(node
->
count
<
MAXKIDS(node))
/*
split won'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(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.

*/

RTREENODE
*
RTreeCreate(
void
)
{
RTREENODE
*
root
=
RTreeNewNode();
root
->
level
=

0
;
/*
leaf
*/


return
root;
}


/*
*
* Destroy a rtree root must be a root of rtree. Free all memory.

*/


void
RTreeDestroy(RTREENODE
*
root)
{
RTreeDestroyNode (root);
}


/*
*
* Search in an index tree or subtree for all data rectangles that overlap the argument rectangle.
* Return the number of qualifying data rects.

*/


int
RTreeSearch( RTREENODE
*
node, RTREEMBR
*
rc, pfnSearchHitCallback pfnSHCB,
void
*
pfnParam)
{

/*
Fix not yet tested.
*/


int
hitCount
=

0
;

int
i;

assert(node
&&
rc);
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(rc,
&
node
->
branch[i].mbr))
hitCount
+=
RTreeSearch(node
->
branch[i].child, rc, 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(rc,
&
node
->
branch[i].mbr))
{
hitCount
++
;


/*
call the user-provided callback and return if callback wants to terminate search early
*/


if
(pfnSHCB
&&

!
pfnSHCB((
int
)node
->
branch[i].child, pfnParam) )

return
hitCount;

}
}

#pragma
warning(pop)

}

return
hitCount;
}


/*
*
* 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
RTreeInsertRect( RTREEMBR
*
rc,
int
tid, RTREENODE
**
root,
int
level)
{
#ifdef _DEBUG

int
i;

#endif


RTREENODE
*
newroot;
RTREENODE
*
newnode;
RTREEBRANCH b;

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



/*
root split
*/


if
(_RTreeInsertRect(rc, tid,
*
root,
&
newnode, level))
{
newroot
=
RTreeNewNode();
/*
grow a new root, & tree taller
*/

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
;
}



/*
*
* 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
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))
{

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


/*
check for redundant root (not leaf, 1 child) and eliminate
*/


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:

/*
*
rtree lib usage example app.

*/

#include
<
stdio.h
>

#include
"
rtree.h
"


RTREEMBR rects[]
=
{
{ {
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
nrects
=

sizeof
(rects)
/

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

};


int
MySearchCallback(
int
id,
void
*
arg)
{

/*
Note: -1 to make up for the +1 when data was inserted
*/

fprintf (stdout,
"
Hit data mbr %d
"
, id
-
1
);

return

1
;
/*
keep going
*/

}


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


int
i, nhits;

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


/*
Insert all the testing data rects
*/


for
(i
=
0
; i
<
nrects; i
++
){
RTreeInsertRect(
&
rects[i],
/*
the mbr being inserted
*/

i
+
10
,
/*
i+1 is mbr ID. ID MUST NEVER BE ZERO
*/


&
root,
/*
the address of rtree's root since root can change undernieth
*/


0

/*
always zero which means to add from the root
*/

);
}

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

fprintf (stdout,
"
Search resulted in %d hits
"
, nhits);

RTreeDestroy (root);


return

0
;
}

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

标签:node,RTREENODE,int,RTree,C语言,branch,rc,源代码,RTREEMBR
From: https://blog.51cto.com/mapaware/6024046

相关文章

  • C语言实现一个简单的单向链表list
    C语言实现一个简单的单向链表listcheungmine用C语言实现一个简单实用的单向链表list,具有一定的实际意义。尤其我们不想使用STL里面的list<...>类的时候。我实现的这个list,结......
  • 基于Oracle OCI的数据访问C语言接口ORADBI
    基于OracleOCI的数据访问C语言接口ORADBI​​[email protected]​​Mar.22, 2008 ORADBI是我在OracleOCI(Oracle调用接口)基础上开发......
  • A Template for C-Language Library Creation - 一个创建C语言运行库的模板
    ATemplateforC-LanguageLibraryCreation一个创建C语言运行库的模板WesupposethelibrarywewanttocreateislibElec.1)Createafolderinyourdisk,suchas......
  • C语言--简单的爱心代码
    新手都能敲出来的爱心代码#include<stdio.h>#include<stdlib.h>//#include<string.h>intmain(){floatx,y,a;for(y=1.5;y>-1.5;y-=0.1){for(x=-1......
  • 上交自瞄算法开源代码-装甲板识别功能分析
    前言开源代码github网址:GitHub-xinyang-go/SJTU-RM-CV-2019:上海交通大学RoboMaster2019赛季视觉代码这里着重分析主函数main.cpp与装甲板识别部分的工程文件armer......
  • C语言经典100例【1、2】
    【1】三位数字重组问题题目:有 1、2、3、4 四个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?分析:分别把1,2,3,4放在个位、十位和百位,用嵌套循环即可解决。注......
  • struct task_struct 源代码
    //structtask_struct代码structtask_struct{#ifdefCONFIG_THREAD_INFO_IN_TASK /* *Forreasonsofheadersoup(seecurrent_thread_info()),this *......
  • 【原创】NES第十波:解说一个NES音乐贺卡的源代码
    我将自己写的一编音乐贺卡源代码拿来做解说。完整的工程和源代码见最后面的下载链接。之前的解说都是保姆级的。从这一章开始,就变得简洁了。 一、定义内存变量(汇编都是......
  • C语言课程设计题目[2023-01-26]
    C语言课程设计题目[2023-01-26]C课程设计题目第一套难度1题目:绩点计算系统一、设计内容录入并保存信息:把学生信息保存到文件stu.txt中,输入学生基本信息、课外表......
  • C语言学生信息管理系统[2023-01-26]
    C语言学生信息管理系统[2023-01-26]第33题学生信息管理系统【涉及知识点】文件的定义和操作;使用文本构建菜单;函数的选择调用;数据的输入输出。【题目介绍】学生......