infoReader

Introduction

In icosahedronViewer, we defined a new simple X3D node that had no child. This is an example on how to create a parent node, meaning a node that can have children. For more details about the API, see the scene graph API page. Here we define an X3DTK::X3D::Info node that can contain two nodes, X3DTK::X3D::Price and X3DTK::X3D::Modeler. We also define a new X3DTK::Date type for the X3DTK::X3D::Info node.

Some important functions and classes:

Defining a new X3D::Date type

We show how to define a new type. Here we define a date type with three integer attributes: day, month and year. Two methods are necessary to define: a constructor from a X3DTK::SFString and a toSFString. These methods are used to load and write the type. We also overload the ostream operator to facilitate the use of the type.

Declaration of the XDTK::Date type:

struct Date { public: Date(); explicit Date(const SFString &date); SFString toSFString() const; int day; int month; int year; }; std::ostream& X3DTK::operator<<(std::ostream& o, const Date &date);
The constructor from an X3DTK::SFString is made explicit to avoid implicit conversion. Notice that the assignement operator is implicitly defined, however you may define it, because it is used for the X3DTK::X3DAbstractNode::clone method. The implementation of these methods are not X3DToolKit specific, nevertheless notice the difference between the ostream operator and the toSFString method. Unlike the ostream operator, the toSFString method returns a string beginning and ending with the '"' character. This is the string written in the X3D file.

Defining X3D::Info

We define a new node which has two children. Let's see the X3DTK::X3D::Info declaration:
class Info : public X3DChildNode { public: Info(); virtual ~Info(); void setDate(const Date &date); inline const Date &getDate() const {return _date;}; inline Price *getPrice() const {return _price;}; inline Modeler *getModeler() const {return _modeler;}; private: Date _date; Price *_price; Modeler *_modeler; };
A node is defined by its attributes which can be atomic attributes or child nodes. An attribute of X3DTK::Date type is defined for which a set and get method are defined. For the child nodes, only a get method is defined. Indeed a generic X3DTK::X3DAbstractNode::setChild method is provided.

Concerning the body definition of the constructor:

Info::Info() : X3DChildNode() { define(Recorder<Info>::getTypeName("Info")); define(Recorder<Info, Date>::getAttribute("date", &Info::_date, Date())); define(Recorder<Info, Price>::getSFNode("price", &Info::_price)); define(Recorder<Info, Modeler>::getSFNode("modeler", &Info::_modeler)); }
Type name, atomic attributes and child nodes are recorded thanks to the overloaded X3DTK::X3DAbstractNode::define function and the template Recorder class that collects necessary informations for the automated X3DTK::X3DAbstractNode::clone, X3DTK::X3DAbstractNode::setChild, X3DTK::X3DAbstractNode::getChildList methods. Notice that the order of which child nodes are recorded appeared is important because, it defines the traversal order. It means that in a graph traversal the X3DTK::X3D::Price node is traversed before the X3DTK::X3D::Modeler node.

The destructor is very simple:

Info::Info() { removeChildren(); }
A call to X3DTK::X3DAbstractNode::removeChildren is just needed. The links between the node and its children are broken.

Defining X3D::Price and X3D::Modeler

These nodes are simple child nodes and are defined like the nodes of the previous examples.

Defining X3D::MyGroupingCreator

To load the new nodes, the creator for the new Grouping component is defined. The declaration of the class is simple:
class MyGroupingCreator : public GroupingCreator { public: MyGroupingCreator(); };

The body is also very simple:

MyGroupingCreator::MyGroupingCreator() : GroupingCreator() { define(Recorder<Info>::getCreationFunction()); }
The recording of the node is made thanks to the template recorder class. the syntax is very similar to the recording of the attributes and of the callback functions (see the simpleNodeCounter example).

Defining a new simple processor

To test our new scene graph, we define a new processor called X3DTK::X3D::InfoReader that extracts and displays the content of the nodes X3DTK::X3D::Info, X3DTK::X3D::Price and X3DTK::X3D::Modeler. You can refer to glNormalViewer for an example page of processor creation.

Code

Date.h

#ifndef DATE_H
#define DATE_H

#include <X3DTK/kernel.h>

namespace X3DTK {

struct Date
{
public:
  Date();
  explicit Date(const SFString &date);
  SFString toSFString() const;

  int day;
  int month;
  int year;    
};

std::ostream& X3DTK::operator<<(std::ostream& o, const Date &date);

}

#endif

Date.cpp

#include "Date.h"
#include <iostream>

using namespace std;

