八叉树的实现(转载)

转载 2009年10月24日 12:05:00

Octree的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或
零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个
立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个。再想象
我们有一个房间,房间里某个角落藏着一枚金币,我们想很快的把金币找出来,
聪明的你会怎么做?我们可以把房间当成一个立方体,先切成八个小立方体,
然后排除掉没有放任何东西的小立方体,再把有可能藏金币的小立方体继续切八
等份….如此下去,平均在Log8(房间内的所有物品数)的时间内就可找到金币。
因此,Octree就是用在3D空间中的场景管理,可以很快地知道物体在3D场景中
的位置,或侦测与其它物体是否有碰撞以及是否在可视范围内。


2、实现Octree的原理
(1). 设定最大递归深度
(2). 找出场景的最大尺寸,并以此尺寸建立第一个立方体
(3). 依序将单位元元素丢入能被包含且没有子节点的立方体
(4). 若没有达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八
个子立方体
(5). 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止
细分,因为跟据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目
还是一样,会造成无穷切割的情形。
(6). 重复3,直到达到最大递归深度。


4、BSP Tree和Octree对比
a) BSP Tree将场景分割为1个面,而Octree分割为3个面。
b) BSP Tree每个节点最多有2个子结点,而Octree最多有8个子结点
因此BSP Tree可以用在不论几唯的场景中,而Octree则常用于三维场景

#include  " stdafx.h "
#include 
< iostream >

