运用访问者模式把四叉树遍历和实现分离

来源:互联网 发布:软件下载模板 编辑:程序博客网 时间:2024/06/07 02:20

四叉树是一种常用的空间分割技术,主要用于地形的瓦片,创建三维模型的lod等。

废话少说,直接上代码:


被访问者:这里我们把访问的总体空间进行抽象。

用户在构造函数中需要输入范围和分层的级数

这里的osg::bouidngbox 是osg里面的类,用户也可以自定义自己的范围类,如下例子

class CBoudingBox

{

public:

     double xMin;

     double yMin;

     double zMin;

     double xMax;

     double yMax;

     double zMax;

}


//被访问者定义如下: accept 定义需要接受一个访问者来对被访问者的访问

CLodArea.h

class CLodArea
{
public:
 CLodArea(int level, osg::BoundingBox bb);

 virtual void accept(CLodAreaVisitor& visitor);
 
 //getter
 osg::BoundingBox getBoundingBox();

 int getLevel();

private:
 //lod的级数
 int level;
 osg::BoundingBox bb;
};


CLodArea.cpp


CLodArea::CLodArea(int level, osg::BoundingBox bb)
{
 this->level = level;
 this->bb = bb;
}

void CLodArea::accept(CLodAreaVisitor& visitor) //虚函数 
{
 visitor.visit(*this);
}


osg::BoundingBox CLodArea::getBoundingBox()
{
 return bb;
}

int CLodArea::getLevel()
{
 return level;
}


//访问者定义如下: 核心是apply,这里使用一个虚函数,允许用户继承后进行使用apply自定义自己的对于范围的处理方法,访问者把访问到的范围提供给apply,这里的遍历方式采用前序遍历,在遍历过程中,有个类似于栈的东西对遍历的父节点序号进行保存。

CLodAreaVisitor.h


class CLodAreaVisitor
{
public:
 void visit(CLodArea& s);

protected:
 virtual bool apply(std::vector<osg::BoundingBox> vecBoudingBox, int curLevel)
 {
  return true;
 }

 //进行遍历 四叉树 
 virtual void visitQuatree(osg::BoundingBox bb, int currentLevel = 1);

protected:
 //计算四叉树区域
 virtual std::vector<osg::BoundingBox> calQuatreeArea(osg::BoundingBox bb);

 virtual void pushOntoIndexPath(int i);

 virtual void popFromIndexPath();

 virtual IndexPath obtainIndexPath();

protected:
 IndexPath indexPath;

private:
 int level;
};


ClodAreaVisitor.cpp


void CLodAreaVisitor::visit(CLodArea& s)
{
 this->level = s.getLevel();
 osg::BoundingBox bb = s.getBoundingBox();
 
 //采用四叉树
 //visitQuatree(bb);
}

void CLodAreaVisitor::visitQuatree(osg::BoundingBox bb, int currentLevel)
{
 if (currentLevel > level) //递归超过最后一级
 {
  return;
 }

 std::vector<osg::BoundingBox> vecBoudingBox = calQuatreeArea(bb);

 //进行处理
 bool isSuccess = apply(vecBoudingBox, currentLevel);

 if (!isSuccess)
 {
  return;
 }

 for (int i = 0; i < vecBoudingBox.size(); i++)
 {
  pushOntoIndexPath(i);
  //递归下一级
  visitQuatree(vecBoudingBox[i], currentLevel + 1);

  popFromIndexPath();
 }
}

std::vector<osg::BoundingBox> CLodAreaVisitor::calQuatreeArea(osg::BoundingBox bb)
{
 //获取范围
 double xMin = bb.xMin();
 double yMin = bb.yMin();

 double xMax = bb.xMax();
 double yMax = bb.yMax();

 double xLength = xMax - xMin;
 double yLength = yMax - yMin;

 //计算分割间隔
 double xInterval = 0.5 * xLength;
 double yInterval = 0.5 * yLength;

 //计算分割范围
 std::vector<osg::BoundingBox> vecBoudingBox;

 for (int yIndex = 0; yIndex < 2; yIndex++)
 {
  for (int xIndex = 0; xIndex < 2; xIndex++)
  {
   double xBlockMin = xMin + xIndex * xInterval;
   double xBlockMax = xBlockMin + xInterval;

   double yBlockMin = yMin + yIndex * yInterval;
   double yBlockMax = yBlockMin + yInterval;

   osg::Vec3d xyzBlockMin(xBlockMin, yBlockMin, 0);
   osg::Vec3d xyzBlockMax(xBlockMax, yBlockMax, 0);
   osg::BoundingBox blockBb;
   blockBb.set(xyzBlockMin, xyzBlockMax);
   vecBoudingBox.push_back(blockBb);
  }
 }

 return vecBoudingBox;
}

void CLodAreaVisitor::pushOntoIndexPath(int i)
{
 indexPath.push_back(i);
}

void CLodAreaVisitor::popFromIndexPath()
{
 indexPath.pop_back();
}

IndexPath CLodAreaVisitor::obtainIndexPath()
{
 return indexPath;
}




0 0
原创粉丝点击