namespace X3DTK {

Date::Date()
: day(0), month(0), year(0)
{
}

Date::Date(const SFString &date)
{
  SFString d, m, y;
  
  m = date.substr(0, 2);
  d = date.substr(3, 2);
  y = date.substr(6, 2);

  day = d.toInt();
  month = m.toInt();
  year = y.toInt();
}

SFString Date::toSFString() const
{
  SFString m = SFString::number(month);
  SFString d = SFString::number(day);
  SFString y = SFString::number(year);
  
  if (m.size() == 1)
    m = '0' + m;
  if (d.size() == 1)
    d = '0' + d;
  if (y.size() == 1)
    y = '0' + y;
  
  return "\"" + m + "/" + d + "/" + y + "\"";
}

std::ostream& X3DTK::operator<<(std::ostream& o, const Date &date)
{
  return o << date.month << "/" << date.day << "/" << date.year;
}

}

X3D_Info.h

#ifndef INFO_H
#define INFO_H

#include <X3DTK/X3D/scenegraph.h>
#include "Date.h"

namespace X3DTK {
namespace X3D {

class Price;
class Modeler;

// Info node.

class Info : public X3DChildNode
{
public:
  Info();
  virtual ~Info();
  
  void setDate(const Date &date);

  inline const Date &getDate() const {return _date;};
  inline Price *getPrice() const {return _price;};
  inline Modeler *getModeler() const {return _modeler;};  

private:
  Date _date;
  Price *_price;
  Modeler *_modeler;
};

}
}

#endif

X3D_Info.cpp

#include "X3D_Info.h"
#include "X3D_Price.h"
#include "X3D_Modeler.h"

namespace X3DTK {
namespace X3D {

Info::Info()
: X3DChildNode()
{
  // Defines the tag of the node. This string is the one read in the X3D file.
  define(Recorder<Info>::getTypeName("Info"));
  
  // Defines an attribute.
  define(Recorder<Info, Date>::getAttribute("date", &Info::_date, Date()));
  
  // Defines a child node.
  define(Recorder<Info, Price>::getSFNode("price", &Info::_price));
  define(Recorder<Info, Modeler>::getSFNode("modeler", &Info::_modeler));
}

Info::~Info()
{
  removeChidlren();
}

void Info::setDate(const Date &date)
{
  _date = date;
}

}
}

X3D_Price.h

#ifndef PRICE_H
#define PRICE_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

// Price node.

class Price : public X3DChildNode
{
public:
  Price();
  virtual ~Price();

  void setPrice(const SFFloat &price);
  void setMoney(const SFString &money);

  inline const SFFloat &getPrice() const {return _price;};
  inline const SFString &getMoney() const {return _money;};
 
private:
  SFFloat _price;
  SFString _money;
};

}
}

#endif

X3D_Price.cpp

#include "X3D_Price.h"

namespace X3DTK {
namespace X3D {

Price::Price()
: X3DChildNode()
{
  // Defines the tag of the node. This string is the one read in the X3D file.
  define(Recorder<Price>::getTypeName("Price"));
  
  // Defines the attributes.
  define(Recorder<Price, SFFloat>::getAttribute("price", &Price::_price, 0.0f));
  define(Recorder<Price, SFString>::getAttribute("money", &Price::_money, "euro"));
}

Price::~Price()
{
}

void Price::setPrice(const SFFloat &price)
{
  _price = price;
}

void Price::setMoney(const SFString &money)
{
  _money = money;
}

}
}

X3D_Modeler.h

#ifndef MODELER_H
#define MODELER_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

// Modeler child node of Info.

class Modeler : public X3DChildNode
{
public:
  Modeler();
  virtual ~Modeler();
  
  void setMName(const SFString &name);

  inline const SFString &getMName() const {return _mname;};
 
private:
  SFString _mname;
};

}
}

#endif

X3D_Modeler.cpp

#include "X3D_Modeler.h"

namespace X3DTK {
namespace X3D {

Modeler::Modeler()
: X3DChildNode()
{
  // Defines the tag of the node. This string is the one read in the X3D file.
  define(Recorder<Modeler>::getTypeName("Modeler", "MyComponent"));
  
  // Defines an attribute.
  define(Recorder<Modeler, SFString>::getAttribute("mname", &Modeler::_mname, ""));
}

Modeler::~Modeler()
{
}

void Modeler::setMName(const SFString &name)
{
  _mname = name;
}

}
}

X3D_MyGroupingCreator.h

#ifndef MYGROUPINGCREATOR_H
#define MYGROUPINGCREATOR_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