using   namespace  std;
// 定义八叉树节点类
template < class  T >
struct  OctreeNode
{
    T data; 
// 节点数据
    T xmin,xmax;  // 节点坐标,即六面体个顶点的坐标
    T ymin,ymax;
    T zmin,zmax;
    OctreeNode 
< T >   * top_left_front, * top_left_back;  // 该节点的个子结点
    OctreeNode  < T >   * top_right_front, * top_right_back;
    OctreeNode 
< T >   * bottom_left_front, * bottom_left_back;
    OctreeNode 
< T >   * bottom_right_front, * bottom_right_back;
    OctreeNode 
// 节点类
        (T nodeValue  =  T(),
        T xminValue 
=  T(),T xmaxValue  =  T(),
        T yminValue 
=  T(),T ymaxValue  =  T(),
        T zminValue 
=  T(),T zmaxValue  =  T(),
        OctreeNode
< T >*  top_left_front_Node  =  NULL,
        OctreeNode
< T >*  top_left_back_Node  =  NULL,
        OctreeNode
< T >*  top_right_front_Node  =  NULL,
        OctreeNode
< T >*  top_right_back_Node  =  NULL,
        OctreeNode
< T >*  bottom_left_front_Node  =  NULL,
        OctreeNode
< T >*  bottom_left_back_Node  =  NULL,
        OctreeNode
< T >*  bottom_right_front_Node  =  NULL,
        OctreeNode
< T >*  bottom_right_back_Node  =  NULL )
        :data(nodeValue),
        xmin(xminValue),xmax(xmaxValue),
        ymin(yminValue),ymax(ymaxValue),
        zmin(zminValue),zmax(zmaxValue),
        top_left_front(top_left_front_Node),
        top_left_back(top_left_back_Node),
        top_right_front(top_right_front_Node),
        top_right_back(top_right_back_Node),
        bottom_left_front(bottom_left_front_Node),
        bottom_left_back(bottom_left_back_Node),
        bottom_right_front(bottom_right_front_Node),
        bottom_right_back(bottom_right_back_Node){}
};
// 创建八叉树
template  < class  T >
void  createOctree(OctreeNode < T >   *   & root, int  maxdepth, double  xmin, double  xmax, double  ymin, double  ymax, double  zmin, double  zmax)
{
    cout
<< " 处理中,请稍候…… " << endl;
    maxdepth
= maxdepth - 1 // 每递归一次就将最大递归深度-1
     if (maxdepth >= 0 )
    {
        root
= new  OctreeNode < T > ();
        root
-> data  =   9 // 为节点赋值,可以存储节点信息,如物体可见性。由于是简单实现八叉树功能,简单赋值为。
        root -> xmin = xmin;  // 为节点坐标赋值
        root -> xmax = xmax;
        root
-> ymin = ymin;
        root
-> ymax = ymax;
        root
-> zmin = zmin;
        root
-> zmax = zmax;
        
double  xm = (xmax - xmin) / 2 ; // 计算节点个维度上的半边长
         double  ym = (ymax - ymin) / 2 ;
        
double  zm = (ymax - ymin) / 2 ;
        
// 递归创建子树,根据每一个节点所处(是几号节点)的位置决定其子结点的坐标。
        createOctree(root -> top_left_front,maxdepth,xmin,xmax - xm,ymax - ym,ymax,zmax - zm,zmax);
        createOctree(root
-> top_left_back,maxdepth,xmin,xmax - xm,ymin,ymax - ym,zmax - zm,zmax);
        createOctree(root
-> top_right_front,maxdepth,xmax - xm,xmax,ymax - ym,ymax,zmax - zm,zmax);
        createOctree(root
-> top_right_back,maxdepth,xmax - xm,xmax,ymin,ymax - ym,zmax - zm,zmax);
        createOctree(root
-> bottom_left_front,maxdepth,xmin,xmax - xm,ymax - ym,ymax,zmin,zmax - zm);
        createOctree(root
-> bottom_left_back,maxdepth,xmin,xmax - xm,ymin,ymax - ym,zmin,zmax - zm);
        createOctree(root
-> bottom_right_front,maxdepth,xmax - xm,xmax,ymax - ym,ymax,zmin,zmax - zm);
        createOctree(root
-> bottom_right_back,maxdepth,xmax - xm,xmax,ymin,ymax - ym,zmin,zmax - zm);
    }
}
int  i = 1 ;
// 先序遍历八叉树
template  < class  T >
void  preOrder( OctreeNode < T >   *   &  p)
{
    
if (p)
    {
        cout
<< i << " .当前节点的值为: " << p -> data << " /n坐标为: " ;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        i
+= 1 ;
        cout
<< endl;
        preOrder(p
-> top_left_front);
        preOrder(p
-> top_left_back);
        preOrder(p
-> top_right_front);
        preOrder(p
-> top_right_back);
        preOrder(p
-> bottom_left_front);
        preOrder(p
-> bottom_left_back);
        preOrder(p
-> bottom_right_front);
        preOrder(p
-> bottom_right_back);
        cout
<< endl;
    }
}
// 求八叉树的深度
template < class  T >
int  depth(OctreeNode < T >   *&  p)
{
    
if (p  ==  NULL)
        
return   - 1 ;
    
int  h  =  depth(p -> top_left_front);
    
return  h + 1 ;
}
// 计算单位长度,为查找点做准备
int  cal( int  num)
{
    
int  result = 1 ;
    
if ( 1 == num)
        result
= 1 ;
    
else
    {
        
for ( int  i = 1 ;i < num;i ++ )
            result
= 2 * result;
    }
    
return  result;
}
// 查找点
int  maxdepth = 0 ;
int  times = 0 ;
static   double  xmin = 0 ,xmax = 0 ,ymin = 0 ,ymax = 0 ,zmin = 0 ,zmax = 0 ;
int  tmaxdepth = 0 ;
double  txm = 1 ,tym = 1 ,tzm = 1 ;
template
< class  T >
void  find(OctreeNode < T >   *&  p, double  x, double  y, double  z)
{
    
double  xm = (p -> xmax - p -> xmin) / 2 ;
    
double  ym = (p -> ymax - p -> ymin) / 2 ;
    
double  zm = (p -> ymax - p -> ymin) / 2 ;
    times
++ ;
    
if (x > xmax  ||  x < xmin  ||  y > ymax  ||  y < ymin  ||  z > zmax  ||  z < zmin)
    {
        cout
<< " 该点不在场景中! " << endl;
        
return ;
    }
    
if (x <= p -> xmin + txm  &&  x >= p -> xmax - txm  &&  y <= p -> ymin + tym  &&  y >= p -> ymax - tym  &&  z <= p -> zmin + tzm  &&  z >= p -> zmax - tzm )
    {
        cout
<< endl << " 找到该点! " << " 该点位于 " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< " 节点内! " << endl;
        cout
<< " 共经过 " << times << " 次递归! " << endl;
    }
    
else   if (x < (p -> xmax - xm)  &&  y < (p -> ymax - ym)  &&  z < (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> bottom_left_back,x,y,z);
    }
    
else   if (x < (p -> xmax - xm)  &&  y < (p -> ymax - ym)  &&  z > (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> top_left_back,x,y,z);
    }
    
else   if (x > (p -> xmax - xm)  &&  y < (p -> ymax - ym)  &&  z < (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> bottom_right_back,x,y,z);
    }
    
else   if (x > (p -> xmax - xm)  &&  y < (p -> ymax - ym)  &&  z > (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> top_right_back,x,y,z);
    }
    
else   if (x < (p -> xmax - xm)  &&  y > (p -> ymax - ym)  &&  z < (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> bottom_left_front,x,y,z);
    }
    
else   if (x < (p -> xmax - xm)  &&  y > (p -> ymax - ym)  &&  z > (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> top_left_front,x,y,z);
    }
    
else   if (x > (p -> xmax - xm)  &&  y > (p -> ymax - ym)  &&  z < (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> bottom_right_front,x,y,z);
    }
    
else   if (x > (p -> xmax - xm)  &&  y > (p -> ymax - ym)  &&  z > (p -> zmax - zm))
    {
        cout
<< " 当前经过节点坐标: " << endl;
        cout
<< "  xmin:  " << p -> xmin << "  xmax:  " << p -> xmax;
        cout
<< "  ymin:  " << p -> ymin << "  ymax:  " << p -> ymax;
        cout
<< "  zmin:  " << p -> zmin << "  zmax:  " << p -> zmax;
        cout
<< endl;
        find(p
-> top_right_front,x,y,z);
    }
}
// main函数
int  main ()
{
    OctreeNode
< double >   *  rootNode  =  NULL;
    
int  choiced  =   0 ;
    
while ( true )
    {
        system(
" cls " );
        cout
<< " 请选择操作:/n " ;
        cout
<< " 1.创建八叉树 2.先序遍历八叉树/n " ;
        cout
<< " 3.查看树深度 4.查找节点   /n " ;
        cout
<< " 0.退出/n/n " ;
        cin
>> choiced;
        
if (choiced  ==   0 )
            
return   0 ;
        
else   if (choiced  ==   1 )
        {
            system(
" cls " );
            cout
<< " 请输入最大递归深度: " << endl;
            cin
>> maxdepth;
            cout
<< " 请输入外包盒坐标,顺序如下:xmin,xmax,ymin,ymax,zmin,zmax " << endl;
            cin
>> xmin >> xmax >> ymin >> ymax >> zmin >> zmax;
            
if (maxdepth >= 0   ||  xmax > xmin  ||  ymax > ymin  ||  zmax > zmin  ||  xmin > 0   ||  ymin > 0   || zmin > 0 )
            {
                tmaxdepth
= cal(maxdepth);
                txm
= (xmax - xmin) / tmaxdepth;
                tym
= (ymax - ymin) / tmaxdepth;
                tzm
= (zmax - zmin) / tmaxdepth;
                createOctree(rootNode,maxdepth,xmin,xmax,ymin,ymax,zmin,zmax);
            }
            
else
            {
                cout
<< " 输入错误! " ;
                
return   0 ;
            }
        }
        
else   if (choiced  ==   2 )
        {
            system(
" cls " );
            cout
<< " 先序遍历八叉树结果:/n " ;
            i
= 1 ;
            preOrder(rootNode);
            cout
<< endl;
            system(
" pause " );
        }
        
else   if (choiced  ==   3 )
        {
            system(
" cls " );
            
int  dep  =  depth(rootNode);
            cout
<< " 此八叉树的深度为 " << dep + 1 << endl;
            system(
" pause " );
        }
        
else   if (choiced  ==   4 )
        {
            system(
" cls " );
            cout
<< " 请输入您希望查找的点的坐标,顺序如下:x,y,z/n " ;
            
double  x,y,z;
            cin
>> x >> y >> z;
            times
= 0 ;
            cout
<< endl << " 开始搜寻该点…… " << endl;
            find(rootNode,x,y,z);
            system(
" pause " );
        }
        
else
        {
            system(
" cls " );
            cout
<< " /n/n错误选择!/n " ;
            system(
" pause " );
        }
    }
}

