精华内容
下载资源
问答
  • # 初始化八叉树,最大树深设置为4 octree = o3d.geometry.Octree(max_depth=4) # 从体素网格中构建八叉树 octree.create_from_voxel_grid(voxel_grid) # 可视化八叉树 o3d.visualization.draw_geometries([octree]) ...
  • 八叉树

    千次阅读 2019-06-05 22:19:59
    一、八叉树基本原理:    用八叉树来表示三维形体,并研究这种表示下的各种操作以及应用,是进入80年代后开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是三维体素阵列表示形体方法的...

    http://hi.baidu.com/onlywater/blog/item/905c5e162ed18f4021a4e9c1.html

    一、八叉树基本原理:

       用八叉树来表示三维形体,并研究这种表示下的各种操作以及应用,是进入80年代后开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广也可以认为是三维体素阵列表示形体方法的一种改进

       八叉树的逻辑结构如下:

       假设要表示的形体V可以放在一个充分大的正方体C中,C的边长为2n,形体V C,他的八叉树可以用以下的递归方法来定义:
       八叉树的每一个节点与C的一个子立方体对应 ,树根与C本身相对应。如果V=C,那么V的八叉树只有树根。 如果V不等于C,则将C等分为8个子立方体,每个子立方体与树根的一个子节点相对应。只要某个子立方体不是完全空白,或者完全为V所占据,就要被八等分,从而对应的节点也就有了八个子节点。这样的递归判断,分割一直要进行到节点所对应的立方体或是完全空吧,或是完全为V所占据,或是其大小已经是预先定义的体素大小,并且对他与V之交左一定的“舍入”,使体素或认为是空白的,或认为是V占据的。
    在这里插入图片描述
             在这里插入图片描述
    如果所生成的八叉树的节点可分为三类:

       灰节点: 它对应的立方体部分的为V所占据;
       白节点: 它对应的立方体没有V的内容;
       黑节点: 它对应的立方体全部为V所占据。

      后两类又称为叶节点。形体V关于C的八叉树的逻辑结构是这样的:他是一棵树,其上的节点要么是叶节点,要么是有八个子节点的灰节点。根节点与C相对应,其他节点与C的某个子立方体相对应。

      根据不同的存储方式,八叉树也可以分别称为常规的、线性的、一对八的八叉树等。

    二、八叉树的存储结构:

      八叉树有三种不同的存贮结构,分别是规则方式线性方式以及一对八方式。相应的八叉树也分别称为规则八叉树、线性八叉树以及一对八式八叉树。不同的存贮结构的空间利用率及运算操作的方便性是不同的。分析表明,一对八式八叉树优点更多一些。

    1. 规则八叉树:

      规则八叉树的存储结构用一个有九个字段的记录来表示树中的每个节点。其中一个字段来描述该节点的特性(再目前假定下,只要描述他是灰,白,黑三类节点中的哪一类就行。)其余八个字段分别用来存放指向其八个子节点的指针。 这是最普遍使用的表示树形结构的存储结构的方式。

      规则八叉树缺陷较多,最大的问题是指针占用了大量的空间。假定每个指针要用两个字节表示,而结点的描述用一个字节,那么存放指针要占总的存贮量的94%。因此,这种方法虽然十分自然,容易掌握,但在存贮空间的使用率方面不很理想。

    2.线性八叉树:

      线性八叉树注重考虑如何提高空间利用率。用某一预先确定的次序遍历八叉树(例如以深度第一的方式),将八叉树转换为一个线性表,表的每个元素与一个节点相对应。对于节点的描述可以相对丰富一点,一如可以用适当的方式来说明他是否是叶节点,如果不是叶节点的话,还可用其八个子节点值的平均值作为非叶节点的值。这样,可以再内存中以紧凑的方式来表示线性表,可以不用指针或者仅用一个指针即可。
    在这里插入图片描述
    线性八叉树不仅节省存储空间,对某些运算也较为方便。但为此的代价是丧失了一定的灵活性。

    3.一对八式八叉树

      一个非叶结点有八个子结点,为了确定起见,将它们分别标记为0,1,2,3,4,5,6,7。从上面的介绍可以看到,如果一个记录与一个结点相对应,那么在这个记录中描述的是这个结点的八个子结点的特性值。而指针给出的则是该八个子结点所对应记录的存放处,而且还隐含地假定了这些子结点记录存放的次序。也就是说,即使某个记录是不必要的(例如,该结点已是叶结点),那么相应的存贮位置也必须空闲在那里(图2-5-3),以保证不会错误地存取到其它同辈结点的记录。这样当然会有一定的浪费,除非它是完全的八叉树,即所有的叶结点均在同一层次出现,而在该层次之上的所有层中的结点均为非叶结点。
    在这里插入图片描述

    展开全文
  • #include <iostream> #include <vector> #include <ctime> #include <pcl/point_cloud.h>... if (octree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, ...
  • 在描述三维场景的过程中常常用到一种名为八叉树的数据结构。描述三维空间的八叉树和描述二维空间的四叉树有相似之处,二维空间中正方形可以被分为四个相同形状的正方形,而三维空间中正方体可以被分为八个形状相同的...

    在描述三维场景的过程中常常用到一种名为八叉树的数据结构。描述三维空间的八叉树和描述二维空间的四叉树有相似之处,二维空间中正方形可以被分为四个相同形状的正方形,而三维空间中正方体可以被分为八个形状相同的正方体。

    八叉树的每个结点表示一个正方体的体积元素,每一个结点有八个子节点,这种用于描述三维空间的树装结构叫做八叉树。为了便利的点云操作,八叉树OcTree被封装在PCL库中。

    八叉树的计算原理

    1. 设定最大递归深度

    2. 找出场景的最大尺寸,并以此尺寸建立第一个立方体

    3. 依序将单位元元素丢入能包含且没有子节点的立方体

    4. 若没达到最大递归深度,就进行细分八等份,再讲该立方体所装的单位元元素全部分组给八个子立方体

    5. 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体一样,则该子立方体停止细分

    (因为根据空间分割理论,细分的空间所得到的分配必定较少,若是一样的数目,再怎么切,数目还是一样)

    6. 重复3,知道到达最大递归深度

    八叉树的数据结构

    首先,八叉树是一种树(废话),所以可以分析它的结点,和枝干数量,这里枝干数量永远是8。假设原目标(点云)被一个大立方体包含,八叉树的作用就是细分该大立方体,每个结点对应一个立方体空间(这里类似于四叉树),八叉树的结点分为三类:

    灰色结点:它对应的立方体部分被目标占据(非叶结点)

    白色结点:它对应的立方体没有被目标占据(叶结点)

    黑色结点:它对应的立方体完全被目标占据(叶结点)

    对于非叶结点,数据结构以八元数法进行区分,分解为更小的子区块,每个区块有结点容量,当结点达到最大容量时结点停止分裂。

    八叉树的存储结构

    八叉树的存储结构一般分为三种:规则八叉树、线性八叉树和一对八式

    规则八叉树,有九个字段,八个子叶结点,一个表征该结点灰白黑的结点,这种表示方式处于贮存空间考量,一般不使用。

    线性八叉树,将八叉树转化为线性表,采用内存紧凑的方式进行表示。

    一对八表示,使用指针表示,好处是顺序可以随机

    八叉树的主要优缺点

    优点,使用八叉树可以快速进行三维目标的集合运算,如交、并、补、差等,亦可快速进行最邻近区域或点的搜索。

    缺点,存储空间消耗。

    八叉树实现

    虽然PCL中封装了八叉树OcTree类,但是我们也有不得不自己写的情况,下面代买是自己摘抄的(自己当然还是用PCL了)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    111

    112

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123

    124

    125

    126

    127

    128

    129

    130

    131

    132

    133

    134

    135

    136

    137

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    189

    190

    191

    192

    193

    194

    195

    196

    197

    198

    199

    200

    201

    202

    203

    204

    205

    206

    207

    208

    209

    210

    211

    212

    213

    214

    215

    216

    217

    218

    219

    220

    221

    222

    223

    224

    225

    226

    227

    228

    229

    230

    231

    232

    233

    234

    235

    236

    237

    238

    239

    240

    241

    242

    243

    244

    245

    246

    247

    248

    249

    250

    251

    252

    253

    254

    255

    256

    257

    258

    259

    260

    261

    262

    263

    264

    265

    266

    267

    268

    269

    270

    271

    272

    273

    274

    275

    276

    277

    278

    279

    280

    281

    282

    283

    284

    285

    286

    287

    288

    289

    290

    #include

    usingnamespacestd;

    //定义八叉树节点类

    template

    structOctreeNode

    {

    Tdata;//节点数据

    Txmin,xmax;//节点坐标,即六面体个顶点的坐标

    Tymin,ymax;

    Tzmin,zmax;

    OctreeNode*top_left_front,*top_left_back;//该节点的个子结点

    OctreeNode*top_right_front,*top_right_back;

    OctreeNode*bottom_left_front,*bottom_left_back;

    OctreeNode*bottom_right_front,*bottom_right_back;

    OctreeNode//节点类

    (TnodeValue=T(),

    TxminValue=T(),TxmaxValue=T(),

    TyminValue=T(),TymaxValue=T(),

    TzminValue=T(),TzmaxValue=T(),

    OctreeNode*top_left_front_Node=NULL,

    OctreeNode*top_left_back_Node=NULL,

    OctreeNode*top_right_front_Node=NULL,

    OctreeNode*top_right_back_Node=NULL,

    OctreeNode*bottom_left_front_Node=NULL,

    OctreeNode*bottom_left_back_Node=NULL,

    OctreeNode*bottom_right_front_Node=NULL,

    OctreeNode*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

    voidcreateOctree(OctreeNode*&root,intmaxdepth,doublexmin,doublexmax,doubleymin,doubleymax,doublezmin,doublezmax)

    {

    //cout<

    maxdepth=maxdepth-1;//每递归一次就将最大递归深度-1

    if(maxdepth>=0)

    {

    root=newOctreeNode();

    cout<

    //root->data =9;//为节点赋值,可以存储节点信息,如物体可见性。由于是简单实现八叉树功能,简单赋值为9。

    cin>>root->data;//为节点赋值

    root->xmin=xmin;//为节点坐标赋值

    root->xmax=xmax;

    root->ymin=ymin;

    root->ymax=ymax;

    root->zmin=zmin;

    root->zmax=zmax;

    doublexm=(xmax-xmin)/2;//计算节点个维度上的半边长

    doubleym=(ymax-ymin)/2;

    doublezm=(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);

    }

    }

    inti=1;

    //先序遍历八叉树

    template

    voidpreOrder(OctreeNode*&p)

    {

    if(p)

    {

    cout<data<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    i+=1;

    cout<

    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<

    }

    }

    //求八叉树的深度

    template

    intdepth(OctreeNode*&p)

    {

    if(p==NULL)

    return-1;

    inth=depth(p->top_left_front);

    returnh+1;

    }

    //计算单位长度,为查找点做准备

    intcal(intnum)

    {

    intresult=1;

    if(1==num)

    result=1;

    else

    {

    for(inti=1;i

    result=2*result;

    }

    returnresult;

    }

    //查找点

    intmaxdepth=0;

    inttimes=0;

    staticdoublexmin=0,xmax=0,ymin=0,ymax=0,zmin=0,zmax=0;

    inttmaxdepth=0;

    doubletxm=1,tym=1,tzm=1;

    template

    voidfind(OctreeNode*&p,doublex,doubley,doublez)

    {

    doublexm=(p->xmax-p->xmin)/2;

    doubleym=(p->ymax-p->ymin)/2;

    doublezm=(p->ymax-p->ymin)/2;

    times++;

    if(x>xmax||xymax||yzmax||z

    {

    cout<

    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<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    cout<

    }

    elseif(xxmax-xm)&&yymax-ym)&&zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_left_back,x,y,z);

    }

    elseif(xxmax-xm)&&yymax-ym)&&z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_left_back,x,y,z);

    }

    elseif(x>(p->xmax-xm)&&yymax-ym)&&zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_right_back,x,y,z);

    }

    elseif(x>(p->xmax-xm)&&yymax-ym)&&z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_right_back,x,y,z);

    }

    elseif(xxmax-xm)&&y>(p->ymax-ym)&&zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_left_front,x,y,z);

    }

    elseif(xxmax-xm)&&y>(p->ymax-ym)&&z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_left_front,x,y,z);

    }

    elseif(x>(p->xmax-xm)&&y>(p->ymax-ym)&&zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_right_front,x,y,z);

    }

    elseif(x>(p->xmax-xm)&&y>(p->ymax-ym)&&z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_right_front,x,y,z);

    }

    }

    //main函数

    intmain()

    {

    OctreeNode*rootNode=NULL;

    intchoiced=0;

    while(true)

    {

    system("cls");

    cout<

    cout<

    cout<

    cout<

    cin>>choiced;

    if(choiced==0)

    return0;

    elseif(choiced==1)

    {

    system("cls");

    cout<

    cin>>maxdepth;

    cout<

    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<

    return0;

    }

    }

    elseif(choiced==2)

    {

    system("cls");

    cout<

    i=1;

    preOrder(rootNode);

    cout<

    system("pause");

    }

    elseif(choiced==3)

    {

    system("cls");

    intdep=depth(rootNode);

    cout<

    system("pause");

    }

    elseif(choiced==4)

    {

    system("cls");

    cout<

    doublex,y,z;

    cin>>x>>y>>z;

    times=0;

    cout<

    find(rootNode,x,y,z);

    system("pause");

    }

    else

    {

    system("cls");

    cout<

    system("pause");

    }

    }

    }

    展开全文
  • 八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是在进入80年代后才比较全面地开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是用三维体素阵列表示形体方法的一种改进。...

    用八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是在进入80年代后才比较全面地开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是用三维体素阵列表示形体方法的一种改进。

    八叉树的逻辑结构如下:

    假设要表示的形体V可以放在一个充分大的正方体C内,C的边长为2 n,形体V C,它的八叉树可以用以下的递归方法来定义:

    八叉树的每个节点与C的一个子立方体对应,树根与C本身相对应,如果V=C,那么V的八叉树仅有树根,如果V≠C,则将C等分为八个子立方体,每个子立方体与树根的一个子节点相对应。只要某个子立方体不是完全空白或完全为V所占据,就要被八等分(图2-5-1),从而对应的节点也就有了八个子节点。这样的递归判断、分割一直要进行到节点所对应的立方体或是完全空白,或是完全为V占据,或是其大小已是预先定义的体素大小,并且对它与V之交作一定的“舍入”,使体素或认为是空白的,或认为是V占据的。

    如此所生成的八叉树上的节点可分为三类:

    灰节点,它对应的立方体部分地为V所占据;

    白节点,它所对应的立方体中无V的内容;

    黑节点,它所对应的立方体全为V所占据。

    后两类又称为叶结点。形体V关于C的八叉树的逻辑结构是这样的:它是一颗树,其上的节点要么是叶节点,要么就是有八个子节点的灰节点。根节点与C相对应,其它节点与C的某个子立方体相对应。

    因为八叉树的结构与四叉树的结构是如此的相似,所以八叉树的存贮结构方式可以完全沿用四叉树的有关方法。因而,根据不同的存贮方式,八叉树也可以分别称为常规的、线性的、一对八的八叉树等等。

    另外,由于这种方法充分利用了形体在空上的相关性,因此,一般来说,它所占用的存贮空间要比三维体素阵列的少。但是实际上它还是使用了相当多的存贮,这并不是八叉树的主要优点。这一方法的主要优点在于可以非常方便地实现有广泛用途的集合运算(例如可以求两个物体的并、交、差等运算),而这些恰是其它表示方法比较难以处理或者需要耗费许多计算资源的地方。不仅如此,由于这种方法的有序性及分层性,因而对显示精度和速度的平衡、隐线和隐面的消除等,带来了很大的方便,特别有用。

    (二)八叉树的存贮结构

    八叉树有三种不同的存贮结构,分别是规则方式、线性方式以及一对八方式。相应的八叉树也分别称为规则八叉树、线性八叉树以及一对八式八叉树。不同的存贮结构的空间利用率及运算操作的方便性是不同的。分析表明,一对八式八叉树优点更多一些。

    1、规则八叉树

    规则八叉树的存贮结构用一个有九个字段的记录来表示树中的每个结点。其中一个字段用来描述该结点的特性(在目前假定下,只要描述它是灰、白、黑三类结点中哪一类即可),其余的八个字段用来作为存放指向其八个子结点的指针。这是最普遍使用的表示树形数据的存贮结构方式。

    规则八叉树缺陷较多,最大的问题是指针占用了大量的空间。假定每个指针要用两个字节表示,而结点的描述用一个字节,那么存放指针要占总的存贮量的94%。因此,这种方法虽然十分自然,容易掌握,但在存贮空间的使用率方面不很理想。

    2、线性八叉树

    线性八叉树注重考虑如何提高空间利用率。用某一预先确定的次序遍历八叉树(例如以深度第一的方式),将八叉树转换成一个线性表(图2-5-2),表的每个元素与一个结点相对应。对于结点的描述可以丰富一点,例如用适当的方式来说明它是否为叶结点,如果不是叶结点时还可用其八个子结点值的平均值作为非叶结点的值等等。这样,可以在内存中以紧凑的方式来表示线性表,可以不用指针或者仅用一个指针表示即可。

    线性八叉树不仅节省存贮空间,对某些运算也较为方便。但是为此付出的代价是丧失了一定的灵活性。例如为了存取属于原图形右下角的子图形对应的结点,那么必须先遍历了其余七个子图形对应的所有结点后才能进行;不能方便地以其它遍历方式对树的结点进行存取,导致了许多与此相关的运算效率变低。因此尽管不少文章讨论了这种八叉树的应用,但是仍很难令人满意

    一个非叶结点有八个子结点,为了确定起见,将它们分别标记为0,1,2,3,4,5,6,7。从上面的介绍可以看到,如果一个记录与一个结点相对应,那么在这个记录中描述的是这个结点的八个子结点的特性值。而指针给出的则是该八个子结点所对应记录的存放处,而且还隐含地假定了这些子结点记录存放的次序。也就是说,即使某个记录是不必要的(例如,该结点已是叶结点),那么相应的存贮位置也必须空闲在那里(图2-5-3),以保证不会错误地存取到其它同辈结点的记录。这样当然会有一定的浪费,除非它是完全的八叉树,即所有的叶结点均在同一层次出现,而在该层次之上的所有层中的结点均为非叶结点。

    为了克服这种缺陷,有两条途径可以采纳。一是增加计算量,在记录中增加一定的信息,使计算工作适当减少或者更方便。

    展开全文
  • (一)基本原理用八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是在进入80年代后才比较全面地开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是用三维体素阵列表示形体方法的...

    (一)基本原理

    用八叉树来表示三维形体,并研究在这种表示下的各种操作及应用是在进入80年代后才比较全面地开展起来的。这种方法,既可以看成是四叉树方法在三维空间的推广,也可以认为是用三维体素阵列表示形体方法的一种改进。

    八叉树的逻辑结构如下:

    假设要表示的形体V可以放在一个充分大的正方体C内,C的边长为2 n,形体V C,它的八叉树可以用以下的递归方法来定义:

    八叉树的每个节点与C的一个子立方体对应,树根与C本身相对应,如果V=C,那么V的八叉树仅有树根,如果V≠C,则将C等分为八个子立方体,每个子立方体与树根的一个子节点相对应。只要某个子立方体不是完全空白或完全为V所占据,就要被八等分(图2-5-1),从而对应的节点也就有了八个子节点。这样的递归判断、分割一直要进行到节点所对应的立方体或是完全空白,或是完全为V占据,或是其大小已是预先定义的体素大小,并且对它与V之交作一定的“舍入”,使体素或认为是空白的,或认为是V占据的。

    如此所生成的八叉树上的节点可分为三类:

    灰节点,它对应的立方体部分地为V所占据;

    白节点,它所对应的立方体中无V的内容;

    黑节点,它所对应的立方体全为V所占据。

    后两类又称为叶结点。形体V关于C的八叉树的逻辑结构是这样的:它是一颗树,其上的节点要么是叶节点,要么就是有八个子节点的灰节点。根节点与C相对应,其它节点与C的某个子立方体相对应。

    因为八叉树的结构与四叉树的结构是如此的相似,所以八叉树的存贮结构方式可以完全沿用四叉树的有关方法。因而,根据不同的存贮方式,八叉树也可以分别称为常规的、线性的、一对八的八叉树等等。

    另外,由于这种方法充分利用了形体在空上的相关性,因此,一般来说,它所占用的存贮空间要比三维体素阵列的少。但是实际上它还是使用了相当多的存贮,这并不是八叉树的主要优点。这一方法的主要优点在于可以非常方便地实现有广泛用途的集合运算(例如可以求两个物体的并、交、差等运算),而这些恰是其它表示方法比较难以处理或者需要耗费许多计算资源的地方。不仅如此,由于这种方法的有序性及分层性,因而对显示精度和速度的平衡、隐线和隐面的消除等,带来了很大的方便,特别有用。

    (二)八叉树的存贮结构

    八叉树有三种不同的存贮结构,分别是规则方式、线性方式以及一对八方式。相应的八叉树也分别称为规则八叉树、线性八叉树以及一对八式八叉树。不同的存贮结构的空间利用率及运算操作的方便性是不同的。分析表明,一对八式八叉树优点更多一些。

    1、规则八叉树

    规则八叉树的存贮结构用一个有九个字段的记录来表示树中的每个结点。其中一个字段用来描述该结点的特性(在目前假定下,只要描述它是灰、白、黑三类结点中哪一类即可),其余的八个字段用来作为存放指向其八个子结点的指针。这是最普遍使用的表示树形数据的存贮结构方式。

    规则八叉树缺陷较多,最大的问题是指针占用了大量的空间。假定每个指针要用两个字节表示,而结点的描述用一个字节,那么存放指针要占总的存贮量的94%。因此,这种方法虽然十分自然,容易掌握,但在存贮空间的使用率方面不很理想。

    2、线性八叉树

    线性八叉树注重考虑如何提高空间利用率。用某一预先确定的次序遍历八叉树(例如以深度第一的方式),将八叉树转换成一个线性表(图2-5-2),表的每个元素与一个结点相对应。对于结点的描述可以丰富一点,例如用适当的方式来说明它是否为叶结点,如果不是叶结点时还可用其八个子结点值的平均值作为非叶结点的值等等。这样,可以在内存中以紧凑的方式来表示线性表,可以不用指针或者仅用一个指针表示即可。

    线性八叉树不仅节省存贮空间,对某些运算也较为方便。但是为此付出的代价是丧失了一定的灵活性。例如为了存取属于原图形右下角的子图形对应的结点,那么必须先遍历了其余七个子图形对应的所有结点后才能进行;不能方便地以其它遍历方式对树的结点进行存取,导致了许多与此相关的运算效率变低。因此尽管不少文章讨论了这种八叉树的应用,但是仍很难令人满意

    一个非叶结点有八个子结点,为了确定起见,将它们分别标记为0,1,2,3,4,5,6,7。从上面的介绍可以看到,如果一个记录与一个结点相对应,那么在这个记录中描述的是这个结点的八个子结点的特性值。而指针给出的则是该八个子结点所对应记录的存放处,而且还隐含地假定了这些子结点记录存放的次序。也就是说,即使某个记录是不必要的(例如,该结点已是叶结点),那么相应的存贮位置也必须空闲在那里(图2-5-3),以保证不会错误地存取到其它同辈结点的记录。这样当然会有一定的浪费,除非它是完全的八叉树,即所有的叶结点均在同一层次出现,而在该层次之上的所有层中的结点均为非叶结点。

    为了克服这种缺陷,有两条途径可以采纳。一是增加计算量,在记录中增加一定的信息,使计算工作适当减少或者更方便。

    ================================================================================

    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 

    using namespace std;

    //定义八叉树节点类

    template

    struct OctreeNode

    {

    T data; //节点数据

    T xmin,xmax; //节点坐标,即六面体个顶点的坐标

    T ymin,ymax;

    T zmin,zmax;

    OctreeNode  *top_left_front,*top_left_back; //该节点的个子结点

    OctreeNode  *top_right_front,*top_right_back;

    OctreeNode  *bottom_left_front,*bottom_left_back;

    OctreeNode  *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* top_left_front_Node = NULL,

    OctreeNode* top_left_back_Node = NULL,

    OctreeNode* top_right_front_Node = NULL,

    OctreeNode* top_right_back_Node = NULL,

    OctreeNode* bottom_left_front_Node = NULL,

    OctreeNode* bottom_left_back_Node = NULL,

    OctreeNode* bottom_right_front_Node = NULL,

    OctreeNode* 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 

    void createOctree(OctreeNode * &root,int maxdepth,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax)

    {

    cout<

    maxdepth=maxdepth-1; //每递归一次就将最大递归深度-1

    if(maxdepth>=0)

    {

    root=new OctreeNode();

    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 

    void preOrder( OctreeNode * & p)

    {

    if(p)

    {

    cout<data<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    i+=1;

    cout<

    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<

    }

    }

    //求八叉树的深度

    template

    int depth(OctreeNode *& 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

    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

    void find(OctreeNode *& 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 || xymax || yzmax || z

    {

    cout<

    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<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    cout<

    }

    else if(xxmax-xm) && yymax-ym) && zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_left_back,x,y,z);

    }

    else if(xxmax-xm) && yymax-ym) && z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_left_back,x,y,z);

    }

    else if(x>(p->xmax-xm) && yymax-ym) && zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_right_back,x,y,z);

    }

    else if(x>(p->xmax-xm) && yymax-ym) && z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_right_back,x,y,z);

    }

    else if(xxmax-xm) && y>(p->ymax-ym) && zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_left_front,x,y,z);

    }

    else if(xxmax-xm) && y>(p->ymax-ym) && z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_left_front,x,y,z);

    }

    else if(x>(p->xmax-xm) && y>(p->ymax-ym) && zzmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->bottom_right_front,x,y,z);

    }

    else if(x>(p->xmax-xm) && y>(p->ymax-ym) && z>(p->zmax-zm))

    {

    cout<

    cout<xmin<xmax;

    cout<ymin<ymax;

    cout<zmin<zmax;

    cout<

    find(p->top_right_front,x,y,z);

    }

    }

    //main函数

    int main ()

    {

    OctreeNode * rootNode = NULL;

    int choiced = 0;

    while(true)

    {

    system("cls");

    cout<

    cout<

    cout<

    cout<

    cin>>choiced;

    if(choiced == 0)

    return 0;

    else if(choiced == 1)

    {

    system("cls");

    cout<

    cin>>maxdepth;

    cout<

    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<

    i=1;

    preOrder(rootNode);

    cout<

    system("pause");

    }

    else if(choiced == 3)

    {

    system("cls");

    int dep = depth(rootNode);

    cout<

    system("pause");

    }

    else if(choiced == 4)

    {

    system("cls");

    cout<

    double x,y,z;

    cin>>x>>y>>z;

    times=0;

    cout<

    find(rootNode,x,y,z);

    system("pause");

    }

    else

    {

    system("cls");

    cout<

    system("pause");

    }

    }

    }

    展开全文
  • 一种基于指针的稀疏八叉树数据结构。 有关线性实现,请参见 。 ·· 安装 该库需要对等依赖关系 。 npm install math-ds sparse-octree 用法 点数 import { Vector3 } from "math-ds" ; import { PointOctree } ...
  • 八叉树维基释义:八叉树(Octree)是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点的体积。一般中心点...
  • 八叉树点云压缩

    2021-03-27 16:30:30
    邻域搜索,K邻域获取,法矢量计算、八叉树点云压缩 邻域搜索,K邻域获取,法矢量计算、八叉树点云压缩 邻域搜索,K邻域获取,法矢量计算、八叉树点云压缩 邻域搜索,K邻域获取,法矢量计算、八叉树点云压缩
  • 最近正好在看吧。就谈一下数据结构。...深度:八叉树划分的层级源点:一般就是(xmin,ymin,zmin)了节点:就像下图划分的一个一个的小立方体(有的会叫voxel,或者cell)这个带颜色的示意图很清楚的解释了八叉树的...
  • 这篇文章主要讲解八叉树算法的原理,并用java进行实现1.算法原理八叉树最早是在1988年,由 M. Gervautz 和 W. Purgathofer 提出,该算法的最大优点是效率高,占用内存少。在图像量化中的思路是,图像rgb通道的值均为...
  • 转载自:http://www.cnblogs.com/21207-iHome/p/7098000.html八叉树(Octree)是一种用于描述三维空间的树状数据结构。想象一个立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个。再想象我们有一个房间...
  • 八叉树学习

    2021-03-15 09:19:21
    八叉树学习八叉树结构八叉树的存储结构1. 规则八叉树:2.线性八叉树:3.一对八式八叉树参考网站 八叉树结构 八叉树结构是由 Hunter 博士于1978年首次提出的一种数据模型。八叉树结构通过对三维空间的几何实体进行体...
  • 基于线性八叉树的一种消隐算法马自萍;马金林;戴立雄【期刊名称】《宁夏工程技术》【年(卷),期】2006(005)003【摘要】为了减少消隐算法中大量直线与面相交的计算量,提高消隐算法效率,提出了基于线性八叉树的消隐算法....
  • 松散八叉树

    2020-09-01 19:17:52
    1八叉树简述 1.1定义 1.2数据 1.3树的建立 1.3.1计算包围体的大小与中心点 1.3.2判断物体所属的包围盒 2松散八叉树 2.1松散八叉树的建立 八叉树简述 定义 八叉树是一种对三维世界进行场景管理...
  • 八叉树算法

    2015-10-08 16:28:06
    文件包含八叉树构建算法; 用100万个点测试,构建效率高; 代码里面还有关于八叉树的相关操作函数; 欢迎广大爱好者使用交流。
  • c++八叉树实现

    2018-10-13 10:45:52
    使用c++的八叉树实现,八叉树(Octree)的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。
  • 龙源期刊网http://www.qikan.com.cn线性八叉树的邻域寻找的新算法作者:廖维猛来源:《数字技术与应用》2010年第04期摘要:提出了一种直接利用三维栅格的编码求其邻域的新算法。这种算法在求相同尺寸邻域时,仅需扫描...
  • c++八叉树

    2021-01-28 09:18:30
    八叉树图片 八叉树(octree),或称八元树,是一种用于描述三维空间(划分空间)的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父...
  • 八叉树场景管理

    千次阅读 2018-12-05 17:09:38
    什么是八叉树(八叉树的数据结构) 八叉树的图例 八叉树的实现算法 八叉树的场景管理器代码实现 八叉树的应用场景 1.什么是八叉树——八叉树的数据结构   八叉树是一个树形结构,它的特点就是每个节点正好拥有八...
  • 八叉树及应用

    千次阅读 2018-10-16 11:55:37
    八叉树及应用八叉树的定义如何搭建一颗八叉树八叉树的作用八叉树的实际应用 上一次介绍了KD树及应用,这次介绍一下八叉树,主要从定义、结构、作用及应用几个方面进行理解。 八叉树的定义 八叉树是在描述三维空间...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,057
精华内容 422
关键字:

八叉树