diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp index 65b2103cf4f602ee158ef701388c5f609af6f697..b9c37ac1f9358b83b41af5c72f0a3090569b9363 100644 --- a/include/eigenpy/details.hpp +++ b/include/eigenpy/details.hpp @@ -119,6 +119,28 @@ namespace eigenpy { return getInstance().CurrentNumpyType; } + + static const PyTypeObject * getNumpyMatrixType() + { + return getInstance().NumpyMatrixType; + } + + static const PyTypeObject * getNumpyArrayType() + { + return getInstance().NumpyArrayType; + } + + static bool isMatrix() + { + return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()), + getInstance().NumpyMatrixType); + } + + static bool isArray() + { + return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(getInstance().CurrentNumpyType.ptr()), + getInstance().NumpyArrayType); + } protected: NumpyType() @@ -150,6 +172,39 @@ namespace eigenpy bp::object NumpyArrayObject; PyTypeObject * NumpyArrayType; }; + + template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime> + struct initEigenObject + { + static MatType * run(PyArrayObject * pyArray, void * storage) + { + assert(PyArray_NDIM(pyArray) == 2); + + const int rows = (int)PyArray_DIMS(pyArray)[0]; + const int cols = (int)PyArray_DIMS(pyArray)[1]; + + return new (storage) MatType(rows,cols); + } + }; + + template<typename MatType> + struct initEigenObject<MatType,true> + { + static MatType * run(PyArrayObject * pyArray, void * storage) + { + if(PyArray_NDIM(pyArray) == 1) + { + const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0]; + return new (storage) MatType(rows_or_cols); + } + else + { + const int rows = (int)PyArray_DIMS(pyArray)[0]; + const int cols = (int)PyArray_DIMS(pyArray)[1]; + return new (storage) MatType(rows,cols); + } + } + }; template<typename MatType> struct EigenObjectAllocator @@ -159,10 +214,7 @@ namespace eigenpy static void allocate(PyArrayObject * pyArray, void * storage) { - const int rows = (int)PyArray_DIMS(pyArray)[0]; - const int cols = (int)PyArray_DIMS(pyArray)[1]; - - Type * mat_ptr = new (storage) Type(rows,cols); + Type * mat_ptr = initEigenObject<Type>::run(pyArray,storage); if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray)) { @@ -294,124 +346,113 @@ namespace eigenpy template<typename MatType> struct EigenFromPy { + + static bool isScalarConvertible(const int np_type) + { + if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type) + return true; + + switch(np_type) + { + case NPY_INT: + return FromTypeToType<int,typename MatType::Scalar>::value; + case NPY_LONG: + return FromTypeToType<long,typename MatType::Scalar>::value; + case NPY_FLOAT: + return FromTypeToType<float,typename MatType::Scalar>::value; + case NPY_DOUBLE: + return FromTypeToType<double,typename MatType::Scalar>::value; + default: + return false; + } + } + /// \brief Determine if pyObj can be converted into a MatType object static void* convertible(PyArrayObject* pyArray) { if(!PyArray_Check(pyArray)) return 0; + + if(!isScalarConvertible(GET_PY_ARRAY_TYPE(pyArray))) + return 0; if(MatType::IsVectorAtCompileTime) { - // Special care of scalar matrix of dimension 1x1. - if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1) - return pyArray; - - if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1) + switch(PyArray_NDIM(pyArray)) { + case 0: + return 0; + case 1: + return pyArray; + case 2: + { + // Special care of scalar matrix of dimension 1x1. + if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1) + return pyArray; + + if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1) + { #ifndef NDEBUG - std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl; + std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl; #endif - return 0; - } - - if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) - || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1))) - { + return 0; + } + + if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) + || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1))) + { #ifndef NDEBUG - if(MatType::ColsAtCompileTime == 1) - std::cerr << "The object is not a column vector" << std::endl; - else - std::cerr << "The object is not a row vector" << std::endl; + if(MatType::ColsAtCompileTime == 1) + std::cerr << "The object is not a column vector" << std::endl; + else + std::cerr << "The object is not a row vector" << std::endl; #endif - return 0; + return 0; + } + break; + } + default: + return 0; } } - - if(PyArray_NDIM(pyArray) != 2) + else // this is a matrix { - if ( (PyArray_NDIM(pyArray) !=1) || (! MatType::IsVectorAtCompileTime) ) + if(PyArray_NDIM(pyArray) != 2) { + if ( (PyArray_NDIM(pyArray) !=1) || (! MatType::IsVectorAtCompileTime) ) + { #ifndef NDEBUG - std::cerr << "The number of dimension of the object is not correct." << std::endl; + std::cerr << "The number of dimension of the object is not correct." << std::endl; #endif - return 0; + return 0; + } } - } - - if(PyArray_NDIM(pyArray) == 2) - { - const int R = (int)PyArray_DIMS(pyArray)[0]; - const int C = (int)PyArray_DIMS(pyArray)[1]; - if( (MatType::RowsAtCompileTime!=R) - && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) - return 0; - if( (MatType::ColsAtCompileTime!=C) - && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) - return 0; - } - - // Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType - if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT) - { - if(!FromTypeToType<int,typename MatType::Scalar>::value) + if(PyArray_NDIM(pyArray) == 2) { -#ifndef NDEBUG - 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; -#endif - return 0; + const int R = (int)PyArray_DIMS(pyArray)[0]; + const int C = (int)PyArray_DIMS(pyArray)[1]; + + if( (MatType::RowsAtCompileTime!=R) + && (MatType::RowsAtCompileTime!=Eigen::Dynamic) ) + return 0; + if( (MatType::ColsAtCompileTime!=C) + && (MatType::ColsAtCompileTime!=Eigen::Dynamic) ) + return 0; } } - else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG) - { - if(!FromTypeToType<long,typename MatType::Scalar>::value) - { -#ifndef NDEBUG - 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; -#endif - return 0; - } - } - else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT) - { - if(!FromTypeToType<float,typename MatType::Scalar>::value) - { -#ifndef NDEBUG - 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; -#endif - return 0; - } - } - else if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE) - { - if(!FromTypeToType<double,typename MatType::Scalar>::value) - { -#ifndef NDEBUG - 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; -#endif - return 0; - } - } - else if(GET_PY_ARRAY_TYPE(pyArray) != NumpyEquivalentType<typename MatType::Scalar>::type_code) - { -#ifndef NDEBUG - std::cerr << "The internal type as no Eigen equivalent." << std::endl; -#endif - return 0; - } - #ifdef NPY_1_8_API_VERSION if(!(PyArray_FLAGS(pyArray))) #else if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED)) #endif - { + { #ifndef NDEBUG - std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; + std::cerr << "NPY non-aligned matrices are not implemented." << std::endl; #endif - return 0; - } + return 0; + } return pyArray; } diff --git a/include/eigenpy/map.hpp b/include/eigenpy/map.hpp index 77677f59e60ccb84ba59a90d2e11d5d0952f56c6..dea2fc3c1a9271eb3f9b48f415c5e1f8871d5467 100644 --- a/include/eigenpy/map.hpp +++ b/include/eigenpy/map.hpp @@ -102,7 +102,8 @@ namespace eigenpy }; template<typename MatType, typename InputScalar> - typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray ) + typename MapNumpy<MatType,InputScalar>::EigenMap + MapNumpy<MatType,InputScalar>::map(PyArrayObject * pyArray) { return Impl::mapImpl(pyArray); }