module.hh 3.13 KB
Newer Older
Joseph Mirabel's avatar
Joseph Mirabel committed
1
2
3
#ifndef DYNAMIC_GRAPH_PYTHON_MODULE_HH
#define DYNAMIC_GRAPH_PYTHON_MODULE_HH

4
5
6
7
8
#ifdef PINOCCHIO_WITH_URDFDOM
// If pinocchio is used, we have to include pinocchio header before boost mpl
#include <pinocchio/fwd.hpp>
#endif

Guilhem Saurel's avatar
Guilhem Saurel committed
9
10
#include <dynamic-graph/entity.h>

Joseph Mirabel's avatar
Joseph Mirabel committed
11
#include <boost/mpl/for_each.hpp>
12
#include <boost/mpl/vector.hpp>
Guilhem Saurel's avatar
Guilhem Saurel committed
13
#include <boost/python.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed
14
15
16
17
18
#include <dynamic-graph/python/dynamic-graph-py.hh>

namespace dynamicgraph {
namespace python {

Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
19
constexpr int AddSignals = 1;
Joseph Mirabel's avatar
Joseph Mirabel committed
20
21
constexpr int AddCommands = 2;

22
23
namespace internal {

Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
24
template <typename T, int Options = AddCommands | AddSignals>
25
26
27
28
29
bp::object makeEntity1(const char* name) {
  Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
  assert(dynamic_cast<T*>(ent) != NULL);
  bp::object obj(bp::ptr(static_cast<T*>(ent)));
  if (Options & AddCommands) entity::addCommands(obj);
Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
30
  if (Options & AddSignals) entity::addSignals(obj);
31
32
  return obj;
}
Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
33
34
35
template <typename T, int Options = AddCommands | AddSignals>
bp::object makeEntity2() {
  return makeEntity1<T, Options>("");
36
37
}

Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
38
39
}  // namespace internal

Joseph Mirabel's avatar
Joseph Mirabel committed
40
41
42
43
44
45
/// \tparam Options by default, all the signals and commands are added as
///         attribute to the Python object. This behaviour works fine for
///         entities that have static commands and signals.
///         If some commands or signals are added or removed dynamiccally, then
///         it is better to disable the default behaviour and handle it
///         specifically.
Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
46
47
48
49
50
template <typename T, typename bases = boost::python::bases<dynamicgraph::Entity>,
          int Options = AddCommands | AddSignals>
inline auto exposeEntity() {
  // std::string hiddenClassName ("_" + T::CLASS_NAME);
  std::string hiddenClassName(T::CLASS_NAME);
Joseph Mirabel's avatar
Joseph Mirabel committed
51
  namespace bp = boost::python;
Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
52
  bp::class_<T, bases, boost::noncopyable> obj(hiddenClassName.c_str(), bp::init<std::string>());
Joseph Mirabel's avatar
Joseph Mirabel committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  /* TODO at the moment, I couldn't easily find a way to define a Python constructor
   * that would create the entity via the factory and then populate the
   * python object with its commands.
   * This is achieved with a factory function of the same name.
  obj.def ("__init__", bp::raw_function(+[](bp::object args, bp::dict) {
          if (bp::len(args) != 2)
            throw std::length_error("Expected 2 arguments.");
          bp::object self = args[0];
          self.attr("__init__")(bp::extract<std::string>(args[1]));
          Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
          if (dynamic_cast<T*>(ent) == NULL)
            std::cout << "foo" << std::endl;
          assert(dynamic_cast<T*>(ent) != NULL);
          self = bp::object(bp::ptr(static_cast<T*>(ent)));
          //dynamicgraph::Entity& unused = bp::extract<dynamicgraph::Entity&>(self);
          //entity::addCommands(self);
        })
  ;
  */
72
73
  bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity1<T, Options>);
  bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity2<T, Options>);
74
75
  if (!(Options & AddCommands)) obj.def("add_commands", &entity::addCommands);
  if (!(Options & AddSignals)) obj.def("add_signals", &entity::addSignals);
Joseph Mirabel's avatar
Joseph Mirabel committed
76
77
78
  return obj;
}

Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
79
80
}  // namespace python
}  // namespace dynamicgraph
Joseph Mirabel's avatar
Joseph Mirabel committed
81

Guilhem Saurel's avatar
Format    
Guilhem Saurel committed
82
#endif  // DYNAMIC_GRAPH_PYTHON_MODULE_HH