4

I am trying to create a wrapper for a c++ method that returns a c++ class(vtkPolyData) which comes from an external c++ library (vtk). The same library has python binding available which is already installed in my python environment. How do you tell pybind that the c++ class (vtkPolydata) and its python variant are the same?

I tried to use this custom type caster macro. but I get TypeError: Unable to convert function return value to a Python type! The signature was : (self: Versa3dLib.skeletonizer, offset distance: float) -> vtkPolyData

which is confusing since it looks like the conversion maps to the correct type but python is unable to interpret it. So I am not sure what's wrong since I don't see anything wrong with the macro either. I noticed that in python vtkPolyData has type vtkCommonDataModelPython.vtkPolyData. is that why the conversion is not done correctly?

#include "skeletonizer.h"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "PybindVTKTypeCaster.h"
#include <vtkSmartPointer.h>

namespace py = pybind11;

PYBIND11_VTK_TYPECASTER(vtkPolyData)
PYBIND11_DECLARE_HOLDER_TYPE(T, vtkSmartPointer<T>);

namespace pybind11 { namespace detail {
    template <typename T>
    struct holder_helper<vtkSmartPointer<T>> { // <-- specialization
        static const T *get(const vtkSmartPointer<T> &p) { return p.GetPointer(); }
    };
}}

PYBIND11_MODULE(Versa3dLib, m)
{
    py::class_<skeletonizer>(m, "skeletonizer")
        .def(py::init<vtkPolyData *>())
        .def("get_offset", &skeletonizer::get_offset,
             "return vtkPolyData offset",
             py::arg("offset distance"));
}

Skeletonizer

#ifndef SKELETONIZER_H
#define SKELETONIZER_H

#include <vtkPolyData.h>
#include <vector>
#include <vtkSmartPointer.h>


using namespace std;

class skeletonizer
{
    public:
        skeletonizer(vtkPolyData* data);
        vtkSmartPointer<vtkPolyData> get_offset(double dist);
};

#endif

skeletonizer cpp

#include "skeletonizer.h"


skeletonizer::skeletonizer(vtkPolyData* data)
{
};

vtkSmartPointer<vtkPolyData> skeletonizer::get_offset(double dist)
{
    vtkSmartPointer<vtkPolyData> offsets = vtkSmartPointer<vtkPolyData>::New();

    return offsets;
};
7
  • Can you add the code where you used this macro? It would help to debug this further (as I'm also curious about this use case). Commented Feb 26, 2019 at 14:44
  • Also, from looking at VTK's object model, it looks like most things would inherit from vtkObjectBase, so it's perhaps possible to write the type-caster in a more generic fashion, e.g. std::enable_if<std::is_base_of<vtkObjectBase, Class>::value>. Commented Feb 26, 2019 at 14:45
  • @EricCousineau Hi, thanks for the responce. I updated the post with the macro in question Commented Feb 26, 2019 at 16:43
  • The main thing to notice I guess is: vtkPythonUtil::GetObjectFromPointer(const_cast< VTK_OBJ *>(&src)); This link to the vtkPythonUtil file is here : github.com/Kitware/VTK/blob/master/Wrapping/PythonCore/… Commented Feb 26, 2019 at 16:43
  • vtkPythonUtil::GetObjectFromPointer, returns a PyObject which at first glance does not seem wrong. Commented Feb 26, 2019 at 16:47

1 Answer 1

1

I think this should be a more general solution (hopefully easier to use?):

I believe this should be an improvement on the VTK code by:

  • Generalizing the type casters using SFINAE (rather than requiring explicit instantiations...).
  • Permit direct casting of vtkSmartPointer and vtkNew (assuming the types inside these are VTK types).

Made the code kind-of follow Drake's C++ + Python binding conventions.

For the above solution you had, I think it was close leveraging the SMTK code, but the holder type instantation was incorrect - you'd need type_caster specializations for the smart pointers (which the vtk_pybind code I posted would provide).

I'll see if I can post an issue on SMTK to see if they want to improve / simplify their binding code (esp. if people refer to it!).

EDIT: Posted issue here: https://gitlab.kitware.com/cmb/smtk/issues/228

Sign up to request clarification or add additional context in comments.

9 Comments

I tried to use your vtk_pybind.h with your example binding code. I get the error pybind11.h(167): error C2064: term does not evaluate to a function taking 0 arguments followed by pybind11.h(167): error C2248: 'pybind11::detail::descr::descr': cannot access protected member declared in class 'pybind11::detail::descr'
did you guys test it on a windows platform as well?
I actually get my vtk files using anaconda. I will try to see if including it as a subfolder in my project makes a difference.
Ah, no, I don't use Windows, so I can't say if it'd work there. Can you post a GitHub Gist to the full traceback of the compilation errors? (the error you mentioned doesn't indicate what in vtk_pybind.h caused the issue...) And I don't have experience with conda, so I can't say what might be going on there.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.