八叉树 C++ 基础 源码

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

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

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

八叉树 C++ 基础 源码_第1张图片

八叉树 C++ 基础 源码_第2张图片

#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");
        }
    }
}

你可能感兴趣的:(C++)