八叉树的实现

  1. //Date : 2008/05/01
  2. //Filename : octree.cpp
  3. //Platform : VC++ 2005
  4. //八叉树的实现
  5. //功能:
  6. //1、创建八叉树。
  7. //此八叉树为满树,即所有节点/叶子全部创建。
  8. //用户可以自定义此八叉树的深度和所处的三维场景中的位置。
  9. //注a:由于创建树时为满树创建,故层数太大时创建时间可能会比较久,请耐心等待。
  10. //注b:创建顺序为(1)上层左前节点-(2)上层右前节点-(3)上层右前节点-(4)上层右后节点
  11. //-(5)下层左前节点-(6)下层右前节点-(7)下层右前节点-(8)下层右后节点-(1)-(2)……
  12. //2、先序遍历八叉树。
  13. //八叉树创建成功后用户可调用此子模块查看此八叉树,会显示每个结点的编号,值和在场景中的坐标。
  14. //3、查看八叉树的深度。
  15. //4、在场景中查找点。
  16. //用户首先输入要查找的坐标。
  17. //如果该点位于场景外则提示用户并返回,否则在场景中递归查找该点。
  18. //找到后输出该点所处的子结点的坐标和递归次数。
  19. #include <iostream>
  20. using namespace std;
  21. //定义八叉树节点类
  22. template<class T>
  23. struct OctreeNode
  24. {
  25.     T data; //节点数据
  26.     T xmin,xmax; //节点坐标,即六面体个顶点的坐标
  27.     T ymin,ymax;
  28.     T zmin,zmax;
  29.     OctreeNode <T> *top_left_front,*top_left_back; //该节点的个子结点,即个子六面体
  30.     OctreeNode <T> *top_right_front,*top_right_back;
  31.     OctreeNode <T> *bottom_left_front,*bottom_left_back;
  32.     OctreeNode <T> *bottom_right_front,*bottom_right_back;
  33.     OctreeNode //节点类
  34.         (T nodeValue = T(),
  35.         T xminValue = T(),T xmaxValue = T(),
  36.         T yminValue = T(),T ymaxValue = T(),
  37.         T zminValue = T(),T zmaxValue = T(),
  38.         OctreeNode<T>* top_left_front_Node = NULL,
  39.         OctreeNode<T>* top_left_back_Node = NULL,
  40.         OctreeNode<T>* top_right_front_Node = NULL,
  41.         OctreeNode<T>* top_right_back_Node = NULL,
  42.         OctreeNode<T>* bottom_left_front_Node = NULL,
  43.         OctreeNode<T>* bottom_left_back_Node = NULL,
  44.         OctreeNode<T>* bottom_right_front_Node = NULL,
  45.         OctreeNode<T>* bottom_right_back_Node = NULL )
  46.         :data(nodeValue),
  47.         xmin(xminValue),xmax(xmaxValue),
  48.         ymin(yminValue),ymax(ymaxValue),
  49.         zmin(zminValue),zmax(zmaxValue),
  50.         top_left_front(top_left_front_Node),
  51.         top_left_back(top_left_back_Node),
  52.         top_right_front(top_right_front_Node),
  53.         top_right_back(top_right_back_Node),
  54.         bottom_left_front(bottom_left_front_Node),
  55.         bottom_left_back(bottom_left_back_Node),
  56.         bottom_right_front(bottom_right_front_Node),
  57.         bottom_right_back(bottom_right_back_Node){}
  58. };
  59. //创建八叉树
  60. template <class T>
  61. void createOctree(OctreeNode<T> * &root,int maxdepth,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax)
  62. {
  63.     cout<<"处理中,请稍候……"<<endl;
  64.     maxdepth=maxdepth-1; //每递归一次就将最大递归深度-1
  65.     if(maxdepth>=0)
  66.     {
  67.         root=new OctreeNode<T>();
  68.         root->data = 9; //为节点赋值,可以存储节点信息,如物体可见性。由于是简单实现八叉树功能,简单赋值为。
  69.         root->xmin=xmin; //为节点坐标赋值
  70.         root->xmax=xmax;
  71.         root->ymin=ymin;
  72.         root->ymax=ymax;
  73.         root->zmin=zmin;
  74.         root->zmax=zmax;
  75.         double xm=(xmax-xmin)/2;//计算节点个维度上的半边长
  76.         double ym=(ymax-ymin)/2;
  77.         double zm=(ymax-ymin)/2;
  78.         //递归创建子树,根据每一个节点所处(是几号节点)的位置决定其子结点的坐标。
  79.         createOctree(root->top_left_front,maxdepth,xmin,xmax-xm,ymax-ym,ymax,zmax-zm,zmax);
  80.         createOctree(root->top_left_back,maxdepth,xmin,xmax-xm,ymin,ymax-ym,zmax-zm,zmax);
  81.         createOctree(root->top_right_front,maxdepth,xmax-xm,xmax,ymax-ym,ymax,zmax-zm,zmax);
  82.         createOctree(root->top_right_back,maxdepth,xmax-xm,xmax,ymin,ymax-ym,zmax-zm,zmax);
  83.         createOctree(root->bottom_left_front,maxdepth,xmin,xmax-xm,ymax-ym,ymax,zmin,zmax-zm);
  84.         createOctree(root->bottom_left_back,maxdepth,xmin,xmax-xm,ymin,ymax-ym,zmin,zmax-zm);
  85.         createOctree(root->bottom_right_front,maxdepth,xmax-xm,xmax,ymax-ym,ymax,zmin,zmax-zm);
  86.         createOctree(root->bottom_right_back,maxdepth,xmax-xm,xmax,ymin,ymax-ym,zmin,zmax-zm);
  87.     }
  88. }
  89. int i=1;
  90. //先序遍历八叉树
  91. template <class T>
  92. void preOrder( OctreeNode<T> * & p)
  93. {
  94.     if(p)
  95.     {
  96.         cout<<i<<".当前节点的值为:"<<p->data<<"/n坐标为:";
  97.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  98.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  99.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  100.         i+=1;
  101.         cout<<endl;
  102.         preOrder(p->top_left_front);
  103.         preOrder(p->top_left_back);
  104.         preOrder(p->top_right_front);
  105.         preOrder(p->top_right_back);
  106.         preOrder(p->bottom_left_front);
  107.         preOrder(p->bottom_left_back);
  108.         preOrder(p->bottom_right_front);
  109.         preOrder(p->bottom_right_back);
  110.         cout<<endl;
  111.     }
  112. }
  113. //求八叉树的深度
  114. template<class T>
  115. int depth(OctreeNode<T> *& p)
  116. {
  117.     if(p == NULL)
  118.         return -1;
  119.     int h = depth(p->top_left_front);
  120.     return h+1;
  121. }
  122. //计算单位长度,为查找点做准备
  123. int cal(int num)
  124. {
  125.     int result=1;
  126.     if(1==num)
  127.         result=1;
  128.     else
  129.     {
  130.         for(int i=1;i<num;i++)
  131.             result=2*result;
  132.     }
  133.     return result;
  134. }
  135. //查找点
  136. int maxdepth=0;
  137. int times=0;
  138. static double xmin=0,xmax=0,ymin=0,ymax=0,zmin=0,zmax=0;
  139. int tmaxdepth=0;
  140. double txm=1,tym=1,tzm=1;
  141. template<class T>
  142. void find(OctreeNode<T> *& p,double x,double y,double z)
  143. {
  144.     double xm=(p->xmax-p->xmin)/2;
  145.     double ym=(p->ymax-p->ymin)/2;
  146.     double zm=(p->ymax-p->ymin)/2;
  147.     times++;
  148.     if(x>xmax || x<xmin || y>ymax || y<ymin || z>zmax || z<zmin)
  149.     {
  150.         cout<<"该点不在场景中!"<<endl;
  151.         return;
  152.     }
  153.     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 )
  154.     {
  155.         cout<<endl<<"找到该点!"<<"该点位于"<<endl;
  156.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  157.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  158.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  159.         cout<<"节点内!"<<endl;
  160.         cout<<"共经过"<<times<<"次递归!"<<endl;
  161.     }
  162.     else if(x<(p->xmax-xm) && y<(p->ymax-ym) && z<(p->zmax-zm))
  163.     {
  164.         cout<<"当前经过节点坐标:"<<endl;
  165.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  166.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  167.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  168.         cout<<endl;
  169.         find(p->bottom_left_back,x,y,z);
  170.     }
  171.     else if(x<(p->xmax-xm) && y<(p->ymax-ym) && z>(p->zmax-zm))
  172.     {
  173.         cout<<"当前经过节点坐标:"<<endl;
  174.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  175.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  176.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  177.         cout<<endl;
  178.         find(p->top_left_back,x,y,z);
  179.     }
  180.     else if(x>(p->xmax-xm) && y<(p->ymax-ym) && z<(p->zmax-zm))
  181.     {
  182.         cout<<"当前经过节点坐标:"<<endl;
  183.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  184.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  185.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  186.         cout<<endl;
  187.         find(p->bottom_right_back,x,y,z);
  188.     }
  189.     else if(x>(p->xmax-xm) && y<(p->ymax-ym) && z>(p->zmax-zm))
  190.     {
  191.         cout<<"当前经过节点坐标:"<<endl;
  192.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  193.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  194.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  195.         cout<<endl;
  196.         find(p->top_right_back,x,y,z);
  197.     }
  198.     else if(x<(p->xmax-xm) && y>(p->ymax-ym) && z<(p->zmax-zm))
  199.     {
  200.         cout<<"当前经过节点坐标:"<<endl;
  201.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  202.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  203.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  204.         cout<<endl;
  205.         find(p->bottom_left_front,x,y,z);
  206.     }
  207.     else if(x<(p->xmax-xm) && y>(p->ymax-ym) && z>(p->zmax-zm))
  208.     {
  209.         cout<<"当前经过节点坐标:"<<endl;
  210.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  211.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  212.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  213.         cout<<endl;
  214.         find(p->top_left_front,x,y,z);
  215.     }
  216.     else if(x>(p->xmax-xm) && y>(p->ymax-ym) && z<(p->zmax-zm))
  217.     {
  218.         cout<<"当前经过节点坐标:"<<endl;
  219.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  220.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  221.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  222.         cout<<endl;
  223.         find(p->bottom_right_front,x,y,z);
  224.     }
  225.     else if(x>(p->xmax-xm) && y>(p->ymax-ym) && z>(p->zmax-zm))
  226.     {
  227.         cout<<"当前经过节点坐标:"<<endl;
  228.         cout<<" xmin: "<<p->xmin<<" xmax: "<<p->xmax;
  229.         cout<<" ymin: "<<p->ymin<<" ymax: "<<p->ymax;
  230.         cout<<" zmin: "<<p->zmin<<" zmax: "<<p->zmax;
  231.         cout<<endl;
  232.         find(p->top_right_front,x,y,z);
  233.     }
  234. }
  235. //main函数
  236. int main ()
  237. {
  238.     OctreeNode<double> * rootNode = NULL;
  239.     int choiced = 0;
  240.     while(true)
  241.     {
  242.         system("cls");
  243.         cout<<"请选择操作:/n";
  244.         cout<<"1.创建八叉树 2.先序遍历八叉树/n";
  245.         cout<<"3.查看树深度 4.查找节点   /n";
  246.         cout<<"0.退出/n/n";
  247.         cin>>choiced;
  248.         if(choiced == 0)
  249.             return 0;
  250.         else if(choiced == 1)
  251.         {
  252.             system("cls");
  253.             cout<<"请输入最大递归深度:"<<endl;
  254.             cin>>maxdepth;
  255.             cout<<"请输入外包盒坐标,顺序如下:xmin,xmax,ymin,ymax,zmin,zmax"<<endl;
  256.             cin>>xmin>>xmax>>ymin>>ymax>>zmin>>zmax;
  257.             if(maxdepth>=0 || xmax>xmin || ymax>ymin || zmax>zmin || xmin>0 || ymin>0 ||zmin>0)
  258.             {
  259.                 tmaxdepth=cal(maxdepth);
  260.                 txm=(xmax-xmin)/tmaxdepth;
  261.                 tym=(ymax-ymin)/tmaxdepth;
  262.                 tzm=(zmax-zmin)/tmaxdepth;
  263.                 createOctree(rootNode,maxdepth,xmin,xmax,ymin,ymax,zmin,zmax);
  264.             }
  265.             else
  266.             {
  267.                 cout<<"输入错误!";
  268.                 return 0;
  269.             }
  270.         }
  271.         else if(choiced == 2)
  272.         {
  273.             system("cls");
  274.             cout<<"先序遍历八叉树结果:/n";
  275.             i=1;
  276.             preOrder(rootNode);
  277.             cout<<endl;
  278.             system("pause");
  279.         }
  280.         else if(choiced == 3)
  281.         {
  282.             system("cls");
  283.             int dep = depth(rootNode);
  284.             cout<<"此八叉树的深度为"<<dep+1<<endl;
  285.             system("pause");
  286.         }
  287.         else if(choiced == 4)
  288.         {
  289.             system("cls");
  290.             cout<<"请输入您希望查找的点的坐标,顺序如下:x,y,z/n";
  291.             double x,y,z;
  292.             cin>>x>>y>>z;
  293.             times=0;
  294.             cout<<endl<<"开始搜寻该点……"<<endl;
  295.             find(rootNode,x,y,z);
  296.             system("pause");
  297.         }
  298.         else
  299.         {
  300.             system("cls");
  301.             cout<<"/n/n错误选择!/n";
  302.             system("pause");
  303.         }
  304.     }
  305. }

你可能感兴趣的:(八叉树的实现)