简单八叉树源码剖析

针对文章:http://www.brandonpelfrey.com/blog/coding-a-simple-octree/ 及其github:https://github.com/brandon...
  • Blues1021
  • Blues1021
  • 2015年08月14日 21:45
  • 731

场景管理:八叉树算法C++实现

简单实现了场景管理八叉树算法 代码结构: object.h,object.cpp 被管理的对象类octree_node.h,octree_node.cpp 八叉树类main.cpp程序入口...
  • u012234115
  • u012234115
  • 2015年07月30日 21:06
  • 3240

八叉树 Octree

原文:http://blog.csdn.net/timzc/article/details/6060591 (一)基本原理     用八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是...
  • wolf96
  • wolf96
  • 2015年07月06日 19:22
  • 1419

java实现:机器人视觉与环境感知基于八叉树算法(待开源)

java实现的机器人视觉与环境感知,基于八叉树算法。 随后我会整理,增加注释,在GitHub开源https://github.com/hjwang1/robot...
  • hjwang1
  • hjwang1
  • 2016年09月14日 18:35
  • 960

八叉树

八叉树 维基释义:八叉树(Octree)是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点...
  • ideallic
  • ideallic
  • 2016年09月14日 15:41
  • 587

八叉树和十六叉树结构

(1)三维和四维数据结构的提出。前面介绍的数据结构都是二维的,然而在有些信息系统中,需要有真三维的空间数据结构。例如矿山开采中的地下资源埋藏和采矿巷道的空间分布,如果用二维的坐标体系就根本无法很好表达...
  • Chinamming
  • Chinamming
  • 2013年11月24日 13:17
  • 5668

