Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing pointer to C++ from python using pybind11

I have created the following class using pybind11:

py::class_<Raster>(m, "Raster")
        .def(py::init<double*, std::size_t, std::size_t, std::size_t, double, double, double>());

However I have no idea how I would call this constructor in Python.. I see that Python expects a float in the place of the double*, but I cannot seem to call it.

I have tried, ctypes.data_as(ctypes.POINTER(ctypes.c_double)) but this does not work...

Edit:

I have distilled the answer from @Sergei answer.

py::class_<Raster>(m, "Raster", py::buffer_protocol())
    .def("__init__", [](Raster& raster, py::array_t<double> buffer, double spacingX, double spacingY, double spacingZ) {
    py::buffer_info info = buffer.request();
    new (&raster) Raster3D(static_cast<double*>(info.ptr), info.shape[0], info.shape[1], info.shape[2], spacingX, spacingY, spacingZ);
    })
like image 388
Frank Avatar asked Sep 18 '19 10:09

Frank


1 Answers

Pybind does automatic conversions. When you bind f(double *) the argument is assumed to be a pointer to a singe value, not a pointer to the array begin, because it would be quite unnatural to expect such input from python side. So pybind will convert argument using this logic.

If you need to pass raw array to c++ use py::buffer like here:

py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
    .def("__init__", [](Matrix &m, py::buffer b) {
        typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;

        /* Request a buffer descriptor from Python */
        py::buffer_info info = b.request();

        /* Some sanity checks ... */
        if (info.format != py::format_descriptor<Scalar>::format())
            throw std::runtime_error("Incompatible format: expected a double array!");

        if (info.ndim != 2)
            throw std::runtime_error("Incompatible buffer dimension!");

        auto strides = Strides(
            info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar),
            info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar));

        auto map = Eigen::Map<Matrix, 0, Strides>(
            static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);

        new (&m) Matrix(map);
    });

To make it work you need to pass a type which follows python buffer protocol.

like image 164
Sergei Avatar answered Oct 20 '22 22:10

Sergei