八叉树 C++ 基础 源码

转载 2017年06月20日 23:28:39

http://blog.csdn.net/pizi0475/article/details/6269060

四叉树或四元树也被称为Q树(Q-Tree)。四叉树广泛应用于图像处理、空间数据索引、2D中的快速碰撞检测、存储稀疏数据等,而八叉树(Octree)主要应用于3D图形处理。

实际的数据结构,就是一个树根不断地往下扩,每次分成八个枝,直到叶子为止。
叶子节点代表了分辨率最高的情况。例如分辨率设成0.01m,那么每个叶子就是一个1cm见方的小方块

这里写图片描述

这里写图片描述

#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 xMind = (xMax - xMin) / 2;//计算节点个维度上的半边长
        double yMind = (yMax - yMin) / 2;
        double zMind = (zMax - zMin) / 2;
        //递归创建子树,根据每一个节点所处(是几号节点)的位置决定其子结点的坐标。
        createOctree(root->top_left_front, maxdepth, xMin, xMax - xMind, yMax - yMind, yMax, zMax - zMind, zMax);
        createOctree(root->top_left_back, maxdepth, xMin, xMax - xMind, yMin, yMax - yMind, zMax - zMind, zMax);
        createOctree(root->top_right_front, maxdepth, xMax - xMind, xMax, yMax - yMind, yMax, zMax - zMind, zMax);
        createOctree(root->top_right_back, maxdepth, xMax - xMind, xMax, yMin, yMax - yMind, zMax - zMind, zMax);
        createOctree(root->bottom_left_front, maxdepth, xMin, xMax - xMind, yMax - yMind, yMax, zMin, zMax - zMind);
        createOctree(root->bottom_left_back, maxdepth, xMin, xMax - xMind, yMin, yMax - yMind, zMin, zMax - zMind);
        createOctree(root->bottom_right_front, maxdepth, xMax - xMind, xMax, yMax - yMind, yMax, zMin, zMax - zMind);
        createOctree(root->bottom_right_back, maxdepth, xMax - xMind, xMax, yMin, yMax - yMind, zMin, zMax - zMind);
    }
}

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 xMind = (p->xMax - p->xMin) / 2;
    double yMind = (p->yMax - p->yMin) / 2;
    double zMind = (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 - xMind) && y < (p->yMax - yMind) && z < (p->zMax - zMind))
    {
        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 - xMind) && y<(p->yMax - yMind) && z>(p->zMax - zMind))
    {
        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 - xMind) && y < (p->yMax - yMind) && z < (p->zMax - zMind))
    {
        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 - xMind) && y<(p->yMax - yMind) && z>(p->zMax - zMind))
    {
        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 - xMind) && y>(p->yMax - yMind) && z < (p->zMax - zMind))
    {
        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 - xMind) && y>(p->yMax - yMind) && z > (p->zMax - zMind))
    {
        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 - xMind) && y > (p->yMax - yMind) && z < (p->zMax - zMind))
    {
        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 - xMind) && y > (p->yMax - yMind) && z > (p->zMax - zMind))
    {
        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");
        }
    }
}

八叉树Octree

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

八叉树Octree

维基释义:八叉树(Octree)是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点的体积。一般中心点...
  • Augusdi
  • Augusdi
  • 2014年06月30日 16:41
  • 12780

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

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

八叉树三维数据结构

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

空间八叉树剖分

空间八叉树剖分转载自:http://hi.baidu.com/j_factory/blog/item/8bc1ca182d7f45f6af5133c3.html  空间八叉树算法是一个空间非均匀网格剖...
  • Augusdi
  • Augusdi
  • 2014年06月30日 16:49
  • 4652

四叉树与八叉树

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

八叉树及K-D树的应用和实现

1. 八叉树、k-d树的原理2. 八叉树、k-d树的应用、优缺点3. 八叉树、k-d树的实现八叉树和k-d树都经常用来处理三维空间数据,k-d树的使用范围更宽泛些,适用于k维空间的数据,在Sift算法...
  • Augusdi
  • Augusdi
  • 2014年06月30日 20:46
  • 2264

基于八叉树的网格生成算法剖析

基于八叉树的网格生成算法剖析前言  对于网格生成这个主题,之前的网格生成系列的三篇博客文章分别介绍了MC算法,SMC算法以及Cuberille算法三种方法。同时还有一篇介绍网格生成与种子点生长算法高效...
  • Kaitiren
  • Kaitiren
  • 2016年03月11日 11:40
  • 2392

四叉树与八叉树

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

叉树Octree原理及简单实现(C++版)

1、对Octree的描述 Octree的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个立方体,我们最少可以切成...
  • Chinamming
  • Chinamming
  • 2013年11月24日 13:22
  • 2094
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:八叉树 C++ 基础 源码
举报原因:
原因补充:

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