I have a simple C Vec3 class, but I am struggling to figure out how to wrap certain class methods with Cython. Here are the files:
vec3.h:
#ifndef VEC3_H
#define VEC3_H
struct Vec3 {
float x, y, z;
Vec3(float x, float y, float z);
Vec3 cross(Vec3 other);
};
#endif
vec3.cpp:
#include "vec3.h"
Vec3::Vec3(float x, float y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
Vec3 Vec3::cross(Vec3 other) {
return Vec3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x);
}
vec3.pyx:
# cython: language_level=3
# distutils: language=c
cdef extern from "vec3.h":
cdef cppclass Vec3:
float x, y, z
Vec3(float x, float y, float z) except
Vec3 cross(Vec3 other)
cdef class py_Vec3:
cdef Vec3 *thisptr
def __cinit__(self, x, y, z):
self.thisptr = new Vec3(x, y, z)
# ...
cpdef cross(self, Vec3 other):
return self.thisptr.cross(other)
I first compile the C code using:
g -c vec3.cpp -o vec3.o
ar rcs vec3.a vec3.o
Then run the following setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
vec3= Extension(
name="vec3", sources=["vec3.pyx"], libraries=["linalg"], language="c "
)
setup(name="vec3-test", ext_modules=cythonize([vec3]))
But I get the following error from the cross
method:
Cannot convert 'Vec3f' to Python object
Is there a proper way to do this?
CodePudding user response:
you have a typo in vec3.cpp
return Vec3f(...);
remove the f
. it doesnt recognize Vec3f
as a class
CodePudding user response:
Becuase Vec3
is a cpp type and py_Vec3
is a python type, and they cannot be converted to each other automatically by cython. In the cpdef
function
cpdef cross(self, Vec3 other):
return self.thisptr.cross(other)
the generated python wrapper version expects a python type argument, but conversion from Vec3
to py_Vec3
fails, so does the return value.
you have to do the conversion manually. Try the following modified version:
cdef class py_Vec3:
cdef Vec3 *thisptr
def __cinit__(self, x, y, z):
self.thisptr = new Vec3(x, y, z)
cdef py_Vec3 from_vec3(self, Vec3 v):
return py_Vec3(v.x, v.y, v.z)
cpdef py_Vec3 cross(self, py_Vec3 other):
return self.from_vec3(self.thisptr.cross(other.thisptr[0]))
def __dealloc__(self):
del self.thisptr
def __repr__(self):
return f"py_Vec3({self.thisptr.x}, {self.thisptr.y}, {self.thisptr.z})"