您的位置:首页 > 编程语言 > C语言/C++

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

2015-07-30 21:06 936 查看
简单实现了场景管理八叉树算法

代码结构:

object.h,object.cpp 被管理的对象类
octree_node.h,octree_node.cpp 八叉树类
main.cpp程序入口

object.h
#pragma once
/*
//被管理的对象类
*/
class Object
{
public:
Object(float _x,float _y,float _z,float _xSize,float _ySize,float _zSize);
~Object();
public:
//对象的属性,例如坐标和长宽高,以左上角为锚点
float x;
float y;
float z;
float xSize;
float ySize;
float zSize;
};


object.cpp
#include "object.h"

Object::Object(float _x,float _y,float _z,float _xSize,float _ySize,float _zSize):
x(_x),
y(_y),
z(_z),
xSize(_xSize),
ySize(_ySize),
zSize(_zSize)
{
}

Object::~Object()
{
}


octree_node.h

/*
//八叉树节点类,用头节点代表八叉树
//采用opengl右手坐标系,靠近原点的那个角为锚点,方便计算
//本八叉树的策略是:1,一次划分所有节点,是满树;2,当立方体空间完全包含某物体才剔除,当立方体空间与某物体相交或者完全包含时才查询;3,对象放在完全包含它的区域叶子节点内,非根节点不存储对象,默认为物体不可能跨多个叶子节点,都在一个叶子节点的空间范围内部,未考虑交叉的情况
*/
#pragma once
#include <list>

//八叉树节点类型
enum OctreeType
{
ROOT,                   //根
BOTTOM_LEFT_FRONT,		// 1
BOTTOM_RIGHT_FRONT,		// 2
BOTTOM_LEFT_BACK,		// 3
BOTTOM_RIGHT_BACK,      // 4
TOP_LEFT_FRONT,         // 5
TOP_RIGHT_FRONT,        // 6
TOP_LEFT_BACK,          // 7
TOP_RIGHT_BACK          // 8
};

template <class T>
class OctreeNode
{
public:
OctreeNode(float _x,float _y,float _z,float _xSize,float _ySize,float _zSize,OctreeType _octreeNodeType,int _level,int _maxLevel);
~OctreeNode();
public:
void BuildTree(int level); //建立八叉树,划分到所有子节点
void InsertObject(T *object); //插入对象
std::list<T *> GetObjectsAt(float px,float py,float pz,float x_size,float y_size,float z_size); //查询对象,获得一片区域里的对象链表,考虑包含或相交,由于
void RemoveObjectsAt(float px,float py,float pz,float x_size,float y_size,float z_size); //删除对象,删除一片区域里的对象,此处只考虑完全包含的
private:
bool IsContain(float px,float py,float pz,float x_size,float y_size,float z_size,T *object) const; //判断某个区域是否包含某对象
bool IsContain(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode<T> *octreeNode) const; //重载,判断某个区域是否包含某个节点
bool IsInterSect(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode<T> *octreeNode) const; //判断某个区域是否与节点相交,如果相交,则查询时要递归到其子节点
public:
std::list<T *> objectList; //节点存储的对象列表
private:
//节点属性
OctreeType octreeNodeType;
float x;
float y;
float z;
float xSize;
float ySize;
float zSize;
int level;
int maxLevel;
//子节点,根据opengl坐标系,依次坐标增大
OctreeNode *bottom_left_front_node;
OctreeNode *bottom_right_front_node;
OctreeNode *bottom_left_back_node;
OctreeNode *bottom_right_back_node;
OctreeNode *top_left_front_node;
OctreeNode *top_right_front_node;
OctreeNode *top_left_back_node;
OctreeNode *top_right_back_node;
};


octree_node.cpp

#include "octree_node.h"

template <class T>
OctreeNode<T>::OctreeNode(float _x,float _y,float _z,float _xSize,float _ySize,float _zSize,OctreeType _octreeNodeType,int _level,int _maxLevel):
x(_x),
y(_y),
z(_z),
xSize(_xSize),
ySize(_ySize),
zSize(_zSize),
octreeNodeType(_octreeNodeType),
level(_level),
maxLevel(_maxLevel)
{
//初始子节点都赋空值
bottom_left_front_node=nullptr;
bottom_right_front_node=nullptr;
bottom_left_back_node=nullptr;
bottom_right_back_node=nullptr;
top_left_front_node=nullptr;
top_right_front_node=nullptr;
top_left_back_node=nullptr;
top_right_back_node=nullptr;
}