八叉树图像处理的java简单实现

一晃工作有段时间了,第一次写博客,有点不知道怎么写,大家将就着看吧,说的有什么不正确的也请大家指正。 最近工作中用到了一个图像压缩的功能。找了一些工具,没有太好的选择。最后选了一个叫jdeli的,奈何...
  • u013206238
  • u013206238
  • 2015年12月16日 15:22
  • 844

四叉树与八叉树

前序 四叉树或四元树也被称为Q树(Q-Tree)。四叉树广泛应用于图像处理、空间数据索引、2D中的快速碰撞检测、存储稀疏数据等,而八叉树(Octree)主要应用于3D图形处理。对游戏编程,这会很有用...
  • zhanxinhang
  • zhanxinhang
  • 2011年08月21日 15:34
  • 39367

四叉树与八叉树

转自:http://blog.csdn.net/zhanxinhang/article/details/6706217 前序 四叉树或四元树也被称为Q树(Q-Tree)。四叉树广泛应用于图像处理...
  • hjwang1
  • hjwang1
  • 2016年09月03日 01:36
  • 1456

八叉树Octree原理

八叉树Octree原理载自:http://bbs.iieeg.com/viewthread.php?tid=1222一、对Octree的描述   Octree的定义是:若不为空树的话,树中任一节点的子...
  • Augusdi
  • Augusdi
  • 2014年07月01日 10:29
  • 2028
收藏助手
不良信息举报
您举报文章:八叉树的实现(转载)
举报原因:
原因补充:

(最多只允许输入30个字)