八叉树三维数据结构及示例程序.docx
- 文档编号:11944259
- 上传时间:2023-06-03
- 格式:DOCX
- 页数:37
- 大小:162.86KB
八叉树三维数据结构及示例程序.docx
《八叉树三维数据结构及示例程序.docx》由会员分享,可在线阅读,更多相关《八叉树三维数据结构及示例程序.docx(37页珍藏版)》请在冰点文库上搜索。
八叉树三维数据结构及示例程序
八叉树三维数据结构及示例程序
八叉树三维数据结构
(一)基本原理
用八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是在进入80年代后才比较全面地开展起来的。
这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是用三维体素阵列表示形体方法的一种改进。
八叉树的逻辑结构如下:
假设要表示的形体V可以放在一个充分大的正方体C内,C的边长为2n,形体VC,它的八叉树可以用以下的递归方法来定义:
八叉树的每个节点与C的一个子立方体对应,树根与C本身相对应,如果V=C,那么V的八叉树仅有树根,如果V≠C,则将C等分为八个子立方体,每个子立方体与树根的一个子节点相对应。
只要某个子立方体不是完全空白或完全为V所占据,就要被八等分(图2-5-1),从而对应的节点也就有了八个子节点。
这样的递归判断、分割一直要进行到节点所对应的立方体或是完全空白,或是完全为V占据,或是其大小已是预先定义的体素大小,并且对它与V之交作一定的“舍入”,使体素或认为是空白的,或认为是V占据的。
然十分自然,容易掌握,但在存贮空间的使用率方面不很理想。
2、线性八叉树
线性八叉树注重考虑如何提高空间利用率。
用某一预先确定的次序遍历八叉树(例如以深度第一的方式),将八叉树转换成一个线性表(图2-5-2),表的每个元素与一个结点相对应。
对于结点的描述可以丰富一点,例如用适当的方式来说明它是否为叶结点,如果不是叶结点时还可用其八个子结点值的平均值作为非叶结点的值等等。
这样,可以在内存中以紧凑的方式来表示线性表,可以不用指针或者仅用一个指针表示即可。
线性八叉树不仅节省存贮空间,对某些运算也较为方便。
但是为此付出的代价是丧失了一定的灵活性。
例如为了存取属于原图形右下角的子图形对应的结点,那么必须先遍历了其余七个子图形对应的所有结点后才能进行;不能方便地以其它遍历方式对树的结点进行存取,导致了许多与此相关的运算效率变低。
因此尽管不少文章讨论了这种八叉树的应用,但是仍很难令人满意。
3、一对八式的八叉树
一个非叶结点有八个子结点,为了确定起见,将它们分别标记为0,1,2,3,4,5,6,7。
从上面的介绍可以看到,如果一个记录与一个结点相对应,那么在这个记录中描述的是这个结点的八个子结点的特性值。
而指针给出的则是该八个子结点所对应记录的存放处,而且还隐含地假定了这些子结点记录存放的次序。
也就是说,即使某个记录是不必要的(例如,该结点已是叶结点),那么相应的存贮位置也必须空闲在那里(图2-5-3),以保证不会错误地存取到其它同辈结点的记录。
这样当然会有一定的浪费,除非它是完全的八叉树,即所有的叶结点均在同一层次出现,而在该层次之上的所有层中的结点均为非叶结点。
为了克服这种缺陷,有两条途径可以采纳。
一是增加计算量,在记录中增加一定的信息,使计算工作适当减少或者更方便。
栅格数据压缩存储方式之四叉树、八叉树编码
四叉树编码(quad-treecode)
四又树结构的基本思想是将一幅栅格地图或图像等分为四部分。
逐块检查其格网属性值(或灰度)。
如果某个子区的所有格网值都具有相同的值。
则这个子区就不再继续分割,否则还要把这个子区再分割成四个子区。
这样依次地分割,直到每个子块都只含有相同的属性值或灰度为止。
四叉树编码法有许多有趣的优点:
①容易而有效地计算多边形的数量特征;②阵列各部分的分辨率是可变的,边界复杂部分四叉树较高即分级多,分辨率也高,而不需表示许多细节的部分则分级少,分辨率低,因而既可精确表示图形结构又可减少存贮量;②栅格到四叉树及四叉树到简单栅格结构的转换比其它压缩方法容易;④多边形中嵌套异类小多边形的表示较方便。
四叉树编码的最大缺点是转换的不定性,用同一形状和大小的多边形可能得出多种不同的四叉树结构,故不利于形状分析和模式识别。
但因它允许多边形中嵌套多边形即所谓“洞”这种结构存在,使越来越多的地理信息系统工作者都对四叉树结构很感兴趣。
上述这些压缩数据的方法应视图形的复杂情况合理选用,同时应在系统中备有相应的程序。
另外,用户的分析目的和分析方法也决定着压缩方法的选取。
四叉树结构按其编码的方法不同又分为常规四叉树和线性四叉树。
常规四叉树除了记录叶结点之外,还要记录中间结点。
结点之间借助指针联系,每个结点需要用六个量表达:
四个叶结点指针,一个父结点指针和一个结点的属性或灰度值。
这些指针不仅增加了数据贮存量,而且增加了操作的复杂性。
常规四叉树主要在数据索引和图幅索引等方面应用。
线性四叉树则只存贮最后叶结点的信息。
包括叶结点的位置、深度和本结点的属性或灰度值。
所谓深度是指处于四叉树的第几层上。
由深度可推知子区的大小。
线性四叉树叶结点的编号需要遵循一定的规则,这种编号称为地址码,它隐含了叶结点的位置和深度信息。
最常用的地址码是四进制或十进制的Morton码。
————————————————————————————————————————————
八叉树结构就是将空间区域不断地分解为八个同样大小的子区域(即将一个六面的立方体再分解为八个相同大小的小立方体),分解的次数越多,子区域就越小,一直到同—区域的属性单一为止。
按从下而上合并的方式来说,就是将研究区空间先按—定的分辨率将三维空间划分为三维栅格网,然后按规定的顺序每次比较3个相邻的栅格单元,如果其属性值相同则合并,否则就记盘。
依次递归运算,直到每个子区域均为单值为止。
八叉树同样可分为常规八叉树和线性八叉树。
常规八叉树的结点要记录十个位,即八个指向子结点的指针,—个指向父结点的指针和一个属性值(或标识号)。
而线性八叉树则只需要记录叶结点的地址码和属性值。
因此,它的主要优点是,其一节省存储空间,因为只需对叶结点编码,节省了大量中间结点的存储。
每个结点的指针也免除了,而从根到某一特定结点的方向和路径的信息隐含在定位码之中,定位码数字的个位数显示分辨率的高低或分解程度;其次,线性八叉树可直接寻址,通过其坐标值则能计算出任何输入结点的定位码(称编码),而不必实际建立八叉树,并且定位码本身就是坐标的另—种形式,不必有意去存储坐标值。
若需要的话还能从定位码中获取其坐标值(称解码);其三,在操作方面,所产生的定位码容易存储和执行,容易实现象集合、相加等组合操作。
八叉树主要用来解决地理信息系统中的三维问题。
#include"stdafx.h"
#include
#include
#include
#include
#include
#include"octree.h"
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
Vec3makeVec3(doublex,doubley,doublez)
{
Vec3v3=(Vec3)malloc(3*sizeof(double));
v3[0]=x;v3[1]=y;v3[2]=z;
returnv3;
}
Vec3copyVec3(Vec3src)
{
Vec3v3=(Vec3)malloc(3*sizeof(double));
v3[0]=src[0];v3[1]=src[1];v3[2]=src[2];
returnv3;
}
/*------------------------------------------------------------------------*/
Octree*make_octree(Vec3min,Vec3max)
{
//Octree*o=(Octree*)malloc(sizeof(Octree));
Octree*o=newOctree;
o->min=copyVec3(min);
o->max=copyVec3(max);
o->children=0;
o->at_max_depth=0;
/*
printf("creatingoctree%.3lf,%.3lf,%.3lf...%.3lf,%.3lf,%.3lf\n",
o->min[2],o->min[1],o->min[0],
o->max[2],o->max[1],o->max[0]);
*/
returno;
}
voidsubpoint(Octree*o,intoc,Vec3min,Vec3max)
{
pvex_nor*m_p1,*m_p2;
POSITIONpos1,pos2;
for(pos1=o->vex.GetHeadPosition(),pos2=o->normal.GetHeadPosition();pos1!
=NULL;)
{
//pos1=o->vex.FindIndex(i);//pos2=o->normal.FindIndex(i);
m_p1=(pvex_nor*)o->vex.GetNext(pos1);m_p2=(pvex_nor*)o->normal.GetNext(pos2);
if((m_p1->x>min[0]&&m_p1->x &&(m_p1->z>min[2]&&m_p1->z { o->children[oc]->vex.AddHead(newpvex_nor(m_p1->x,m_p1->y,m_p1->z)); o->children[oc]->normal.AddHead(newpvex_nor(m_p2->x,m_p2->y,m_p2->z)); } } } voidsplit_octree(Octree*o) { doubleoc_min[3]; doubleoc_max[3]; Vec3mid=makeVec3((o->min[0]+o->max[0])*0.5, (o->min[1]+o->max[1])*0.5, (o->min[2]+o->max[2])*0.5); intxp,yp,zp; intoc=0; //o->children=(Octree**)malloc(8*sizeof(Octree*)); o->children=newOctree*; for(zp=0;zp<2;zp++) { if(zp==0) { oc_min[2]=o->min[2]; oc_max[2]=mid[2]; } else { oc_min[2]=mid[2]; oc_max[2]=o->max[2]; } for(yp=0;yp<2;yp++) { if(yp==0) { oc_min[1]=o->min[1]; oc_max[1]=mid[1]; } else { oc_min[1]=mid[1]; oc_max[1]=o->max[1]; } for(xp=0;xp<2;xp++) { if(xp==0) { oc_min[0]=o->min[0]; oc_max[0]=mid[0]; } else { oc_min[0]=mid[0]; oc_max[0]=o->max[0]; } o->children[(zp*4)+(yp*2)+xp]=make_octree(oc_min,oc_max); subpoint(o,(zp*4)+(yp*2)+xp,oc_min,oc_max); } } } } /*------------------------------------------------------------------------*/ intrecursively_evaluate_octree(intmin_depth,intmax_depth,intcurrent_depth,Octree*o) { intdeepest_child=current_depth; //intxp,yp,zp; intoc; intcd; //pvex_nor*m_p; //POSITIONpos; /*Vec3point=makeVec3(0,0,0); intp=0; for(zp=0;zp<2;zp++) { point[2]=(zp==0)? o->min[2]: o->max[2]; for(yp=0;yp<2;yp++) { point[1]=(yp==0)? o->min[1]: o->max[1]; for(xp=0;xp<2;xp++) { point[0]=(xp==0)? o->min[0]: o->max[0]; o->value[p++]=evaluate_point(point,o); } } } */ o->density=evaluate1_point(o); current_depth++; o->not_fully_divided=(char)octree_needs_to_be_split(o); if(current_depth<=max_depth) { if((current_depth<=min_depth)||(o->not_fully_divided)) { //if(deepest_child==current_depth||deepest_child==0) //{ split_octree(o); //} for(oc=0;oc<8;oc++) { /*Vex.RemoveAll(); for(pos=vex[oc].GetHeadPosition();pos! =NULL;) { m_p=(pvex_nor*)vex[oc].GetNext(pos); Vex.AddHead(newpvex_nor(m_p->x,m_p->y,m_p->z)); }*/ //if(deepest_child==current_depth||deepest_child==0) //{ cd=recursively_evaluate_octree(min_depth,max_depth,current_depth,o->children[oc]); //} if(cd>deepest_child) deepest_child=cd; } } } else { o->at_max_depth=1; } returndeepest_child; } /*------------------------------------------------------------------------*/ intsubdivide_octree(intmin_depth,intmax_depth,Octree*o) { returnrecursively_evaluate_octree(min_depth,max_depth,0,o); } doubledemo1(Vec3pos) { /*demo1: thesurfaceisasphereofradius0.75centeredat0,0,0 functionreturns1.0ifpointinsidesphere,0.0otherwise */ doubledist_sq=(pos[0]*pos[0])+(pos[1]*pos[1])+(pos[2]*pos[2]); return(dist_sq<0.5625)? 1.0: 0.0; } doubledemo2(Vec3pos) { /*demo2: thesurfaceistwospheres, A: radius0.25centeredat-.25,-.5,0 andB: radius0.5centeredat-0.5,0,0 functionreturns1.0ifpointinsidesphereA,2.0forsphereB,0.0forneither */ doubledist_sq_a=((pos[0]+.25)*(pos[0]+.25))+((pos[1]+.5)*(pos[1]+.5))+(pos[2]*pos[2]); doubledist_sq_b=((pos[0]+.8)*(pos[0]+.8))+(pos[1]*pos[1])+(pos[2]*pos[2]); if(dist_sq_a<=.0625) return1.0; if(dist_sq_b<=.25) return2.0; return0.0; } doubledemo3(Vec3pos) { /*demo3: thesurfaceistinysphere,radius0.1centeredat-.5,.5,0 functionreturns1.0ifpointinsidesphereA,0.0otherwise */ doubledist_sq=((pos[0]+.5)*(pos[0]+.5))+((pos[1]-.5)*(pos[1]-.5))+(pos[2]*pos[2]); return(dist_sq<0.01)? 1.0: 0.0; } doubledemo4(Vec3pos) { /*demo4: waveysurface functionreturns1.0ifpoint'near'surface,0.0otherwise */ doublesurface_height=sin((pos[0]*3.0))*cos((pos[1]*3.0)); doubledistance_sq=(pos[2]-surface_height)*(pos[2]-surface_height); return(distance_sq<0.01)? 1.0: 0.0; } doubledemo5(Vec3pos) { /*demo5: hemisphere,center0,0,0radius0.5,cutbyplaneatz=0 */ doubleabs_dist_sq=((pos[0])*(pos[0]))+((pos[1])*(pos[1]))+(pos[2]*pos[2]); doublesurf_dist_sq=abs_dist_sq-0.5625; if(surf_dist_sq<0) surf_dist_sq=-surf_dist_sq; if((pos[2]>0)&&(surf_dist_sq<0.1)) return1.0; else return.0; } doubledemo6(Vec3pos) { /*demo6: anotherwaveysurface functionreturns1.0ifpoint'near'surface,0.0otherwise */ doublesurface_height=sin((pos[0]*2.0))+sin((pos[1]*2.0)); doubledistance_sq=(pos[2]-surface_height)*(pos[2]-surface_height); return(distance_sq<0.01)? 1.0: 0.0; } doubledemo7(Vec3pos) { /*demo7: acylinder functionreturns1.0ifpoint'near'surface,0.0otherwise */ doubledisc_dist_sq=((pos[1])*(pos[1]))+((pos[2]*pos[2])); doublesurf_dist_sq=disc_dist_sq-0.5625; if(surf_dist_sq<0) surf_dist_sq=-surf_dist_sq; if((pos[0]>-0.75)&&(pos[0]<0.75)) { if(surf_dist_sq<0.1) return1.0; } return0.0; } doubledemo8(Vec3pos) { /*demo8: mandlebrot*/ intmax_iters=500; intit_count=0; doublecr,ci,zr,zi,new_zr,new_zi; intinside=1; /*onlyexistsneartheplanez=0*/ if((pos[2]>0.001)||(pos[2]<-0.001)) return.0; zr=cr=(pos[0]*2.0); zi=ci=(pos[1]*2.0); while((it_count { /*z=z^2+
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 八叉树 三维 数据结构 示例 程序