template <class T>
OctreeNode<T>::~OctreeNode()
{

}

template <class T>
bool OctreeNode<T>::IsContain(float px,float py,float pz,float x_size,float y_size,float z_size,T *object) const
{
if(object->x>=px
&&object->x+object->xSize<=px+x_size
&&object->y>=py
&&object->y+object->ySize<=py+y_size
&&object->z>=pz
&&object->z+object->zSize<=pz+z_size)
return true;
return false;
}

template <class T>
bool OctreeNode<T>::IsContain(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode<T> *octreeNode) const
{
if(octreeNode->x>=px
&&octreeNode->x+octreeNode->xSize<=px+x_size
&&octreeNode->y>=py
&&octreeNode->y+octreeNode->ySize<=py+y_size
&&octreeNode->z>=pz
&&octreeNode->z+octreeNode->zSize<=pz+z_size)
return true;
return false;
}

template <class T>
bool OctreeNode<T>::IsInterSect(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode<T> *octreeNode) const
{
if(octreeNode->x>px+x_size
||octreeNode->x+xSize<px
||octreeNode->y>py+y_size
||octreeNode->y+ySize<py
||octreeNode->z+zSize<pz
||octreeNode->z>pz+z_size)
return false;
return true;
}

template <class T>
void OctreeNode<T>::BuildTree(int level)
{
//递归地进行八叉树空间划分,直到最大深度
if(level==maxLevel)
return;
//创建子节点
bottom_left_front_node=new OctreeNode(x,y,z,xSize/2,ySize/2,zSize/2,BOTTOM_LEFT_FRONT,level+1,maxLevel);
bottom_right_front_node=new OctreeNode(x+xSize/2,y,z,xSize/2,ySize/2,zSize/2,BOTTOM_RIGHT_FRONT,level+1,maxLevel);
bottom_left_back_node=new OctreeNode(x,y+ySize/2,z,xSize/2,ySize/2,zSize/2,BOTTOM_LEFT_BACK,level+1,maxLevel);
bottom_right_back_node=new OctreeNode(x+xSize/2,y+ySize/2,z,xSize/2,ySize/2,zSize/2,BOTTOM_RIGHT_BACK,level+1,maxLevel);
top_left_front_node=new OctreeNode(x,y,z+zSize/2,xSize/2,ySize/2,zSize/2,TOP_LEFT_FRONT,level+1,maxLevel);
top_right_front_node=new OctreeNode(x+xSize/2,y,z+zSize/2,xSize/2,ySize/2,zSize/2,TOP_RIGHT_FRONT,level+1,maxLevel);
top_left_back_node=new OctreeNode(x,y+ySize/2,z+zSize/2,xSize/2,ySize/2,zSize/2,TOP_LEFT_BACK,level+1,maxLevel);
top_right_back_node=new OctreeNode(x+xSize/2,y+ySize/2,z+zSize/2,xSize/2,ySize/2,zSize/2,TOP_RIGHT_BACK,level+1,maxLevel);
//递归构造
bottom_left_front_node->BuildTree(level+1);
bottom_right_front_node->BuildTree(level+1);
bottom_left_back_node->BuildTree(level+1);
bottom_right_back_node->BuildTree(level+1);
top_left_front_node->BuildTree(level+1);
top_right_front_node->BuildTree(level+1);
top_left_back_node->BuildTree(level+1);
top_right_back_node->BuildTree(level+1);
}

template <class T>
void OctreeNode<T>::InsertObject(T *object)
{
if(level==maxLevel)
{
objectList.push_back(object);
return;
}
//递归地插入,直到叶子节点
//1
if(bottom_left_front_node&&IsContain(x,y,z,xSize/2,ySize/2,zSize/2,object))
{
bottom_left_front_node->InsertObject(object);
return;
}
//2
if(bottom_right_front_node&&IsContain(x+xSize/2,y,z,xSize/2,ySize/2,zSize/2,object))
{
bottom_right_front_node->InsertObject(object);
return;
}
//3
if(bottom_left_back_node&&IsContain(x,y+ySize/2,z,xSize/2,ySize/2,zSize/2,object))
{
bottom_left_back_node->InsertObject(object);
return;
}
//4
if(bottom_right_back_node&&IsContain(x+xSize/2,y+ySize/2,z,xSize/2,ySize/2,zSize/2,object))
{
bottom_right_back_node->InsertObject(object);
return;
}
//5
if(top_left_front_node&&IsContain(x,y,z+zSize/2,xSize/2,ySize/2,zSize/2,object))
{
top_left_front_node->InsertObject(object);
return;
}
//6
if(top_right_front_node&&IsContain(x+xSize/2,y,z+zSize/2,xSize/2,ySize/2,zSize/2,object))
{
top_right_front_node->InsertObject(object);
return;
}
//7
if(top_left_back_node&&IsContain(x,y+ySize/2,z+zSize/2,xSize/2,ySize/2,zSize/2,object))
{
top_left_back_node->InsertObject(object);
return;
}
//8
if(top_right_back_node&&IsContain(x+xSize/2,y+ySize/2,z+zSize/2,xSize/2,ySize/2,zSize/2,object))
{
top_right_back_node->InsertObject(object);
return;
}
}

