C语言实现一个四叉树quadtree
cheungmine
用C语言实现一个2维四叉树quadtree,具有一定的实际意义。你可以把几何图形的索引(用long型的id标识)放到这个树中(根据最小边界矩形)。quadtree可以用来快速区域查找图形,虽然不是那么精确,但是毕竟没有漏掉的。虽然quadtree的效率不如RTree?但是RTree的实现毕竟复杂了些,我会尽快收集整理出RTree的代码。RTree确实比QuadTree好的多?(起码RTree很时髦啊!)
头文件如下:
/*
* quadtree.h
* Quad tree structure -- for spatial quick searching
* cheungmine
* Oct. 5, 2007. All rights reserved.
*/
#ifndef QUADTREE_H_INCLUDED
#define
QUADTREE_H_INCLUDED
#include
"
unistd.h
"
#include
"
list.h
"
#define
QUAD_SUBNODES 4
#define
QBOX_OVERLAP_MAX 0.4
#define
QBOX_OVERLAP_MIN 0.02
#define
QTREE_DEPTH_MAX 8
#define
QTREE_DEPTH_MIN 4
#define
QUADRANT_BITS 3
/*
a quadrant defined below:
NW(1) | NE(0)
-----------|-----------
SW(2) | SE(3)
*/
typedef
enum
{
NE
=
0
,
NW
=
1
,
SW
=
2
,
SE
=
3
}QuadrantEnum;
/*
a box defined below:
_____max
|__|__|
|__|__|
min
*/
typedef
struct
_quadbox_t
{
double
_xmin,
_ymin,
_xmax,
_ymax;
}quadbox_t;
/*
quad node
*/
typedef
struct
_quadnode_t
{
quadbox_t _box;
/*
node bound box
*/
list_t
*
_lst;
/*
node data list
*/
struct
_quadnode_t
*
_sub[QUAD_SUBNODES];
/*
pointer to subnodes of this node
*/
}quadnode_t;
/*
quad tree
*/
typedef
struct
_quadtree_t
{
quadnode_t
*
_root;
int
_depth;
/*
max depth of tree: 0-based
*/
float
_overlap;
/*
overlapped ratio of quanbox
*/
}quadtree_t;
/*
=============================================================================
Public Functions
=============================================================================
*/
/*
creates a quadtree and returns a pointer to it
*/
extern
quadtree_t
*
quadtree_create (quadbox_t box,
int
depth,
/*
4~8
*/
float
overlap
/*
0.02 ~ 0.4
*/
);
/*
destroys a quad tree and free all memory
*/
extern
void
quadtree_destroy (IN quadtree_t
*
qtree
);
/*
inserts a node identified by node_key into a quadtree, returns the node quadtree encoding
*/
extern
quadnode_t
*
quadtree_insert (IN quadtree_t
*
qtree,
IN
long
node_key,
IN quadbox_t
*
node_box
);
/*
searches nodes inside search_box
*/
extern
void
quadtree_search (IN
const
quadtree_t
*
qtree,
IN quadbox_t
*
search_box,
OUT list_t
*
results_list
);
#endif
//
QUADTREE_H_INCLUDED
实现文件如下:
/*
* quadtree.c
* Quad tree implementation -- for spatial quick searching
* cheungmine
* Oct. 5, 2007. All rights reserved.
*/
#include
"
quadtree.h
"
#include
<
assert.h
>
/*
=============================================================================
Private Functions
=============================================================================
*/
static
BOOL quadbox_is_valid (quadbox_t
*
qb)
{
return
(qb
->
_xmin
<
qb
->
_xmax
&&
qb
->
_ymin
<
qb
->
_ymax)
?
TRUE : FALSE;
}
static
double
quadbox_width (
const
quadbox_t
*
qb)
{
return
(qb
->
_xmax
-
qb
->
_xmin);
}
static
double
quadbox_height (
const
quadbox_t
*
qb)
{
return
(qb
->
_ymax
-
qb
->
_ymin);
}
static
void
quadbox_init (quadbox_t
*
qb,
double
xmin,
double
ymin,
double
xmax,
double
ymax)
{
qb
->
_xmin
=
xmin; qb
->
_ymin
=
ymin; qb
->
_xmax
=
xmax; qb
->
_ymax
=
ymax;
assert (quadbox_is_valid (qb) );
}
static
void
quadbox_inflate(quadbox_t
*
qb,
double
dx,
double
dy)
{
assert (dx
>
0
&&
dy
>
0
);
qb
->
_xmin
-=
(dx
/
2
);
qb
->
_xmax
+=
(dx
/
2
);
qb
->
_ymin
-=
(dy
/
2
);
qb
->
_ymax
+=
(dy
/
2
);
}
/*
splits the quadrant such as below:
nw(0010) | ne(0001)
----------|----------
sw(0100) | se(1000)
*/
static
void
quadbox_split(
const
quadbox_t
*
qb,
quadbox_t
*
ne, quadbox_t
*
nw, quadbox_t
*
se, quadbox_t
*
sw,
float
overlap)
{
double
dx
=
quadbox_width(qb)
*
(
1.0
+
overlap)
/
2
;
double
dy
=
quadbox_height(qb)
*
(
1.0
+
overlap)
/
2
;
assert (overlap
>=
QBOX_OVERLAP_MIN
-
0.0001
);
assert (overlap
<=
QBOX_OVERLAP_MAX
+
0.0001
);
quadbox_init (ne, qb
->
_xmax
-
dx, qb
->
_ymax
-
dy, qb
->
_xmax, qb
->
_ymax);
quadbox_init (nw, qb
->
_xmin, qb
->
_ymax
-
dy, qb
->
_xmin
+
dx, qb
->
_ymax);
quadbox_init (sw, qb
->
_xmin, qb
->
_ymin, qb
->
_xmin
+
dx, qb
->
_ymin
+
dy);
quadbox_init (se, qb
->
_xmax
-
dx, qb
->
_ymin, qb
->
_xmax, qb
->
_ymin
+
dy);
}
/*
returns TRUE if the first is inside the senond
*/
static
BOOL quadbox_is_inside(
const
quadbox_t
*
_first,
const
quadbox_t
*
_second)
{
return
(_second
->
_xmin
<
_first
->
_xmin
&&
_second
->
_xmax
>
_first
->
_xmax
&&
_second
->
_ymin
<
_first
->
_ymin
&&
_second
->
_ymax
>
_first
->
_ymax)
?
TRUE : FALSE;
}
/*
returns TRUE if two quad_box is overlapped
*/
static
BOOL quadbox_is_overlapped(
const
quadbox_t
*
_first,
const
quadbox_t
*
_second)
{
return
(_first
->
_xmin
>
_second
->
_xmax
||
_first
->
_xmax
<
_second
->
_xmin
||
_first
->
_ymin
>
_second
->
_ymax
||
_first
->
_ymax
<
_second
->
_ymin)
?
FALSE : TRUE;
}
static
quadnode_t
*
quadnode_create (
const
quadbox_t
*
box)
{
quadnode_t
*
node
=
(quadnode_t
*
) calloc (
1
,
sizeof
(quadnode_t));
if
(node)
memcpy (
&
(node
->
_box), box,
sizeof
(quadbox_t));
return
node;
}
static
void
quadnode_destroy(quadnode_t
*
node)
{
if
(node
->
_sub[NE]
!=
0
){
quadnode_destroy (node
->
_sub[NE]);
quadnode_destroy (node
->
_sub[NW]);
quadnode_destroy (node
->
_sub[SE]);
quadnode_destroy (node
->
_sub[SW]);
}
if
(node
->
_lst)
list_destroy(node
->
_lst, NULL);
free (node);
}
static
void
quadnode_create_child(quadnode_t
*
node,
float
overlap,
int
depth)
{
quadbox_t ne, nw, se, sw;
assert (node);
quadbox_split (
&
(node
->
_box),
&
ne,
&
nw,
&
se,
&
sw, overlap );
node
->
_sub[NE]
=
quadnode_create (
&
ne);
node
->
_sub[NW]
=
quadnode_create (
&
nw);
node
->
_sub[SW]
=
quadnode_create (
&
sw);
node
->
_sub[SE]
=
quadnode_create (
&
se);
}
static
BOOL quadnode_has_child(
const
quadnode_t
*
node)
{
return
(node
->
_sub[NE]
!=
0
);
}
static
BOOL quadnode_has_data (
const
quadnode_t
*
node)
{
return
(node
->
_lst
&&
node
->
_lst
->
size
>
0
)
?
TRUE: FALSE;
}
static
void
quadnode_add_data ( quadnode_t
*
node,
long
node_key )
{
assert (node);
if
(
!
node
->
_lst) node
->
_lst
=
list_create();
assert (node
->
_lst);
list_append_node (node
->
_lst, list_key_create (node_key));
}
/*
inserts a node to parent node of tree. returns pointer to node
*/
static
quadnode_t
*
quadtree_insert_node ( quadtree_t
*
tree,
quadnode_t
*
parent,
long
node_key,
quadbox_t
*
node_box,
int
*
depth
)
{
if
( quadbox_is_inside (node_box,
&
(parent
->
_box)) )
{
if
(
++
(
*
depth)
<
tree
->
_depth )
{
if
(
!
quadnode_has_child ( parent ) )
quadnode_create_child (parent, tree
->
_overlap, (
*
depth));
if
( quadbox_is_inside (node_box,
&
(parent
->
_sub[NE]
->
_box) ) )
return
quadtree_insert_node (tree, parent
->
_sub[NE], node_key, node_box, depth);
if
( quadbox_is_inside (node_box,
&
(parent
->
_sub[NW]
->
_box) ) )
return
quadtree_insert_node (tree, parent
->
_sub[NW], node_key, node_box, depth);
if
( quadbox_is_inside (node_box,
&
(parent
->
_sub[SW]
->
_box) ) )
return
quadtree_insert_node (tree, parent
->
_sub[SW], node_key, node_box, depth);
if
( quadbox_is_inside (node_box,
&
(parent
->
_sub[SE]
->
_box) ) )
return
quadtree_insert_node (tree, parent
->
_sub[SE], node_key, node_box, depth);
}
/*
inserts into this node since it can NOT be included in any subnodes
*/
quadnode_add_data (parent, node_key);
return
parent;
}
return
NULL;
}
/*
searched tree nodes
*/
static
void
quadtree_search_nodes (quadnode_t
*
current_node,
quadbox_t
*
search_box,
list_t
*
results_list
)
{
if
( quadbox_is_overlapped (
&
(current_node
->
_box), search_box ) )
{
if
( quadnode_has_data (current_node) )
list_append_node (results_list, list_node_create(current_node));
if
( quadnode_has_child (current_node) )
{
quadtree_search_nodes (current_node
->
_sub[NE], search_box, results_list);
quadtree_search_nodes (current_node
->
_sub[NW], search_box, results_list);
quadtree_search_nodes (current_node
->
_sub[SW], search_box, results_list);
quadtree_search_nodes (current_node
->
_sub[SE], search_box, results_list);
}
}
}
/*
=============================================================================
Public Functions
=============================================================================
*/
quadtree_t
*
quadtree_create (quadbox_t box,
int
depth,
/*
4~8
*/
float
overlap
/*
0.02 ~ 0.4
*/
)
{
quadtree_t
*
qt
=
NULL;
assert (depth
>=
QTREE_DEPTH_MIN
-
0.0001
&&
depth
<=
QTREE_DEPTH_MAX
+
0.0001
);
assert (overlap
>=
QBOX_OVERLAP_MIN
-
0.0001
&&
overlap
<=
QBOX_OVERLAP_MAX
+
0.0001
);
qt
=
(quadtree_t
*
) calloc (
1
,
sizeof
(quadtree_t));
if
(qt)
{
qt
->
_depth
=
depth;
qt
->
_overlap
=
overlap;
quadbox_inflate (
&
box, quadbox_width(
&
box)
*
overlap, quadbox_height(
&
box)
*
overlap);
qt
->
_root
=
quadnode_create (
&
box);
assert (qt
->
_root);
if
(
!
qt
->
_root)
{
free (qt);
qt
=
NULL;
}
}
assert (qt);
return
qt;
}
/*
destroys a quad tree
*/
void
quadtree_destroy (IN quadtree_t
*
qtree)
{
assert (qtree
&&
qtree
->
_root);
quadnode_destroy (qtree
->
_root);
free (qtree);
}
/*
inserts a node into quadtree and return pointer to new node
*/
quadnode_t
*
quadtree_insert (IN quadtree_t
*
qtree,
IN
long
node_key,
IN quadbox_t
*
node_box
)
{
int
depth
=
-
1
;
return
quadtree_insert_node (qtree, qtree
->
_root, node_key, node_box,
&
depth);
}
/*
searches nodes inside search_box
*/
void
quadtree_search (IN
const
quadtree_t
*
qtree,
IN quadbox_t
*
search_box,
OUT list_t
*
results_list
)
{
quadtree_search_nodes (qtree
->
_root, search_box, results_list);
}
其中用到的文件(list.h,list.c,unistd.h)参考我的另一篇文章:
C语言实现一个简单的单向链表list