From d6354b9d06457b740d8497595572c908461b5c1c Mon Sep 17 00:00:00 2001 From: Francois Budin Date: Sat, 23 Mar 2019 20:48:35 -0400 Subject: [PATCH] ENH: Adds wrapping for std::vector::Pointer> and typemaps Wrapping std::vector of itk::Image SmartPointer allows passing arguments to methods that require that type of arguments, such as the method `SetPrincipalComponentImages` in the class `itkPCAShapeSignedDistanceFunction`. This wrapped type accepts itk::Image raw pointers as an input to the vector methods (`push_back`,...) since Python SWIG wrapped itk::Images are raw pointers. Additionally, a list of itk::Image raw vector (Python itk::Image) can be directly passed to methods accepting std::vector::Pointer> if the correct typemap(in) which is defined in `PyBase.i` is added to the Python wrapping of the class using the SWIG method `DECL_PYTHON_STD_VEC_RAW_TO_SMARTPTR_TYPEMAP`. Note that for ITK images, the `itkImage_ext.i` file will have to be included in the interface file of the class that needs the typemap(in) of std::vector of itk::Image since the typemap(in) is defined in the image interface file to support all wrapped image templates. --- .../wrapping/test/CMakeLists.txt | 3 +- .../test/itkPCAShapeSignedDistanceFunction.py | 38 +++++++++++++++ Wrapping/Generators/Python/CMakeLists.txt | 15 ++++++ Wrapping/Generators/Python/PyBase/pyBase.i | 48 +++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 Modules/Segmentation/SignedDistanceFunction/wrapping/test/itkPCAShapeSignedDistanceFunction.py diff --git a/Modules/Segmentation/SignedDistanceFunction/wrapping/test/CMakeLists.txt b/Modules/Segmentation/SignedDistanceFunction/wrapping/test/CMakeLists.txt index fab32abfbf8..cb02d7ed551 100644 --- a/Modules/Segmentation/SignedDistanceFunction/wrapping/test/CMakeLists.txt +++ b/Modules/Segmentation/SignedDistanceFunction/wrapping/test/CMakeLists.txt @@ -1 +1,2 @@ -itk_python_expression_add_test(NAME itkPCAShapeSignedDistanceFunctionPythonTest EXPRESSION "itkPCAShapeSignedDistanceFunction = itk.PCAShapeSignedDistanceFunction.New()") +itk_python_add_test(NAME itkPCAShapeSignedDistanceFunctionPythonTest + COMMAND itkPCAShapeSignedDistanceFunction.py) diff --git a/Modules/Segmentation/SignedDistanceFunction/wrapping/test/itkPCAShapeSignedDistanceFunction.py b/Modules/Segmentation/SignedDistanceFunction/wrapping/test/itkPCAShapeSignedDistanceFunction.py new file mode 100644 index 00000000000..f3cd9fa89de --- /dev/null +++ b/Modules/Segmentation/SignedDistanceFunction/wrapping/test/itkPCAShapeSignedDistanceFunction.py @@ -0,0 +1,38 @@ +#========================================================================== +# +# Copyright Insight Software Consortium +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0.txt +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#==========================================================================*/ + + +import itk +from sys import argv +itk.auto_progress(2) + +dim = 2 +IType = itk.Image[itk.F, dim] + +pca_function = itk.PCAShapeSignedDistanceFunction[itk.D, dim, IType].New() +im = IType.New() +im.SetRegions([10,10]) +im.Allocate() +l = [im, im] +# Test that it is possible to use a list of image +pca_function.SetPrincipalComponentImages (l) +# Test that it is possible to use an std::vector of image +vec = itk.vector[IType]() +vec.push_back(im) +vec.push_back(im) +pca_function.SetPrincipalComponentImages(vec) diff --git a/Wrapping/Generators/Python/CMakeLists.txt b/Wrapping/Generators/Python/CMakeLists.txt index 7fc64fcb0d0..ec2c076b089 100644 --- a/Wrapping/Generators/Python/CMakeLists.txt +++ b/Wrapping/Generators/Python/CMakeLists.txt @@ -833,6 +833,21 @@ macro(itk_wrap_simple_type_python wrap_class swig_name) ADD_PYTHON_CONFIG_TEMPLATE("vector" "std::vector" "vector${swig_name}" "${cpp_name}< ${template_params} >") endif() + if("${cpp_name}" STREQUAL "itk::Image" AND NOT "${swig_name}" MATCHES "Pointer$") + set(ITK_WRAP_PYTHON_SWIG_EXT "${ITK_WRAP_PYTHON_SWIG_EXT}DECL_PYTHON_STD_VEC_RAW_TO_SMARTPTR_TYPEMAP(${swig_name}, ${swig_name}_Pointer)\n") + set(ITK_WRAP_PYTHON_SWIG_EXT "${ITK_WRAP_PYTHON_SWIG_EXT}%template(vector${swig_name}) std::vector< ${swig_name}_Pointer >;\n") + ADD_PYTHON_CONFIG_TEMPLATE("vector" "std::vector" "vector${swig_name}" "${cpp_name}< ${template_params} > ") + endif() + + if("${cpp_name}" STREQUAL "itk::PCAShapeSignedDistanceFunction" AND NOT "${swig_name}" MATCHES "Pointer$") + + set(import_text "%include ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/python/itkImage_ext.i\n") + string(FIND ${ITK_WRAP_PYTHON_SWIG_EXT} ${import_text} pos) + if(${pos} EQUAL -1) + set(ITK_WRAP_PYTHON_SWIG_EXT "${import_text}${ITK_WRAP_PYTHON_SWIG_EXT}") + endif() + endif() + if("${cpp_name}" STREQUAL "itk::Index") ADD_PYTHON_SEQ_TYPEMAP("${swig_name}" "${template_params}") diff --git a/Wrapping/Generators/Python/PyBase/pyBase.i b/Wrapping/Generators/Python/PyBase/pyBase.i index 5955bab98de..f49a4c28bd3 100644 --- a/Wrapping/Generators/Python/PyBase/pyBase.i +++ b/Wrapping/Generators/Python/PyBase/pyBase.i @@ -765,6 +765,54 @@ str = str %enddef + +%define DECL_PYTHON_STD_VEC_RAW_TO_SMARTPTR_TYPEMAP(swig_name, swig_name_ptr) + + %typemap(in) std::vector< swig_name_ptr >::value_type const & (swig_name_ptr smart_ptr) { + swig_name * img; + if( SWIG_ConvertPtr($input,(void **)(&img),$descriptor(swig_name *), 0) == 0 ) + { + smart_ptr = img; + $1 = &smart_ptr; + } + else + { + PyErr_SetString(PyExc_TypeError, "Expecting argument of type " #swig_name "."); + SWIG_fail; + } + } + + %typemap(in) std::vector (std::vector< swig_name_ptr> vec_smartptr, + std::vector< swig_name_ptr> *vec_smartptr_ptr) { + if ((SWIG_ConvertPtr($input,(void **)(&vec_smartptr_ptr),$descriptor(std::vector *), 0)) == -1) { + PyErr_Clear(); + if (PySequence_Check($input)) { + for (Py_ssize_t i =0; i < PyObject_Length($input); i++) { + PyObject *o = PySequence_GetItem($input,i); + swig_name * raw_ptr; + if(SWIG_ConvertPtr(o,(void **)(&raw_ptr),$descriptor(swig_name *), 0) == 0) { + vec_smartptr.push_back(raw_ptr); + } else { + PyErr_SetString(PyExc_ValueError,"Expecting a sequence of raw pointers (" #swig_name ")." ); + SWIG_fail; + } + } + $1 = vec_smartptr; + } + else { + PyErr_SetString(PyExc_ValueError,"Expecting a sequence of raw pointers (" #swig_name ") or a std::vector of SmartPointers (" #swig_name_ptr ")."); + SWIG_fail; + } + } else if( vec_smartptr_ptr != NULL ) { + $1 = *vec_smartptr_ptr; + } else { + PyErr_SetString(PyExc_ValueError, "Value can't be None"); + SWIG_fail; + } + } +%enddef + + // some code from stl %template(mapULD) std::map< unsigned long, double >;