Skip to content
Snippets Groups Projects

Resolve "Factory documentation"

Merged Joan Solà Ortega requested to merge 299-factory-documentation into devel
1 file
+ 42
103
Compare changes
  • Side-by-side
  • Inline
@@ -27,143 +27,92 @@ namespace wolf
*
* Specific object creation is invoked by create(TYPE, params), and the TYPE of processor is identified with a string.
* For example, the following processor types are implemented,
* - "ODOM 3d" for ProcessorOdom3d
* - "ODOM 2d" for ProcessorOdom2d
* - "GPS" for ProcessorGPS
*
* The rule to make new TYPE strings unique is that you skip the prefix 'Processor' from your class name,
* and you build a string in CAPITALS with space separators.
* - ProcessorImageFeature -> ````"IMAGE"````
* - ProcessorLaser2d -> ````"LASER 2d"````
* - etc.
*
* The methods to create specific processors are called __creators__.
* Creators must be registered to the factory before they can be invoked for processor creation.
*
* This documentation shows you how to:
* - Access the Factory
* - Register and unregister creators
* - Create processors
* - Write a processor creator for ProcessorOdom2d (example).
*
* #### Accessing the Factory
* The FactoryProcessor class is a singleton: it can only exist once in your application.
* To obtain an instance of it, use the static method get(),
*
* \code
* FactoryProcessor::get()
* \endcode
* - "ProcessorOdom2d" for ProcessorOdom2d
* - "ProcessorOdom3d" for ProcessorOdom3d
* - "ProcessorDiffDrive" for ProcessorDiffDrive
*
* You can then call the methods you like, e.g. to create a processor, you type:
*
* \code
* FactoryProcessor::get().create(...); // see below for creating processors ...
* \endcode
*
* #### Registering processor creators
* Prior to invoking the creation of a processor of a particular type,
* you must register the creator for this type into the factory.
* among others.
*
* Registering processor creators into the factory is done through registerCreator().
* You provide a processor type string (above), and a pointer to a static method
* that knows how to create your specific processor, e.g.:
* Find general Factory documentation in class Factory:
* - Access the factory
* - Register/unregister creators
* - Invoke object creation
*
* \code
* FactoryProcessor::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create);
* \endcode
*
* The method ProcessorOdom2d::create() exists in the ProcessorOdom2d class as a static method.
* All these ProcessorXxx::create() methods need to have exactly the same API, regardless of the processor type.
* This API includes a processor name, and a pointer to a base struct of parameters, ParamsProcessorBasePtr,
* that can be derived for each derived processor.
* This documentation shows you how to use the FactoryProcessor specifically:
* - Write a processor creator
* - Create processors
*
* Here is an example of ProcessorOdom2d::create() extracted from processor_odom_2d.h:
* #### Write processor creators
* Processor creators have the following API:
*
* \code
* static ProcessorBasePtr create(const std::string& _name, ParamsProcessorBasePtr _params)
* {
* // cast _params to good type
* ParamsProcessorOdom2d* params = (ParamsProcessorOdom2d*)_params;
*
* ProcessorBasePtr prc = new ProcessorOdom2d(params);
* prc->setName(_name); // pass the name to the created ProcessorOdom2d.
* return prc;
* }
* static ProcessorBasePtr create(const std::string& _name, ParamsProcessorBasePtr _params_processor);
* \endcode
*
* #### Achieving automatic registration
* Currently, registering is performed in each specific ProcessorXxxx source file, processor_xxxx.cpp.
* For example, in processor_odom_2d.cpp we find the line:
* They follow the general implementation shown below:
*
* \code
* const bool registered_odom_2d = FactoryProcessor::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create);
* \endcode
* static ProcessorBasePtr create(const std::string& _unique_name, ParamsProcessorBasePtr _params_processor)
* {
* // cast processor parameters to good type --- example: ParamsProcessorOdom3d
* auto params_processor_ptr = std::static_pointer_cast<ParamsProcessorOdom3d>(_params_processor);
*
* which is a static invocation (i.e., it is placed at global scope outside of the ProcessorOdom2d class).
* Therefore, at application level, all processors that have a .cpp file compiled are automatically registered.
* // Do create the Processor object --- example: ProcessorOdom3d
* auto prc_ptr = std::make_shared<ProcessorOdom3d>(params_processor_ptr);
*
* #### Unregister processor creators
* The method unregisterCreator() unregisters the ProcessorXxx::create() method.
* It only needs to be passed the string of the processor type.
* // Complete the processor setup with a unique name identifying the processor
* prc_ptr->setName(_unique_name);
*
* \code
* FactoryProcessor::get().unregisterCreator("ProcessorOdom2d");
* return prc_ptr;
* }
* \endcode
*
* #### Creating processors
* Prior to invoking the creation of a processor of a particular type,
* Note: Prior to invoking the creation of a processor of a particular type,
* you must register the creator for this type into the factory.
*
* To create a ProcessorOdom2d, you type:
*
* \code
* FactoryProcessor::get().create("ProcessorOdom2d", "main odometry", params_ptr);
* auto prc_odom2d_ptr = FactoryProcessor::get().create("ProcessorOdom2d", "main odometry", params_ptr);
* \endcode
*
* #### Example 1 : using the Factories alone
* #### Example 1 : Create a sensor and its processor
* We provide the necessary steps to create a processor of class ProcessorOdom2d in our application,
* and bind it to a SensorOdom2d:
*
* \code
* #include "core/sensor/sensor_odom_2d.h" // provides SensorOdom2d and FactorySensor
* #include "core/sensor/sensor_odom_2d.h" // provides SensorOdom2d and FactorySensor
* #include "core/processor/processor_odom_2d.h" // provides ProcessorOdom2d and FactoryProcessor
*
* // Note: SensorOdom2d::create() is already registered, automatically.
* // Note: ProcessorOdom2d::create() is already registered, automatically.
*
* // First create the sensor (See FactorySensor for details)
* SensorBasePtr sensor_ptr = FactorySensor::get().create ( "FactorOdom2d" , "Main odometer" , extrinsics , &intrinsics );
* SensorBasePtr sensor_ptr = FactorySensor::get().create ( "SensorOdom2d" , "Main odometer" , extrinsics , &intrinsics );
*
* // To create a odometry integrator, provide a type="ODOM 2d", a name="main odometry", and a pointer to the parameters struct:
* // To create a odometry integrator, provide a type="ProcessorOdom2d", a name="main odometry", and a pointer to the parameters struct:
*
* ParamsProcessorOdom2d params({...}); // fill in the derived struct (note: ProcessorOdom2d actually has no input params)
* auto params = make_shared<ParamsProcessorOdom2d>({...}); // fill in the derived struct (note: ProcessorOdom2d actually has no input params)
*
* ProcessorBasePtr processor_ptr =
* FactoryProcessor::get().create ( "ProcessorOdom2d" , "main odometry" , &params );
* FactoryProcessor::get().create ( "ProcessorOdom2d" , "main odometry" , params );
*
* // Bind processor to sensor
* sensor_ptr->addProcessor(processor_ptr);
* \endcode
*
* #### Example 2: Using the helper API in class Problem
* The WOLF uppermost node, Problem, makes the creation of sensors and processors, and the binding between them, even simpler.
*
* The creation is basically replicating the factories' API. The binding is accomplished by passing the sensor name to the Processor installer.
*
* The example 1 above can be accomplished as follows (we obviated for simplicity all the parameter creation),
*
* \code
* #include "core/sensor/sensor_odom_2d.h"
* #include "core/processor/processor_odom_2d.h"
* #include "core/problem/problem.h"
*
* Problem problem(FRM_PO_2d);
* problem.installSensor ( "SensorOdom2d" , "Main odometer" , extrinsics , &intrinsics );
* problem.installProcessor ( "ProcessorOdom2d" , "Odometry" , "Main odometer" , &params );
* \endcode
*
* You can also check the code in the example file ````src/examples/test_wolf_factories.cpp````.
*/
typedef Factory<ProcessorBase,
const std::string&,
const ParamsProcessorBasePtr> FactoryProcessor;
template<>
inline std::string FactoryProcessor::getClass() const
{
return "FactoryProcessor";
}
// ParamsProcessor factory
struct ParamsProcessorBase;
@@ -175,16 +124,6 @@ inline std::string FactoryParamsProcessor::getClass() const
return "FactoryParamsProcessor";
}
// Processor factory
typedef Factory<ProcessorBase,
const std::string&,
const ParamsProcessorBasePtr> FactoryProcessor;
template<>
inline std::string FactoryProcessor::getClass() const
{
return "FactoryProcessor";
}
#define WOLF_REGISTER_PROCESSOR(ProcessorType) \
namespace{ const bool WOLF_UNUSED ProcessorType##Registered = \
wolf::FactoryProcessor::get().registerCreator(#ProcessorType, ProcessorType::create); } \
Loading