template <class T>
std::list<T *> OctreeNode<T>::GetObjectsAt(float px,float py,float pz,float x_size,float y_size,float z_size)
{
if(level==maxLevel)
return objectList;
std::list<T *> resObjects;
//递归地判断选定区域是否与某个节点相交(包含或被包含都算)
//1
if(bottom_left_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_left_front_node))
{
std::list<T *> childObjects1=bottom_left_front_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects1.begin(),childObjects1.end());
}
//2
if(bottom_right_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_right_front_node))
{
std::list<T *> childObjects2=bottom_right_front_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects2.begin(),childObjects2.end());
}
//3
if(bottom_left_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_left_back_node))
{
std::list<T *> childObjects3=bottom_left_back_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects3.begin(),childObjects3.end());
}
//4
if(bottom_right_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_right_back_node))
{
std::list<T *> childObjects4=bottom_right_back_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects4.begin(),childObjects4.end());
}
//5
if(top_left_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_left_front_node))
{
std::list<T *> childObjects5=top_left_front_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects5.begin(),childObjects5.end());
}
//6
if(top_right_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_right_front_node))
{
std::list<T *> childObjects6=top_right_front_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects6.begin(),childObjects6.end());
}
//7
if(top_left_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_left_back_node))
{
std::list<T *> childObjects7=top_left_back_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects7.begin(),childObjects7.end());
}
//8
if(top_right_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_right_back_node))
{
std::list<T *> childObjects8=top_right_back_node->GetObjectsAt(px,py,pz,x_size,y_size,z_size);
resObjects.insert(resObjects.end(),childObjects8.begin(),childObjects8.end());
}

return resObjects;
}

template <class T>
void OctreeNode<T>::RemoveObjectsAt(float px,float py,float pz,float x_size,float y_size,float z_size)
{
if(level==maxLevel)
{
if(IsContain(px,py,pz,x_size,y_size,z_size,this))
objectList.clear(); //到了叶子节点且完全被包含就把该节点存储的对象清空
return;
}
//递归地判断选定区域是否与某个节点相交(包含或被包含都算),没有相交就不用再递归了
//1
if(bottom_left_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_left_front_node))
bottom_left_front_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//2
if(bottom_right_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_right_front_node))
bottom_right_front_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//3
if(bottom_left_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_left_back_node))
bottom_left_back_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//4
if(bottom_right_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_right_back_node))
bottom_right_back_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//5
if(top_left_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_left_front_node))
top_left_front_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//6
if(top_right_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_right_front_node))
top_right_front_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//7
if(top_left_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_left_back_node))
top_left_back_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
//8
if(top_right_back_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,top_right_back_node))
top_right_back_node->RemoveObjectsAt(px,py,pz,x_size,y_size,z_size);
}


main.cpp
#include <iostream>
#include "object.h"
#include "octree_node.h"
#include "octree_node.cpp" //模板分开写要包含h和cpp
using namespace std;
int main()
{
OctreeNode<Object> *octree=new OctreeNode<Object>(0,0,0,200,200,200,ROOT,1,3);
octree->BuildTree(1);

octree->InsertObject(new Object(10,10,10,30,30,30));
octree->InsertObject(new Object(11,11,11,32,32,32));
octree->InsertObject(new Object(110,60,60,30,30,30));
octree->InsertObject(new Object(110,110,110,30,30,30));

octree->RemoveObjectsAt(0,0,0,110,70,70);
list<Object *> resObjects=octree->GetObjectsAt(0,0,0,130,130,130);
cout<<resObjects.size()<<endl;
for(auto &t:resObjects)
cout<<t->x<<' '<<t->y<<' '<<t->z<<' '<<t->xSize<<' '<<t->ySize<<' '<<t->zSize<<endl;

delete octree;
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: