264 lines
7.8 KiB
C++
264 lines
7.8 KiB
C++
#pragma once
|
||
#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>();
|
||
//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;
|
||
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;
|
||
}
|
||
template<class T>
|
||
int num(OctreeNode<T>*& p)
|
||
{
|
||
if (p == NULL)
|
||
return 0;
|
||
return 1 + num(p->top_left_front) + num(p->top_left_back) + num(p->top_right_back) + num(p->top_right_front) + num(p->bottom_left_back) + num(p->bottom_left_front) + num(p->bottom_right_back) + num(p->bottom_right_front);
|
||
}
|
||
//计算单位长度,为查找点做准备
|
||
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;
|
||
}
|
||
|
||
template<class T>
|
||
int find(OctreeNode<T>*& p, double x, double y, double z)
|
||
{
|
||
//查找点
|
||
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;
|
||
|
||
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 0;
|
||
}
|
||
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;
|
||
return 1;
|
||
}
|
||
else if (x < (p->xmax - xm) && y < (p->ymax - ym) && z < (p->zmax - zm))
|
||
{
|
||
find(p->bottom_left_back, x, y, z);
|
||
}
|
||
else if (x < (p->xmax - xm) && y<(p->ymax - ym) && z>(p->zmax - zm))
|
||
{
|
||
find(p->top_left_back, x, y, z);
|
||
}
|
||
else if (x > (p->xmax - xm) && y < (p->ymax - ym) && z < (p->zmax - zm))
|
||
{
|
||
find(p->bottom_right_back, x, y, z);
|
||
}
|
||
else if (x > (p->xmax - xm) && y<(p->ymax - ym) && z>(p->zmax - zm))
|
||
{
|
||
find(p->top_right_back, x, y, z);
|
||
}
|
||
else if (x<(p->xmax - xm) && y>(p->ymax - ym) && z < (p->zmax - zm))
|
||
{
|
||
find(p->bottom_left_front, x, y, z);
|
||
}
|
||
else if (x<(p->xmax - xm) && y>(p->ymax - ym) && z > (p->zmax - zm))
|
||
{
|
||
find(p->top_left_front, x, y, z);
|
||
}
|
||
else if (x > (p->xmax - xm) && y > (p->ymax - ym) && z < (p->zmax - zm))
|
||
{
|
||
find(p->bottom_right_front, x, y, z);
|
||
}
|
||
else if (x > (p->xmax - xm) && y > (p->ymax - ym) && z > (p->zmax - zm))
|
||
{
|
||
find(p->top_right_front, x, y, z);
|
||
}
|
||
}
|
||
//main函数
|
||
/*
|
||
int main()
|
||
{
|
||
OctreeNode<double>* rootNode = NULL;
|
||
int choiced = 0;
|
||
cout << "系统开始前请先创建八叉树" << endl;
|
||
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);
|
||
}
|
||
while (true)
|
||
{
|
||
system("cls");
|
||
|
||
cout << "请选择操作:\n";
|
||
cout << "\t1.计算空间中区域的个数\n";
|
||
cout << "\t2.先序遍历八叉树\n";
|
||
cout << "\t3.查看树深度\n";
|
||
cout << "\t4.查找节点 \n";
|
||
cout << "\t0.退出\n";
|
||
cin >> choiced;
|
||
|
||
if (choiced == 0)
|
||
return 0;
|
||
if (choiced == 1)
|
||
{
|
||
system("cls");
|
||
cout << "空间区域个数" << endl;
|
||
cout << num(rootNode);
|
||
}
|
||
|
||
if (choiced == 2)
|
||
{
|
||
system("cls");
|
||
cout << "先序遍历八叉树结果:/n";
|
||
i = 1;
|
||
preOrder(rootNode);
|
||
cout << endl;
|
||
system("pause");
|
||
}
|
||
if (choiced == 3)
|
||
{
|
||
system("cls");
|
||
int dep = depth(rootNode);
|
||
cout << "此八叉树的深度为" << dep + 1 << endl;
|
||
system("pause");
|
||
}
|
||
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");
|
||
}
|
||
}
|
||
*/ |