66#ifndef __eigenpy_details_hpp__
77#define __eigenpy_details_hpp__
88
9+ #include " eigenpy/details/rvalue_from_python_data.hpp"
910#include " eigenpy/fwd.hpp"
1011
1112#include < patchlevel.h> // For PY_MAJOR_VERSION
1819
1920#define GET_PY_ARRAY_TYPE (array ) PyArray_ObjectType(reinterpret_cast <PyObject *>(array), 0 )
2021
21-
2222namespace eigenpy
2323{
2424 template <typename SCALAR> struct NumpyEquivalentType {};
@@ -146,33 +146,75 @@ namespace eigenpy
146146 const int rows = (int )PyArray_DIMS (pyArray)[0 ];
147147 const int cols = (int )PyArray_DIMS (pyArray)[1 ];
148148
149- Type * mat_ptr = new (storage) Type (rows,cols);
149+ Type * mat_ptr = new (storage) Type (rows,cols);
150+
151+ if (NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE (pyArray))
152+ {
153+ *mat_ptr = MapNumpy<MatType,Scalar>::map (pyArray); // avoid useless cast
154+ return ;
155+ }
156+
150157 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_INT)
158+ {
151159 *mat_ptr = MapNumpy<MatType,int >::map (pyArray).template cast <Scalar>();
160+ return ;
161+ }
152162
153163 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_LONG)
164+ {
154165 *mat_ptr = MapNumpy<MatType,long >::map (pyArray).template cast <Scalar>();
166+ return ;
167+ }
155168
156169 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_FLOAT)
170+ {
157171 *mat_ptr = MapNumpy<MatType,float >::map (pyArray).template cast <Scalar>();
172+ return ;
173+ }
158174
159175 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_DOUBLE)
176+ {
160177 *mat_ptr = MapNumpy<MatType,double >::map (pyArray).template cast <Scalar>();
178+ return ;
179+ }
161180 }
162181
163- static void convert (Type const & mat , PyArrayObject * pyArray)
182+ // / \brief Copy mat into the Python array using Eigen::Map
183+ template <typename MatrixDerived>
184+ static void convert (const Eigen::MatrixBase<MatrixDerived> & mat_,
185+ PyArrayObject * pyArray)
164186 {
187+ const MatrixDerived & mat = const_cast <const MatrixDerived &>(mat_.derived ());
188+
189+ if (NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE (pyArray))
190+ {
191+ MapNumpy<MatType,Scalar>::map (pyArray) = mat; // no cast needed
192+ return ;
193+ }
194+
165195 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_INT)
196+ {
166197 MapNumpy<MatType,int >::map (pyArray) = mat.template cast <int >();
198+ return ;
199+ }
167200
168201 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_LONG)
202+ {
169203 MapNumpy<MatType,long >::map (pyArray) = mat.template cast <long >();
204+ return ;
205+ }
170206
171207 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_FLOAT)
208+ {
172209 MapNumpy<MatType,float >::map (pyArray) = mat.template cast <float >();
210+ return ;
211+ }
173212
174213 if (GET_PY_ARRAY_TYPE (pyArray) == NPY_DOUBLE)
214+ {
175215 MapNumpy<MatType,double >::map (pyArray) = mat.template cast <double >();
216+ return ;
217+ }
176218 }
177219 };
178220
@@ -186,51 +228,47 @@ namespace eigenpy
186228 static void allocate (PyArrayObject * pyArray, void * storage)
187229 {
188230 typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map (pyArray);
189- new (storage) Type (numpyMap);
231+ new (storage) Type (numpyMap);
190232 }
191233
192- static void convert (Type const & mat , PyArrayObject * pyArray)
234+ static void convert (Type const & mat, PyArrayObject * pyArray)
193235 {
194- if (GET_PY_ARRAY_TYPE (pyArray) == NPY_INT)
195- MapNumpy<MatType,int >::map (pyArray) = mat.template cast <int >();
196-
197- if (GET_PY_ARRAY_TYPE (pyArray) == NPY_LONG)
198- MapNumpy<MatType,long >::map (pyArray) = mat.template cast <long >();
199-
200- if (GET_PY_ARRAY_TYPE (pyArray) == NPY_FLOAT)
201- MapNumpy<MatType,float >::map (pyArray) = mat.template cast <float >();
202-
203- if (GET_PY_ARRAY_TYPE (pyArray) == NPY_DOUBLE)
204- MapNumpy<MatType,double >::map (pyArray) = mat.template cast <double >();
236+ EigenObjectAllocator<MatType>::convert (mat,pyArray);
205237 }
206238 };
207239#endif
240+
208241 /* --- TO PYTHON -------------------------------------------------------------- */
242+
209243 template <typename MatType>
210244 struct EigenToPy
211245 {
212- static PyObject* convert (MatType const & mat)
246+ static PyObject* convert (MatType const & mat)
213247 {
214- typedef typename MatType::Scalar T ;
248+ typedef typename MatType::Scalar Scalar ;
215249 assert ( (mat.rows ()<INT_MAX) && (mat.cols ()<INT_MAX)
216250 && " Matrix range larger than int ... should never happen." );
217251 const int R = (int )mat.rows (), C = (int )mat.cols ();
218252
219253 PyArrayObject* pyArray;
220- if (C == 1 && NumpyType::getType () == ARRAY_TYPE)
254+ // Allocate Python memory
255+ if (C == 1 && NumpyType::getType () == ARRAY_TYPE) // Handle array with a single dimension
221256 {
222257 npy_intp shape[1 ] = { R };
223258 pyArray = (PyArrayObject*) PyArray_SimpleNew (1 , shape,
224- NumpyEquivalentType<T >::type_code);
259+ NumpyEquivalentType<Scalar >::type_code);
225260 }
226261 else
227262 {
228263 npy_intp shape[2 ] = { R,C };
229264 pyArray = (PyArrayObject*) PyArray_SimpleNew (2 , shape,
230- NumpyEquivalentType<T >::type_code);
265+ NumpyEquivalentType<Scalar >::type_code);
231266 }
232267
268+ // Allocate memory
233269 EigenObjectAllocator<MatType>::convert (mat,pyArray);
270+
271+ // Create an instance (either np.array or np.matrix)
234272 return NumpyType::getInstance ().make (pyArray).ptr ();
235273 }
236274 };
@@ -240,28 +278,28 @@ namespace eigenpy
240278 template <typename MatType>
241279 struct EigenFromPy
242280 {
243- // Determine if obj_ptr can be converted in a Eigenvec
244- static void * convertible (PyArrayObject* obj_ptr )
281+ // / \brief Determine if pyObj can be converted into a MatType object
282+ static void * convertible (PyArrayObject* pyObj )
245283 {
246- if (!PyArray_Check (obj_ptr ))
284+ if (!PyArray_Check (pyObj ))
247285 return 0 ;
248286
249287 if (MatType::IsVectorAtCompileTime)
250288 {
251289 // Special care of scalar matrix of dimension 1x1.
252- if (PyArray_DIMS (obj_ptr )[0 ] == 1 && PyArray_DIMS (obj_ptr )[1 ] == 1 )
253- return obj_ptr ;
290+ if (PyArray_DIMS (pyObj )[0 ] == 1 && PyArray_DIMS (pyObj )[1 ] == 1 )
291+ return pyObj ;
254292
255- if (PyArray_DIMS (obj_ptr )[0 ] > 1 && PyArray_DIMS (obj_ptr )[1 ] > 1 )
293+ if (PyArray_DIMS (pyObj )[0 ] > 1 && PyArray_DIMS (pyObj )[1 ] > 1 )
256294 {
257295#ifndef NDEBUG
258296 std::cerr << " The number of dimension of the object does not correspond to a vector" << std::endl;
259297#endif
260298 return 0 ;
261299 }
262300
263- if (((PyArray_DIMS (obj_ptr )[0 ] == 1 ) && (MatType::ColsAtCompileTime == 1 ))
264- || ((PyArray_DIMS (obj_ptr )[1 ] == 1 ) && (MatType::RowsAtCompileTime == 1 )))
301+ if (((PyArray_DIMS (pyObj )[0 ] == 1 ) && (MatType::ColsAtCompileTime == 1 ))
302+ || ((PyArray_DIMS (pyObj )[1 ] == 1 ) && (MatType::RowsAtCompileTime == 1 )))
265303 {
266304#ifndef NDEBUG
267305 if (MatType::ColsAtCompileTime == 1 )
@@ -273,9 +311,9 @@ namespace eigenpy
273311 }
274312 }
275313
276- if (PyArray_NDIM (obj_ptr ) != 2 )
314+ if (PyArray_NDIM (pyObj ) != 2 )
277315 {
278- if ( (PyArray_NDIM (obj_ptr ) !=1 ) || (! MatType::IsVectorAtCompileTime) )
316+ if ( (PyArray_NDIM (pyObj ) !=1 ) || (! MatType::IsVectorAtCompileTime) )
279317 {
280318#ifndef NDEBUG
281319 std::cerr << " The number of dimension of the object is not correct." << std::endl;
@@ -284,10 +322,10 @@ namespace eigenpy
284322 }
285323 }
286324
287- if (PyArray_NDIM (obj_ptr ) == 2 )
325+ if (PyArray_NDIM (pyObj ) == 2 )
288326 {
289- const int R = (int )PyArray_DIMS (obj_ptr )[0 ];
290- const int C = (int )PyArray_DIMS (obj_ptr )[1 ];
327+ const int R = (int )PyArray_DIMS (pyObj )[0 ];
328+ const int C = (int )PyArray_DIMS (pyObj )[1 ];
291329
292330 if ( (MatType::RowsAtCompileTime!=R)
293331 && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
@@ -298,7 +336,7 @@ namespace eigenpy
298336 }
299337
300338 // Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
301- if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(obj_ptr ), 0 )) == NPY_INT)
339+ if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(pyObj ), 0 )) == NPY_INT)
302340 {
303341 if (!FromTypeToType<int ,typename MatType::Scalar>::value)
304342 {
@@ -308,7 +346,7 @@ namespace eigenpy
308346 return 0 ;
309347 }
310348 }
311- else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(obj_ptr ), 0 )) == NPY_LONG)
349+ else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(pyObj ), 0 )) == NPY_LONG)
312350 {
313351 if (!FromTypeToType<long ,typename MatType::Scalar>::value)
314352 {
@@ -318,7 +356,7 @@ namespace eigenpy
318356 return 0 ;
319357 }
320358 }
321- else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(obj_ptr ), 0 )) == NPY_FLOAT)
359+ else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(pyObj ), 0 )) == NPY_FLOAT)
322360 {
323361 if (!FromTypeToType<float ,typename MatType::Scalar>::value)
324362 {
@@ -328,7 +366,7 @@ namespace eigenpy
328366 return 0 ;
329367 }
330368 }
331- else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(obj_ptr ), 0 )) == NPY_DOUBLE)
369+ else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(pyObj ), 0 )) == NPY_DOUBLE)
332370 {
333371 if (!FromTypeToType<double ,typename MatType::Scalar>::value)
334372 {
@@ -338,7 +376,7 @@ namespace eigenpy
338376 return 0 ;
339377 }
340378 }
341- else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(obj_ptr ), 0 ))
379+ else if ((PyArray_ObjectType (reinterpret_cast <PyObject *>(pyObj ), 0 ))
342380 != NumpyEquivalentType<typename MatType::Scalar>::type_code)
343381 {
344382#ifndef NDEBUG
@@ -349,7 +387,7 @@ namespace eigenpy
349387 }
350388
351389#ifdef NPY_1_8_API_VERSION
352- if (!(PyArray_FLAGS (obj_ptr )))
390+ if (!(PyArray_FLAGS (pyObj )))
353391#else
354392 if (!(PyArray_FLAGS (obj_ptr) & NPY_ALIGNED))
355393#endif
@@ -360,15 +398,13 @@ namespace eigenpy
360398 return 0 ;
361399 }
362400
363- return obj_ptr ;
401+ return pyObj ;
364402 }
365403
366- // Convert obj_ptr into an Eigen::Vector
404+ // / \brief Allocate memory and copy pyObj in the new storage
367405 static void construct (PyObject* pyObj,
368406 bp::converter::rvalue_from_python_stage1_data* memory)
369407 {
370- using namespace Eigen ;
371-
372408 PyArrayObject * pyArray = reinterpret_cast <PyArrayObject*>(pyObj);
373409 assert ((PyArray_DIMS (pyArray)[0 ]<INT_MAX) && (PyArray_DIMS (pyArray)[1 ]<INT_MAX));
374410
@@ -379,6 +415,42 @@ namespace eigenpy
379415
380416 memory->convertible = storage;
381417 }
418+
419+ static void registration ()
420+ {
421+ bp::converter::registry::push_back
422+ (reinterpret_cast <void *(*)(_object *)>(&EigenFromPy::convertible),
423+ &EigenFromPy::construct,bp::type_id<MatType>());
424+ }
425+ };
426+
427+ template <typename MatType>
428+ struct EigenFromPy < Eigen::MatrixBase<MatType> >
429+ {
430+ typedef EigenFromPy<MatType> EigenFromPyDerived;
431+ typedef Eigen::MatrixBase<MatType> Base;
432+
433+ // / \brief Determine if pyObj can be converted into a MatType object
434+ static void * convertible (PyArrayObject* pyObj)
435+ {
436+ std::cout << " call: EigenFromPy< Eigen::MatrixBase<MatType> >::convertible" << std::endl;
437+ return EigenFromPyDerived::convertible (pyObj);
438+ }
439+
440+ // / \brief Allocate memory and copy pyObj in the new storage
441+ static void construct (PyObject* pyObj,
442+ bp::converter::rvalue_from_python_stage1_data* memory)
443+ {
444+ std::cout << " call: EigenFromPy< Eigen::MatrixBase<MatType> >::construct" << std::endl;
445+ EigenFromPyDerived::construct (pyObj,memory);
446+ }
447+
448+ static void registration ()
449+ {
450+ bp::converter::registry::push_back
451+ (reinterpret_cast <void *(*)(_object *)>(&EigenFromPy::convertible),
452+ &EigenFromPy::construct,bp::type_id<Base>());
453+ }
382454 };
383455
384456#define numpy_import_array () {if (_import_array () < 0 ) {PyErr_Print (); PyErr_SetString (PyExc_ImportError, " numpy.core.multiarray failed to import" ); } }
@@ -394,14 +466,11 @@ namespace eigenpy
394466 {
395467 static void registration ()
396468 {
397- bp::converter::registry::push_back
398- (reinterpret_cast <void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
399- &EigenFromPy<MatType>::construct,bp::type_id<MatType>());
400-
469+ EigenFromPy<MatType>::registration ();
470+
401471 // Add also conversion to Eigen::MatrixBase<MatType>
402- bp::converter::registry::push_back
403- (reinterpret_cast <void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
404- &EigenFromPy<MatType>::construct,bp::type_id< Eigen::MatrixBase<MatType> >());
472+ typedef Eigen::MatrixBase<MatType> MatTypeBase;
473+ EigenFromPy<MatTypeBase>::registration ();
405474 }
406475 };
407476
@@ -419,7 +488,6 @@ namespace eigenpy
419488 };
420489#endif
421490
422-
423491 template <typename MatType>
424492 void enableEigenPySpecific ()
425493 {
0 commit comments