Example from and to python converters

From KitwarePublic
Jump to navigationJump to search

Example code to illustrate how to use Boost.Python to wrap code, which uses VTK objects in the wrapped functions either as return value or as a function argument.

Useful discussions and descriptions:

* How to write boost converters
* vtkusers: Can I mix Boost-Python and VTK-Python
* Use of VTK in Visit project
* Python C-API
* vtkusers: Mails leading to this page

PythonModule_BoostVTKConversion.cxx:

<source lang="cpp">

  1. include <boost/python.hpp>
  1. include <vtkUnstructuredGrid.h>
  2. include <vtkPoints.h>


using namespace boost::python;


template<class T> struct vtkObjectPointer_to_python { static PyObject *convert(const T &p) { if(p == NULL) { return incref(Py_None); } std::ostringstream oss; oss << (vtkObjectBase*) p; // here don't get address std::string address_str = oss.str();

object obj = import("vtk").attr("vtkObjectBase")(address_str); return incref(obj.ptr()); } };

// // This python to C++ converter uses the fact that VTK Python objects have an // attribute called __this__, which is a string containing the memory address // of the VTK C++ object and its class name. // E.g. for a vtkPoints object __this__ might be "_0000000105a64420_p_vtkPoints" // void* extract_vtk_wrapped_pointer(PyObject* obj) {

   char thisStr[] = "__this__";
   //first we need to get the __this__ attribute from the Python Object
   if (!PyObject_HasAttrString(obj, thisStr))
       return NULL;
   PyObject* thisAttr = PyObject_GetAttrString(obj, thisStr);
   if (thisAttr == NULL)
       return NULL;
   const char* str = PyString_AsString(thisAttr);
   if(str == 0 || strlen(str) < 1)
       return NULL;
   char hex_address[32], *pEnd;
   char *_p_ = strstr(str, "_p_vtk");
   if(_p_ == NULL) return NULL;
   char *class_name = strstr(_p_, "vtk");
   if(class_name == NULL) return NULL;
   strcpy(hex_address, str+1);
   hex_address[_p_-str-1] = '\0';
   long address = strtol(hex_address, &pEnd, 16);
   vtkObjectBase* vtk_object = (vtkObjectBase*)((void*)address);
   if(vtk_object->IsA(class_name))
   {
       return vtk_object;
   }
   return NULL;

}


  1. define VTK_PYTHON_CONVERSION(type) \
   /* register the to-python converter */ \
   to_python_converter<type*, \
           vtkObjectPointer_to_python<type*> >(); \
   /* register the from-python converter */ \
   converter::registry::insert(&extract_vtk_wrapped_pointer, type_id<type>());


// // Example class to illustrate Boost Python wrapped class, which has // functions which return VTK object pointers // struct MyClass { MyClass(); ~MyClass(); void SetPoints(vtkPoints * pts); vtkUnstructuredGrid * GetGrid() { return m_Grid; } void DeleteGrid(); vtkUnstructuredGrid * m_Grid; };

MyClass::MyClass() { m_Grid = vtkUnstructuredGrid::New();

 	m_Grid->Allocate();
 	
 	vtkPoints *pts = vtkPoints::New();  	
 	pts->InsertNextPoint(0,0,0);
 	pts->InsertNextPoint(1,0,0);
 	m_Grid->SetPoints(pts);
 	pts->Delete();

}

MyClass::~MyClass() { if(m_Grid) this->DeleteGrid(); }

void MyClass::DeleteGrid() { m_Grid->Delete(); m_Grid = NULL; }

void MyClass::SetPoints(vtkPoints *pts) {

   m_Grid->SetPoints(pts);

}


// // Create Python Module, with converters and MyClass wrapped // BOOST_PYTHON_MODULE(libBoostVTKConversion) { VTK_PYTHON_CONVERSION(vtkUnstructuredGrid); VTK_PYTHON_CONVERSION(vtkPoints);

class_<MyClass>("MyClass") .def("GetGrid",&MyClass::GetGrid, return_value_policy<return_by_value>()) .def("DeleteGrid",&MyClass::DeleteGrid,"Delete the grid") .def("SetPoints",&MyClass::SetPoints,"Set new points") ; } </source>



CMakeLists.txt:

<source lang="cmake"> PROJECT(BoostPythonVTK)

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

FIND_PACKAGE(VTK REQUIRED) INCLUDE(${VTK_USE_FILE}) SET(VTK_LIBS vtkGraphics vtkIO vtkCommon vtkImaging vtkFiltering)

FIND_PACKAGE(PythonLibs REQUIRED) MESSAGE(STATUS "PYTHON_LIBRARIES " ${PYTHON_LIBRARIES})

FIND_PACKAGE(Boost 1.45.0) IF(Boost_FOUND)

 INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
 SET(Boost_USE_STATIC_LIBS OFF)
 SET(Boost_USE_MULTITHREADED ON)
 SET(Boost_USE_STATIC_RUNTIME OFF)
 FIND_PACKAGE(Boost 1.45.0 COMPONENTS python REQUIRED)
 ADD_LIBRARY(BoostVTKConversion MODULE PythonModule_BoostVTKConversion.cxx)
 TARGET_LINK_LIBRARIES(BoostVTKConversion ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${VTK_LIBS})

ELSE()

 MESSAGE(FATAL_ERROR "Unable to find correct Boost version. Did you set BOOST_ROOT?")

ENDIF() </source>