SEARCH
TOOLBOX
LANGUAGES
ObjectFactory

ObjectFactory

From SOFAWiki

Jump to: navigation, search
The ObjectFactory

The ObjectFactory is mostly a register which gives a correspondancy between a component name and a function pointer to a method able to construct that object. It is located in the sofacore library.

Contents

Registering a component

In SOFA a component is a class which has sofa::core::objectmodel::BaseObject in its class inheritance hierarchy. In order to make your component available in SOFA you have to call the registration method of the ObjectFactory, and use two macros SOFA_DECL_CLASS and SOFA_LINK_CLASS whose purpose is to make sure that the code which actually registers the component in the factory is called in the output binary.

The summary of the steps to follow is here :

  • Add a : SOFA_DECL_CLASS(NewComponent) in your .cpp file, NewComponent being the class name of your component.
  • Register the component: it is generally done in the .cpp of your new component class.

if your component is not template:

#include <sofa/core/ObjectFactory.h>
 
 int NewComponentClass = sofa::core::RegisterObject("Description of your component")
.add< NewComponentClass >();

if your component is template with Vec3dTypes and Vec3fTypes (for instance)

 int NewComponentClass = sofa::core::RegisterObject("Description of your component")
.add< NewComponent<Vec3dTypes> >()
.add< NewComponent<Vec3fTypes> >()
;
  • Add a : SOFA_LINK_CLASS(NewComponent) in the init file.
    • If you chose to put your components directly inside SOFA modules directories you will find a file called initNameCategoryComponent.cpp with NameCategoryComponent being the category of your component: ForceField, Constraint, Mapping ... This is were you put the SOFA_LINK_CLASS macro
    • If you are writing a plugin, you have to call in the SOFA_LINK_CLASS macro from your initMyPlugin.cpp.

The documentation about the methods regarding the registration component can be found in the doxygen documentation of the sofa::core::RegisterObject class. link to api doc

The ObjectFactory and the XML (MechanicalObject example)

For a given instance of SOFA we can know what are the available components by looking at the ObjectFactory entries. An entry in the ObjectFactory can point to multiple constructors, which happens to be useful when you write components which depend on a template parameter. For example if we look at the .cpp of sofa::component::container::MechanicalObject :

int MechanicalObjectClass = core::RegisterObject("mechanical state vectors")
#ifdef SOFA_FLOAT
.add< MechanicalObject<Vec3fTypes> >(true) // default template
#else
.add< MechanicalObject<Vec3dTypes> >(true) // default template
#ifndef SOFA_DOUBLE
.add< MechanicalObject<Vec3fTypes> >()
#endif
#endif
#ifndef SOFA_FLOAT
.add< MechanicalObject<Vec2dTypes> >()
.add< MechanicalObject<Vec1dTypes> >()
.add< MechanicalObject<Vec6dTypes> >()
.add< MechanicalObject<Rigid3dTypes> >()
.add< MechanicalObject<Rigid2dTypes> >()
#endif
#ifndef SOFA_DOUBLE
.add< MechanicalObject<Vec2fTypes> >()
.add< MechanicalObject<Vec1fTypes> >()
.add< MechanicalObject<Vec6fTypes> >()
.add< MechanicalObject<Rigid3fTypes> >()
.add< MechanicalObject<Rigid2fTypes> >()
#endif
.add< MechanicalObject<LaparoscopicRigid3Types> >()
;

We can see that the same entry "MechanicalObject" has multiple flavor depending on the template parameter, and that the default entry points to a

  • sofa::component::container::MechanicalObject<Vec3fTypes> if SOFA is compiled in float mode
  • sofa::component::container::MechanicalObject<Vec3dTypes> if SOFA is compiled in double mode

When you write a SOFA scene in XML this means that such a line

<MechanicalObject />

will be translated by the default instance of MechanicalObject registered in the ObjectFactory.

If you want a specific flavor of MechanicalObject, you have to specify it by using the template attribute in the XML.

<MechanicalObject template="Rigid" />

This will produce a MechanicalObject<Rigid3dTypes> if SOFA is compiled with double and MechanicalObject<Rigid3fTypes> otherwise The template attribute is resolved using the templateName method. Ultimately for a RigidType in 3D ( ie Rigid3dTypes Rigid3fTypes) this points to :

        /// Note: Many scenes use Rigid as template for 3D double-precision rigid type. Changing it to Rigid3d would break backward compatibility.
#ifdef SOFA_FLOAT
        template<> inline const char* Rigid3dTypes::Name() { return "Rigid3d"; }
        template<> inline const char* Rigid3fTypes::Name() { return "Rigid"; }
#else
        template<> inline const char* Rigid3dTypes::Name() { return "Rigid"; }
        template<> inline const char* Rigid3fTypes::Name() { return "Rigid3f"; }
#endif

Using the ObjectFactory createObject method from c++ code

The createObject method

objectmodel::BaseObject::SPtr ObjectFactory::createObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg)

The method needs two parameters  :

Example of the TetrahedronFEMForceField

    sofa::core::objectmodel::BaseObjectDescription options("myFF1","TetrahedronFEMForceField");
    options.setAttribute("youngModulus", "10000");
    BaseForceField* ff = dynamic_cast<BaseForceField*>(sofa::core::ObjectFactory::CreateObject(node, &options));