简单实现了场景管理八叉树算法
代码结构:
#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;
};
#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()
{
}
/*
//八叉树节点类,用头节点代表八叉树
//采用opengl右手坐标系,靠近原点的那个角为锚点,方便计算
//本八叉树的策略是:1,一次划分所有节点,是满树;2,当立方体空间完全包含某物体才剔除,当立方体空间与某物体相交或者完全包含时才查询;3,对象放在完全包含它的区域叶子节点内,非根节点不存储对象,默认为物体不可能跨多个叶子节点,都在一个叶子节点的空间范围内部,未考虑交叉的情况
*/
#pragma once
#include
//八叉树节点类型
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 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 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 *octreeNode) const; //重载,判断某个区域是否包含某个节点
bool IsInterSect(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode *octreeNode) const; //判断某个区域是否与节点相交,如果相交,则查询时要递归到其子节点
public:
std::list 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;
};
#include "octree_node.h"
template
OctreeNode::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
OctreeNode::~OctreeNode()
{
}
template
bool OctreeNode::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
bool OctreeNode::IsContain(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode *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
bool OctreeNode::IsInterSect(float px,float py,float pz,float x_size,float y_size,float z_size,OctreeNode *octreeNode) const
{
if(octreeNode->x>px+x_size
||octreeNode->x+xSizey>py+y_size
||octreeNode->y+ySizez+zSizez>pz+z_size)
return false;
return true;
}
template
void OctreeNode::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
void OctreeNode::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
std::list OctreeNode::GetObjectsAt(float px,float py,float pz,float x_size,float y_size,float z_size)
{
if(level==maxLevel)
return objectList;
std::list resObjects;
//递归地判断选定区域是否与某个节点相交(包含或被包含都算)
//1
if(bottom_left_front_node&&IsInterSect(px,py,pz,x_size,y_size,z_size,bottom_left_front_node))
{
std::list 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 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 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 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 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 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 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 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
void OctreeNode::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);
}
#include
#include "object.h"
#include "octree_node.h"
#include "octree_node.cpp" //模板分开写要包含h和cpp
using namespace std;
int main()
{
OctreeNode