MIRA
EigenHelpers.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_TOOLBOXES_PYTHON_EIGENHELPERS_H_
48 #define _MIRA_TOOLBOXES_PYTHON_EIGENHELPERS_H_
49 
50 #include <transform/Pose.h>
51 #include <geometry/Point.h>
52 #include <geometry/Size.h>
53 
54 #include <utils/ToString.h>
55 #include <python/UnitWrapper.h>
56 
57 #if BOOST_VERSION >= 106500
58  #define TYPE_WITH_ALIGNMENT boost::python::detail::type_with_alignment
59  #define ALIGNMENT_OF boost::python::detail::alignment_of
60 
61  #define IS_CLASS boost::python::detail::is_class
62  #define IS_UNION boost::python::detail::is_union
63 #else
64  #define TYPE_WITH_ALIGNMENT type_with_alignment
65  #define ALIGNMENT_OF ::boost::alignment_of
66 
67  #define IS_CLASS is_class
68  #define IS_UNION is_union
69 #endif
70 
71 // Py_SET_SIZE was added in Python 3.9, must be used from Python 3.11:
72 // https://docs.python.org/3/c-api/structures.html#c.Py_SET_SIZE
73 #if PY_VERSION_HEX >= 0x03090000
74  #define SET_SIZE(DEST, SRC) Py_SET_SIZE(DEST, SRC)
75 #else
76  #define SET_SIZE(DEST, SRC) Py_SIZE(DEST) = SRC
77 #endif
78 
79 // Note: Boost.Python 1.77ff seems to try to respect alignment of exposed types by itself,
80 // see https://github.com/boostorg/python/commit/aca3c80c4f80dd3d52219e1ee299e08bb980bcfd
81 // so this entire helper may not be required anymore at some time
82 
83 #if BOOST_VERSION >= 107700
84  #define INSTANCE_STORAGE_ADDRESS &instance->storage.bytes
85 #else
86  #define INSTANCE_STORAGE_ADDRESS &instance->storage
87 #endif
88 
89 // Fix alignment issues when exposing Eigen classes or classes with Eigen members to python
90 // see http://fhtagn.net/prog/2015/04/16/quaternion_boost_python.html
91 #define BOOST_PYTHON_ALIGN(DataType, Name) \
92 typedef boost::python::objects::value_holder<DataType> Name##Holder; \
93 namespace boost { namespace python { namespace objects { \
94 template<> \
95 struct instance<Name##Holder> \
96 { \
97  typedef Name##Holder Data; \
98  PyObject_VAR_HEAD \
99  PyObject* dict; \
100  PyObject* weakrefs; \
101  instance_holder* objects; \
102  typedef typename TYPE_WITH_ALIGNMENT< \
103  ALIGNMENT_OF<Data>::value \
104  >::type align_t; \
105  union \
106  { \
107  align_t align; \
108  char bytes[sizeof(Data) + 16]; \
109  } storage; \
110 }; \
111 template<class Derived> \
112 struct make_instance_impl<DataType, Name##Holder, Derived> \
113 { \
114  typedef DataType T; \
115  typedef Name##Holder Holder; \
116  typedef objects::instance<Holder> instance_t; \
117  template <class Arg> \
118  static inline PyObject* execute(Arg& x) \
119  { \
120  BOOST_MPL_ASSERT((mpl::or_<IS_CLASS<T>, IS_UNION<T> >)); \
121  PyTypeObject* type = Derived::get_class_object(x); \
122  if (type == 0) \
123  return python::detail::none(); \
124  PyObject* raw_result = type->tp_alloc( \
125  type, objects::additional_instance_size<Holder>::value); \
126  if (raw_result != 0) \
127  { \
128  python::detail::decref_guard protect(raw_result); \
129  instance_t* instance = (instance_t*)raw_result; \
130  Holder* holder = Derived::construct( \
131  INSTANCE_STORAGE_ADDRESS, (PyObject*)instance, x); \
132  holder->install(raw_result); \
133  size_t holder_offset = reinterpret_cast<size_t>(holder) \
134  - reinterpret_cast<size_t>(INSTANCE_STORAGE_ADDRESS) \
135  + offsetof(instance_t, storage); \
136  SET_SIZE(instance, holder_offset); \
137  protect.cancel(); \
138  } \
139  return raw_result; \
140  } \
141 }; \
142 template<> \
143 struct make_instance<DataType, Name##Holder> \
144  : make_instance_impl<DataType, Name##Holder, make_instance<DataType,Name##Holder> > \
145 { \
146  typedef DataType T; \
147  typedef Name##Holder Holder; \
148  template <class U> \
149  static inline PyTypeObject* get_class_object(U&) \
150  { \
151  return converter::registered<T>::converters.get_class_object(); \
152  } \
153  static inline Holder* construct(void* storage, PyObject* instance, reference_wrapper<T const> x) \
154  { \
155  void* aligned_storage = reinterpret_cast<void*>( \
156  (reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16); \
157  Holder* new_holder = new (aligned_storage) Holder(instance, x); \
158  return new_holder; \
159  } \
160 }; \
161 }}}
162 
173 
174 using Matrix6f = Eigen::Matrix<float,6,6>;
176 
177 namespace mira {
178 namespace python {
179 
181 
182 template<typename Derived>
184 
185  static std::string str(const Derived& m) {
186  return toString(m);
187  }
188 
189  static int rows(const Derived& m) {
190  return m.rows();
191  }
192 };
193 
194 template<typename Derived>
195 struct EigenMatrixAccessor : public EigenBaseAccessor<Derived> {
196 
197  static typename Derived::Scalar get(const Derived& m, int row, int col) {
198  return m(row, col);
199  }
200 
201  static void set(Derived& m, int row, int col,
202  typename Derived::Scalar value) {
203  m(row, col) = value;
204  }
205 
206  static int cols(const Derived& m) {
207  return m.cols();
208  }
209 };
210 
211 template<typename Derived>
212 struct EigenVectorAccessor : public EigenBaseAccessor<Derived> {
213  static typename Derived::Scalar get(const Derived& m, int row) {
214  return m(row);
215  }
216 
217  static void set(Derived& m, int row,
218  typename Derived::Scalar value) {
219  m(row) = value;
220  }
221 };
222 
231 template<typename M>
233 {
234  static M Zero()
235  {
236  return M::Zero();
237  }
238 };
239 
240 template<>
241 struct ZeroMatrix<Eigen::VectorXf>
242 {
243  static Eigen::VectorXf Zero(int rows)
244  {
245  return Eigen::VectorXf::Zero(rows);
246  }
247 };
248 
249 template<>
250 struct ZeroMatrix<Eigen::MatrixXf>
251 {
252  static Eigen::MatrixXf Zero(int rows, int cols)
253  {
254  return Eigen::MatrixXf::Zero(rows, cols);
255  }
256 };
257 
259 
260 template<typename M>
262 {
263  static void expose(const std::string& name)
264  {
265  using namespace boost::python;
266 
267  class_<M>(name.c_str(), init<>())
268  .def("cols", &EigenMatrixAccessor<M>::cols)
269  .def("rows", &EigenMatrixAccessor<M>::rows)
270  .def("get", &EigenMatrixAccessor<M>::get)
271  .def("set", &EigenMatrixAccessor<M>::set)
272  .def("zeros", &ZeroMatrix<M>::Zero).staticmethod("zeros")
273  .def("__repr__", &EigenMatrixAccessor<M>::str)
275  ;
276  }
277 };
278 
279 
281 
282 } /* namespace python */
283 } /* namespace mira */
284 
285 #endif /* _MIRA_TOOLBOXES_PYTHON_EIGENHELPERS_H_ */
Quaternion< float > Quaternionf
static Eigen::VectorXf Zero(int rows)
Definition: EigenHelpers.h:243
ZeroMatrix serves 2 purposes:
Definition: EigenHelpers.h:232
Definition: EigenHelpers.h:183
Point< int, 2 > Point2i
Definition: EigenHelpers.h:195
#define MIRA_PYTHONCONNECTOR_NAMED_TYPE_FOOTER(type, name)
static M Zero()
Definition: EigenHelpers.h:234
Definition: EigenHelpers.h:212
std::string toString(const T &value, int precision=-1)
Point< int, 3 > Point3i
static std::string str(const Derived &m)
Definition: EigenHelpers.h:185
Definition: EigenHelpers.h:261
RigidTransformCov< float, 3 > PoseCov3
static void expose(const std::string &name)
Definition: EigenHelpers.h:263
static Eigen::MatrixXf Zero(int rows, int cols)
Definition: EigenHelpers.h:252
static int cols(const Derived &m)
Definition: EigenHelpers.h:206
Python wrapper for MIRA units.
#define BOOST_PYTHON_ALIGN(DataType, Name)
Definition: EigenHelpers.h:91
static int rows(const Derived &m)
Definition: EigenHelpers.h:189