1 |
|
|
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS. |
2 |
|
|
|
3 |
|
|
#include <dynamic-graph/linear-algebra.h> |
4 |
|
|
#include <dynamic-graph/signal-base.h> |
5 |
|
|
#include <dynamic-graph/signal-ptr.h> |
6 |
|
|
#include <dynamic-graph/signal-time-dependent.h> |
7 |
|
|
#include <dynamic-graph/signal.h> |
8 |
|
|
#include <dynamic-graph/value.h> |
9 |
|
|
|
10 |
|
|
#include <boost/python.hpp> |
11 |
|
|
#include <iostream> |
12 |
|
|
#include <sstream> |
13 |
|
|
|
14 |
|
|
#include "dynamic-graph/python/dynamic-graph-py.hh" |
15 |
|
|
#include "dynamic-graph/python/signal-wrapper.hh" |
16 |
|
|
#include "dynamic-graph/python/signal.hh" |
17 |
|
|
|
18 |
|
|
using dynamicgraph::SignalBase; |
19 |
|
|
|
20 |
|
|
namespace bp = boost::python; |
21 |
|
|
|
22 |
|
|
namespace dynamicgraph { |
23 |
|
|
namespace python { |
24 |
|
|
|
25 |
|
|
typedef int time_type; |
26 |
|
|
|
27 |
|
|
typedef Eigen::AngleAxis<double> VectorUTheta; |
28 |
|
|
typedef Eigen::Quaternion<double> Quaternion; |
29 |
|
|
|
30 |
|
|
typedef Eigen::VectorXd Vector; |
31 |
|
|
typedef Eigen::Vector3d Vector3; |
32 |
|
|
typedef Eigen::Matrix<double, 7, 1> Vector7; |
33 |
|
|
|
34 |
|
|
typedef Eigen::MatrixXd Matrix; |
35 |
|
|
typedef Eigen::Matrix<double, 3, 3> MatrixRotation; |
36 |
|
|
typedef Eigen::Matrix<double, 4, 4> Matrix4; |
37 |
|
|
typedef Eigen::Transform<double, 3, Eigen::Affine> MatrixHomogeneous; |
38 |
|
|
typedef Eigen::Matrix<double, 6, 6> MatrixTwist; |
39 |
|
|
|
40 |
|
|
template <typename Time> |
41 |
|
2 |
void exposeSignalBase(const char* name) { |
42 |
|
|
typedef SignalBase<Time> S_t; |
43 |
✓✗ |
2 |
bp::class_<S_t, boost::noncopyable>(name, bp::no_init) |
44 |
|
|
.add_property("time", |
45 |
|
|
bp::make_function( |
46 |
|
|
&S_t::getTime, |
47 |
|
|
bp::return_value_policy<bp::copy_const_reference>()), |
48 |
|
|
&S_t::setTime) |
49 |
✓✗ |
6 |
.add_property("name", |
50 |
|
|
bp::make_function( |
51 |
|
|
&S_t::getName, |
52 |
|
|
bp::return_value_policy<bp::copy_const_reference>())) |
53 |
|
|
|
54 |
✓✗✓✗ ✓✗ |
6 |
.def("getName", &S_t::getName, |
55 |
|
|
bp::return_value_policy<bp::copy_const_reference>()) |
56 |
|
|
.def( |
57 |
|
|
"getClassName", |
58 |
|
|
+[](const S_t& s) -> std::string { |
59 |
|
|
std::string ret; |
60 |
|
|
s.getClassName(ret); |
61 |
|
|
return ret; |
62 |
|
|
}) |
63 |
|
|
|
64 |
✓✗✓✗
|
2 |
.def("plug", &S_t::plug, "Plug the signal to another signal") |
65 |
|
4 |
.def("unplug", &S_t::unplug, "Unplug the signal") |
66 |
✓✗ |
2 |
.def("isPlugged", &S_t::isPlugged, "Whether the signal is plugged") |
67 |
✓✗ |
2 |
.def("getPlugged", &S_t::getPluged, |
68 |
|
|
bp::return_value_policy<bp::reference_existing_object>(), |
69 |
|
|
"To which signal the signal is plugged") |
70 |
|
|
|
71 |
✓✗ |
2 |
.def("recompute", &S_t::recompute, "Recompute the signal at given time") |
72 |
|
|
|
73 |
✓✗ |
2 |
.def( |
74 |
|
|
"__str__", |
75 |
|
|
+[](const S_t& s) -> std::string { |
76 |
|
|
std::ostringstream oss; |
77 |
|
|
s.display(oss); |
78 |
|
|
return oss.str(); |
79 |
|
|
}) |
80 |
✓✗✓✗
|
4 |
.def( |
81 |
|
|
"displayDependencies", |
82 |
|
|
+[](const S_t& s, int time) -> std::string { |
83 |
|
|
std::ostringstream oss; |
84 |
|
|
s.displayDependencies(oss, time); |
85 |
|
|
return oss.str(); |
86 |
|
|
}, |
87 |
|
|
"Print the signal dependencies in a string"); |
88 |
|
2 |
} |
89 |
|
|
|
90 |
|
|
template <> |
91 |
|
2 |
auto exposeSignal<MatrixHomogeneous, time_type>(const std::string& name) { |
92 |
|
|
typedef Signal<MatrixHomogeneous, time_type> S_t; |
93 |
|
|
bp::class_<S_t, bp::bases<SignalBase<time_type> >, boost::noncopyable> obj( |
94 |
✓✗ |
2 |
name.c_str(), bp::init<std::string>()); |
95 |
|
|
obj.add_property( |
96 |
|
|
"value", |
97 |
|
|
+[](const S_t& signal) -> Matrix4 { |
98 |
|
|
return signal.accessCopy().matrix(); |
99 |
|
|
}, |
100 |
|
|
+[](S_t& signal, const Matrix4& v) { |
101 |
|
|
// TODO it isn't hard to support pinocchio::SE3 type here. |
102 |
|
|
// However, this adds a dependency to pinocchio. |
103 |
|
|
signal.setConstant(MatrixHomogeneous(v)); |
104 |
|
|
}, |
105 |
✓✗ |
2 |
"the signal value."); |
106 |
|
2 |
return obj; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
2 |
void exposeSignals() { |
110 |
|
2 |
exposeSignalBase<time_type>("SignalBase"); |
111 |
|
|
|
112 |
✓✗✓✗
|
2 |
exposeSignalsOfType<bool, time_type>("Bool"); |
113 |
✓✗✓✗
|
2 |
exposeSignalsOfType<int, time_type>("Int"); |
114 |
✓✗✓✗
|
2 |
exposeSignalsOfType<double, time_type>("Double"); |
115 |
|
|
|
116 |
✓✗✓✗
|
2 |
exposeSignalsOfType<Vector, time_type>("Vector"); |
117 |
✓✗✓✗
|
2 |
exposeSignalsOfType<Vector3, time_type>("Vector3"); |
118 |
✓✗✓✗
|
2 |
exposeSignalsOfType<Vector7, time_type>("Vector7"); |
119 |
|
|
|
120 |
✓✗✓✗
|
2 |
exposeSignalsOfType<Matrix, time_type>("Matrix"); |
121 |
✓✗✓✗
|
2 |
exposeSignalsOfType<MatrixRotation, time_type>("MatrixRotation"); |
122 |
✓✗✓✗
|
2 |
exposeSignalsOfType<MatrixHomogeneous, time_type>("MatrixHomogeneous"); |
123 |
✓✗✓✗
|
2 |
exposeSignalsOfType<MatrixTwist, time_type>("MatrixTwist"); |
124 |
|
|
|
125 |
✓✗✓✗
|
2 |
exposeSignalsOfType<Quaternion, time_type>("Quaternion"); |
126 |
✓✗✓✗
|
2 |
exposeSignalsOfType<VectorUTheta, time_type>("VectorUTheta"); |
127 |
|
2 |
} |
128 |
|
|
|
129 |
|
|
namespace signalBase { |
130 |
|
|
|
131 |
|
|
template <class T> |
132 |
|
|
SignalWrapper<T, int>* createSignalWrapperTpl(const char* name, bp::object o, |
133 |
|
|
std::string& error) { |
134 |
|
|
typedef SignalWrapper<T, int> SignalWrapper_t; |
135 |
|
|
if (!SignalWrapper_t::checkCallable(o, error)) { |
136 |
|
|
return NULL; |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
SignalWrapper_t* obj = new SignalWrapper_t(name, o); |
140 |
|
|
return obj; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
PythonSignalContainer* getPythonSignalContainer() { |
144 |
|
|
Entity* obj = entity::create("PythonSignalContainer", "python_signals"); |
145 |
|
|
return dynamic_cast<PythonSignalContainer*>(obj); |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
#define SIGNAL_WRAPPER_TYPE(IF, Enum, Type) \ |
149 |
|
|
IF(command::Value::typeName(command::Value::Enum).compare(type) == 0) { \ |
150 |
|
|
obj = createSignalWrapperTpl<Type>(name, object, error); \ |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
/** |
154 |
|
|
\brief Create an instance of SignalWrapper |
155 |
|
|
*/ |
156 |
|
|
SignalBase<int>* createSignalWrapper(const char* name, const char* type, |
157 |
|
|
bp::object object) { |
158 |
|
|
PythonSignalContainer* psc = getPythonSignalContainer(); |
159 |
|
|
if (psc == NULL) return NULL; |
160 |
|
|
|
161 |
|
|
SignalBase<int>* obj = NULL; |
162 |
|
|
std::string error; |
163 |
|
|
SIGNAL_WRAPPER_TYPE(if, BOOL, bool) |
164 |
|
|
// SIGNAL_WRAPPER_TYPE(else if, UNSIGNED ,bool) |
165 |
|
|
SIGNAL_WRAPPER_TYPE(else if, INT, int) |
166 |
|
|
SIGNAL_WRAPPER_TYPE(else if, FLOAT, float) |
167 |
|
|
SIGNAL_WRAPPER_TYPE(else if, DOUBLE, double) |
168 |
|
|
// SIGNAL_WRAPPER_TYPE(else if, STRING ,bool) |
169 |
|
|
SIGNAL_WRAPPER_TYPE(else if, VECTOR, Vector) |
170 |
|
|
// SIGNAL_WRAPPER_TYPE(else if, MATRIX ,bool) |
171 |
|
|
// SIGNAL_WRAPPER_TYPE(else if, MATRIX4D ,bool) |
172 |
|
|
else { |
173 |
|
|
error = "Type not understood"; |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
if (obj == NULL) throw std::runtime_error(error); |
177 |
|
|
// Register signal into the python signal container |
178 |
|
|
psc->signalRegistration(*obj); |
179 |
|
|
|
180 |
|
|
// Return the pointer |
181 |
|
|
return obj; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
} // namespace signalBase |
185 |
|
|
} // namespace python |
186 |
|
|
} // namespace dynamicgraph |