// Component creator deriving the Grouping component creator defining the default 
// X3D nodes, plus the new ones.

class MyGroupingCreator : public GroupingCreator
{
public:
  // Constructor.
  MyGroupingCreator();
};

}
}

#endif

X3D_MyGroupingCreator.cpp

#include "X3D_MyGroupingCreator.h"
#include "X3D_Info.h"

namespace X3DTK {
namespace X3D {

MyGroupingCreator::MyGroupingCreator()
: GroupingCreator()
{
  // Defines the new nodes.
  define(Recorder<Info>::getCreationFunction());
}

}
}

X3D_InfoReaderGroupingVisitor.h

#ifndef INFOREADERGROUPINGVISITOR_H
#define INFOREADERGROUPINGVISITOR_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

class Info;
class Price;
class Modeler;

// Visitor for the Grouping component of the InfoReader processor.

class InfoReaderGroupingVisitor : public GroupingVisitor
{
public:
  InfoReaderGroupingVisitor();

  static void enterInfo(Info *I);
  static void enterPrice(Price *P);
  static void enterModeler(Modeler *M);
};

}
}

#endif

X3D_InfoReaderGroupingVisitor.cpp

#include "X3D_InfoReaderGroupingVisitor.h"
#include "X3D_Info.h"
#include "X3D_Price.h"
#include "X3D_Modeler.h"

#include <iostream>

using namespace std;

namespace X3DTK {
namespace X3D {

InfoReaderGroupingVisitor::InfoReaderGroupingVisitor()
: GroupingVisitor()
{
  // Enter functions.
  define(Recorder<Info>::getEnterFunction(&InfoReaderGroupingVisitor::enterInfo));
  define(Recorder<Price>::getEnterFunction(&InfoReaderGroupingVisitor::enterPrice));
  define(Recorder<Modeler>::getEnterFunction(&InfoReaderGroupingVisitor::enterModeler));    
}

void InfoReaderGroupingVisitor::enterInfo(Info *I)
{
  cout << "Informations relative to the scene:"<< endl;
  cout << "Date = " << I->getDate() << endl;
}

void InfoReaderGroupingVisitor::enterPrice(Price *P)
{
  cout << "  price = " << P->getPrice() << " " << P->getMoney() << endl;
}

void InfoReaderGroupingVisitor::enterModeler(Modeler *M)
{
  cout << "  realized on the " << M->getMName() << " modeler" << endl;
}

}
}

X3D_InfoReader.h

#ifndef INFOREADER_H
#define INFOREADER_H

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

namespace X3DTK {
namespace X3D {

// InfoReader processor.

class InfoReader : public X3DOnePassProcessor
{
public:
  InfoReader();
  
  virtual void read(SFNode N);
};

}
}

#endif

X3D_InfoReader.cpp

#include "X3D_InfoReader.h"
#include "X3D_InfoReaderGroupingVisitor.h"

namespace X3DTK {
namespace X3D {

InfoReader::InfoReader()
{
  // new GraphTraversal.
  setGraphTraversal(new DFSGraphTraversal());
  // Setting the new component visitor.
  setComponentVisitor(new InfoReaderGroupingVisitor());
}

void InfoReader::read(SFNode N)
{
  traverse(N);
}

}
}

main.cpp

#include "X3D_InfoReader.h"
#include "X3D_MyGroupingCreator.h"

#include <X3DTK/X3D/scenegraph.h>
#include <X3DTK/X3D/scenesaver.h>
#include <iostream>

using namespace X3DTK;
using namespace std;

int main(int argc, char *argv[])
{
  if (argc <= 1)
  {
    cerr << "usage: infoReader input" << endl;
    exit(0);
  }
  
  // DefaultLoader to load the default X3D Nodes.
  X3D::Loader *loader = Singleton<X3D::Loader>::getInstance();
  loader->setComponentCreator(new X3D::MyGroupingCreator());
  
  // Instanciation of the new InfoReader.
  X3D::InfoReader *infoReader = Singleton<X3D::InfoReader>::getInstance();

  X3D::SceneSaver *saver = Singleton<X3D::SceneSaver>::getInstance();
  
  // Loads the scene.
  X3D::Scene *s = loader->load(argv[1], false);
  // reads the graph.
  infoReader->read(s);
  saver->saveAs(s, "myfile.x3d");
  
  // Removes the instances.
  Singleton<X3D::InfoReader>::removeInstance();
  Singleton<X3D::InfoReader>::removeInstance();
      
  return 1;
}

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