simpleNodeCounter

Introduction

This an example of how to write a simple processor acting on the X3D scene graph. A processor is a graph traversal and a visitor that applies on each traversed node.

We want to count the number of nodes of an X3D scene.

Some important functions and classes:

X3D::SimpleNodeCounterStateVariables

To memorize the number of visited nodes, we use a state variables class that stores these numbers, and that is accessed by a singleton manager X3DTK::Singleton.

Declaration of the class which inherits X3DTK::StateVariables:

class SimpleNodeCounterStateVariables : public StateVariables { public: SimpleNodeCounterStateVariables(); void init(); void addNode(); inline unsigned int getNodeNumber() const {return _count;}; private: unsigned int _count; };
It is important to have a constructor with no parameter, because the instantiation of the class is accessed by the X3DTK::Singleton class. The definition of the class contains no X3DToolKit specific code.

X3D::SimpleNodeCounterCoreVisitor

We define a visitor for the Core component, because all the nodes of an X3D scene derive from X3DTK::X3D::X3DNode that belong to the Core component.

Declaration of the class which inherits X3DTK::X3D::CoreVisitor:

class SimpleNodeCounterCoreVisitor : public CoreVisitor { public: SimpleNodeCounterCoreVisitor(); static void enterX3DNode(X3DNode *N); };
The callback function is a static enter function taking an X3DTK::X3D::X3DNode in parameter. The function must be static because if you want to reuse this function in another component visitor, you don't need to have a pointer to X3DTK::X3D::SimpleNodeCounterCoreVisitor.

Let's see the definition of the constructor:

SimpleNodeCounterCoreVisitor::SimpleNodeCounterCoreVisitor() : CoreVisitor() { define(Recorder<X3DNode>::getEnterFunction(&SimpleNodeCounterCoreVisitor::enterX3DNode)); }
The body of the constructor contains the most important line: the recording of the callback. The portable syntax is quite complicated. A generic template class X3DTK::Recorder collects informations relative to the function. The member function pointer is used. The line means that an enter function acting on an X3DTK::X3D::X3DNode is defined for X3DTK::X3D::SimpleNodeCounterVisitor.

And now the body of the callback function:

void SimpleNodeCounterCoreVisitor::enterX3DNode(X3DNode *N) { Singleton<SimpleNodeCounterStateVariables>::getInstance()->addNode(); }
The state variables are accessed by the template X3DTK::Singleton class ensuring that they are shared.

X3D::SimpleNodeCounter

This is the facade of the processor which aggregates the visitors of the different components. It also defines the walking algorithm. A constructor, a destructor and a method taking in parameter a sub-graph are usually defined.

Declaration of the class which inherits X3DTK::X3DOnePassProcessor:

class SimpleNodeCounter : public X3DOnePassProcessor { public: SimpleNodeCounter(); virtual ~SimpleNodeCounter(); virtual void count(X3DNode *N); };
It is important to have a constructor with no parameter since it is usual to instantiate the class by a singleton. Methods are made virtual to allow reuse.

Let's have a look at the body of the constructor:

SimpleNodeCounter::SimpleNodeCounter() : X3DOnePassProcessor() { setGraphTraversal(new DFSGraphTraversal()); setComponentVisitor(new SimpleNodeCounterCoreVisitor()); }
The first line assigns a Depth First Search walking algorithm, and the second one adds the component visitor previously defined.

Definition of the destructor:

SimpleNodeCounter::~SimpleNodeCounter() { Singleton<SimpleNodeCounterStateVariables>::removeInstance(); }
The instance of the state variables is removed in the destructor, because it is useless.

Definition of the count method:

void SimpleNodeCounter::count(X3DNode *N) { Singleton<SimpleNodeCounterStateVariables>::getInstance()->init(); traverse(N); cout << "number of nodes is " << Singleton<SimpleNodeCounterStateVariables>::getInstance()->getNodeNumber() << endl; }
The initialisation of the state variables is made as well as the call to the X3DTK::X3DOnePassProcessor::traverse function, launching the graph traversal. It is often very important to have a call to an initialisation function, because of the use of singleton, the state variables are not destroyed at the end of the graph traversal and old values remain.

