SEARCH
TOOLBOX
LANGUAGES
ComponentCreation

ComponentCreation

From SOFAWiki

Jump to: navigation, search
Basic instructions to create a new Component

A SOFA Component is a class deriving, directly or not, from sofa::core::objectmodel::BaseObject.

Contents

Where to put your files

  • The best way to write new components is to integrate them in a new Plugin
  • Conversely you can to place your files next to other existing components, located in Sofa/modules/sofa/components/, in the subdirectory corresponding to the type of your component (forcefield, constraint, linearsolver, ...).


Creating a new component

  • Your components must derive from the sofa::core::objectmodel::BaseObject class or an existing component (e.g: sofa::core::visual::VisualModel ).

In your header file :

#include <sofa/core/objectmodel/BaseObject.h>
 
class MyComponent : public sofa::core::objectmodel::BaseObject
{
public:
SOFA_CLASS(MyComponent ,sofa::core::objectmodel::BaseObject);
 
    MyComponent ();
    virtual ~MyComponent ();
};


Modifications of the .pro file

  • If you chose to put your components directly inside sofa directories (fast and dirty), open the .pro file in the same directory as your component
  • If you have a separated project, then you should already have a .pro file (take example on one of our projects), open this .pro file
  • Modify the opened .pro file by
    • Adding in the HEADERS section, the list of the new .h and .inl files
    • Adding in the SOURCES section, the list of the new .cpp files

Recreate the project

  1. For windows users, you have to run projectVC8.bat or projectVC9.bat depending on your version of Microsoft Visual Studio C++.
  2. For the others, simply run qmake at the Sofa main directory

Build Sofa

Launch the compilation. A good way to verify that your component's creation went well, is to launch the Modeler, and try to find it in the Library. If it doesn't appear, it means probably that you failed to register your component properly

Documentation

A scene has to be created, with the same name as your component, and placed inside Sofa/examples/Components and its good subdirectory. Finally, you can write a small paragraph for the sofa documentation placed in Sofa/doc, and a link to a publication, if any exists.

Basic Component Concepts

We will introduce some of the basic concepts of building a component by creating two example components, ComponentA and ComponentB.

Data

The type Data provides the link between your Component's code and your scene graph. The Data type acts like a wrapper around whatever data type you want to describe in your scene graph and manipulate in your code. Image that in ComponentA, we want to have a string that we can initialize in the scene graph. In our header file, we would define it as follows:

#include <sofa/core/objectmodel/BaseObject.h>
#include <string>
 
class ComponentA : public sofa::core::objectmodel::BaseObject
{
public:
SOFA_CLASS(ComponentA ,sofa::core::objectmodel::BaseObject);
 
    ComponentA ();
    virtual ~ComponentA ();
 
    Data<std::string> stringA;
 
};

Now, we want it to be a parameter in our scene graph, so do not forget to register it in the object constructor, which should look like this:

ComponentA::ComponentA() : stringA(initData(&stringA, "defaultString", "myString", "Our string parameter" ))
{}

The initData function sets the link between the scene graph and our stringup for us. The second argument, "defaultString", is the default value that stringA will be set to if nothing is specified in the scene graph. "myString" is the parameter name in the scene graph. "Our string parameter" is a description of our parameter.

Now, we create a scene graph to use our brand new component and parameter.

<Node name="Root" gravity="0 0 0" dt="1" >
    < ComponentA name="myComponentA" myInt="test string" \>
</Node >

Now, when the scene graph is loaded, an instant of the class ComponentA will be created, and its Data StringA will hold the value "test string".

Accessing Data

Now that we have our parameter initialized from the scene graph, we want to do something with it. Because of the Data wrapper, we can't access our string directly. The getValue() function allows us to do read only computations with our Data.

void ComponentA::myOutputFunction()
{
    std::string tempString = stringA.getValue();
    std::cout << tempString << std::endl;
}

When myOutputFunction() is called on the myComponentA instance of ComponentA, it will output test string.