Example from and to python converters

From KitwarePublic
Revision as of 18:05, 13 June 2011 by Blloyd (talk | contribs) (Added useful URLs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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>