Skip to content
Snippets Groups Projects
Commit af0bf067 authored by Joan Solà Ortega's avatar Joan Solà Ortega
Browse files

Put factories in less files.

parent 0dd12897
No related branches found
No related tags found
1 merge request!313WIP: Resolve "Processor constructors and creators requiring a sensor pointer?"
......@@ -245,7 +245,6 @@ SET(HDRS_LANDMARK
include/core/landmark/landmark_match.h
)
SET(HDRS_PROCESSOR
include/core/processor/autoconf_processor_factory.h
include/core/processor/motion_buffer.h
include/core/processor/processor_base.h
include/core/processor/processor_diff_drive.h
......@@ -261,7 +260,6 @@ SET(HDRS_PROCESSOR
include/core/processor/track_matrix.h
)
SET(HDRS_SENSOR
include/core/sensor/autoconf_sensor_factory.h
include/core/sensor/sensor_base.h
include/core/sensor/sensor_diff_drive.h
include/core/sensor/sensor_factory.h
......@@ -368,6 +366,7 @@ SET(SRCS_SOLVER
)
SET(SRCS_YAML
src/yaml/processor_odom_3D_yaml.cpp
src/yaml/sensor_odom_2D_yaml.cpp
src/yaml/sensor_odom_3D_yaml.cpp
)
#OPTIONALS
......
......@@ -157,7 +157,6 @@ namespace wolf
{
WOLF_REGISTER_PROCESSOR("RANGE BEARING", ProcessorRangeBearing)
} // namespace wolf
#include "core/processor/autoconf_processor_factory.h"
namespace wolf
{
WOLF_REGISTER_PROCESSOR_AUTO("RANGE BEARING", ProcessorRangeBearing)
......
......@@ -56,7 +56,6 @@ namespace wolf
{
WOLF_REGISTER_SENSOR("RANGE BEARING", SensorRangeBearing)
} // namespace wolf
#include "core/sensor/autoconf_sensor_factory.h"
namespace wolf
{
WOLF_REGISTER_SENSOR_AUTO("RANGE BEARING", SensorRangeBearing)
......
......@@ -19,8 +19,8 @@ struct ProcessorParamsBase;
#include "core/frame/frame_base.h"
#include "core/state_block/state_block.h"
#include "core/utils/params_server.hpp"
#include "core/sensor/autoconf_sensor_factory.h"
#include "core/processor/autoconf_processor_factory.h"
#include "core/sensor/sensor_factory.h"
#include "core/processor/processor_factory.h"
// std includes
#include <mutex>
......
/**
* \file processor_factory.h
*
* Created on: May 4, 2016
* \author: jsola
*/
#ifndef AUTOCONF_PROCESSOR_FACTORY_H_
#define AUTOCONF_PROCESSOR_FACTORY_H_
namespace wolf
{
class ProcessorBase;
struct ProcessorParamsBase;
}
// wolf
#include "core/common/factory.h"
// std
namespace wolf
{
/** \brief Processor factory class
*
* This factory can create objects of classes deriving from ProcessorBase.
*
* 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 ProcessorFactory class is a singleton: it can only exist once in your application.
* To obtain an instance of it, use the static method get(),
*
* \code
* ProcessorFactory::get()
* \endcode
*
* You can then call the methods you like, e.g. to create a processor, you type:
*
* \code
* ProcessorFactory::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.
*
* 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.:
*
* \code
* ProcessorFactory::get().registerCreator("ODOM 2D", 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, ProcessorParamsBasePtr,
* that can be derived for each derived processor.
*
* Here is an example of ProcessorOdom2D::create() extracted from processor_odom_2D.h:
*
* \code
* static ProcessorBasePtr create(const std::string& _name, ProcessorParamsBasePtr _params)
* {
* // cast _params to good type
* ProcessorParamsOdom2D* params = (ProcessorParamsOdom2D*)_params;
*
* ProcessorBasePtr prc = new ProcessorOdom2D(params);
* prc->setName(_name); // pass the name to the created ProcessorOdom2D.
* return prc;
* }
* \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:
*
* \code
* const bool registered_odom_2D = ProcessorFactory::get().registerCreator("ODOM 2D", ProcessorOdom2D::create);
* \endcode
*
* 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.
*
* #### Unregister processor creators
* The method unregisterCreator() unregisters the ProcessorXxx::create() method.
* It only needs to be passed the string of the processor type.
*
* \code
* ProcessorFactory::get().unregisterCreator("ODOM 2D");
* \endcode
*
* #### Creating processors
* 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
* ProcessorFactory::get().create("ODOM 2D", "main odometry", params_ptr);
* \endcode
*
* #### Example 1 : using the Factories alone
* We provide the necessary steps to create a processor of class ProcessorOdom2D in our application,
* and bind it to a SensorOdom2D:
*
* \code
* #include "sensor_odom_2D.h" // provides SensorOdom2D and SensorFactory
* #include "processor_odom_2D.h" // provides ProcessorOdom2D and ProcessorFactory
*
* // Note: SensorOdom2D::create() is already registered, automatically.
* // Note: ProcessorOdom2D::create() is already registered, automatically.
*
* // First create the sensor (See SensorFactory for details)
* SensorBasePtr sensor_ptr = SensorFactory::get().create ( "ODOM 2D" , "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:
*
* ProcessorParamsOdom2D params({...}); // fill in the derived struct (note: ProcessorOdom2D actually has no input params)
*
* ProcessorBasePtr processor_ptr =
* ProcessorFactory::get().create ( "ODOM 2D" , "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 "sensor_odom_2D.h"
* #include "processor_odom_2D.h"
* #include "problem.h"
*
* Problem problem(FRM_PO_2D);
* problem.installSensor ( "ODOM 2D" , "Main odometer" , extrinsics , &intrinsics );
* problem.installProcessor ( "ODOM 2D" , "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 ParamsServer&> AutoConfProcessorFactory;
template<>
inline std::string AutoConfProcessorFactory::getClass()
{
return "AutoConfProcessorFactory";
}
#define WOLF_REGISTER_PROCESSOR_AUTO(ProcessorType, ProcessorName) \
namespace{ const bool WOLF_UNUSED ProcessorName##AutoConf##Registered = \
wolf::AutoConfProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::createAutoConf); }\
} /* namespace wolf */
#endif /* PROCESSOR_FACTORY_H_ */
......@@ -174,9 +174,23 @@ inline std::string ProcessorFactory::getClass()
return "ProcessorFactory";
}
#define WOLF_REGISTER_PROCESSOR(ProcessorType, ProcessorName) \
namespace{ const bool WOLF_UNUSED ProcessorName##Registered = \
wolf::ProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::create); }\
#define WOLF_REGISTER_PROCESSOR(ProcessorType, ProcessorName) \
namespace{ const bool WOLF_UNUSED ProcessorName##Registered = \
wolf::ProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::create); } \
typedef Factory<ProcessorBase,
const std::string&,
const ParamsServer&> AutoConfProcessorFactory;
template<>
inline std::string AutoConfProcessorFactory::getClass()
{
return "AutoConfProcessorFactory";
}
#define WOLF_REGISTER_PROCESSOR_AUTO(ProcessorType, ProcessorName) \
namespace{ const bool WOLF_UNUSED ProcessorName##AutoConfRegistered = \
wolf::AutoConfProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::createAutoConf); } \
} /* namespace wolf */
......
/**
* \file sensor_factory.h
*
* Created on: Apr 25, 2016
* \author: jsola
*/
#ifndef AUTOCONF_SENSOR_FACTORY_H_
#define AUTOCONF_SENSOR_FACTORY_H_
namespace wolf
{
class SensorBase;
struct IntrinsicsBase;
}
// wolf
#include "core/common/factory.h"
namespace wolf
{
/** \brief Sensor factory class
*
* This factory can create objects of classes deriving from SensorBase.
*
* Specific object creation is invoked by ````create(TYPE, params ... )````, and the TYPE of sensor is identified with a string.
* Currently, the following sensor types are implemented,
* - "CAMERA" for SensorCamera
* - "ODOM 2D" for SensorOdom2D
* - "GPS FIX" for SensorGPSFix
*
* The rule to make new TYPE strings unique is that you skip the prefix 'Sensor' from your class name,
* and you build a string in CAPITALS with space separators, e.g.:
* - SensorCamera -> ````"CAMERA"````
* - SensorLaser2D -> ````"LASER 2D"````
* - etc.
*
* The methods to create specific sensors are called __creators__.
* Creators must be registered to the factory before they can be invoked for sensor creation.
*
* This documentation shows you how to:
* - Access the factory
* - Register and unregister creators
* - Create sensors
* - Write a sensor creator for SensorCamera (example).
*
* #### Accessing the factory
* The SensorFactory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application.
* To obtain an instance of it, use the static method get(),
*
* \code
* SensorFactory::get()
* \endcode
*
* You can then call the methods you like, e.g. to create a sensor, you type:
*
* \code
* SensorFactory::get().create(...); // see below for creating sensors ...
* \endcode
*
* #### Registering sensor creators
* Prior to invoking the creation of a sensor of a particular type,
* you must register the creator for this type into the factory.
*
* Registering sensor creators into the factory is done through registerCreator().
* You provide a sensor type string (above), and a pointer to a static method
* that knows how to create your specific sensor, e.g.:
*
* \code
* SensorFactory::get().registerCreator("CAMERA", SensorCamera::create);
* \endcode
*
* The method SensorCamera::create() exists in the SensorCamera class as a static method.
* All these ````SensorXxx::create()```` methods need to have exactly the same API, regardless of the sensor type.
* This API includes a sensor name, a vector of extrinsic parameters,
* and a pointer to a base struct of intrinsic parameters, IntrinsicsBasePtr,
* that can be derived for each derived sensor:
*
* \code
* static SensorBasePtr create(const std::string& _name, Eigen::VectorXs& _extrinsics_pq, IntrinsicsBasePtr _intrinsics)
* \endcode
*
* See further down for an implementation example.
*
* #### Achieving automatic registration
* Currently, registering is performed in each specific SensorXxxx source file, sensor_xxxx.cpp.
* For example, in sensor_camera.cpp we find the line:
*
* \code
* const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create);
* \endcode
*
* which is a static invocation (i.e., it is placed at global scope outside of the SensorCamera class).
* Therefore, at application level, all sensors that have a .cpp file compiled are automatically registered.
*
* #### Unregistering sensor creators
* The method unregisterCreator() unregisters the SensorXxx::create() method. It only needs to be passed the string of the sensor type.
*
* \code
* SensorFactory::get().unregisterCreator("CAMERA");
* \endcode
*
* #### Creating sensors
* Note: Prior to invoking the creation of a sensor of a particular type,
* you must register the creator for this type into the factory.
*
* To create e.g. a SensorCamera, you type:
*
* \code
* SensorFactory::get().create("CAMERA", "Front-left camera", extrinsics, intrinsics_ptr);
* \endcode
*
* where ABSOLUTELY ALL input parameters are important. In particular, the sensor name "Front-left camera" will be used to identify this camera
* and to assign it the appropriate processors. DO NOT USE IT WITH DUMMY PARAMETERS!
*
* #### See also
* - IntrinsicsFactory: to create intrinsic structs deriving from IntrinsicsBase directly from YAML files.
* - ProcessorFactory: to create processors that will be bound to sensors.
* - Problem::installSensor() : to install sensors in WOLF Problem.
*
* #### Example 1: writing a specific sensor creator
* Here is an example of SensorCamera::create() extracted from sensor_camera.cpp:
*
* \code
* static SensorBasePtr create(const std::string& _name, Eigen::VectorXs& _extrinsics_pq, IntrinsicsBasePtr _intrinsics)
* {
* // check extrinsics vector
* assert(_extrinsics_pq.size() == 7 && "Bad extrinsics vector length. Should be 7 for 3D.");
*
* // cast instrinsics to good type
* IntrinsicsCamera* intrinsics_ptr = (IntrinsicsCamera*) _intrinsics;
*
* // Do create the SensorCamera object, and complete its setup
* SensorCamera* sen_ptr = new SensorCamera(_extrinsics_pq, intrinsics_ptr);
* sen_ptr->setName(_unique_name);
*
* return sen_ptr;
* }
* \endcode
*
* #### Example 2: registering a sensor creator into the factory
* Registration can be done manually or automatically. It involves the call to static functions.
* It is advisable to put these calls within unnamed namespaces.
*
* - __Manual registration__: you control registration at application level.
* Put the code either at global scope (you must define a dummy variable for this),
* \code
* namespace {
* const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create);
* }
* main () { ... }
* \endcode
* or inside your main(), where a direct call is possible:
* \code
* main () {
* SensorFactory::get().registerCreator("CAMERA", SensorCamera::create);
* ...
* }
* \endcode
*
* - __Automatic registration__: registration is performed at library level.
* Put the code at the last line of the sensor_xxx.cpp file,
* \code
* namespace {
* const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create);
* }
* \endcode
* Automatic registration is recommended in wolf, and implemented in the classes shipped with it.
* You are free to comment out these lines and place them wherever you consider it more convenient for your design.
*
* #### Example 2: creating sensors
* We finally provide the necessary steps to create a sensor of class SensorCamera in our application:
*
* \code
* #include "sensor_factory.h"
* #include "sensor_camera.h" // provides SensorCamera
*
* // Note: SensorCamera::create() is already registered, automatically.
*
* using namespace wolf;
* int main() {
*
* // To create a camera, provide:
* // a type = "CAMERA",
* // a name = "Front-left camera",
* // an extrinsics vector, and
* // a pointer to the intrinsics struct:
*
* Eigen::VectorXs extrinsics_1(7); // give it some values...
* IntrinsicsCamera intrinsics_1({...}); // see IntrinsicsFactory to fill in the derived struct
*
* SensorBasePtr camera_1_ptr =
* SensorFactory::get().create ( "CAMERA" , "Front-left camera" , extrinsics_1 , &intrinsics_1 );
*
* // A second camera... with a different name!
*
* Eigen::VectorXs extrinsics_2(7);
* IntrinsicsCamera intrinsics_2({...});
*
* SensorBasePtr camera_2_ptr =
* SensorFactory::get().create( "CAMERA" , "Front-right camera" , extrinsics_2 , &intrinsics_2 );
*
* return 0;
* }
* \endcode
*
* You can also check the code in the example file ````src/examples/test_wolf_factories.cpp````.
*/
typedef Factory<SensorBase,
const std::string&,
const ParamsServer&> AutoConfSensorFactory;
template<>
inline std::string AutoConfSensorFactory::getClass()
{
return "AutoConfSensorFactory";
}
#define WOLF_REGISTER_SENSOR_AUTO(SensorType, SensorName) \
namespace{ const bool WOLF_UNUSED SensorName##AutConf##Registered = \
AutoConfSensorFactory::get().registerCreator(SensorType, SensorName::createAutoConf); } \
} /* namespace wolf */
#endif /* SENSOR_FACTORY_H_ */
......@@ -218,9 +218,25 @@ inline std::string SensorFactory::getClass()
return "SensorFactory";
}
#define WOLF_REGISTER_SENSOR(SensorType, SensorName) \
namespace{ const bool WOLF_UNUSED SensorName##Registered = \
SensorFactory::get().registerCreator(SensorType, SensorName::create); }\
#define WOLF_REGISTER_SENSOR(SensorType, SensorName) \
namespace{ const bool WOLF_UNUSED SensorName##Registered = \
SensorFactory::get().registerCreator(SensorType, SensorName::create); } \
typedef Factory<SensorBase,
const std::string&,
const ParamsServer&> AutoConfSensorFactory;
template<>
inline std::string AutoConfSensorFactory::getClass()
{
return "AutoConfSensorFactory";
}
#define WOLF_REGISTER_SENSOR_AUTO(SensorType, SensorName) \
namespace{ const bool WOLF_UNUSED SensorName##AutoConfRegistered = \
AutoConfSensorFactory::get().registerCreator(SensorType, SensorName::createAutoConf); } \
} /* namespace wolf */
......
......@@ -176,7 +176,6 @@ FactorBasePtr ProcessorDiffDrive::emplaceFactor(FeatureBasePtr _feature,
namespace wolf {
WOLF_REGISTER_PROCESSOR("DIFF DRIVE", ProcessorDiffDrive)
} // namespace wolf
#include "core/processor/autoconf_processor_factory.h"
namespace wolf {
WOLF_REGISTER_PROCESSOR_AUTO("DIFF DRIVE", ProcessorDiffDrive)
} // namespace wolf
......
......@@ -176,7 +176,6 @@ FeatureBasePtr ProcessorOdom2D::emplaceFeature(CaptureMotionPtr _capture_motion)
namespace wolf {
WOLF_REGISTER_PROCESSOR("ODOM 2D", ProcessorOdom2D)
} // namespace wolf
#include "core/processor/autoconf_processor_factory.h"
namespace wolf {
WOLF_REGISTER_PROCESSOR_AUTO("ODOM 2D", ProcessorOdom2D)
} // namespace wolf
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment