Skip to content

Commit ff7cb4d

Browse files
authored
Merge pull request #124 from jcarpent/devel
Allows to convert a np.array of dimension 1 into any Eigen::Vector Row or Col major
2 parents 77b2063 + aa9b571 commit ff7cb4d

File tree

2 files changed

+133
-91
lines changed

2 files changed

+133
-91
lines changed

include/eigenpy/details.hpp

Lines changed: 131 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,28 @@ namespace eigenpy
119119
{
120120
return getInstance().CurrentNumpyType;
121121
}
122+
123+
static const PyTypeObject * getNumpyMatrixType()
124+
{
125+
return getInstance().NumpyMatrixType;
126+
}
127+
128+
static const PyTypeObject * getNumpyArrayType()
129+
{
130+
return getInstance().NumpyArrayType;
131+
}
132+
133+
static bool isMatrix()
134+
{
135+
return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()),
136+
getInstance().NumpyMatrixType);
137+
}
138+
139+
static bool isArray()
140+
{
141+
return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()),
142+
getInstance().NumpyArrayType);
143+
}
122144

123145
protected:
124146
NumpyType()
@@ -150,6 +172,39 @@ namespace eigenpy
150172
bp::object NumpyArrayObject; PyTypeObject * NumpyArrayType;
151173

152174
};
175+
176+
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
177+
struct initEigenObject
178+
{
179+
static MatType * run(PyArrayObject * pyArray, void * storage)
180+
{
181+
assert(PyArray_NDIM(pyArray) == 2);
182+
183+
const int rows = (int)PyArray_DIMS(pyArray)[0];
184+
const int cols = (int)PyArray_DIMS(pyArray)[1];
185+
186+
return new (storage) MatType(rows,cols);
187+
}
188+
};
189+
190+
template<typename MatType>
191+
struct initEigenObject<MatType,true>
192+
{
193+
static MatType * run(PyArrayObject * pyArray, void * storage)
194+
{
195+
if(PyArray_NDIM(pyArray) == 1)
196+
{
197+
const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0];
198+
return new (storage) MatType(rows_or_cols);
199+
}
200+
else
201+
{
202+
const int rows = (int)PyArray_DIMS(pyArray)[0];
203+
const int cols = (int)PyArray_DIMS(pyArray)[1];
204+
return new (storage) MatType(rows,cols);
205+
}
206+
}
207+
};
153208

154209
template<typename MatType>
155210
struct EigenObjectAllocator
@@ -159,10 +214,7 @@ namespace eigenpy
159214