Code

X3D_SimpleNodeCounterStateVariables.h

#ifndef X3D_SIMPLENODECOUNTERSTATEVARIABLES_H
#define X3D_SIMPLENODECOUNTERSTATEVARIABLES_H

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace X3D {

class SimpleNodeCounterStateVariables : public StateVariables
{
public:
  SimpleNodeCounterStateVariables();
  
  void init();
  void addNode();
  inline unsigned int getNodeNumber() const {return _count;};
  
private:
  unsigned int _count;  
};

}
}

#endif

X3D_SimpleNodeCounterStateVariables.cpp

#include "X3D_SimpleNodeCounterStateVariables.h"

namespace X3DTK {
namespace X3D {

SimpleNodeCounterStateVariables::SimpleNodeCounterStateVariables()
: _count(0)
{
}
 
void SimpleNodeCounterStateVariables::init()
{
  _count = 0;
}

void SimpleNodeCounterStateVariables::addNode()
{
  ++_count;
}

}
}

X3D_SimpleNodeCounterCoreVisitor.h

#ifndef X3D_SIMPLENODECOUNTERCOREVISITOR_H
#define X3D_SIMPLENODECOUNTERCOREVISITOR_H

#include <X3DTK/kernel.h>
#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

class SimpleNodeCounterCoreVisitor : public CoreVisitor
{
public:
  SimpleNodeCounterCoreVisitor();
  
  static void enterX3DNode(X3DNode *N);
};

}
}

#endif

X3D_SimpleNodeCounterCoreVisitor.cpp

#include "X3D_SimpleNodeCounterCoreVisitor.h"
#include "X3D_SimpleNodeCounterStateVariables.h"

namespace X3DTK {
namespace X3D {

SimpleNodeCounterCoreVisitor::SimpleNodeCounterCoreVisitor()
: CoreVisitor()
{
  define(Recorder<X3DNode>::getEnterFunction(&SimpleNodeCounterCoreVisitor::enterX3DNode));
}
  
void SimpleNodeCounterCoreVisitor::enterX3DNode(X3DNode *N)
{
  Singleton<SimpleNodeCounterStateVariables>::getInstance()->addNode();
}

}
}

X3D_SimpleNodeCounter.h

#ifndef X3D_SIMPLENODECOUNTER_H
#define X3D_SIMPLENODECOUNTER_H

#include <X3DTK/kernel.h>
#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

class SimpleNodeCounter : public X3DOnePassProcessor
{
public:
  SimpleNodeCounter();
  virtual ~SimpleNodeCounter();
  
  virtual void count(X3DNode *N);
};

}
}

#endif

X3D_SimpleNodeCounter.cpp

#include "X3D_SimpleNodeCounter.h"
#include "X3D_SimpleNodeCounterCoreVisitor.h"
#include "X3D_SimpleNodeCounterStateVariables.h"
#include <iostream>

using namespace std;

namespace X3DTK {
namespace X3D {

SimpleNodeCounter::SimpleNodeCounter()
: X3DOnePassProcessor()
{
  setGraphTraversal(new DFSGraphTraversal());
  setComponentVisitor(new SimpleNodeCounterCoreVisitor());
}

SimpleNodeCounter::~SimpleNodeCounter()
{
  Singleton<SimpleNodeCounterStateVariables>::removeInstance();
}
  
void SimpleNodeCounter::count(X3DNode *N)
{
  Singleton<SimpleNodeCounterStateVariables>::getInstance()->init();
  traverse(N);
  cout << "number of nodes is " << Singleton<SimpleNodeCounterStateVariables>::getInstance()->getNodeNumber() << endl;
}
  
}
}  

Generated on Fri Jul 30 12:02:33 2004 for X3DToolKit by doxygen 1.3.6