How best to wrap C++ classes which uses Eigen?

619 views
Skip to first unread message

Hans Müller

unread,
Apr 19, 2015, 3:59:07 PM4/19/15
to cython...@googlegroups.com
Hi,

I try to write a wrapper for C++ library which uses Eigen heavily, e.g.

surface.hpp:
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/StdVector>

class Surface
{
public:
    std
::vector<Eigen::Vector3d, Eigen::aligned_allocator<Eigen::Vector3d> > nodes;
   
virtual void transform(const Eigen::Matrix3d &transformation);
}

What would be the best way to wrap this code? I managed to write the wrapper for the rest of the class, but this eludes me. I googled "cython eigen" but did not find any answer.

Can anyone of you experts point me in the right direction? Thanks.

Hans

Hans Müller

unread,
Apr 26, 2015, 10:31:33 AM4/26/15
to cython...@googlegroups.com
After a lot of googling I finally came up with the following solution -
mainly with the help of
https://studywolf.wordpress.com/2012/09/18/cython-journey-part-2-including-eigen/
:

decl_eigen.pxd:
cdef extern from "Eigen/Dense" namespace "Eigen":

cdef cppclass Vector3d:

Vector3d() except +

Vector3d(double c0, double c1, double c2) except +

double coeff(int row, int col)

decl_surface.pxd:

from libcpp.string cimport string

cimport decl_eigen

cdef extern from "../surface.hpp" namespace "MyProject":

cdef cppclass Surface:
Surface(const string &id_str) except +
void rotate(decl_eigen.Vector3d &axis, double angle)

surface.pyx:
import decl_eigen

cimport decl_surface

cdef class Surface:

cdef decl_surface.Surface *thisptr


def __cinit__(self, str id_str):

self.thisptr = new decl_surface.Surface(id_str)


def __dealloc__(self):

del self.thisptr


property id:

def __get__(self): return self.thisptr.id


def rotate(self, axis, double angle):


if len(axis) != 3:

raise TypeError(

'rotate(): rotation axis must have 3 elements '

'({} given)'.format(len(axis)))

cdef decl_eigen.Vector3d a = decl_eigen.Vector3d(axis[0], axis[1],
axis[2])

self.thisptr.rotate(a, angle)

setup.py:

from distutils.core import setup, Extension

from Cython.Build import cythonize

setup(

name='myproject',

ext_modules=cythonize(
[Extension(

'surface',

sources=['surface.pyx'],
language='c++',
extra_compile_args = ['-std=c++11',],

include_dirs = ['/usr/local/include/eigen3', '..'],

libraries = ['myproject'],
),])

)

So far, so good! this seems to work. (I have not tackled the Surface.nodes
yet.)

But the function transform(Eigen::Matrix3d) needs a 3x3 matrix. I declared
Matrix3d in decl_eigen.pxd similar to Vector3d. The problem I run into is
that I cannot initialize the matrix with the values, because Matrix3d does
not have such a constructor. So I have to set the values after
initialisation. I know that I can get the coefficient with the method coeff(row,
col), but how do I set the coefficient in Cython?

def transform(self, transformation):
cdef decl_eigen.Matrix3d t = decl_eigen.Matrix3d()
t(0, 0) = transformation[0][0] # Does not work in Cython!
t.insert(0, 0, transformation[0][0]) # Does not work either!

Can anybody with more insight help me here?


Thanks,

Hans

Hans Müller

unread,
Apr 29, 2015, 1:56:30 AM4/29/15
to cython...@googlegroups.com
Stack Overflow came to the rescue here. See http://stackoverflow.com/questions/29913524/set-coefficient-element-of-eigenmatrix3d-in-cython for two possible solutions.
Reply all
Reply to author
Forward
0 new messages