160215
static void allocate(PyArrayObject * pyArray, void * storage)
161216
{
162-
const int rows = (int)PyArray_DIMS(pyArray)[0];
163-
const int cols = (int)PyArray_DIMS(pyArray)[1];
164-
165-
Type * mat_ptr = new (storage) Type(rows,cols);
217+
Type * mat_ptr = initEigenObject<Type>::run(pyArray,storage);
166218

167219
if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray))
168220
{
@@ -294,124 +346,113 @@ namespace eigenpy
294346
template<typename MatType>
295347
struct EigenFromPy
296348
{
349+
350+
static bool isScalarConvertible(const int np_type)
351+
{
352+
if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type)
353+
return true;
354+
355+
switch(np_type)
356+
{
357+
case NPY_INT:
358+
return FromTypeToType<int,typename MatType::Scalar>::value;
359+
case NPY_LONG:
360+
return FromTypeToType<long,typename MatType::Scalar>::value;
361+
case NPY_FLOAT:
362+
return FromTypeToType<float,typename MatType::Scalar>::value;
363+
case NPY_DOUBLE:
364+
return FromTypeToType<double,typename MatType::Scalar>::value;
365+
default:
366+
return false;
367+
}
368+
}
369+
297370
/// \brief Determine if pyObj can be converted into a MatType object
298371
static void* convertible(PyArrayObject* pyArray)
299372
{
300373
if(!PyArray_Check(pyArray))
301374
return 0;
375+
376+
if(!isScalarConvertible(GET_PY_ARRAY_TYPE(pyArray)))
377+
return 0;
302378

303379
if(MatType::IsVectorAtCompileTime)
304380
{
305-
// Special care of scalar matrix of dimension 1x1.
306-
if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1)
307-
return pyArray;
308-
309-
if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1)
381+
switch(PyArray_NDIM(pyArray))
310382
{
383+
case 0:
384+
return 0;
385+
case 1:
386+
return pyArray;
387+
case 2:
388+
{
389+
// Special care of scalar matrix of dimension 1x1.
390+
if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1)
391+
return pyArray;
392+
393+
if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1)
394+
{
311395
#ifndef NDEBUG
312-
std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
396+
std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
313397
#endif
314-
return 0;
315-
}
316-
317-
if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1))
318-
|| ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
319-
{
398+
return 0;
399+
}
400+
401+
if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1))
402+
|| ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
403+
{
320404
#ifndef NDEBUG
321-
if(MatType::ColsAtCompileTime == 1)
322-
std::cerr << "The object is not a column vector" << std::endl;
323-
else
324-
std::cerr << "The object is not a row vector" << std::endl;
405+
if(MatType::ColsAtCompileTime == 1)
406+
std::cerr << "The object is not a column vector" << std::endl;
407+
else
408+
std::cerr << "The object is not a row vector" << std::endl;
325409
#endif
326-
return 0;
410+
return 0;
411+
}
412+
break;
413+
}
414+
default:
415+
return 0;
327416
}
328417
}
329-
330-
if(PyArray_NDIM(pyArray) != 2)
418+
else // this is a matrix
331419
{
332-
if ( (PyArray_NDIM(pyArray) !=1) || (! MatType::IsVectorAtCompileTime) )
420+
if(PyArray_NDIM(pyArray) != 2)
333421
{
422+
if ( (PyArray_NDIM(pyArray) !=1) || (! MatType::IsVectorAtCompileTime) )
423+
{
334424
#ifndef NDEBUG
335-
std::cerr << "The number of dimension of the object is not correct." << std::endl;
425+
std::cerr << "The number of dimension of the object is not correct." << std::endl;
336426
#endif
337-
return 0;
427+
return 0;
428+
}
338429
}
339-
}
340-
341-
if(PyArray_NDIM(pyArray) == 2)
342-
{
343-
const int R = (int)PyArray_DIMS(pyArray)[0];
344-
const int C = (int)PyArray_DIMS(pyArray)[1];
345430

346-
if( (MatType::RowsAtCompileTime!=R)
347-
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
348-
return 0;
349-
if( (MatType::ColsAtCompileTime!=C)
350-
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
351-
return 0;
352-
}
353-
354-
// Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
355-
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
356-
{
357-
if(!FromTypeToType<int,typename MatType::Scalar>::value)
431+
if(PyArray_NDIM(pyArray) == 2)
358432
{
359-
#ifndef NDEBUG
360-
std::cerr << "The Python matrix scalar type (int) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
361-
#endif
362-
return 0;
433+
const int R = (int)PyArray_DIMS(pyArray)[0];
434+
const int C = (int)PyArray_DIMS(pyArray)[1];
435+
436+
if( (MatType::RowsAtCompileTime!=R)
437+
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
438+
return 0;
439+
if( (MatType::ColsAtCompileTime!=C)
440+
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
441+
return 0;
363442
}
364443
}
365-
else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
366-
{
367-
if(!FromTypeToType<long,typename MatType::Scalar>::value)
368-
{
369-
#ifndef NDEBUG
370-
std::cerr << "The Python matrix scalar type (long) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
371-
#endif
372-
return 0;
373-
}
374-
}
375-
else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
376-
{
377-
if(!FromTypeToType<float,typename MatType::Scalar>::value)
378-
{
379-
#ifndef NDEBUG
380-
std::cerr << "The Python matrix scalar type (float) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
381-
#endif
382-
return 0;
383-
}
384-
}
385-
else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
386-
{
387-
if(!FromTypeToType<double,typename MatType::Scalar>::value)
388-
{
389-
#ifndef NDEBUG
390-
std::cerr << "The Python matrix scalar (double) type cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision." << std::endl;
391-
#endif
392-
return 0;
393-
}
394-
}
395-
else if(GET_PY_ARRAY_TYPE(pyArray) != NumpyEquivalentType<typename MatType::Scalar>::type_code)
396-
{
397-
#ifndef NDEBUG
398-
std::cerr << "The internal type as no Eigen equivalent." << std::endl;
399-
#endif
400444

401-
return 0;
402-
}
403-
404445
#ifdef NPY_1_8_API_VERSION
405446
if(!(PyArray_FLAGS(pyArray)))
406447
#else
407448
if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
408449
#endif
409-
{
450+
{
410451
#ifndef NDEBUG
411-
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
452+
std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
412453
#endif
413-
return 0;
414-
}
454+
return 0;
455+
}
415456

416457
return pyArray;
417458
}

include/eigenpy/map.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ namespace eigenpy
102102
};
103103

104104
template<typename MatType, typename InputScalar>
105-
typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray )
105+
typename MapNumpy<MatType,InputScalar>::EigenMap
106+
MapNumpy<MatType,InputScalar>::map(PyArrayObject * pyArray)
106107
{
107108
return Impl::mapImpl(pyArray);
108109
}

0 commit comments

Comments
 (0)