zoukankan      html  css  js  c++  java
  • 关于NodeVisitor访问者模式

    OSG通过对NodeVisitor的使用,实现了GOF的Visitor的模式.在Osg的实现中,这个模式实现了双派发.所以在Node中有一个虚方法为apply(NodeVisitor),而在NodeVisitor中有一个方法apply(Node&).这两个方法的调用是有区别的.我们应该总是调用Node::accept而别使用NodeVisitor::apply.因为只有调用前者才能享受到双派发的能力.(Node的具体类型和NodeVisitor的具体类型都参与到了Visitor模式)

    那么我们就从Node::accept的方法看起:

    void Node::accept(NodeVisitor& nv)
    {
        if (nv.validNodeMask(*this)) 
        {
            nv.pushOntoNodePath(this);
            nv.apply(*this);
            nv.popFromNodePath();
        }
    }

    这个方法很简单,

    1)首先nv会根据NodeMask来检查这个结点是否需要传递给当前的NodeVisitor.

    2)处理NodePath,让当前被apply的节点成为NodePath中最后一个节点,NodePath将是一个从顶级根节点到当前节点的序列.

    3)调用apply

    4)恢复NodePath

    这里涉及到NodeMask和NodePath的处理,在后面我们越来越了解Osg的时候,我们再来分析它们的作用,目前暂且不管.

    可以看出要使用NodeVisitor来遍历场景图,只需要自己定义一个NodeVisitor派生来 然后对着用Viewer的Node调用accept就可以了.

    下面是一个很简单的例子:我们写一个NodeVisitor来将系统中的非Geode都过滤掉,让系统恢复到最原始的几何世界:

    1.首先定义我们的类HowtoNodeVisitor从NodeVisitor派生:

    #pragma once
    #include "stdafx.h"
    class HowtoNodeVisitor :
      public NodeVisitor
    {
    public:
      HowtoNodeVisitor(void);
      ~HowtoNodeVisitor(void);
    
      void apply(Geode& node);
      Group* getFilterResult(){return mNodeGroup.get();}
    
    private:  
      ref_ptr<Group> mNodeGroup;
    };

    2.实现这个类的代码也极为简单:

    #include "StdAfx.h"
    #include "HowtoNodeVisitor.h"
    
    HowtoNodeVisitor::HowtoNodeVisitor(void):NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
    {
      mNodeGroup=new Group();
    }
    
    HowtoNodeVisitor::~HowtoNodeVisitor(void)
    {
    }
    void HowtoNodeVisitor::apply(Geode& node)
    {
      if(this->mNodeGroup->containsNode(&node)){
        return;
      }else{
        this->mNodeGroup->addChild(&node);
      }  
    }

    3.下面是使用的代码:

    #include "stdafx.h"
    #include "HowtoNodeVisitor.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        Viewer* viewer=new Viewer();
      //Node* rootNode=osgDB::readNodeFile("cow.osg");
      //Node* rootNode=osgDB::readNodeFile("axes.osg");
      Node* rootNode=osgDB::readNodeFile("spaceship.osg");
    
      HowtoNodeVisitor visitor;
      rootNode->accept(visitor);
      rootNode=visitor.getFilterResult();
    
      viewer->setSceneData (rootNode);
      viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
      viewer->addEventHandler (new StatsHandler());
     
      viewer->realize();
      return viewer->run();
    }

    如果把有下划线的那三行代码注释掉,你会看到一个喷火的航天飞机.但是加上我们的代码后,这个飞机就不喷火了. 因为喷火不是Geode结点能直接做出来的.

    这个例子很简单,目的在于展示NodeVisitor这种模式. 实际上NodeVisitor本身并不简单,去读源代码就知道了,那个类还是比较大的.

  • 相关阅读:
    spider
    python 2.X
    django 创建项目
    NameError: name 'pip' is not defined
    异常捕获
    @property
    node-Telnet
    ES6-模块化
    高级排序算法之双路快速排序
    高级排序算法之快速排序
  • 原文地址:https://www.cnblogs.com/lizhengjin/p/1673841.html
Copyright © 2011-2022 走看看