[Scipy-svn] r4562 - trunk/scipy/ndimage/src

scipy-svn@scip... scipy-svn@scip...
Fri Jul 25 11:26:27 CDT 2008


Author: fcady
Date: 2008-07-25 11:26:25 -0500 (Fri, 25 Jul 2008)
New Revision: 4562

Modified:
   trunk/scipy/ndimage/src/nd_image.c
   trunk/scipy/ndimage/src/nd_image.h
   trunk/scipy/ndimage/src/ni_filters.c
   trunk/scipy/ndimage/src/ni_filters.h
   trunk/scipy/ndimage/src/ni_fourier.c
   trunk/scipy/ndimage/src/ni_fourier.h
   trunk/scipy/ndimage/src/ni_interpolation.c
   trunk/scipy/ndimage/src/ni_interpolation.h
   trunk/scipy/ndimage/src/ni_measure.c
   trunk/scipy/ndimage/src/ni_measure.h
   trunk/scipy/ndimage/src/ni_morphology.c
   trunk/scipy/ndimage/src/ni_morphology.h
   trunk/scipy/ndimage/src/ni_support.c
   trunk/scipy/ndimage/src/ni_support.h
Log:
used a python script to change spacing from 2 to 4

Modified: trunk/scipy/ndimage/src/nd_image.c
===================================================================
--- trunk/scipy/ndimage/src/nd_image.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/nd_image.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,1320 +1,1320 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define ND_IMPORT_ARRAY
-#include "nd_image.h"
-#undef ND_IMPORT_ARRAY
-#include "ni_support.h"
-#include "ni_filters.h"
-#include "ni_fourier.h"
-#include "ni_morphology.h"
-#include "ni_interpolation.h"
-#include "ni_measure.h"
-
-typedef struct {
-  PyObject *function;
-  PyObject *extra_arguments;
-  PyObject *extra_keywords;
-} NI_PythonCallbackData;
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToInputArray(PyObject *object, PyArrayObject **array)
-{
-  *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-  return *array ? 1 : 0;
-}
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalInputArray(PyObject *object, PyArrayObject **array)
-{
-  if (object == Py_None) {
-    *array = NULL;
-    return 1;
-  } else {
-    *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-    return *array ? 1 : 0;
-  }
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOutputArray(PyObject *object, PyArrayObject **array)
-{
-  *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-  return *array ? 1 : 0;
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalOutputArray(PyObject *object, PyArrayObject **array)
-{
-  if (object == Py_None) {
-    *array = NULL;
-    return 1;
-  } else {
-    *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-    return *array ? 1 : 0;
-  }
-}
-
-/* Convert an input/output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToIoArray(PyObject *object, PyArrayObject **array)
-{
-  *array = NA_IoArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-  return *array ? 1 : 0;
-}
-
-/* Convert an Long sequence */
-static maybelong
-NI_ObjectToLongSequenceAndLength(PyObject *object, maybelong **sequence)
-{
-  long *pa, ii;
-  PyArrayObject *array = NA_InputArray(object, PyArray_LONG, NPY_CARRAY);
-  maybelong length = PyArray_SIZE(array);
-
-  *sequence = (maybelong*)malloc(length * sizeof(maybelong));
-  if (!*sequence) {
-    PyErr_NoMemory();
-    Py_XDECREF(array);
-    return -1;
-  }
-  pa = (long*)PyArray_DATA(array);
-  for(ii = 0; ii < length; ii++)
-    (*sequence)[ii] = pa[ii];
-  Py_XDECREF(array);
-  return length;
-}
-
-static int
-NI_ObjectToLongSequence(PyObject *object, maybelong **sequence)
-{
-  return NI_ObjectToLongSequenceAndLength(object, sequence) >= 0;
-}
-
-/*********************************************************************/
-/* wrapper functions: */
-/*********************************************************************/
-
-static PyObject *Py_Correlate1D(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
-  int axis, mode;
-  long origin;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&O&iO&idl", NI_ObjectToInputArray, &input,
-                  NI_ObjectToInputArray, &weights, &axis,
-                  NI_ObjectToOutputArray, &output, &mode, &cval, &origin))
-    goto exit;
-  if (!NI_Correlate1D(input, weights, axis, output,
-                      (NI_ExtendMode)mode, cval, origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(weights);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_Correlate(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
-  maybelong *origin = NULL;
-  int mode;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&idO&", NI_ObjectToInputArray, &input,
-          NI_ObjectToInputArray, &weights, NI_ObjectToOutputArray, &output,
-          &mode, &cval, NI_ObjectToLongSequence, &origin))
-    goto exit;
-  if (!NI_Correlate(input, weights, output, (NI_ExtendMode)mode, cval,
-                    origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(weights);
-  Py_XDECREF(output);
-  if (origin)
-    free(origin);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_UniformFilter1D(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL;
-  int axis, mode;
-  long filter_size, origin;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&liO&idl", NI_ObjectToInputArray, &input,
-                    &filter_size, &axis, NI_ObjectToOutputArray, &output,
-                    &mode, &cval, &origin))
-    goto exit;
-  if (!NI_UniformFilter1D(input, filter_size, axis, output,
-                                       (NI_ExtendMode)mode, cval, origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter1D(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL;
-  int axis, mode, minimum;
-  long filter_size, origin;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&liO&idli", NI_ObjectToInputArray, &input,
-                    &filter_size, &axis, NI_ObjectToOutputArray, &output,
-                    &mode, &cval, &origin, &minimum))
-    goto exit;
-  if (!NI_MinOrMaxFilter1D(input, filter_size, axis, output,
-                              (NI_ExtendMode)mode, cval, origin, minimum))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-  PyArrayObject *structure = NULL;
-  maybelong *origin = NULL;
-  int mode, minimum;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&O&idO&i", NI_ObjectToInputArray,
-                    &input, NI_ObjectToInputArray, &footprint,
-                    NI_ObjectToOptionalInputArray, &structure,
-                    NI_ObjectToOutputArray, &output, &mode, &cval,
-                    NI_ObjectToLongSequence, &origin, &minimum))
-    goto exit;
-  if (!NI_MinOrMaxFilter(input, footprint, structure, output,
-                        (NI_ExtendMode)mode, cval, origin, minimum))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(footprint);
-  Py_XDECREF(structure);
-  Py_XDECREF(output);
-  if (origin)
-    free(origin);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_RankFilter(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-  maybelong *origin = NULL;
-  int mode, rank;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&iO&O&idO&", NI_ObjectToInputArray,
-                    &input, &rank, NI_ObjectToInputArray, &footprint,
-                    NI_ObjectToOutputArray, &output, &mode, &cval,
-                    NI_ObjectToLongSequence, &origin))
-    goto exit;
-  if (!NI_RankFilter(input, rank, footprint, output, (NI_ExtendMode)mode,
-                     cval, origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(footprint);
-  Py_XDECREF(output);
-  if (origin)
-    free(origin);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_Filter1DFunc(double *iline, maybelong ilen,
-                           double *oline, maybelong olen, void *data)
-{
-  PyArrayObject *py_ibuffer = NULL, *py_obuffer = NULL;
-  PyObject *rv = NULL, *args = NULL, *tmp = NULL;
-  maybelong ii;
-  double *po = NULL;
-  NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-  py_ibuffer = NA_NewArray(iline, PyArray_DOUBLE, 1, &ilen);
-  py_obuffer = NA_NewArray(NULL, PyArray_DOUBLE, 1, &olen);
-  if (!py_ibuffer || !py_obuffer)
-    goto exit;
-  tmp = Py_BuildValue("(OO)", py_ibuffer, py_obuffer);
-  if (!tmp)
-    goto exit;
-  args = PySequence_Concat(tmp, cbdata->extra_arguments);
-  if (!args)
-    goto exit;
-  rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-  if (!rv)
-    goto exit;
-  po = (double*)PyArray_DATA(py_obuffer);
-  for(ii = 0; ii < olen; ii++)
-    oline[ii] = po[ii];
-exit:
-  Py_XDECREF(py_ibuffer);
-  Py_XDECREF(py_obuffer);
-  Py_XDECREF(rv);
-  Py_XDECREF(args);
-  Py_XDECREF(tmp);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter1D(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL;
-  PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-  void *func = Py_Filter1DFunc, *data = NULL;
-  NI_PythonCallbackData cbdata;
-  int axis, mode;
-  long origin, filter_size;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&OliO&idlOO", NI_ObjectToInputArray,
-        &input, &fnc, &filter_size, &axis, NI_ObjectToOutputArray,
-        &output, &mode, &cval, &origin, &extra_arguments, &extra_keywords))
-    goto exit;
-  if (!PyTuple_Check(extra_arguments)) {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "extra_arguments must be a tuple");
-    goto exit;
-  }
-  if (!PyDict_Check(extra_keywords)) {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "extra_keywords must be a dictionary");
-    goto exit;
-  }
-  if (PyCObject_Check(fnc)) {
-    func = PyCObject_AsVoidPtr(fnc);
-    data = PyCObject_GetDesc(fnc);
-  } else if (PyCallable_Check(fnc)) {
-    cbdata.function = fnc;
-    cbdata.extra_arguments = extra_arguments;
-    cbdata.extra_keywords = extra_keywords;
-    data = (void*)&cbdata;
-  } else {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "function parameter is not callable");
-    goto exit;
-  }
-  if (!NI_GenericFilter1D(input, func, data, filter_size, axis, output,
-                                        (NI_ExtendMode)mode, cval, origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_FilterFunc(double *buffer, maybelong filter_size,
-                         double *output, void *data)
-{
-  PyArrayObject *py_buffer = NULL;
-  PyObject *rv = NULL, *args = NULL, *tmp = NULL;
-  NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-  py_buffer = NA_NewArray(buffer, PyArray_DOUBLE, 1, &filter_size);
-  if (!py_buffer)
-    goto exit;
-  tmp = Py_BuildValue("(O)", py_buffer);
-  if (!tmp)
-    goto exit;
-  args = PySequence_Concat(tmp, cbdata->extra_arguments);
-  if (!args)
-    goto exit;
-  rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-  if (!rv)
-    goto exit;
-  *output = PyFloat_AsDouble(rv);
-exit:
-  Py_XDECREF(py_buffer);
-  Py_XDECREF(rv);
-  Py_XDECREF(args);
-  Py_XDECREF(tmp);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-  PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-  void *func = Py_FilterFunc, *data = NULL;
-  NI_PythonCallbackData cbdata;
-  int mode;
-  maybelong *origin = NULL;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&OO&O&idO&OO", NI_ObjectToInputArray,
-                        &input, &fnc, NI_ObjectToInputArray, &footprint,
-                        NI_ObjectToOutputArray, &output, &mode, &cval,
-                        NI_ObjectToLongSequence, &origin,
-                        &extra_arguments, &extra_keywords))
-    goto exit;
-  if (!PyTuple_Check(extra_arguments)) {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "extra_arguments must be a tuple");
-    goto exit;
-  }
-  if (!PyDict_Check(extra_keywords)) {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "extra_keywords must be a dictionary");
-    goto exit;
-  }
-  if (PyCObject_Check(fnc)) {
-    func = PyCObject_AsVoidPtr(fnc);
-    data = PyCObject_GetDesc(fnc);
-  } else if (PyCallable_Check(fnc)) {
-    cbdata.function = fnc;
-    cbdata.extra_arguments = extra_arguments;
-    cbdata.extra_keywords = extra_keywords;
-    data = (void*)&cbdata;
-  } else {
-    PyErr_SetString(PyExc_RuntimeError,
-                    "function parameter is not callable");
-    goto exit;
-  }
-  if (!NI_GenericFilter(input, func, data, footprint, output,
-                        (NI_ExtendMode)mode, cval, origin))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  Py_XDECREF(footprint);
-  if (origin)
-    free(origin);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_FourierFilter(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *parameters = NULL;
-  int axis, filter_type;
-  long n;
-
-  if (!PyArg_ParseTuple(args, "O&O&liO&i", NI_ObjectToInputArray, &input,
-                    NI_ObjectToInputArray, &parameters, &n, &axis,
-                    NI_ObjectToOutputArray, &output, &filter_type))
-    goto exit;
-
-  if (!NI_FourierFilter(input, parameters, n, axis, output, filter_type))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(parameters);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_FourierShift(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *shifts = NULL;
-  int axis;
-  long n;
-
-  if (!PyArg_ParseTuple(args, "O&O&liO&", NI_ObjectToInputArray, &input,
-                    NI_ObjectToInputArray, &shifts, &n, &axis,
-                    NI_ObjectToOutputArray, &output))
-    goto exit;
-
-  if (!NI_FourierShift(input, shifts, n, axis, output))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(shifts);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_SplineFilter1D(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL;
-  int axis, order;
-
-  if (!PyArg_ParseTuple(args, "O&iiO&", NI_ObjectToInputArray, &input,
-          &order, &axis, NI_ObjectToOutputArray, &output))
-    goto exit;
-
-  if (!NI_SplineFilter1D(input, order, axis, output))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_Map(maybelong *ocoor, double* icoor, int orank, int irank,
-                  void *data)
-{
-  PyObject *coors = NULL, *rets = NULL, *args = NULL, *tmp = NULL;
-  maybelong ii;
-  NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-  coors = PyTuple_New(orank);
-  if (!coors)
-    goto exit;
-  for(ii = 0; ii < orank; ii++) {
-    PyTuple_SetItem(coors, ii, PyInt_FromLong(ocoor[ii]));
-    if (PyErr_Occurred())
-      goto exit;
-  }
-  tmp = Py_BuildValue("(O)", coors);
-  if (!tmp)
-    goto exit;
-  args = PySequence_Concat(tmp, cbdata->extra_arguments);
-  if (!args)
-    goto exit;
-  rets = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-  if (!rets)
-    goto exit;
-  for(ii = 0; ii < irank; ii++) {
-    icoor[ii] = PyFloat_AsDouble(PyTuple_GetItem(rets, ii));
-    if (PyErr_Occurred())
-      goto exit;
-  }
-exit:
-  Py_XDECREF(coors);
-  Py_XDECREF(tmp);
-  Py_XDECREF(rets);
-  Py_XDECREF(args);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-
-static PyObject *Py_GeometricTransform(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL;
-  PyArrayObject *coordinates = NULL, *matrix = NULL, *shift = NULL;
-  PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-  int mode, order;
-  double cval;
-  void *func = NULL, *data = NULL;
-  NI_PythonCallbackData cbdata;
-
-  if (!PyArg_ParseTuple(args, "O&OO&O&O&O&iidOO", NI_ObjectToInputArray,
-                        &input, &fnc, NI_ObjectToOptionalInputArray,
-                        &coordinates, NI_ObjectToOptionalInputArray,
-                        &matrix, NI_ObjectToOptionalInputArray, &shift,
-                        NI_ObjectToOutputArray, &output, &order, &mode,
-                        &cval, &extra_arguments, &extra_keywords))
-    goto exit;
-
-  if (fnc != Py_None) {
-    if (!PyTuple_Check(extra_arguments)) {
-      PyErr_SetString(PyExc_RuntimeError,
-                      "extra_arguments must be a tuple");
-      goto exit;
-    }
-    if (!PyDict_Check(extra_keywords)) {
-      PyErr_SetString(PyExc_RuntimeError,
-                      "extra_keywords must be a dictionary");
-      goto exit;
-    }
-    if (PyCObject_Check(fnc)) {
-      func = PyCObject_AsVoidPtr(fnc);
-      data = PyCObject_GetDesc(fnc);
-    } else if (PyCallable_Check(fnc)) {
-      func = Py_Map;
-      cbdata.function = fnc;
-      cbdata.extra_arguments = extra_arguments;
-      cbdata.extra_keywords = extra_keywords;
-      data = (void*)&cbdata;
-    } else {
-      PyErr_SetString(PyExc_RuntimeError,
-                      "function parameter is not callable");
-      goto exit;
-    }
-  }
-
-  if (!NI_GeometricTransform(input, func, data, matrix, shift, coordinates,
-                          output, order, (NI_ExtendMode)mode, cval))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(output);
-  Py_XDECREF(coordinates);
-  Py_XDECREF(matrix);
-  Py_XDECREF(shift);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_ZoomShift(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *shift = NULL;
-  PyArrayObject *zoom = NULL;
-  int mode, order;
-  double cval;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&O&iid", NI_ObjectToInputArray,
-          &input, NI_ObjectToOptionalInputArray, &zoom,
-          NI_ObjectToOptionalInputArray, &shift, NI_ObjectToOutputArray,
-          &output, &order, &mode, &cval))
-    goto exit;
-
-  if (!NI_ZoomShift(input, zoom, shift, output, order, (NI_ExtendMode)mode,
-                    cval))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(shift);
-  Py_XDECREF(zoom);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_Label(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
-  maybelong max_label;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
-          NI_ObjectToInputArray, &strct, NI_ObjectToOutputArray, &output))
-    goto exit;
-
-  if (!NI_Label(input, strct, &max_label, output))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(strct);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("l", (long)max_label);
-}
-
-static PyObject *Py_FindObjects(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL;
-  PyObject *result = NULL, *tuple = NULL, *start = NULL, *end = NULL;
-  PyObject *slc = NULL;
-  int jj;
-  long max_label;
-  maybelong ii, *regions = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&l", NI_ObjectToInputArray, &input,
-                        &max_label))
-    goto exit;
-
-  if (max_label < 0)
-    max_label = 0;
-  if (max_label > 0) {
-    if (input->nd > 0) {
-      regions = (maybelong*)malloc(2 * max_label * input->nd *
-                                                    sizeof(maybelong));
-    } else {
-      regions = (maybelong*)malloc(max_label * sizeof(maybelong));
-    }
-    if (!regions) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-
-  if (!NI_FindObjects(input, max_label, regions))
-    goto exit;
-
-  result = PyList_New(max_label);
-  if (!result) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-
-  for(ii = 0; ii < max_label; ii++) {
-    maybelong idx = input->nd > 0 ? 2 * input->nd * ii : ii;
-    if (regions[idx] >= 0) {
-      PyObject *tuple = PyTuple_New(input->nd);
-      if (!tuple) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-      for(jj = 0; jj < input->nd; jj++) {
-        start = PyInt_FromLong(regions[idx + jj]);
-        end = PyInt_FromLong(regions[idx + jj + input->nd]);
-        if (!start || !end) {
-          PyErr_NoMemory();
-          goto exit;
-        }
-        slc = PySlice_New(start, end, NULL);
-        if (!slc) {
-          PyErr_NoMemory();
-          goto exit;
-        }
-        Py_XDECREF(start);
-        Py_XDECREF(end);
-        start = end = NULL;
-        PyTuple_SetItem(tuple, jj, slc);
-        slc = NULL;
-      }
-      PyList_SetItem(result, ii, tuple);
-      tuple = NULL;
-    } else {
-      Py_INCREF(Py_None);
-      PyList_SetItem(result, ii, Py_None);
-    }
-  }
-
-  Py_INCREF(result);
-
- exit:
-  Py_XDECREF(input);
-  Py_XDECREF(result);
-  Py_XDECREF(tuple);
-  Py_XDECREF(start);
-  Py_XDECREF(end);
-  Py_XDECREF(slc);
-  if (regions)
-    free(regions);
-  if (PyErr_Occurred()) {
-    Py_XDECREF(result);
-    return NULL;
-  } else {
-    return result;
-  }
-}
-
-static PyObject *Py_WatershedIFT(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *markers = NULL;
-  PyArrayObject *strct = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&O&", NI_ObjectToInputArray, &input,
-          NI_ObjectToInputArray, &markers, NI_ObjectToInputArray,
-          &strct, NI_ObjectToOutputArray, &output))
-    goto exit;
-
-  if (!NI_WatershedIFT(input, markers, strct, output))
-    goto exit;
-
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(markers);
-  Py_XDECREF(strct);
-  Py_XDECREF(output);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int _NI_GetIndices(PyObject* indices_object,
-                          maybelong** result_indices, maybelong* min_label,
-                          maybelong* max_label, maybelong* n_results)
-{
-  maybelong *indices = NULL, n_indices, ii;
-
-  if (indices_object == Py_None) {
-    *min_label = -1;
-    *n_results = 1;
-  } else {
-    n_indices = NI_ObjectToLongSequenceAndLength(indices_object, &indices);
-    if (n_indices < 0)
-      goto exit;
-    if (n_indices < 1) {
-      PyErr_SetString(PyExc_RuntimeError, "no correct indices provided");
-      goto exit;
-    } else {
-      *min_label = *max_label = indices[0];
-      if (*min_label < 0) {
-        PyErr_SetString(PyExc_RuntimeError,
-                        "negative indices not allowed");
-        goto exit;
-      }
-      for(ii = 1; ii < n_indices; ii++) {
-        if (indices[ii] < 0) {
-          PyErr_SetString(PyExc_RuntimeError,
-                          "negative indices not allowed");
-          goto exit;
-        }
-        if (indices[ii] < *min_label)
-          *min_label = indices[ii];
-        if (indices[ii] > *max_label)
-          *max_label = indices[ii];
-      }
-      *result_indices = (maybelong*)malloc((*max_label - *min_label + 1) *
-                                           sizeof(maybelong));
-      if (!*result_indices) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-      for(ii = 0; ii < *max_label - *min_label + 1; ii++)
-        (*result_indices)[ii] = -1;
-      *n_results = 0;
-      for(ii = 0; ii < n_indices; ii++) {
-        if ((*result_indices)[indices[ii] - *min_label] >= 0) {
-          PyErr_SetString(PyExc_RuntimeError, "duplicate index");
-          goto exit;
-        }
-        (*result_indices)[indices[ii] - *min_label] = ii;
-        ++(*n_results);
-      }
-    }
-  }
- exit:
-  if (indices)
-    free(indices);
-  return PyErr_Occurred() == NULL;
-}
-
-
-PyObject* _NI_BuildMeasurementResultArrayObject(maybelong n_results,
-                                                PyArrayObject** values)
-{
-  PyObject *result = NULL;
-  if (n_results > 1) {
-    result = PyList_New(n_results);
-    if (result) {
-      maybelong ii;
-      for(ii = 0; ii < n_results; ii++) {
-        PyList_SET_ITEM(result, ii, (PyObject*)values[ii]);
-        Py_XINCREF(values[ii]);
-      }
-    }
-  } else {
-    result = (PyObject*)values[0];
-    Py_XINCREF(values[0]);
-  }
-  return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultDouble(maybelong n_results,
-                                           double* values)
-{
-  PyObject *result = NULL;
-  if (n_results > 1) {
-    result = PyList_New(n_results);
-    if (result) {
-      int ii;
-      for(ii = 0; ii < n_results; ii++) {
-        PyObject* val = PyFloat_FromDouble(values[ii]);
-        if (!val) {
-          Py_XDECREF(result);
-          return NULL;
-        }
-        PyList_SET_ITEM(result, ii, val);
-      }
-    }
-  } else {
-    result = Py_BuildValue("d", values[0]);
-  }
-  return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultDoubleTuple(maybelong n_results,
-                                            int tuple_size, double* values)
-{
-  PyObject *result = NULL;
-  maybelong ii;
-  int jj;
-
-  if (n_results > 1) {
-    result = PyList_New(n_results);
-    if (result) {
-      for(ii = 0; ii < n_results; ii++) {
-        PyObject* val = PyTuple_New(tuple_size);
-        if (!val) {
-          Py_XDECREF(result);
-          return NULL;
-        }
-        for(jj = 0; jj < tuple_size; jj++) {
-          maybelong idx = jj + ii * tuple_size;
-          PyTuple_SetItem(val, jj, PyFloat_FromDouble(values[idx]));
-          if (PyErr_Occurred()) {
-            Py_XDECREF(result);
-            return NULL;
-          }
-        }
-        PyList_SET_ITEM(result, ii, val);
-      }
-    }
-  } else {
-    result = PyTuple_New(tuple_size);
-    if (result) {
-      for(ii = 0; ii < tuple_size; ii++) {
-        PyTuple_SetItem(result, ii, PyFloat_FromDouble(values[ii]));
-        if (PyErr_Occurred()) {
-          Py_XDECREF(result);
-          return NULL;
-        }
-      }
-    }
-  }
-  return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultInt(maybelong n_results,
-                                        maybelong* values)
-{
-  PyObject *result = NULL;
-  if (n_results > 1) {
-    result = PyList_New(n_results);
-    if (result) {
-      maybelong ii;
-      for(ii = 0; ii < n_results; ii++) {
-        PyObject* val = PyInt_FromLong(values[ii]);
-        if (!val) {
-          Py_XDECREF(result);
-          return NULL;
-        }
-        PyList_SET_ITEM(result, ii, val);
-      }
-    }
-  } else {
-    result = Py_BuildValue("l", values[0]);
-  }
-  return result;
-}
-
-
-static PyObject *Py_Statistics(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *labels = NULL;
-  PyObject *indices_object, *result = NULL;
-  PyObject *res1 = NULL, *res2 = NULL, *res3 = NULL, *res4 = NULL;
-  double *dresult1 = NULL, *dresult2 = NULL;
-  maybelong *lresult1 = NULL, *lresult2 = NULL;
-  maybelong min_label, max_label, *result_indices = NULL, n_results, ii;
-  int type;
-
-  if (!PyArg_ParseTuple(args, "O&O&Oi", NI_ObjectToInputArray, &input,
-          NI_ObjectToOptionalInputArray, &labels, &indices_object, &type))
-    goto exit;
-
-  if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                      &max_label, &n_results))
-    goto exit;
-
-  if (type >= 0 && type <= 7) {
-    dresult1 = (double*)malloc(n_results * sizeof(double));
-    if (!dresult1) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  if (type == 2 || type == 7) {
-    dresult2 = (double*)malloc(n_results * sizeof(double));
-    if (!dresult2) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  if (type == 1 || type == 2 || (type >= 5 && type <= 7)) {
-    lresult1 = (maybelong*)malloc(n_results * sizeof(maybelong));
-    if (!lresult1) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  if (type == 7) {
-    lresult2 = (maybelong*)malloc(n_results * sizeof(maybelong));
-    if (!lresult2) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  switch(type) {
-  case 0:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                  n_results, dresult1, NULL, NULL, NULL, NULL, NULL, NULL))
-      goto exit;
-    result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-    break;
-  case 1:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-              n_results, dresult1, lresult1, NULL, NULL, NULL, NULL, NULL))
-      goto exit;
-    for(ii = 0; ii < n_results; ii++)
-      dresult1[ii] = lresult1[ii] > 0 ? dresult1[ii] / lresult1[ii] : 0.0;
-
-    result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-    break;
-  case 2:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-          n_results, dresult1, lresult1, dresult2, NULL, NULL, NULL, NULL))
-      goto exit;
-    result = _NI_BuildMeasurementResultDouble(n_results, dresult2);
-    break;
-  case 3:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                  n_results, NULL, NULL, NULL, dresult1, NULL, NULL, NULL))
-      goto exit;
-    result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-    break;
-  case 4:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                  n_results, NULL, NULL, NULL, NULL, dresult1, NULL, NULL))
-      goto exit;
-    result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-    break;
-  case 5:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-              n_results, NULL, NULL, NULL, dresult1, NULL, lresult1, NULL))
-      goto exit;
-    result = _NI_BuildMeasurementResultInt(n_results, lresult1);
-    break;
-  case 6:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-              n_results, NULL, NULL, NULL, NULL, dresult1, NULL, lresult1))
-      goto exit;
-    result = _NI_BuildMeasurementResultInt(n_results, lresult1);
-    break;
-  case 7:
-    if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                       n_results, NULL, NULL, NULL, dresult1, dresult2,
-                       lresult1, lresult2))
-      goto exit;
-    res1 = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-    res2 = _NI_BuildMeasurementResultDouble(n_results, dresult2);
-    res3 = _NI_BuildMeasurementResultInt(n_results, lresult1);
-    res4 = _NI_BuildMeasurementResultInt(n_results, lresult2);
-    if (!res1 || !res2 || !res3 || !res4)
-      goto exit;
-    result = Py_BuildValue("OOOO", res1, res2, res3, res4);
-    break;
-  default:
-    PyErr_SetString(PyExc_RuntimeError, "operation not supported");
-    goto exit;
-  }
-
- exit:
-  Py_XDECREF(input);
-  Py_XDECREF(labels);
-  if (result_indices)
-    free(result_indices);
-  if (dresult1)
-    free(dresult1);
-  if (dresult2)
-    free(dresult2);
-  if (lresult1)
-    free(lresult1);
-  if (lresult2)
-    free(lresult2);
-  return result;
-}
-
-
-static PyObject *Py_CenterOfMass(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *labels = NULL;
-  PyObject *indices_object, *result = NULL;
-  double *center_of_mass = NULL;
-  maybelong min_label, max_label, *result_indices = NULL, n_results;
-
-  if (!PyArg_ParseTuple(args, "O&O&O", NI_ObjectToInputArray, &input,
-                  NI_ObjectToOptionalInputArray, &labels, &indices_object))
-    goto exit;
-
-  if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                      &max_label, &n_results))
-    goto exit;
-
-  center_of_mass = (double*)malloc(input->nd * n_results *
-                                   sizeof(double));
-  if (!center_of_mass) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-
-  if (!NI_CenterOfMass(input, labels, min_label, max_label,
-                       result_indices, n_results, center_of_mass))
-    goto exit;
-
-  result = _NI_BuildMeasurementResultDoubleTuple(n_results, input->nd,
-                                                 center_of_mass);
-
- exit:
-  Py_XDECREF(input);
-  Py_XDECREF(labels);
-  if (result_indices)
-    free(result_indices);
-  if (center_of_mass)
-    free(center_of_mass);
-  return result;
-}
-
-static PyObject *Py_Histogram(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *labels = NULL, **histograms = NULL;
-  PyObject *indices_object, *result = NULL;
-  maybelong min_label, max_label, *result_indices = NULL, n_results;
-  maybelong jj, nbins;
-  long nbins_in;
-  double min, max;
-
-  if (!PyArg_ParseTuple(args, "O&ddlO&O", NI_ObjectToInputArray, &input,
-                        &min, &max, &nbins_in, NI_ObjectToOptionalInputArray,
-                        &labels, &indices_object))
-    goto exit;
-  nbins = nbins_in;
-
-  if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                      &max_label, &n_results))
-    goto exit;
-
-  /* Set all pointers to NULL, so that freeing the memory */
-  /* doesn't cause problems. */
-  histograms = (PyArrayObject**)calloc(input->nd * n_results,
-                                       sizeof(PyArrayObject*));
-  if (!histograms) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < n_results; jj++) {
-    histograms[jj] = NA_NewArray(NULL, tInt32, 1, &nbins);
-    if (!histograms[jj]) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-
-  if (!NI_Histogram(input, labels, min_label, max_label, result_indices,
-                    n_results, histograms, min, max, nbins))
-    goto exit;
-
-  result = _NI_BuildMeasurementResultArrayObject(n_results, histograms);
-
- exit:
-  Py_XDECREF(input);
-  Py_XDECREF(labels);
-  if (result_indices)
-    free(result_indices);
-  if (histograms) {
-    for(jj = 0; jj < n_results; jj++) {
-      Py_XDECREF(histograms[jj]);
-    }
-    free(histograms);
-  }
-  return result;
-}
-
-static PyObject *Py_DistanceTransformBruteForce(PyObject *obj,
-                                                PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *features = NULL;
-  PyArrayObject *sampling = NULL;
-  int metric;
-
-  if (!PyArg_ParseTuple(args, "O&iO&O&O&", NI_ObjectToInputArray, &input,
-                        &metric, NI_ObjectToOptionalInputArray, &sampling,
-                        NI_ObjectToOptionalOutputArray, &output,
-                        NI_ObjectToOptionalOutputArray, &features))
-    goto exit;
-  if (!NI_DistanceTransformBruteForce(input, metric, sampling,
-                                      output, features))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(sampling);
-  Py_XDECREF(output);
-  Py_XDECREF(features);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_DistanceTransformOnePass(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *strct = NULL, *distances = NULL, *features = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &strct,
-                        NI_ObjectToIoArray, &distances,
-                        NI_ObjectToOptionalOutputArray, &features))
-    goto exit;
-  if (!NI_DistanceTransformOnePass(strct, distances, features))
-    goto exit;
-exit:
-  Py_XDECREF(strct);
-  Py_XDECREF(distances);
-  Py_XDECREF(features);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_EuclideanFeatureTransform(PyObject *obj,
-                                              PyObject *args)
-{
-  PyArrayObject *input = NULL, *features = NULL, *sampling = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
-                        NI_ObjectToOptionalInputArray, &sampling,
-                        NI_ObjectToOutputArray, &features))
-    goto exit;
-  if (!NI_EuclideanFeatureTransform(input, sampling, features))
-    goto exit;
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(sampling);
-  Py_XDECREF(features);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static void _FreeCoordinateList(void* ptr)
-{
-  NI_FreeCoordinateList((NI_CoordinateList*)ptr);
-}
-
-static PyObject *Py_BinaryErosion(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
-  PyArrayObject *mask = NULL;
-  PyObject *cobj = NULL;
-  int border_value, invert, center_is_true;
-  int changed = 0, return_coordinates;
-  NI_CoordinateList *coordinate_list = NULL;
-  maybelong *origins = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&O&iO&iii", NI_ObjectToInputArray,
-                        &input, NI_ObjectToInputArray, &strct,
-                        NI_ObjectToOptionalInputArray, &mask,
-                        NI_ObjectToOutputArray, &output, &border_value,
-                        NI_ObjectToLongSequence, &origins,  &invert,
-                        &center_is_true, &return_coordinates))
-    goto exit;
-  if (!NI_BinaryErosion(input, strct, mask, output, border_value,
-                        origins, invert, center_is_true, &changed,
-                        return_coordinates ? &coordinate_list : NULL))
-    goto exit;
-  if (return_coordinates) {
-    cobj = PyCObject_FromVoidPtr(coordinate_list, _FreeCoordinateList);
-  }
-exit:
-  Py_XDECREF(input);
-  Py_XDECREF(strct);
-  Py_XDECREF(mask);
-  Py_XDECREF(output);
-  if (origins)
-    free(origins);
-  if (PyErr_Occurred()) {
-    Py_XDECREF(cobj);
-    return NULL;
-  } else {
-    if (return_coordinates) {
-      return Py_BuildValue("iN", changed, cobj);
-    } else {
-      return Py_BuildValue("i", changed);
-    }
-  }
-}
-
-static PyObject *Py_BinaryErosion2(PyObject *obj, PyObject *args)
-{
-  PyArrayObject *array = NULL, *strct = NULL, *mask = NULL;
-  PyObject *cobj = NULL;
-  int invert, niter;
-  maybelong *origins = NULL;
-
-  if (!PyArg_ParseTuple(args, "O&O&O&iO&iO", NI_ObjectToIoArray, &array,
-          NI_ObjectToInputArray, &strct, NI_ObjectToOptionalInputArray,
-          &mask, &niter, NI_ObjectToLongSequence, &origins, &invert,
-          &cobj))
-    goto exit;
-
-  if (PyCObject_Check(cobj)) {
-    NI_CoordinateList *cobj_data = PyCObject_AsVoidPtr(cobj);
-    if (!NI_BinaryErosion2(array, strct, mask, niter, origins, invert,
-                           &cobj_data))
-      goto exit;
-  } else {
-    PyErr_SetString(PyExc_RuntimeError, "cannot convert CObject");
-    goto exit;
-  }
-exit:
-  Py_XDECREF(array);
-  Py_XDECREF(strct);
-  Py_XDECREF(mask);
-  if (origins) free(origins);
-  return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyMethodDef methods[] = {
-  {"correlate1d",           (PyCFunction)Py_Correlate1D,
-   METH_VARARGS, NULL},
-  {"correlate",             (PyCFunction)Py_Correlate,
-   METH_VARARGS, NULL},
-  {"uniform_filter1d",      (PyCFunction)Py_UniformFilter1D,
-   METH_VARARGS, NULL},
-  {"min_or_max_filter1d",   (PyCFunction)Py_MinOrMaxFilter1D,
-    METH_VARARGS, NULL},
-  {"min_or_max_filter",     (PyCFunction)Py_MinOrMaxFilter,
-    METH_VARARGS, NULL},
-  {"rank_filter",           (PyCFunction)Py_RankFilter,
-   METH_VARARGS, NULL},
-  {"generic_filter",        (PyCFunction)Py_GenericFilter,
-   METH_VARARGS, NULL},
-  {"generic_filter1d",      (PyCFunction)Py_GenericFilter1D,
-   METH_VARARGS, NULL},
-  {"fourier_filter",        (PyCFunction)Py_FourierFilter,
-   METH_VARARGS, NULL},
-  {"fourier_shift",         (PyCFunction)Py_FourierShift,
-   METH_VARARGS, NULL},
-  {"spline_filter1d",       (PyCFunction)Py_SplineFilter1D,
-   METH_VARARGS, NULL},
-  {"geometric_transform",   (PyCFunction)Py_GeometricTransform,
-    METH_VARARGS, NULL},
-  {"zoom_shift",            (PyCFunction)Py_ZoomShift,
-   METH_VARARGS, NULL},
-  {"label",                 (PyCFunction)Py_Label,
-   METH_VARARGS, NULL},
-  {"find_objects",          (PyCFunction)Py_FindObjects,
-   METH_VARARGS, NULL},
-  {"watershed_ift",         (PyCFunction)Py_WatershedIFT,
-   METH_VARARGS, NULL},
-  {"statistics",            (PyCFunction)Py_Statistics,
-   METH_VARARGS, NULL},
-  {"center_of_mass",        (PyCFunction)Py_CenterOfMass,
-   METH_VARARGS, NULL},
-  {"histogram",             (PyCFunction)Py_Histogram,
-   METH_VARARGS, NULL},
-  {"distance_transform_bf", (PyCFunction)Py_DistanceTransformBruteForce,
-   METH_VARARGS, NULL},
-  {"distance_transform_op", (PyCFunction)Py_DistanceTransformOnePass,
-   METH_VARARGS, NULL},
-  {"euclidean_feature_transform",
-   (PyCFunction)Py_EuclideanFeatureTransform, 
-   METH_VARARGS, NULL},
-  {"binary_erosion",        (PyCFunction)Py_BinaryErosion,
-   METH_VARARGS, NULL},
-  {"binary_erosion2",       (PyCFunction)Py_BinaryErosion2,
-   METH_VARARGS, NULL},
-  {NULL, NULL, 0, NULL}
-};
-
-PyMODINIT_FUNC init_nd_image(void)
-{
-  Py_InitModule("_nd_image", methods);
-  import_array();
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define ND_IMPORT_ARRAY
+#include "nd_image.h"
+#undef ND_IMPORT_ARRAY
+#include "ni_support.h"
+#include "ni_filters.h"
+#include "ni_fourier.h"
+#include "ni_morphology.h"
+#include "ni_interpolation.h"
+#include "ni_measure.h"
+
+typedef struct {
+    PyObject *function;
+    PyObject *extra_arguments;
+    PyObject *extra_keywords;
+} NI_PythonCallbackData;
+
+/* Convert an input array of any type, not necessarily contiguous */
+static int
+NI_ObjectToInputArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an input array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOptionalInputArray(PyObject *object, PyArrayObject **array)
+{
+    if (object == Py_None) {
+        *array = NULL;
+        return 1;
+    } else {
+        *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+        return *array ? 1 : 0;
+    }
+}
+
+/* Convert an output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOutputArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOptionalOutputArray(PyObject *object, PyArrayObject **array)
+{
+    if (object == Py_None) {
+        *array = NULL;
+        return 1;
+    } else {
+        *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+        return *array ? 1 : 0;
+    }
+}
+
+/* Convert an input/output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToIoArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_IoArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an Long sequence */
+static maybelong
+NI_ObjectToLongSequenceAndLength(PyObject *object, maybelong **sequence)
+{
+    long *pa, ii;
+    PyArrayObject *array = NA_InputArray(object, PyArray_LONG, NPY_CARRAY);
+    maybelong length = PyArray_SIZE(array);
+
+    *sequence = (maybelong*)malloc(length * sizeof(maybelong));
+    if (!*sequence) {
+        PyErr_NoMemory();
+        Py_XDECREF(array);
+        return -1;
+    }
+    pa = (long*)PyArray_DATA(array);
+    for(ii = 0; ii < length; ii++)
+        (*sequence)[ii] = pa[ii];
+    Py_XDECREF(array);
+    return length;
+}
+
+static int
+NI_ObjectToLongSequence(PyObject *object, maybelong **sequence)
+{
+    return NI_ObjectToLongSequenceAndLength(object, sequence) >= 0;
+}
+
+/*********************************************************************/
+/* wrapper functions: */
+/*********************************************************************/
+
+static PyObject *Py_Correlate1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
+    int axis, mode;
+    long origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&iO&idl", NI_ObjectToInputArray, &input,
+                                    NI_ObjectToInputArray, &weights, &axis,
+                                    NI_ObjectToOutputArray, &output, &mode, &cval, &origin))
+        goto exit;
+    if (!NI_Correlate1D(input, weights, axis, output,
+                                            (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(weights);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_Correlate(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
+    maybelong *origin = NULL;
+    int mode;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&idO&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &weights, NI_ObjectToOutputArray, &output,
+                    &mode, &cval, NI_ObjectToLongSequence, &origin))
+        goto exit;
+    if (!NI_Correlate(input, weights, output, (NI_ExtendMode)mode, cval,
+                                        origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(weights);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_UniformFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, mode;
+    long filter_size, origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&liO&idl", NI_ObjectToInputArray, &input,
+                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
+                                        &mode, &cval, &origin))
+        goto exit;
+    if (!NI_UniformFilter1D(input, filter_size, axis, output,
+                                                                             (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_MinOrMaxFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, mode, minimum;
+    long filter_size, origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&liO&idli", NI_ObjectToInputArray, &input,
+                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
+                                        &mode, &cval, &origin, &minimum))
+        goto exit;
+    if (!NI_MinOrMaxFilter1D(input, filter_size, axis, output,
+                                                            (NI_ExtendMode)mode, cval, origin, minimum))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_MinOrMaxFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    PyArrayObject *structure = NULL;
+    maybelong *origin = NULL;
+    int mode, minimum;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&idO&i", NI_ObjectToInputArray,
+                                        &input, NI_ObjectToInputArray, &footprint,
+                                        NI_ObjectToOptionalInputArray, &structure,
+                                        NI_ObjectToOutputArray, &output, &mode, &cval,
+                                        NI_ObjectToLongSequence, &origin, &minimum))
+        goto exit;
+    if (!NI_MinOrMaxFilter(input, footprint, structure, output,
+                                                (NI_ExtendMode)mode, cval, origin, minimum))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(footprint);
+    Py_XDECREF(structure);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_RankFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    maybelong *origin = NULL;
+    int mode, rank;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&iO&O&idO&", NI_ObjectToInputArray,
+                                        &input, &rank, NI_ObjectToInputArray, &footprint,
+                                        NI_ObjectToOutputArray, &output, &mode, &cval,
+                                        NI_ObjectToLongSequence, &origin))
+        goto exit;
+    if (!NI_RankFilter(input, rank, footprint, output, (NI_ExtendMode)mode,
+                                         cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(footprint);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_Filter1DFunc(double *iline, maybelong ilen,
+                                                     double *oline, maybelong olen, void *data)
+{
+    PyArrayObject *py_ibuffer = NULL, *py_obuffer = NULL;
+    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
+    maybelong ii;
+    double *po = NULL;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    py_ibuffer = NA_NewArray(iline, PyArray_DOUBLE, 1, &ilen);
+    py_obuffer = NA_NewArray(NULL, PyArray_DOUBLE, 1, &olen);
+    if (!py_ibuffer || !py_obuffer)
+        goto exit;
+    tmp = Py_BuildValue("(OO)", py_ibuffer, py_obuffer);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rv)
+        goto exit;
+    po = (double*)PyArray_DATA(py_obuffer);
+    for(ii = 0; ii < olen; ii++)
+        oline[ii] = po[ii];
+exit:
+    Py_XDECREF(py_ibuffer);
+    Py_XDECREF(py_obuffer);
+    Py_XDECREF(rv);
+    Py_XDECREF(args);
+    Py_XDECREF(tmp);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static PyObject *Py_GenericFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    void *func = Py_Filter1DFunc, *data = NULL;
+    NI_PythonCallbackData cbdata;
+    int axis, mode;
+    long origin, filter_size;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&OliO&idlOO", NI_ObjectToInputArray,
+                &input, &fnc, &filter_size, &axis, NI_ObjectToOutputArray,
+                &output, &mode, &cval, &origin, &extra_arguments, &extra_keywords))
+        goto exit;
+    if (!PyTuple_Check(extra_arguments)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_arguments must be a tuple");
+        goto exit;
+    }
+    if (!PyDict_Check(extra_keywords)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_keywords must be a dictionary");
+        goto exit;
+    }
+    if (PyCObject_Check(fnc)) {
+        func = PyCObject_AsVoidPtr(fnc);
+        data = PyCObject_GetDesc(fnc);
+    } else if (PyCallable_Check(fnc)) {
+        cbdata.function = fnc;
+        cbdata.extra_arguments = extra_arguments;
+        cbdata.extra_keywords = extra_keywords;
+        data = (void*)&cbdata;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "function parameter is not callable");
+        goto exit;
+    }
+    if (!NI_GenericFilter1D(input, func, data, filter_size, axis, output,
+                                                                                (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_FilterFunc(double *buffer, maybelong filter_size,
+                                                 double *output, void *data)
+{
+    PyArrayObject *py_buffer = NULL;
+    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    py_buffer = NA_NewArray(buffer, PyArray_DOUBLE, 1, &filter_size);
+    if (!py_buffer)
+        goto exit;
+    tmp = Py_BuildValue("(O)", py_buffer);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rv)
+        goto exit;
+    *output = PyFloat_AsDouble(rv);
+exit:
+    Py_XDECREF(py_buffer);
+    Py_XDECREF(rv);
+    Py_XDECREF(args);
+    Py_XDECREF(tmp);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static PyObject *Py_GenericFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    void *func = Py_FilterFunc, *data = NULL;
+    NI_PythonCallbackData cbdata;
+    int mode;
+    maybelong *origin = NULL;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&OO&O&idO&OO", NI_ObjectToInputArray,
+                                                &input, &fnc, NI_ObjectToInputArray, &footprint,
+                                                NI_ObjectToOutputArray, &output, &mode, &cval,
+                                                NI_ObjectToLongSequence, &origin,
+                                                &extra_arguments, &extra_keywords))
+        goto exit;
+    if (!PyTuple_Check(extra_arguments)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_arguments must be a tuple");
+        goto exit;
+    }
+    if (!PyDict_Check(extra_keywords)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_keywords must be a dictionary");
+        goto exit;
+    }
+    if (PyCObject_Check(fnc)) {
+        func = PyCObject_AsVoidPtr(fnc);
+        data = PyCObject_GetDesc(fnc);
+    } else if (PyCallable_Check(fnc)) {
+        cbdata.function = fnc;
+        cbdata.extra_arguments = extra_arguments;
+        cbdata.extra_keywords = extra_keywords;
+        data = (void*)&cbdata;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "function parameter is not callable");
+        goto exit;
+    }
+    if (!NI_GenericFilter(input, func, data, footprint, output,
+                                                (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    Py_XDECREF(footprint);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_FourierFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *parameters = NULL;
+    int axis, filter_type;
+    long n;
+
+    if (!PyArg_ParseTuple(args, "O&O&liO&i", NI_ObjectToInputArray, &input,
+                                        NI_ObjectToInputArray, &parameters, &n, &axis,
+                                        NI_ObjectToOutputArray, &output, &filter_type))
+        goto exit;
+
+    if (!NI_FourierFilter(input, parameters, n, axis, output, filter_type))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(parameters);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_FourierShift(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *shifts = NULL;
+    int axis;
+    long n;
+
+    if (!PyArg_ParseTuple(args, "O&O&liO&", NI_ObjectToInputArray, &input,
+                                        NI_ObjectToInputArray, &shifts, &n, &axis,
+                                        NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_FourierShift(input, shifts, n, axis, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(shifts);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_SplineFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, order;
+
+    if (!PyArg_ParseTuple(args, "O&iiO&", NI_ObjectToInputArray, &input,
+                    &order, &axis, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_SplineFilter1D(input, order, axis, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_Map(maybelong *ocoor, double* icoor, int orank, int irank,
+                                    void *data)
+{
+    PyObject *coors = NULL, *rets = NULL, *args = NULL, *tmp = NULL;
+    maybelong ii;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    coors = PyTuple_New(orank);
+    if (!coors)
+        goto exit;
+    for(ii = 0; ii < orank; ii++) {
+        PyTuple_SetItem(coors, ii, PyInt_FromLong(ocoor[ii]));
+        if (PyErr_Occurred())
+            goto exit;
+    }
+    tmp = Py_BuildValue("(O)", coors);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rets = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rets)
+        goto exit;
+    for(ii = 0; ii < irank; ii++) {
+        icoor[ii] = PyFloat_AsDouble(PyTuple_GetItem(rets, ii));
+        if (PyErr_Occurred())
+            goto exit;
+    }
+exit:
+    Py_XDECREF(coors);
+    Py_XDECREF(tmp);
+    Py_XDECREF(rets);
+    Py_XDECREF(args);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+static PyObject *Py_GeometricTransform(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    PyArrayObject *coordinates = NULL, *matrix = NULL, *shift = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    int mode, order;
+    double cval;
+    void *func = NULL, *data = NULL;
+    NI_PythonCallbackData cbdata;
+
+    if (!PyArg_ParseTuple(args, "O&OO&O&O&O&iidOO", NI_ObjectToInputArray,
+                                                &input, &fnc, NI_ObjectToOptionalInputArray,
+                                                &coordinates, NI_ObjectToOptionalInputArray,
+                                                &matrix, NI_ObjectToOptionalInputArray, &shift,
+                                                NI_ObjectToOutputArray, &output, &order, &mode,
+                                                &cval, &extra_arguments, &extra_keywords))
+        goto exit;
+
+    if (fnc != Py_None) {
+        if (!PyTuple_Check(extra_arguments)) {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "extra_arguments must be a tuple");
+            goto exit;
+        }
+        if (!PyDict_Check(extra_keywords)) {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "extra_keywords must be a dictionary");
+            goto exit;
+        }
+        if (PyCObject_Check(fnc)) {
+            func = PyCObject_AsVoidPtr(fnc);
+            data = PyCObject_GetDesc(fnc);
+        } else if (PyCallable_Check(fnc)) {
+            func = Py_Map;
+            cbdata.function = fnc;
+            cbdata.extra_arguments = extra_arguments;
+            cbdata.extra_keywords = extra_keywords;
+            data = (void*)&cbdata;
+        } else {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "function parameter is not callable");
+            goto exit;
+        }
+    }
+
+    if (!NI_GeometricTransform(input, func, data, matrix, shift, coordinates,
+                                                    output, order, (NI_ExtendMode)mode, cval))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    Py_XDECREF(coordinates);
+    Py_XDECREF(matrix);
+    Py_XDECREF(shift);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_ZoomShift(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *shift = NULL;
+    PyArrayObject *zoom = NULL;
+    int mode, order;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&iid", NI_ObjectToInputArray,
+                    &input, NI_ObjectToOptionalInputArray, &zoom,
+                    NI_ObjectToOptionalInputArray, &shift, NI_ObjectToOutputArray,
+                    &output, &order, &mode, &cval))
+        goto exit;
+
+    if (!NI_ZoomShift(input, zoom, shift, output, order, (NI_ExtendMode)mode,
+                                        cval))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(shift);
+    Py_XDECREF(zoom);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_Label(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
+    maybelong max_label;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &strct, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_Label(input, strct, &max_label, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(strct);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("l", (long)max_label);
+}
+
+static PyObject *Py_FindObjects(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL;
+    PyObject *result = NULL, *tuple = NULL, *start = NULL, *end = NULL;
+    PyObject *slc = NULL;
+    int jj;
+    long max_label;
+    maybelong ii, *regions = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&l", NI_ObjectToInputArray, &input,
+                                                &max_label))
+        goto exit;
+
+    if (max_label < 0)
+        max_label = 0;
+    if (max_label > 0) {
+        if (input->nd > 0) {
+            regions = (maybelong*)malloc(2 * max_label * input->nd *
+                                                                                                        sizeof(maybelong));
+        } else {
+            regions = (maybelong*)malloc(max_label * sizeof(maybelong));
+        }
+        if (!regions) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    if (!NI_FindObjects(input, max_label, regions))
+        goto exit;
+
+    result = PyList_New(max_label);
+    if (!result) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    for(ii = 0; ii < max_label; ii++) {
+        maybelong idx = input->nd > 0 ? 2 * input->nd * ii : ii;
+        if (regions[idx] >= 0) {
+            PyObject *tuple = PyTuple_New(input->nd);
+            if (!tuple) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            for(jj = 0; jj < input->nd; jj++) {
+                start = PyInt_FromLong(regions[idx + jj]);
+                end = PyInt_FromLong(regions[idx + jj + input->nd]);
+                if (!start || !end) {
+                    PyErr_NoMemory();
+                    goto exit;
+                }
+                slc = PySlice_New(start, end, NULL);
+                if (!slc) {
+                    PyErr_NoMemory();
+                    goto exit;
+                }
+                Py_XDECREF(start);
+                Py_XDECREF(end);
+                start = end = NULL;
+                PyTuple_SetItem(tuple, jj, slc);
+                slc = NULL;
+            }
+            PyList_SetItem(result, ii, tuple);
+            tuple = NULL;
+        } else {
+            Py_INCREF(Py_None);
+            PyList_SetItem(result, ii, Py_None);
+        }
+    }
+
+    Py_INCREF(result);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(result);
+    Py_XDECREF(tuple);
+    Py_XDECREF(start);
+    Py_XDECREF(end);
+    Py_XDECREF(slc);
+    if (regions)
+        free(regions);
+    if (PyErr_Occurred()) {
+        Py_XDECREF(result);
+        return NULL;
+    } else {
+        return result;
+    }
+}
+
+static PyObject *Py_WatershedIFT(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *markers = NULL;
+    PyArrayObject *strct = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &markers, NI_ObjectToInputArray,
+                    &strct, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_WatershedIFT(input, markers, strct, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(markers);
+    Py_XDECREF(strct);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int _NI_GetIndices(PyObject* indices_object,
+                                                    maybelong** result_indices, maybelong* min_label,
+                                                    maybelong* max_label, maybelong* n_results)
+{
+    maybelong *indices = NULL, n_indices, ii;
+
+    if (indices_object == Py_None) {
+        *min_label = -1;
+        *n_results = 1;
+    } else {
+        n_indices = NI_ObjectToLongSequenceAndLength(indices_object, &indices);
+        if (n_indices < 0)
+            goto exit;
+        if (n_indices < 1) {
+            PyErr_SetString(PyExc_RuntimeError, "no correct indices provided");
+            goto exit;
+        } else {
+            *min_label = *max_label = indices[0];
+            if (*min_label < 0) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                                "negative indices not allowed");
+                goto exit;
+            }
+            for(ii = 1; ii < n_indices; ii++) {
+                if (indices[ii] < 0) {
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "negative indices not allowed");
+                    goto exit;
+                }
+                if (indices[ii] < *min_label)
+                    *min_label = indices[ii];
+                if (indices[ii] > *max_label)
+                    *max_label = indices[ii];
+            }
+            *result_indices = (maybelong*)malloc((*max_label - *min_label + 1) *
+                                                                                     sizeof(maybelong));
+            if (!*result_indices) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            for(ii = 0; ii < *max_label - *min_label + 1; ii++)
+                (*result_indices)[ii] = -1;
+            *n_results = 0;
+            for(ii = 0; ii < n_indices; ii++) {
+                if ((*result_indices)[indices[ii] - *min_label] >= 0) {
+                    PyErr_SetString(PyExc_RuntimeError, "duplicate index");
+                    goto exit;
+                }
+                (*result_indices)[indices[ii] - *min_label] = ii;
+                ++(*n_results);
+            }
+        }
+    }
+ exit:
+    if (indices)
+        free(indices);
+    return PyErr_Occurred() == NULL;
+}
+
+
+PyObject* _NI_BuildMeasurementResultArrayObject(maybelong n_results,
+                                                                                                PyArrayObject** values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            maybelong ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyList_SET_ITEM(result, ii, (PyObject*)values[ii]);
+                Py_XINCREF(values[ii]);
+            }
+        }
+    } else {
+        result = (PyObject*)values[0];
+        Py_XINCREF(values[0]);
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultDouble(maybelong n_results,
+                                                                                     double* values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            int ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyFloat_FromDouble(values[ii]);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = Py_BuildValue("d", values[0]);
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultDoubleTuple(maybelong n_results,
+                                                                                        int tuple_size, double* values)
+{
+    PyObject *result = NULL;
+    maybelong ii;
+    int jj;
+
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyTuple_New(tuple_size);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                for(jj = 0; jj < tuple_size; jj++) {
+                    maybelong idx = jj + ii * tuple_size;
+                    PyTuple_SetItem(val, jj, PyFloat_FromDouble(values[idx]));
+                    if (PyErr_Occurred()) {
+                        Py_XDECREF(result);
+                        return NULL;
+                    }
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = PyTuple_New(tuple_size);
+        if (result) {
+            for(ii = 0; ii < tuple_size; ii++) {
+                PyTuple_SetItem(result, ii, PyFloat_FromDouble(values[ii]));
+                if (PyErr_Occurred()) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultInt(maybelong n_results,
+                                                                                maybelong* values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            maybelong ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyInt_FromLong(values[ii]);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = Py_BuildValue("l", values[0]);
+    }
+    return result;
+}
+
+
+static PyObject *Py_Statistics(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL;
+    PyObject *indices_object, *result = NULL;
+    PyObject *res1 = NULL, *res2 = NULL, *res3 = NULL, *res4 = NULL;
+    double *dresult1 = NULL, *dresult2 = NULL;
+    maybelong *lresult1 = NULL, *lresult2 = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results, ii;
+    int type;
+
+    if (!PyArg_ParseTuple(args, "O&O&Oi", NI_ObjectToInputArray, &input,
+                    NI_ObjectToOptionalInputArray, &labels, &indices_object, &type))
+        goto exit;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    if (type >= 0 && type <= 7) {
+        dresult1 = (double*)malloc(n_results * sizeof(double));
+        if (!dresult1) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 2 || type == 7) {
+        dresult2 = (double*)malloc(n_results * sizeof(double));
+        if (!dresult2) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 1 || type == 2 || (type >= 5 && type <= 7)) {
+        lresult1 = (maybelong*)malloc(n_results * sizeof(maybelong));
+        if (!lresult1) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 7) {
+        lresult2 = (maybelong*)malloc(n_results * sizeof(maybelong));
+        if (!lresult2) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    switch(type) {
+    case 0:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, dresult1, NULL, NULL, NULL, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 1:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, dresult1, lresult1, NULL, NULL, NULL, NULL, NULL))
+            goto exit;
+        for(ii = 0; ii < n_results; ii++)
+            dresult1[ii] = lresult1[ii] > 0 ? dresult1[ii] / lresult1[ii] : 0.0;
+
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 2:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                    n_results, dresult1, lresult1, dresult2, NULL, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult2);
+        break;
+    case 3:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, NULL, NULL, NULL, dresult1, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 4:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, NULL, NULL, NULL, NULL, dresult1, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 5:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, NULL, NULL, NULL, dresult1, NULL, lresult1, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        break;
+    case 6:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, NULL, NULL, NULL, NULL, dresult1, NULL, lresult1))
+            goto exit;
+        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        break;
+    case 7:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                             n_results, NULL, NULL, NULL, dresult1, dresult2,
+                                             lresult1, lresult2))
+            goto exit;
+        res1 = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        res2 = _NI_BuildMeasurementResultDouble(n_results, dresult2);
+        res3 = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        res4 = _NI_BuildMeasurementResultInt(n_results, lresult2);
+        if (!res1 || !res2 || !res3 || !res4)
+            goto exit;
+        result = Py_BuildValue("OOOO", res1, res2, res3, res4);
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError, "operation not supported");
+        goto exit;
+    }
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (dresult1)
+        free(dresult1);
+    if (dresult2)
+        free(dresult2);
+    if (lresult1)
+        free(lresult1);
+    if (lresult2)
+        free(lresult2);
+    return result;
+}
+
+
+static PyObject *Py_CenterOfMass(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL;
+    PyObject *indices_object, *result = NULL;
+    double *center_of_mass = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results;
+
+    if (!PyArg_ParseTuple(args, "O&O&O", NI_ObjectToInputArray, &input,
+                                    NI_ObjectToOptionalInputArray, &labels, &indices_object))
+        goto exit;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    center_of_mass = (double*)malloc(input->nd * n_results *
+                                                                     sizeof(double));
+    if (!center_of_mass) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    if (!NI_CenterOfMass(input, labels, min_label, max_label,
+                                             result_indices, n_results, center_of_mass))
+        goto exit;
+
+    result = _NI_BuildMeasurementResultDoubleTuple(n_results, input->nd,
+                                                                                                 center_of_mass);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (center_of_mass)
+        free(center_of_mass);
+    return result;
+}
+
+static PyObject *Py_Histogram(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL, **histograms = NULL;
+    PyObject *indices_object, *result = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results;
+    maybelong jj, nbins;
+    long nbins_in;
+    double min, max;
+
+    if (!PyArg_ParseTuple(args, "O&ddlO&O", NI_ObjectToInputArray, &input,
+                                                &min, &max, &nbins_in, NI_ObjectToOptionalInputArray,
+                                                &labels, &indices_object))
+        goto exit;
+    nbins = nbins_in;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    /* Set all pointers to NULL, so that freeing the memory */
+    /* doesn't cause problems. */
+    histograms = (PyArrayObject**)calloc(input->nd * n_results,
+                                                                             sizeof(PyArrayObject*));
+    if (!histograms) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+        histograms[jj] = NA_NewArray(NULL, tInt32, 1, &nbins);
+        if (!histograms[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    if (!NI_Histogram(input, labels, min_label, max_label, result_indices,
+                                        n_results, histograms, min, max, nbins))
+        goto exit;
+
+    result = _NI_BuildMeasurementResultArrayObject(n_results, histograms);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (histograms) {
+        for(jj = 0; jj < n_results; jj++) {
+            Py_XDECREF(histograms[jj]);
+        }
+        free(histograms);
+    }
+    return result;
+}
+
+static PyObject *Py_DistanceTransformBruteForce(PyObject *obj,
+                                                                                                PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *features = NULL;
+    PyArrayObject *sampling = NULL;
+    int metric;
+
+    if (!PyArg_ParseTuple(args, "O&iO&O&O&", NI_ObjectToInputArray, &input,
+                                                &metric, NI_ObjectToOptionalInputArray, &sampling,
+                                                NI_ObjectToOptionalOutputArray, &output,
+                                                NI_ObjectToOptionalOutputArray, &features))
+        goto exit;
+    if (!NI_DistanceTransformBruteForce(input, metric, sampling,
+                                                                            output, features))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(sampling);
+    Py_XDECREF(output);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_DistanceTransformOnePass(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *strct = NULL, *distances = NULL, *features = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &strct,
+                                                NI_ObjectToIoArray, &distances,
+                                                NI_ObjectToOptionalOutputArray, &features))
+        goto exit;
+    if (!NI_DistanceTransformOnePass(strct, distances, features))
+        goto exit;
+exit:
+    Py_XDECREF(strct);
+    Py_XDECREF(distances);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_EuclideanFeatureTransform(PyObject *obj,
+                                                                                            PyObject *args)
+{
+    PyArrayObject *input = NULL, *features = NULL, *sampling = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
+                                                NI_ObjectToOptionalInputArray, &sampling,
+                                                NI_ObjectToOutputArray, &features))
+        goto exit;
+    if (!NI_EuclideanFeatureTransform(input, sampling, features))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(sampling);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static void _FreeCoordinateList(void* ptr)
+{
+    NI_FreeCoordinateList((NI_CoordinateList*)ptr);
+}
+
+static PyObject *Py_BinaryErosion(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
+    PyArrayObject *mask = NULL;
+    PyObject *cobj = NULL;
+    int border_value, invert, center_is_true;
+    int changed = 0, return_coordinates;
+    NI_CoordinateList *coordinate_list = NULL;
+    maybelong *origins = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&iO&iii", NI_ObjectToInputArray,
+                                                &input, NI_ObjectToInputArray, &strct,
+                                                NI_ObjectToOptionalInputArray, &mask,
+                                                NI_ObjectToOutputArray, &output, &border_value,
+                                                NI_ObjectToLongSequence, &origins,  &invert,
+                                                &center_is_true, &return_coordinates))
+        goto exit;
+    if (!NI_BinaryErosion(input, strct, mask, output, border_value,
+                                                origins, invert, center_is_true, &changed,
+                                                return_coordinates ? &coordinate_list : NULL))
+        goto exit;
+    if (return_coordinates) {
+        cobj = PyCObject_FromVoidPtr(coordinate_list, _FreeCoordinateList);
+    }
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(strct);
+    Py_XDECREF(mask);
+    Py_XDECREF(output);
+    if (origins)
+        free(origins);
+    if (PyErr_Occurred()) {
+        Py_XDECREF(cobj);
+        return NULL;
+    } else {
+        if (return_coordinates) {
+            return Py_BuildValue("iN", changed, cobj);
+        } else {
+            return Py_BuildValue("i", changed);
+        }
+    }
+}
+
+static PyObject *Py_BinaryErosion2(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *array = NULL, *strct = NULL, *mask = NULL;
+    PyObject *cobj = NULL;
+    int invert, niter;
+    maybelong *origins = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&iO&iO", NI_ObjectToIoArray, &array,
+                    NI_ObjectToInputArray, &strct, NI_ObjectToOptionalInputArray,
+                    &mask, &niter, NI_ObjectToLongSequence, &origins, &invert,
+                    &cobj))
+        goto exit;
+
+    if (PyCObject_Check(cobj)) {
+        NI_CoordinateList *cobj_data = PyCObject_AsVoidPtr(cobj);
+        if (!NI_BinaryErosion2(array, strct, mask, niter, origins, invert,
+                                                     &cobj_data))
+            goto exit;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError, "cannot convert CObject");
+        goto exit;
+    }
+exit:
+    Py_XDECREF(array);
+    Py_XDECREF(strct);
+    Py_XDECREF(mask);
+    if (origins) free(origins);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyMethodDef methods[] = {
+    {"correlate1d",           (PyCFunction)Py_Correlate1D,
+     METH_VARARGS, NULL},
+    {"correlate",             (PyCFunction)Py_Correlate,
+     METH_VARARGS, NULL},
+    {"uniform_filter1d",      (PyCFunction)Py_UniformFilter1D,
+     METH_VARARGS, NULL},
+    {"min_or_max_filter1d",   (PyCFunction)Py_MinOrMaxFilter1D,
+        METH_VARARGS, NULL},
+    {"min_or_max_filter",     (PyCFunction)Py_MinOrMaxFilter,
+        METH_VARARGS, NULL},
+    {"rank_filter",           (PyCFunction)Py_RankFilter,
+     METH_VARARGS, NULL},
+    {"generic_filter",        (PyCFunction)Py_GenericFilter,
+     METH_VARARGS, NULL},
+    {"generic_filter1d",      (PyCFunction)Py_GenericFilter1D,
+     METH_VARARGS, NULL},
+    {"fourier_filter",        (PyCFunction)Py_FourierFilter,
+     METH_VARARGS, NULL},
+    {"fourier_shift",         (PyCFunction)Py_FourierShift,
+     METH_VARARGS, NULL},
+    {"spline_filter1d",       (PyCFunction)Py_SplineFilter1D,
+     METH_VARARGS, NULL},
+    {"geometric_transform",   (PyCFunction)Py_GeometricTransform,
+        METH_VARARGS, NULL},
+    {"zoom_shift",            (PyCFunction)Py_ZoomShift,
+     METH_VARARGS, NULL},
+    {"label",                 (PyCFunction)Py_Label,
+     METH_VARARGS, NULL},
+    {"find_objects",          (PyCFunction)Py_FindObjects,
+     METH_VARARGS, NULL},
+    {"watershed_ift",         (PyCFunction)Py_WatershedIFT,
+     METH_VARARGS, NULL},
+    {"statistics",            (PyCFunction)Py_Statistics,
+     METH_VARARGS, NULL},
+    {"center_of_mass",        (PyCFunction)Py_CenterOfMass,
+     METH_VARARGS, NULL},
+    {"histogram",             (PyCFunction)Py_Histogram,
+     METH_VARARGS, NULL},
+    {"distance_transform_bf", (PyCFunction)Py_DistanceTransformBruteForce,
+     METH_VARARGS, NULL},
+    {"distance_transform_op", (PyCFunction)Py_DistanceTransformOnePass,
+     METH_VARARGS, NULL},
+    {"euclidean_feature_transform",
+     (PyCFunction)Py_EuclideanFeatureTransform, 
+     METH_VARARGS, NULL},
+    {"binary_erosion",        (PyCFunction)Py_BinaryErosion,
+     METH_VARARGS, NULL},
+    {"binary_erosion2",       (PyCFunction)Py_BinaryErosion2,
+     METH_VARARGS, NULL},
+    {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC init_nd_image(void)
+{
+    Py_InitModule("_nd_image", methods);
+    import_array();
+}

Modified: trunk/scipy/ndimage/src/nd_image.h
===================================================================
--- trunk/scipy/ndimage/src/nd_image.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/nd_image.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,278 +1,278 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ND_IMAGE_H
-#define ND_IMAGE_H
-
-#include "Python.h"
-
-#ifndef ND_IMPORT_ARRAY
-#define NO_IMPORT_ARRAY
-#endif
-
-#include <numpy/noprefix.h>
-#undef NO_IMPORT_ARRAY
-
-/* Eventually get rid of everything below this line */
-
-typedef enum
-{
-     tAny=-1,
-     tBool=PyArray_BOOL,
-     tInt8=PyArray_INT8,
-     tUInt8=PyArray_UINT8,
-     tInt16=PyArray_INT16,
-     tUInt16=PyArray_UINT16,
-     tInt32=PyArray_INT32,
-     tUInt32=PyArray_UINT32,
-     tInt64=PyArray_INT64,
-     tUInt64=PyArray_UINT64,
-     tFloat32=PyArray_FLOAT32,
-     tFloat64=PyArray_FLOAT64,
-     tComplex64=PyArray_COMPLEX64,
-     tComplex128=PyArray_COMPLEX128,
-     tObject=PyArray_OBJECT,        /* placeholder... does nothing */
-     tMaxType=PyArray_NTYPES,
-     tDefault=PyArray_FLOAT64,
-     tLong=PyArray_LONG,
-} NumarrayType;
-
-#define NI_MAXDIM NPY_MAXDIMS
-
-typedef npy_intp maybelong;
-#define MAXDIM NPY_MAXDIMS
-
-#define HAS_UINT64 1
-
-
-
-#ifdef ND_IMPORT_ARRAY
-
-/* Numarray Helper Functions */
-
-static PyArrayObject*
-NA_InputArray(PyObject *a, NumarrayType t, int requires)
-{
-    PyArray_Descr *descr;
-    if (t == tAny) descr = NULL;
-    else descr = PyArray_DescrFromType(t);
-    return (PyArrayObject *)                                            \
-        PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
-}
-
-/* satisfies ensures that 'a' meets a set of requirements and matches
-the specified type.
-*/
-static int
-satisfies(PyArrayObject *a, int requirements, NumarrayType t)
-{
-    int type_ok = (a->descr->type_num == t) || (t == tAny);
-
-    if (PyArray_ISCARRAY(a))
-        return type_ok;
-    if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
-        return 0;
-    if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
-        return 0;
-    if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
-        return 0;
-    if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
-        return 0;
-    if (requirements & NPY_ENSURECOPY)
-        return 0;
-    return type_ok;
-}
-
-static PyArrayObject *
-NA_OutputArray(PyObject *a, NumarrayType t, int requires)
-{
-    PyArray_Descr *dtype;
-    PyArrayObject *ret;
-
-    if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
-        PyErr_Format(PyExc_TypeError,
-                     "NA_OutputArray: only writeable arrays work for output.");
-        return NULL;
-    }
-
-    if (satisfies((PyArrayObject *)a, requires, t)) {
-        Py_INCREF(a);
-        return (PyArrayObject *)a;
-    }
-    if (t == tAny) {
-        dtype = PyArray_DESCR(a);
-        Py_INCREF(dtype);
-    }
-    else {
-        dtype = PyArray_DescrFromType(t);
-    }
-    ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
-                                         dtype, 0);
-    ret->flags |= NPY_UPDATEIFCOPY;
-    ret->base = a;
-    PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
-    Py_INCREF(a);
-    return ret;
-}
-
-/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
-
-Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
-of the input array.
-
-Unlike NA_InputArray, deallocating any resulting temporary array results in a
-copy from the temporary back to the original.
-*/
-static PyArrayObject *
-NA_IoArray(PyObject *a, NumarrayType t, int requires)
-{
-    PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
-
-    if (!shadow) return NULL;
-
-    /* Guard against non-writable, but otherwise satisfying requires.
-       In this case,  shadow == a.
-    */
-    if (!PyArray_ISWRITEABLE(shadow)) {
-        PyErr_Format(PyExc_TypeError,
-                     "NA_IoArray: I/O array must be writable array");
-        PyArray_XDECREF_ERR(shadow);
-        return NULL;
-    }
-
-    return shadow;
-}
-
-#define NUM_LITTLE_ENDIAN 0
-#define NUM_BIG_ENDIAN 1
-
-static int
-NA_ByteOrder(void)
-{
-    unsigned long byteorder_test;
-    byteorder_test = 1;
-    if (*((char *) &byteorder_test))
-        return NUM_LITTLE_ENDIAN;
-    else
-        return NUM_BIG_ENDIAN;
-}
-
-/* ignores bytestride */
-static PyArrayObject *
-NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
-                    PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
-                    int byteorder, int aligned, int writeable)
-{
-    PyArrayObject *self = NULL;
-    PyArray_Descr *dtype;
-
-    if (type == tAny)
-        type = tDefault;
-
-    dtype = PyArray_DescrFromType(type);
-    if (dtype == NULL) return NULL;
-
-    if (byteorder != NA_ByteOrder()) {
-        PyArray_Descr *temp;
-        temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
-        Py_DECREF(dtype);
-        if (temp == NULL) return NULL;
-        dtype = temp;
-    }
-
-    if (bufferObject == Py_None || bufferObject == NULL) {
-        self = (PyArrayObject *)                                        \
-            PyArray_NewFromDescr(&PyArray_Type, dtype,
-                                 ndim, shape, NULL, NULL,
-                                 0, NULL);
-    }
-    else {
-        npy_intp size = 1;
-        int i;
-        PyArrayObject *newself;
-        PyArray_Dims newdims;
-        for(i=0; i<ndim; i++) {
-            size *= shape[i];
-        }
-        self = (PyArrayObject *)                                \
-            PyArray_FromBuffer(bufferObject, dtype,
-                               size, byteoffset);
-        if (self == NULL) return self;
-        newdims.len = ndim;
-        newdims.ptr = shape;
-        newself = (PyArrayObject *)                                     \
-            PyArray_Newshape(self, &newdims, PyArray_CORDER);
-        Py_DECREF(self);
-        self = newself;
-    }
-
-    return self;
-}
-
-static PyArrayObject *
-NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
-          void *buffer, maybelong byteoffset, maybelong bytestride,
-          int byteorder, int aligned, int writeable)
-{
-    PyArrayObject *result = NA_NewAllFromBuffer(
-                                                ndim, shape, type, Py_None,
-                                                byteoffset, bytestride,
-                                                byteorder, aligned, writeable);
-    if (result) {
-        if (!PyArray_Check((PyObject *) result)) {
-            PyErr_Format( PyExc_TypeError,
-                          "NA_NewAll: non-NumArray result");
-            result = NULL;
-        } else {
-            if (buffer) {
-                memcpy(result->data, buffer, PyArray_NBYTES(result));
-            } else {
-                memset(result->data, 0, PyArray_NBYTES(result));
-            }
-        }
-    }
-    return  result;
-}
-
-/* Create a new numarray which is initially a C_array, or which
-references a C_array: aligned, !byteswapped, contiguous, ...
-Call with buffer==NULL to allocate storage.
-*/
-static PyArrayObject *
-NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
-{
-    return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
-                                       NA_ByteOrder(), 1, 1);
-}
-
-#endif /* ND_IMPORT_ARRAY */
-
-#endif /* ND_IMAGE_H */
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ND_IMAGE_H
+#define ND_IMAGE_H
+
+#include "Python.h"
+
+#ifndef ND_IMPORT_ARRAY
+#define NO_IMPORT_ARRAY
+#endif
+
+#include <numpy/noprefix.h>
+#undef NO_IMPORT_ARRAY
+
+/* Eventually get rid of everything below this line */
+
+typedef enum
+{
+         tAny=-1,
+         tBool=PyArray_BOOL,
+         tInt8=PyArray_INT8,
+         tUInt8=PyArray_UINT8,
+         tInt16=PyArray_INT16,
+         tUInt16=PyArray_UINT16,
+         tInt32=PyArray_INT32,
+         tUInt32=PyArray_UINT32,
+         tInt64=PyArray_INT64,
+         tUInt64=PyArray_UINT64,
+         tFloat32=PyArray_FLOAT32,
+         tFloat64=PyArray_FLOAT64,
+         tComplex64=PyArray_COMPLEX64,
+         tComplex128=PyArray_COMPLEX128,
+         tObject=PyArray_OBJECT,        /* placeholder... does nothing */
+         tMaxType=PyArray_NTYPES,
+         tDefault=PyArray_FLOAT64,
+         tLong=PyArray_LONG,
+} NumarrayType;
+
+#define NI_MAXDIM NPY_MAXDIMS
+
+typedef npy_intp maybelong;
+#define MAXDIM NPY_MAXDIMS
+
+#define HAS_UINT64 1
+
+
+
+#ifdef ND_IMPORT_ARRAY
+
+/* Numarray Helper Functions */
+
+static PyArrayObject*
+NA_InputArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArray_Descr *descr;
+        if (t == tAny) descr = NULL;
+        else descr = PyArray_DescrFromType(t);
+        return (PyArrayObject *)                                            \
+                PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
+}
+
+/* satisfies ensures that 'a' meets a set of requirements and matches
+the specified type.
+*/
+static int
+satisfies(PyArrayObject *a, int requirements, NumarrayType t)
+{
+        int type_ok = (a->descr->type_num == t) || (t == tAny);
+
+        if (PyArray_ISCARRAY(a))
+                return type_ok;
+        if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
+                return 0;
+        if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
+                return 0;
+        if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
+                return 0;
+        if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
+                return 0;
+        if (requirements & NPY_ENSURECOPY)
+                return 0;
+        return type_ok;
+}
+
+static PyArrayObject *
+NA_OutputArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArray_Descr *dtype;
+        PyArrayObject *ret;
+
+        if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
+                PyErr_Format(PyExc_TypeError,
+                                         "NA_OutputArray: only writeable arrays work for output.");
+                return NULL;
+        }
+
+        if (satisfies((PyArrayObject *)a, requires, t)) {
+                Py_INCREF(a);
+                return (PyArrayObject *)a;
+        }
+        if (t == tAny) {
+                dtype = PyArray_DESCR(a);
+                Py_INCREF(dtype);
+        }
+        else {
+                dtype = PyArray_DescrFromType(t);
+        }
+        ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
+                                                                                 dtype, 0);
+        ret->flags |= NPY_UPDATEIFCOPY;
+        ret->base = a;
+        PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
+        Py_INCREF(a);
+        return ret;
+}
+
+/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
+
+Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
+of the input array.
+
+Unlike NA_InputArray, deallocating any resulting temporary array results in a
+copy from the temporary back to the original.
+*/
+static PyArrayObject *
+NA_IoArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
+
+        if (!shadow) return NULL;
+
+        /* Guard against non-writable, but otherwise satisfying requires.
+             In this case,  shadow == a.
+        */
+        if (!PyArray_ISWRITEABLE(shadow)) {
+                PyErr_Format(PyExc_TypeError,
+                                         "NA_IoArray: I/O array must be writable array");
+                PyArray_XDECREF_ERR(shadow);
+                return NULL;
+        }
+
+        return shadow;
+}
+
+#define NUM_LITTLE_ENDIAN 0
+#define NUM_BIG_ENDIAN 1
+
+static int
+NA_ByteOrder(void)
+{
+        unsigned long byteorder_test;
+        byteorder_test = 1;
+        if (*((char *) &byteorder_test))
+                return NUM_LITTLE_ENDIAN;
+        else
+                return NUM_BIG_ENDIAN;
+}
+
+/* ignores bytestride */
+static PyArrayObject *
+NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
+                                        PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
+                                        int byteorder, int aligned, int writeable)
+{
+        PyArrayObject *self = NULL;
+        PyArray_Descr *dtype;
+
+        if (type == tAny)
+                type = tDefault;
+
+        dtype = PyArray_DescrFromType(type);
+        if (dtype == NULL) return NULL;
+
+        if (byteorder != NA_ByteOrder()) {
+                PyArray_Descr *temp;
+                temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
+                Py_DECREF(dtype);
+                if (temp == NULL) return NULL;
+                dtype = temp;
+        }
+
+        if (bufferObject == Py_None || bufferObject == NULL) {
+                self = (PyArrayObject *)                                        \
+                        PyArray_NewFromDescr(&PyArray_Type, dtype,
+                                                                 ndim, shape, NULL, NULL,
+                                                                 0, NULL);
+        }
+        else {
+                npy_intp size = 1;
+                int i;
+                PyArrayObject *newself;
+                PyArray_Dims newdims;
+                for(i=0; i<ndim; i++) {
+                        size *= shape[i];
+                }
+                self = (PyArrayObject *)                                \
+                        PyArray_FromBuffer(bufferObject, dtype,
+                                                             size, byteoffset);
+                if (self == NULL) return self;
+                newdims.len = ndim;
+                newdims.ptr = shape;
+                newself = (PyArrayObject *)                                     \
+                        PyArray_Newshape(self, &newdims, PyArray_CORDER);
+                Py_DECREF(self);
+                self = newself;
+        }
+
+        return self;
+}
+
+static PyArrayObject *
+NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
+                    void *buffer, maybelong byteoffset, maybelong bytestride,
+                    int byteorder, int aligned, int writeable)
+{
+        PyArrayObject *result = NA_NewAllFromBuffer(
+                                                                                                ndim, shape, type, Py_None,
+                                                                                                byteoffset, bytestride,
+                                                                                                byteorder, aligned, writeable);
+        if (result) {
+                if (!PyArray_Check((PyObject *) result)) {
+                        PyErr_Format( PyExc_TypeError,
+                                                    "NA_NewAll: non-NumArray result");
+                        result = NULL;
+                } else {
+                        if (buffer) {
+                                memcpy(result->data, buffer, PyArray_NBYTES(result));
+                        } else {
+                                memset(result->data, 0, PyArray_NBYTES(result));
+                        }
+                }
+        }
+        return  result;
+}
+
+/* Create a new numarray which is initially a C_array, or which
+references a C_array: aligned, !byteswapped, contiguous, ...
+Call with buffer==NULL to allocate storage.
+*/
+static PyArrayObject *
+NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
+{
+        return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
+                                                                             NA_ByteOrder(), 1, 1);
+}
+
+#endif /* ND_IMPORT_ARRAY */
+
+#endif /* ND_IMAGE_H */

Modified: trunk/scipy/ndimage/src/ni_filters.c
===================================================================
--- trunk/scipy/ndimage/src/ni_filters.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_filters.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,888 +1,888 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_filters.h"
-#include <stdlib.h>
-#include <math.h>
-
-#define BUFFER_SIZE 256000
-
-int NI_Correlate1D(PyArrayObject *input, PyArrayObject *weights,
-                   int axis, PyArrayObject *output, NI_ExtendMode mode,
-                   double cval, maybelong origin)
-{
-  int symmetric = 0, ii, jj, more;
-  maybelong ll, lines, length, size1, size2, filter_size;
-  double *ibuffer = NULL, *obuffer = NULL;
-  Float64 *fw;
-  NI_LineBuffer iline_buffer, oline_buffer;
-
-  /* test for symmetry or anti-symmetry: */
-  filter_size = weights->dimensions[0];
-  size1 = filter_size / 2;
-  size2 = filter_size - size1 - 1;
-  fw = (void *)PyArray_DATA(weights);
-  if (filter_size & 0x1) {
-    symmetric = 1;
-    for(ii = 1; ii <= filter_size / 2; ii++) {
-      if (fabs(fw[ii + size1] - fw[size1 - ii]) > DBL_EPSILON) {
-        symmetric = 0;
-        break;
-      }
-    }
-    if (symmetric == 0) {
-      symmetric = -1;
-      for(ii = 1; ii <= filter_size / 2; ii++) {
-        if (fabs(fw[size1 + ii] + fw[size1 - ii]) > DBL_EPSILON) {
-          symmetric = 0;
-          break;
-        }
-      }
-    }
-  }
-  /* allocate and initialize the line buffers: */
-  lines = -1;
-  if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
-                             &lines, BUFFER_SIZE, &ibuffer))
-    goto exit;
-  if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
-                             &obuffer))
-    goto exit;
-  if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
-                              lines, ibuffer, mode, cval, &iline_buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
-                         &oline_buffer))
-    goto exit;
-  length = input->nd > 0 ? input->dimensions[axis] : 1;
-  fw += size1;
-  /* iterate over all the array lines: */
-  do {
-    /* copy lines from array to buffer: */
-    if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-      goto exit;
-    /* iterate over the lines in the buffers: */
-    for(ii = 0; ii < lines; ii++) {
-      /* get lines: */
-      double *iline = NI_GET_LINE(iline_buffer, ii) + size1;
-      double *oline = NI_GET_LINE(oline_buffer, ii);
-      /* the correlation calculation: */
-      if (symmetric > 0) {
-        for(ll = 0; ll < length; ll++) {
-          oline[ll] = iline[0] * fw[0];
-          for(jj = -size1 ; jj < 0; jj++)
-            oline[ll] += (iline[jj] + iline[-jj]) * fw[jj];
-          ++iline;
-        }
-      } else if (symmetric < 0) {
-        for(ll = 0; ll < length; ll++) {
-          oline[ll] = iline[0] * fw[0];
-          for(jj = -size1 ; jj < 0; jj++)
-            oline[ll] += (iline[jj] - iline[-jj]) * fw[jj];
-          ++iline;
-        }
-      } else {
-        for(ll = 0; ll < length; ll++) {
-          oline[ll] = iline[size2] * fw[size2];
-          for(jj = -size1; jj < size2; jj++)
-            oline[ll] += iline[jj] * fw[jj];
-          ++iline;
-        }
-      }
-    }
-    /* copy lines from buffer to array: */
-    if (!NI_LineBufferToArray(&oline_buffer))
-      goto exit;
-  } while(more);
-exit:
-  if (ibuffer) free(ibuffer);
-  if (obuffer) free(obuffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_CORRELATE_POINT(_pi, _weights, _offsets, _filter_size, \
-                             _cvalue, _type, _res, _mv)             \
-case t ## _type:                                                    \
-{                                                                   \
-  maybelong _ii, _offset;                                           \
-  for(_ii = 0; _ii < _filter_size; _ii++) {                         \
-    _offset = _offsets[_ii];                                        \
-    if (_offset == _mv)                                             \
-      _res += _weights[_ii] * _cvalue;                              \
-    else                                                            \
-      _res += _weights[_ii] * (double)*(_type*)(_pi + _offset);     \
-  }                                                                 \
-}                                                                   \
-break
-
-#define CASE_FILTER_OUT(_po, _tmp, _type) \
-case t ## _type:                          \
-  *(_type*)_po = (_type)_tmp;             \
-  break
-
-int NI_Correlate(PyArrayObject* input, PyArrayObject* weights,
-                        PyArrayObject* output, NI_ExtendMode mode,
-                        double cvalue, maybelong *origins)
-{
-  Bool *pf = NULL;
-  maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
-  maybelong *offsets = NULL, *oo, size;
-  NI_FilterIterator fi;
-  NI_Iterator ii, io;
-  char *pi, *po;
-  Float64 *pw;
-  Float64 *ww = NULL;
-  int ll;
-
-  /* get the the footprint: */
-  fsize = 1;
-  for(ll = 0; ll < weights->nd; ll++)
-    fsize *= weights->dimensions[ll];
-  pw = (Float64*)PyArray_DATA(weights);
-  pf = (Bool*)malloc(fsize * sizeof(Bool));
-  if (!pf) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < fsize; jj++) {
-    if (fabs(pw[jj]) > DBL_EPSILON) {
-      pf[jj] = 1;
-      ++filter_size;
-    } else {
-      pf[jj] = 0;
-    }
-  }
-  /* copy the weights to contiguous memory: */
-  ww = (Float64*)malloc(filter_size * sizeof(Float64));
-  if (!ww) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  jj = 0;
-  for(kk = 0; kk < fsize; kk++) {
-    if (pf[kk]) {
-      ww[jj++] = pw[kk];
-    }
-  }
-  /* initialize filter offsets: */
-  if (!NI_InitFilterOffsets(input, pf, weights->dimensions, origins,
-                            mode, &offsets, &border_flag_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, weights->dimensions, filter_size,
-                             input->dimensions, origins, &fi))
-    goto exit;
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* get data pointers an array size: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* iterator over the elements: */
-  oo = offsets;
-  for(jj = 0; jj < size; jj++) {
-    double tmp = 0.0;
-    switch (input->descr->type_num) {
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Bool,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt8,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt16,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt32,
-                           tmp, border_flag_value);
-#if HAS_UINT64
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt64,
-                           tmp, border_flag_value);
-#endif
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int8,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int16,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int32,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int64,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float32,
-                           tmp, border_flag_value);
-      CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float64,
-                           tmp, border_flag_value);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-      CASE_FILTER_OUT(po, tmp, Bool);
-      CASE_FILTER_OUT(po, tmp, UInt8);
-      CASE_FILTER_OUT(po, tmp, UInt16);
-      CASE_FILTER_OUT(po, tmp, UInt32);
-#if HAS_UINT64
-      CASE_FILTER_OUT(po, tmp, UInt64);
-#endif
-      CASE_FILTER_OUT(po, tmp, Int8);
-      CASE_FILTER_OUT(po, tmp, Int16);
-      CASE_FILTER_OUT(po, tmp, Int32);
-      CASE_FILTER_OUT(po, tmp, Int64);
-      CASE_FILTER_OUT(po, tmp, Float32);
-      CASE_FILTER_OUT(po, tmp, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
-  }
-exit:
-  if (offsets) free(offsets);
-  if (ww) free(ww);
-  if (pf) free(pf);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-int
-NI_UniformFilter1D(PyArrayObject *input, long filter_size,
-                   int axis, PyArrayObject *output, NI_ExtendMode mode,
-                   double cval, long origin)
-{
-  maybelong lines, kk, ll, length, size1, size2;
-  int more;
-  double *ibuffer = NULL, *obuffer = NULL;
-  NI_LineBuffer iline_buffer, oline_buffer;
-
-  size1 = filter_size / 2;
-  size2 = filter_size - size1 - 1;
-  /* allocate and initialize the line buffers: */
-  lines = -1;
-  if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
-                             &lines, BUFFER_SIZE, &ibuffer))
-    goto exit;
-  if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
-                             &obuffer))
-    goto exit;
-  if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
-                              lines, ibuffer, mode, cval, &iline_buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
-                         &oline_buffer))
-    goto exit;
-  length = input->nd > 0 ? input->dimensions[axis] : 1;
-
-  /* iterate over all the array lines: */
-  do {
-    /* copy lines from array to buffer: */
-    if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-      goto exit;
-    /* iterate over the lines in the buffers: */
-    for(kk = 0; kk < lines; kk++) {
-      /* get lines: */
-      double *iline = NI_GET_LINE(iline_buffer, kk);
-      double *oline = NI_GET_LINE(oline_buffer, kk);
-      /* do the uniform filter: */
-      double tmp = 0.0;
-      double *l1 = iline;
-      double *l2 = iline + filter_size;
-      for(ll = 0; ll < filter_size; ll++)
-        tmp += iline[ll];
-      tmp /= (double)filter_size;
-      oline[0] = tmp;
-      for(ll = 1; ll < length; ll++) {
-        tmp += (*l2++ - *l1++) / (double)filter_size;
-        oline[ll] = tmp;
-      }
-    }
-    /* copy lines from buffer to array: */
-    if (!NI_LineBufferToArray(&oline_buffer))
-      goto exit;
-  } while(more);
-
- exit:
-  if (ibuffer) free(ibuffer);
-  if (obuffer) free(obuffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-int
-NI_MinOrMaxFilter1D(PyArrayObject *input, long filter_size,
-                    int axis, PyArrayObject *output, NI_ExtendMode mode,
-                    double cval, long origin, int minimum)
-{
-  maybelong lines, kk, jj, ll, length, size1, size2;
-  int more;
-  double *ibuffer = NULL, *obuffer = NULL;
-  NI_LineBuffer iline_buffer, oline_buffer;
-
-  size1 = filter_size / 2;
-  size2 = filter_size - size1 - 1;
-  /* allocate and initialize the line buffers: */
-  lines = -1;
-  if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
-                             &lines, BUFFER_SIZE, &ibuffer))
-    goto exit;
-  if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
-                             &obuffer))
-    goto exit;
-  if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
-                               lines, ibuffer, mode, cval, &iline_buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
-                         &oline_buffer))
-    goto exit;
-  length = input->nd > 0 ? input->dimensions[axis] : 1;
-
-  /* iterate over all the array lines: */
-  do {
-    /* copy lines from array to buffer: */
-    if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-      goto exit;
-    /* iterate over the lines in the buffers: */
-    for(kk = 0; kk < lines; kk++) {
-      /* get lines: */
-      double *iline = NI_GET_LINE(iline_buffer, kk) + size1;
-      double *oline = NI_GET_LINE(oline_buffer, kk);
-      for(ll = 0; ll < length; ll++) {
-      /* find minimum or maximum filter: */
-        double val = iline[ll - size1];
-        for(jj = -size1 + 1; jj <= size2; jj++) {
-          double tmp = iline[ll + jj];
-          if (minimum) {
-            if (tmp < val)
-              val = tmp;
-          } else {
-            if (tmp > val)
-              val = tmp;
-          }
-        }
-        oline[ll] = val;
-      }
-    }
-    /* copy lines from buffer to array: */
-    if (!NI_LineBufferToArray(&oline_buffer))
-      goto exit;
-  } while(more);
-
- exit:
-  if (ibuffer) free(ibuffer);
-  if (obuffer) free(obuffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-
-#define CASE_MIN_OR_MAX_POINT(_pi, _offsets, _filter_size, _cval, \
-                              _type, _minimum, _res, _mv, _ss)    \
-case t ## _type:                                                  \
-{                                                                 \
-  maybelong _ii, _oo = *_offsets;                                 \
-  _type _cv = (_type)_cval, _tmp;                                 \
-  _res = _oo == _mv ? _cv : *(_type*)(_pi + _oo);                 \
-  if (_ss)                                                        \
-    _res += *_ss;                                                 \
-  for(_ii = 1; _ii < _filter_size; _ii++) {                       \
-    _oo = _offsets[_ii];                                          \
-    _tmp = _oo == _mv ? _cv : *(_type*)(_pi + _oo);               \
-    if (_ss)                                                      \
-      _tmp += _ss[_ii];                                           \
-    if (_minimum) {                                               \
-      if (_tmp < _res)                                            \
-        _res = (_type)_tmp;                                       \
-    } else {                                                      \
-      if (_tmp > _res)                                            \
-        _res = (_type)_tmp;                                       \
-    }                                                             \
-  }                                                               \
-}                                                                 \
-break
-
-int NI_MinOrMaxFilter(PyArrayObject* input, PyArrayObject* footprint,
-        PyArrayObject* structure, PyArrayObject* output,
-        NI_ExtendMode mode, double cvalue, maybelong *origins, int minimum)
-{
-  Bool *pf = NULL;
-  maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
-  maybelong *offsets = NULL, *oo, size;
-  NI_FilterIterator fi;
-  NI_Iterator ii, io;
-  char *pi, *po;
-  int ll;
-  double *ss = NULL;
-  Float64 *ps;
-
-  /* get the the footprint: */
-  fsize = 1;
-  for(ll = 0; ll < footprint->nd; ll++)
-    fsize *= footprint->dimensions[ll];
-  pf = (Bool*)PyArray_DATA(footprint);
-  for(jj = 0; jj < fsize; jj++) {
-    if (pf[jj]) {
-      ++filter_size;
-    }
-  }
-  /* get the structure: */
-  if (structure) {
-    ss = (double*)malloc(filter_size * sizeof(double));
-    if (!ss) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-    /* copy the weights to contiguous memory: */
-    ps = (Float64*)PyArray_DATA(structure);
-    jj = 0;
-    for(kk = 0; kk < fsize; kk++)
-      if (pf[kk])
-        ss[jj++] = minimum ? -ps[kk] : ps[kk];
-  }
-  /* initialize filter offsets: */
-  if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
-                            mode, &offsets, &border_flag_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
-                             filter_size, input->dimensions, origins, &fi))
-    goto exit;
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* get data pointers an array size: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* iterator over the elements: */
-  oo = offsets;
-  for(jj = 0; jj < size; jj++) {
-    double tmp = 0.0;
-    switch (input->descr->type_num) {
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Bool,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt8,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt16,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt32,
-                            minimum, tmp, border_flag_value, ss);
-#if HAS_UINT64
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt64,
-                            minimum, tmp, border_flag_value, ss);
-#endif
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int8,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int16,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int32,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int64,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float32,
-                            minimum, tmp, border_flag_value, ss);
-      CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float64,
-                            minimum, tmp, border_flag_value, ss);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-      CASE_FILTER_OUT(po, tmp, Bool);
-      CASE_FILTER_OUT(po, tmp, UInt8);
-      CASE_FILTER_OUT(po, tmp, UInt16);
-      CASE_FILTER_OUT(po, tmp, UInt32);
-#if HAS_UINT64
-      CASE_FILTER_OUT(po, tmp, UInt64);
-#endif
-      CASE_FILTER_OUT(po, tmp, Int8);
-      CASE_FILTER_OUT(po, tmp, Int16);
-      CASE_FILTER_OUT(po, tmp, Int32);
-      CASE_FILTER_OUT(po, tmp, Int64);
-      CASE_FILTER_OUT(po, tmp, Float32);
-      CASE_FILTER_OUT(po, tmp, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
-  }
-exit:
-  if (offsets) free(offsets);
-  if (ss) free(ss);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-static double NI_Select(double *buffer, int min, int max, int rank)
-{
-  int ii, jj;
-  double x, t;
-
-  if (min == max)
-    return buffer[min];
-
-  x = buffer[min];
-  ii = min - 1;
-  jj = max + 1;
-  for(;;) {
-    do
-      jj--;
-    while(buffer[jj] > x);
-    do
-      ii++;
-    while(buffer[ii] < x);
-    if (ii < jj) {
-      t = buffer[ii];
-      buffer[ii] = buffer[jj];
-      buffer[jj] = t;
-    } else {
-      break;
-    }
-  }
-
-  ii = jj - min + 1;
-  if (rank < ii)
-    return NI_Select(buffer, min, jj, rank);
-  else
-    return NI_Select(buffer, jj + 1, max, rank - ii);
-}
-
-#define CASE_RANK_POINT(_pi, _offsets, _filter_size, _cval, _type, \
-                        _rank, _buffer, _res, _mv)                 \
-case t ## _type:                                                   \
-{                                                                  \
-  maybelong _ii;                                                   \
-  for(_ii = 0; _ii < _filter_size; _ii++) {                        \
-    maybelong _offset = _offsets[_ii];                             \
-    if (_offset == _mv)                                            \
-      _buffer[_ii] = (_type)_cval;                                 \
-    else                                                           \
-      _buffer[_ii] = *(_type*)(_pi + _offsets[_ii]);               \
-  }                                                                \
-  _res = (_type)NI_Select(_buffer, 0, _filter_size - 1, _rank);    \
-}                                                                  \
-break
-
-int NI_RankFilter(PyArrayObject* input, int rank,
-                  PyArrayObject* footprint, PyArrayObject* output,
-                  NI_ExtendMode mode, double cvalue, maybelong *origins)
-{
-  maybelong fsize, jj, filter_size = 0, border_flag_value;
-  maybelong *offsets = NULL, *oo, size;
-  NI_FilterIterator fi;
-  NI_Iterator ii, io;
-  char *pi, *po;
-  Bool *pf = NULL;
-  double *buffer = NULL;
-  int ll;
-
-  /* get the the footprint: */
-  fsize = 1;
-  for(ll = 0; ll < footprint->nd; ll++)
-    fsize *= footprint->dimensions[ll];
-  pf = (Bool*)PyArray_DATA(footprint);
-  for(jj = 0; jj < fsize; jj++) {
-    if (pf[jj]) {
-      ++filter_size;
-    }
-  }
-  /* buffer for rank calculation: */
-  buffer = (double*)malloc(filter_size * sizeof(double));
-  if (!buffer) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  /* iterator over the elements: */
-  oo = offsets;
-  /* initialize filter offsets: */
-  if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
-                            mode, &offsets, &border_flag_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
-                             filter_size, input->dimensions, origins, &fi))
-    goto exit;
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* get data pointers an array size: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* iterator over the elements: */
-  oo = offsets;
-  for(jj = 0; jj < size; jj++) {
-    double tmp = 0.0;
-    switch (input->descr->type_num) {
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Bool,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt8,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt16,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt32,
-                      rank, buffer, tmp, border_flag_value);
-#if HAS_UINT64
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt64,
-                      rank, buffer, tmp, border_flag_value);
-#endif
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int8,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int16,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int32,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int64,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float32,
-                      rank, buffer, tmp, border_flag_value);
-      CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float64,
-                      rank, buffer, tmp, border_flag_value);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-      CASE_FILTER_OUT(po, tmp, Bool);
-      CASE_FILTER_OUT(po, tmp, UInt8);
-      CASE_FILTER_OUT(po, tmp, UInt16);
-      CASE_FILTER_OUT(po, tmp, UInt32);
-#if HAS_UINT64
-      CASE_FILTER_OUT(po, tmp, UInt64);
-#endif
-      CASE_FILTER_OUT(po, tmp, Int8);
-      CASE_FILTER_OUT(po, tmp, Int16);
-      CASE_FILTER_OUT(po, tmp, Int32);
-      CASE_FILTER_OUT(po, tmp, Int64);
-      CASE_FILTER_OUT(po, tmp, Float32);
-      CASE_FILTER_OUT(po, tmp, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
-  }
-exit:
-  if (offsets) free(offsets);
-  if (buffer) free(buffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-int NI_GenericFilter1D(PyArrayObject *input,
-        int (*function)(double*, maybelong, double*, maybelong, void*),
-        void* data, long filter_size, int axis, PyArrayObject *output,
-        NI_ExtendMode mode, double cval, long origin)
-{
-  int more;
-  maybelong ii, lines, length, size1, size2;
-  double *ibuffer = NULL, *obuffer = NULL;
-  NI_LineBuffer iline_buffer, oline_buffer;
-
-  /* allocate and initialize the line buffers: */
-  size1 = filter_size / 2;
-  size2 = filter_size - size1 - 1;
-  lines = -1;
-  if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
-                             &lines, BUFFER_SIZE, &ibuffer))
-    goto exit;
-  if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
-                             &obuffer))
-    goto exit;
-  if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
-                              lines, ibuffer, mode, cval, &iline_buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
-                         &oline_buffer))
-    goto exit;
-  length = input->nd > 0 ? input->dimensions[axis] : 1;
-  /* iterate over all the array lines: */
-  do {
-    /* copy lines from array to buffer: */
-    if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-      goto exit;
-    /* iterate over the lines in the buffers: */
-    for(ii = 0; ii < lines; ii++) {
-      /* get lines: */
-      double *iline = NI_GET_LINE(iline_buffer, ii);
-      double *oline = NI_GET_LINE(oline_buffer, ii);
-      if (!function(iline, length + size1 + size2, oline, length, data)) {
-        if (!PyErr_Occurred())
-          PyErr_SetString(PyExc_RuntimeError,
-                          "unknown error in line processing function");
-        goto exit;
-      }
-    }
-    /* copy lines from buffer to array: */
-    if (!NI_LineBufferToArray(&oline_buffer))
-      goto exit;
-  } while(more);
-exit:
-  if (ibuffer) free(ibuffer);
-  if (obuffer) free(obuffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_FILTER_POINT(_pi, _offsets, _filter_size, _cvalue, _type, \
-                          _res, _mv, _function, _data, _buffer)        \
-case t ## _type:                                                       \
-{                                                                      \
-  maybelong _ii, _offset;                                              \
-  for(_ii = 0; _ii < _filter_size; _ii++) {                            \
-    _offset = _offsets[_ii];                                           \
-    if (_offset == _mv)                                                \
-      _buffer[_ii] = (double)_cvalue;                                  \
-    else                                                               \
-      _buffer[_ii] = (double)*(_type*)(_pi + _offset);                 \
-  }                                                                    \
-  if (!_function(_buffer, _filter_size, &_res, _data)) {               \
-    if (!PyErr_Occurred())                                             \
-      PyErr_SetString(PyExc_RuntimeError,                              \
-                      "unknown error in filter function");             \
-      goto exit;                                                       \
-  }                                                                    \
-}                                                                      \
-break
-
-
-int NI_GenericFilter(PyArrayObject* input,
-      int (*function)(double*, maybelong, double*, void*), void *data,
-      PyArrayObject* footprint, PyArrayObject* output,
-      NI_ExtendMode mode, double cvalue, maybelong *origins)
-{
-  Bool *pf = NULL;
-  maybelong fsize, jj, filter_size = 0, border_flag_value;
-  maybelong *offsets = NULL, *oo, size;
-  NI_FilterIterator fi;
-  NI_Iterator ii, io;
-  char *pi, *po;
-  double *buffer = NULL;
-  int ll;
-
-  /* get the the footprint: */
-  fsize = 1;
-  for(ll = 0; ll < footprint->nd; ll++)
-    fsize *= footprint->dimensions[ll];
-  pf = (Bool*)PyArray_DATA(footprint);
-  for(jj = 0; jj < fsize; jj++) {
-    if (pf[jj])
-      ++filter_size;
-  }
-  /* initialize filter offsets: */
-  if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
-                            mode, &offsets, &border_flag_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
-                             filter_size, input->dimensions, origins, &fi))
-    goto exit;
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* get data pointers an array size: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* buffer for filter calculation: */
-  buffer = (double*)malloc(filter_size * sizeof(double));
-  if (!buffer) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  /* iterate over the elements: */
-  oo = offsets;
-  for(jj = 0; jj < size; jj++) {
-    double tmp = 0.0;
-    switch (input->descr->type_num) {
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Bool,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt8,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt16,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt32,
-                        tmp, border_flag_value, function, data, buffer);
-#if HAS_UINT64
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt64,
-                        tmp, border_flag_value, function, data, buffer);
-#endif
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int8,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int16,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int32,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int64,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float32,
-                        tmp, border_flag_value, function, data, buffer);
-      CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float64,
-                        tmp, border_flag_value, function, data, buffer);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-      CASE_FILTER_OUT(po, tmp, Bool);
-      CASE_FILTER_OUT(po, tmp, UInt8);
-      CASE_FILTER_OUT(po, tmp, UInt16);
-      CASE_FILTER_OUT(po, tmp, UInt32);
-#if HAS_UINT64
-      CASE_FILTER_OUT(po, tmp, UInt64);
-#endif
-      CASE_FILTER_OUT(po, tmp, Int8);
-      CASE_FILTER_OUT(po, tmp, Int16);
-      CASE_FILTER_OUT(po, tmp, Int32);
-      CASE_FILTER_OUT(po, tmp, Int64);
-      CASE_FILTER_OUT(po, tmp, Float32);
-      CASE_FILTER_OUT(po, tmp, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      goto exit;
-    }
-    NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
-  }
-exit:
-  if (offsets) free(offsets);
-  if (buffer) free(buffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+#include "ni_filters.h"
+#include <stdlib.h>
+#include <math.h>
+
+#define BUFFER_SIZE 256000
+
+int NI_Correlate1D(PyArrayObject *input, PyArrayObject *weights,
+                                     int axis, PyArrayObject *output, NI_ExtendMode mode,
+                                     double cval, maybelong origin)
+{
+    int symmetric = 0, ii, jj, more;
+    maybelong ll, lines, length, size1, size2, filter_size;
+    double *ibuffer = NULL, *obuffer = NULL;
+    Float64 *fw;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    /* test for symmetry or anti-symmetry: */
+    filter_size = weights->dimensions[0];
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    fw = (void *)PyArray_DATA(weights);
+    if (filter_size & 0x1) {
+        symmetric = 1;
+        for(ii = 1; ii <= filter_size / 2; ii++) {
+            if (fabs(fw[ii + size1] - fw[size1 - ii]) > DBL_EPSILON) {
+                symmetric = 0;
+                break;
+            }
+        }
+        if (symmetric == 0) {
+            symmetric = -1;
+            for(ii = 1; ii <= filter_size / 2; ii++) {
+                if (fabs(fw[size1 + ii] + fw[size1 - ii]) > DBL_EPSILON) {
+                    symmetric = 0;
+                    break;
+                }
+            }
+        }
+    }
+    /* allocate and initialize the line buffers: */
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                         &lines, BUFFER_SIZE, &ibuffer))
+        goto exit;
+    if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &obuffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                            lines, ibuffer, mode, cval, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
+                                                 &oline_buffer))
+        goto exit;
+    length = input->nd > 0 ? input->dimensions[axis] : 1;
+    fw += size1;
+    /* iterate over all the array lines: */
+    do {
+        /* copy lines from array to buffer: */
+        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
+            goto exit;
+        /* iterate over the lines in the buffers: */
+        for(ii = 0; ii < lines; ii++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, ii) + size1;
+            double *oline = NI_GET_LINE(oline_buffer, ii);
+            /* the correlation calculation: */
+            if (symmetric > 0) {
+                for(ll = 0; ll < length; ll++) {
+                    oline[ll] = iline[0] * fw[0];
+                    for(jj = -size1 ; jj < 0; jj++)
+                        oline[ll] += (iline[jj] + iline[-jj]) * fw[jj];
+                    ++iline;
+                }
+            } else if (symmetric < 0) {
+                for(ll = 0; ll < length; ll++) {
+                    oline[ll] = iline[0] * fw[0];
+                    for(jj = -size1 ; jj < 0; jj++)
+                        oline[ll] += (iline[jj] - iline[-jj]) * fw[jj];
+                    ++iline;
+                }
+            } else {
+                for(ll = 0; ll < length; ll++) {
+                    oline[ll] = iline[size2] * fw[size2];
+                    for(jj = -size1; jj < size2; jj++)
+                        oline[ll] += iline[jj] * fw[jj];
+                    ++iline;
+                }
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+exit:
+    if (ibuffer) free(ibuffer);
+    if (obuffer) free(obuffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_CORRELATE_POINT(_pi, _weights, _offsets, _filter_size, \
+                                                         _cvalue, _type, _res, _mv)             \
+case t ## _type:                                                    \
+{                                                                   \
+    maybelong _ii, _offset;                                           \
+    for(_ii = 0; _ii < _filter_size; _ii++) {                         \
+        _offset = _offsets[_ii];                                        \
+        if (_offset == _mv)                                             \
+            _res += _weights[_ii] * _cvalue;                              \
+        else                                                            \
+            _res += _weights[_ii] * (double)*(_type*)(_pi + _offset);     \
+    }                                                                 \
+}                                                                   \
+break
+
+#define CASE_FILTER_OUT(_po, _tmp, _type) \
+case t ## _type:                          \
+    *(_type*)_po = (_type)_tmp;             \
+    break
+
+int NI_Correlate(PyArrayObject* input, PyArrayObject* weights,
+                                                PyArrayObject* output, NI_ExtendMode mode,
+                                                double cvalue, maybelong *origins)
+{
+    Bool *pf = NULL;
+    maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    Float64 *pw;
+    Float64 *ww = NULL;
+    int ll;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < weights->nd; ll++)
+        fsize *= weights->dimensions[ll];
+    pw = (Float64*)PyArray_DATA(weights);
+    pf = (Bool*)malloc(fsize * sizeof(Bool));
+    if (!pf) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < fsize; jj++) {
+        if (fabs(pw[jj]) > DBL_EPSILON) {
+            pf[jj] = 1;
+            ++filter_size;
+        } else {
+            pf[jj] = 0;
+        }
+    }
+    /* copy the weights to contiguous memory: */
+    ww = (Float64*)malloc(filter_size * sizeof(Float64));
+    if (!ww) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    jj = 0;
+    for(kk = 0; kk < fsize; kk++) {
+        if (pf[kk]) {
+            ww[jj++] = pw[kk];
+        }
+    }
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, weights->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, weights->dimensions, filter_size,
+                                                         input->dimensions, origins, &fi))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Bool,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt8,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt16,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt32,
+                                                     tmp, border_flag_value);
+#if HAS_UINT64
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt64,
+                                                     tmp, border_flag_value);
+#endif
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int8,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int16,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int32,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int64,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float32,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float64,
+                                                     tmp, border_flag_value);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (ww) free(ww);
+    if (pf) free(pf);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int
+NI_UniformFilter1D(PyArrayObject *input, long filter_size,
+                                     int axis, PyArrayObject *output, NI_ExtendMode mode,
+                                     double cval, long origin)
+{
+    maybelong lines, kk, ll, length, size1, size2;
+    int more;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    /* allocate and initialize the line buffers: */
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                         &lines, BUFFER_SIZE, &ibuffer))
+        goto exit;
+    if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &obuffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                            lines, ibuffer, mode, cval, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
+                                                 &oline_buffer))
+        goto exit;
+    length = input->nd > 0 ? input->dimensions[axis] : 1;
+
+    /* iterate over all the array lines: */
+    do {
+        /* copy lines from array to buffer: */
+        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
+            goto exit;
+        /* iterate over the lines in the buffers: */
+        for(kk = 0; kk < lines; kk++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, kk);
+            double *oline = NI_GET_LINE(oline_buffer, kk);
+            /* do the uniform filter: */
+            double tmp = 0.0;
+            double *l1 = iline;
+            double *l2 = iline + filter_size;
+            for(ll = 0; ll < filter_size; ll++)
+                tmp += iline[ll];
+            tmp /= (double)filter_size;
+            oline[0] = tmp;
+            for(ll = 1; ll < length; ll++) {
+                tmp += (*l2++ - *l1++) / (double)filter_size;
+                oline[ll] = tmp;
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+
+ exit:
+    if (ibuffer) free(ibuffer);
+    if (obuffer) free(obuffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int
+NI_MinOrMaxFilter1D(PyArrayObject *input, long filter_size,
+                                        int axis, PyArrayObject *output, NI_ExtendMode mode,
+                                        double cval, long origin, int minimum)
+{
+    maybelong lines, kk, jj, ll, length, size1, size2;
+    int more;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    /* allocate and initialize the line buffers: */
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                         &lines, BUFFER_SIZE, &ibuffer))
+        goto exit;
+    if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &obuffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                             lines, ibuffer, mode, cval, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
+                                                 &oline_buffer))
+        goto exit;
+    length = input->nd > 0 ? input->dimensions[axis] : 1;
+
+    /* iterate over all the array lines: */
+    do {
+        /* copy lines from array to buffer: */
+        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
+            goto exit;
+        /* iterate over the lines in the buffers: */
+        for(kk = 0; kk < lines; kk++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, kk) + size1;
+            double *oline = NI_GET_LINE(oline_buffer, kk);
+            for(ll = 0; ll < length; ll++) {
+            /* find minimum or maximum filter: */
+                double val = iline[ll - size1];
+                for(jj = -size1 + 1; jj <= size2; jj++) {
+                    double tmp = iline[ll + jj];
+                    if (minimum) {
+                        if (tmp < val)
+                            val = tmp;
+                    } else {
+                        if (tmp > val)
+                            val = tmp;
+                    }
+                }
+                oline[ll] = val;
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+
+ exit:
+    if (ibuffer) free(ibuffer);
+    if (obuffer) free(obuffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+#define CASE_MIN_OR_MAX_POINT(_pi, _offsets, _filter_size, _cval, \
+                                                            _type, _minimum, _res, _mv, _ss)    \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii, _oo = *_offsets;                                 \
+    _type _cv = (_type)_cval, _tmp;                                 \
+    _res = _oo == _mv ? _cv : *(_type*)(_pi + _oo);                 \
+    if (_ss)                                                        \
+        _res += *_ss;                                                 \
+    for(_ii = 1; _ii < _filter_size; _ii++) {                       \
+        _oo = _offsets[_ii];                                          \
+        _tmp = _oo == _mv ? _cv : *(_type*)(_pi + _oo);               \
+        if (_ss)                                                      \
+            _tmp += _ss[_ii];                                           \
+        if (_minimum) {                                               \
+            if (_tmp < _res)                                            \
+                _res = (_type)_tmp;                                       \
+        } else {                                                      \
+            if (_tmp > _res)                                            \
+                _res = (_type)_tmp;                                       \
+        }                                                             \
+    }                                                               \
+}                                                                 \
+break
+
+int NI_MinOrMaxFilter(PyArrayObject* input, PyArrayObject* footprint,
+                PyArrayObject* structure, PyArrayObject* output,
+                NI_ExtendMode mode, double cvalue, maybelong *origins, int minimum)
+{
+    Bool *pf = NULL;
+    maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    int ll;
+    double *ss = NULL;
+    Float64 *ps;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj]) {
+            ++filter_size;
+        }
+    }
+    /* get the structure: */
+    if (structure) {
+        ss = (double*)malloc(filter_size * sizeof(double));
+        if (!ss) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        /* copy the weights to contiguous memory: */
+        ps = (Float64*)PyArray_DATA(structure);
+        jj = 0;
+        for(kk = 0; kk < fsize; kk++)
+            if (pf[kk])
+                ss[jj++] = minimum ? -ps[kk] : ps[kk];
+    }
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
+                                                         filter_size, input->dimensions, origins, &fi))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Bool,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                                        minimum, tmp, border_flag_value, ss);
+#if HAS_UINT64
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                                        minimum, tmp, border_flag_value, ss);
+#endif
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int8,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int16,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int32,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int64,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float32,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float64,
+                                                        minimum, tmp, border_flag_value, ss);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (ss) free(ss);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static double NI_Select(double *buffer, int min, int max, int rank)
+{
+    int ii, jj;
+    double x, t;
+
+    if (min == max)
+        return buffer[min];
+
+    x = buffer[min];
+    ii = min - 1;
+    jj = max + 1;
+    for(;;) {
+        do
+            jj--;
+        while(buffer[jj] > x);
+        do
+            ii++;
+        while(buffer[ii] < x);
+        if (ii < jj) {
+            t = buffer[ii];
+            buffer[ii] = buffer[jj];
+            buffer[jj] = t;
+        } else {
+            break;
+        }
+    }
+
+    ii = jj - min + 1;
+    if (rank < ii)
+        return NI_Select(buffer, min, jj, rank);
+    else
+        return NI_Select(buffer, jj + 1, max, rank - ii);
+}
+
+#define CASE_RANK_POINT(_pi, _offsets, _filter_size, _cval, _type, \
+                                                _rank, _buffer, _res, _mv)                 \
+case t ## _type:                                                   \
+{                                                                  \
+    maybelong _ii;                                                   \
+    for(_ii = 0; _ii < _filter_size; _ii++) {                        \
+        maybelong _offset = _offsets[_ii];                             \
+        if (_offset == _mv)                                            \
+            _buffer[_ii] = (_type)_cval;                                 \
+        else                                                           \
+            _buffer[_ii] = *(_type*)(_pi + _offsets[_ii]);               \
+    }                                                                \
+    _res = (_type)NI_Select(_buffer, 0, _filter_size - 1, _rank);    \
+}                                                                  \
+break
+
+int NI_RankFilter(PyArrayObject* input, int rank,
+                                    PyArrayObject* footprint, PyArrayObject* output,
+                                    NI_ExtendMode mode, double cvalue, maybelong *origins)
+{
+    maybelong fsize, jj, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    Bool *pf = NULL;
+    double *buffer = NULL;
+    int ll;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj]) {
+            ++filter_size;
+        }
+    }
+    /* buffer for rank calculation: */
+    buffer = (double*)malloc(filter_size * sizeof(double));
+    if (!buffer) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
+                                                         filter_size, input->dimensions, origins, &fi))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Bool,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                            rank, buffer, tmp, border_flag_value);
+#if HAS_UINT64
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                            rank, buffer, tmp, border_flag_value);
+#endif
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int8,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int16,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int32,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int64,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float32,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float64,
+                                            rank, buffer, tmp, border_flag_value);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int NI_GenericFilter1D(PyArrayObject *input,
+                int (*function)(double*, maybelong, double*, maybelong, void*),
+                void* data, long filter_size, int axis, PyArrayObject *output,
+                NI_ExtendMode mode, double cval, long origin)
+{
+    int more;
+    maybelong ii, lines, length, size1, size2;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    /* allocate and initialize the line buffers: */
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                         &lines, BUFFER_SIZE, &ibuffer))
+        goto exit;
+    if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &obuffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
+                                                            lines, ibuffer, mode, cval, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
+                                                 &oline_buffer))
+        goto exit;
+    length = input->nd > 0 ? input->dimensions[axis] : 1;
+    /* iterate over all the array lines: */
+    do {
+        /* copy lines from array to buffer: */
+        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
+            goto exit;
+        /* iterate over the lines in the buffers: */
+        for(ii = 0; ii < lines; ii++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, ii);
+            double *oline = NI_GET_LINE(oline_buffer, ii);
+            if (!function(iline, length + size1 + size2, oline, length, data)) {
+                if (!PyErr_Occurred())
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "unknown error in line processing function");
+                goto exit;
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+exit:
+    if (ibuffer) free(ibuffer);
+    if (obuffer) free(obuffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_FILTER_POINT(_pi, _offsets, _filter_size, _cvalue, _type, \
+                                                    _res, _mv, _function, _data, _buffer)        \
+case t ## _type:                                                       \
+{                                                                      \
+    maybelong _ii, _offset;                                              \
+    for(_ii = 0; _ii < _filter_size; _ii++) {                            \
+        _offset = _offsets[_ii];                                           \
+        if (_offset == _mv)                                                \
+            _buffer[_ii] = (double)_cvalue;                                  \
+        else                                                               \
+            _buffer[_ii] = (double)*(_type*)(_pi + _offset);                 \
+    }                                                                    \
+    if (!_function(_buffer, _filter_size, &_res, _data)) {               \
+        if (!PyErr_Occurred())                                             \
+            PyErr_SetString(PyExc_RuntimeError,                              \
+                                            "unknown error in filter function");             \
+            goto exit;                                                       \
+    }                                                                    \
+}                                                                      \
+break
+
+
+int NI_GenericFilter(PyArrayObject* input,
+            int (*function)(double*, maybelong, double*, void*), void *data,
+            PyArrayObject* footprint, PyArrayObject* output,
+            NI_ExtendMode mode, double cvalue, maybelong *origins)
+{
+    Bool *pf = NULL;
+    maybelong fsize, jj, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *buffer = NULL;
+    int ll;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj])
+            ++filter_size;
+    }
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->dimensions,
+                                                         filter_size, input->dimensions, origins, &fi))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* buffer for filter calculation: */
+    buffer = (double*)malloc(filter_size * sizeof(double));
+    if (!buffer) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    /* iterate over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Bool,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                                tmp, border_flag_value, function, data, buffer);
+#if HAS_UINT64
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                                tmp, border_flag_value, function, data, buffer);
+#endif
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int8,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int16,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int32,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int64,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float32,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float64,
+                                                tmp, border_flag_value, function, data, buffer);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}

Modified: trunk/scipy/ndimage/src/ni_filters.h
===================================================================
--- trunk/scipy/ndimage/src/ni_filters.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_filters.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,54 +1,54 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met: 
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
- */
-
-#ifndef NI_FILTERS_H
-#define NI_FILTERS_H
-
-int NI_Correlate1D(PyArrayObject*, PyArrayObject*, int, PyArrayObject*,
-                   NI_ExtendMode, double, maybelong);
-int NI_Correlate(PyArrayObject*, PyArrayObject*, PyArrayObject*,
-                 NI_ExtendMode, double, maybelong*);
-int NI_UniformFilter1D(PyArrayObject*, long, int, PyArrayObject*,
-                       NI_ExtendMode, double, long);
-int NI_MinOrMaxFilter1D(PyArrayObject*, long, int, PyArrayObject*,
-                        NI_ExtendMode, double, long, int);
-int NI_MinOrMaxFilter(PyArrayObject*, PyArrayObject*, PyArrayObject*,
-                      PyArrayObject*, NI_ExtendMode, double, maybelong*,
-                      int);
-int NI_RankFilter(PyArrayObject*, int, PyArrayObject*, PyArrayObject*,
-                  NI_ExtendMode, double, maybelong*);
-int NI_GenericFilter1D(PyArrayObject*, int (*)(double*, maybelong, 
-                       double*, maybelong, void*), void*, long, int,
-                       PyArrayObject*, NI_ExtendMode, double, long);
-int NI_GenericFilter(PyArrayObject*, int (*)(double*, maybelong, double*,
-                     void*), void*, PyArrayObject*, PyArrayObject*,
-                     NI_ExtendMode, double, maybelong*);
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
+ */
+
+#ifndef NI_FILTERS_H
+#define NI_FILTERS_H
+
+int NI_Correlate1D(PyArrayObject*, PyArrayObject*, int, PyArrayObject*,
+                                     NI_ExtendMode, double, maybelong);
+int NI_Correlate(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                 NI_ExtendMode, double, maybelong*);
+int NI_UniformFilter1D(PyArrayObject*, long, int, PyArrayObject*,
+                                             NI_ExtendMode, double, long);
+int NI_MinOrMaxFilter1D(PyArrayObject*, long, int, PyArrayObject*,
+                                                NI_ExtendMode, double, long, int);
+int NI_MinOrMaxFilter(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                            PyArrayObject*, NI_ExtendMode, double, maybelong*,
+                                            int);
+int NI_RankFilter(PyArrayObject*, int, PyArrayObject*, PyArrayObject*,
+                                    NI_ExtendMode, double, maybelong*);
+int NI_GenericFilter1D(PyArrayObject*, int (*)(double*, maybelong, 
+                                             double*, maybelong, void*), void*, long, int,
+                                             PyArrayObject*, NI_ExtendMode, double, long);
+int NI_GenericFilter(PyArrayObject*, int (*)(double*, maybelong, double*,
+                                         void*), void*, PyArrayObject*, PyArrayObject*,
+                                         NI_ExtendMode, double, maybelong*);
+#endif

Modified: trunk/scipy/ndimage/src/ni_fourier.c
===================================================================
--- trunk/scipy/ndimage/src/ni_fourier.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_fourier.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,548 +1,548 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include <stdlib.h>
-#include <math.h>
-#include <assert.h>
-
-#if !defined(M_PI)
-#define M_PI 3.14159265358979323846
-#endif
-
-#define _NI_GAUSSIAN 0
-#define _NI_UNIFORM 1
-#define _NI_ELLIPSOID 2
-
-static double polevl(double x, const double coef[], int N)
-{
-  double ans;
-  const double *p = coef;
-  int i = N;
-
-  ans = *p++;
-  do
-    ans = ans * x + *p++;
-  while(--i);
-
-  return ans ;
-}
-
-double p1evl(double x, const double coef[], int N)
-{
-  double ans;
-  const double *p = coef;
-  int i = N - 1;
-
-  ans = x + *p++;
-  do
-    ans = ans * x + *p++;
-  while(--i);
-
-  return ans;
-}
-
-#define THPIO4 2.35619449019234492885
-#define SQ2OPI .79788456080286535588
-#define Z1 1.46819706421238932572E1
-#define Z2 4.92184563216946036703E1
-
-static double _bessel_j1(double x)
-{
-  double w, z, p, q, xn;
-  const double RP[4] = {
-    -8.99971225705559398224E8,
-    4.52228297998194034323E11,
-    -7.27494245221818276015E13,
-    3.68295732863852883286E15,
-  };
-  const double RQ[8] = {
-    6.20836478118054335476E2,
-    2.56987256757748830383E5,
-    8.35146791431949253037E7,
-    2.21511595479792499675E10,
-    4.74914122079991414898E12,
-    7.84369607876235854894E14,
-    8.95222336184627338078E16,
-    5.32278620332680085395E18,
-  };
-  const double PP[7] = {
-    7.62125616208173112003E-4,
-    7.31397056940917570436E-2,
-    1.12719608129684925192E0,
-    5.11207951146807644818E0,
-    8.42404590141772420927E0,
-    5.21451598682361504063E0,
-    1.00000000000000000254E0,
-  };
-  const double PQ[7] = {
-    5.71323128072548699714E-4,
-    6.88455908754495404082E-2,
-    1.10514232634061696926E0,
-    5.07386386128601488557E0,
-    8.39985554327604159757E0,
-    5.20982848682361821619E0,
-    9.99999999999999997461E-1,
-  };
-  const double QP[8] = {
-    5.10862594750176621635E-2,
-    4.98213872951233449420E0,
-    7.58238284132545283818E1,
-    3.66779609360150777800E2,
-    7.10856304998926107277E2,
-    5.97489612400613639965E2,
-    2.11688757100572135698E2,
-    2.52070205858023719784E1,
-  };
-  const double QQ[7] = {
-    7.42373277035675149943E1,
-    1.05644886038262816351E3,
-    4.98641058337653607651E3,
-    9.56231892404756170795E3,
-    7.99704160447350683650E3,
-    2.82619278517639096600E3,
-    3.36093607810698293419E2,
-  };
-
-  w = x;
-  if (x < 0)
-    w = -x;
-
-  if (w <= 5.0) {
-    z = x * x;
-    w = polevl(z, RP, 3) / p1evl(z, RQ, 8);
-    w = w * x * (z - Z1) * (z - Z2);
-    return w ;
-  }
-
-  w = 5.0 / x;
-  z = w * w;
-  p = polevl(z, PP, 6) / polevl(z, PQ, 6);
-  q = polevl(z, QP, 7) / p1evl(z, QQ, 7);
-  xn = x - THPIO4;
-  p = p * cos(xn) - w * q * sin(xn);
-  return p * SQ2OPI / sqrt(x);
-}
-
-#define CASE_FOURIER_OUT_RR(_po, _tmp, _type) \
-case t ## _type:                              \
-  *(_type*)_po = _tmp;                        \
-  break
-
-#define CASE_FOURIER_OUT_RC(_po, _tmp, _type) \
-case t ## _type:                              \
-  (*(_type*)_po).real = tmp;                  \
-  (*(_type*)_po).imag = 0.0;                  \
-  break
-
-#define CASE_FOURIER_OUT_CC(_po, _tmp_r, _tmp_i, _type) \
-case t ## _type:                                        \
-  (*(_type*)_po).real = _tmp_r;                         \
-  (*(_type*)_po).imag = _tmp_i;                         \
-  break
-
-#define CASE_FOURIER_FILTER_RC(_pi, _tmp, _tmp_r, _tmp_i, _type) \
-case t ## _type:                                                 \
-  _tmp_r = (*(_type*)_pi).real * _tmp;                           \
-  _tmp_i = (*(_type*)_pi).imag * _tmp;                           \
-  break;
-
-#define CASE_FOURIER_FILTER_RR(_pi, _tmp, _type) \
-case t ## _type:                                 \
-  _tmp *= *(_type*)_pi;                          \
-  break;
-
-int NI_FourierFilter(PyArrayObject *input, PyArrayObject* parameter_array,
-            maybelong n, int axis, PyArrayObject* output, int filter_type)
-{
-  NI_Iterator ii, io;
-  char *pi, *po;
-  double *parameters = NULL, **params = NULL;
-  maybelong kk, hh, size;
-  Float64 *iparameters = (void *)PyArray_DATA(parameter_array);
-  int ll;
-
-  /* precalculate the parameters: */
-  parameters = (double*)malloc(input->nd * sizeof(double));
-  if (!parameters) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(kk = 0; kk < input->nd; kk++) {
-    /* along the direction of the real transform we must use the given
-       length of that dimensons, unless a complex transform is assumed
-       (n < 0): */
-    int shape = kk == axis ?
-            (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
-    switch (filter_type) {
-      case _NI_GAUSSIAN:
-        parameters[kk] = *iparameters++ * M_PI / (double)shape;
-        parameters[kk] = -2.0 * parameters[kk] * parameters[kk];
-        break;
-      case _NI_ELLIPSOID:
-      case _NI_UNIFORM:
-        parameters[kk] = *iparameters++;
-        break;
-    }
-  }
-  /* allocate memory for tables: */
-  params = (double**) malloc(input->nd * sizeof(double*));
-  if (!params) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(kk = 0; kk < input->nd; kk++)
-    params[kk] = NULL;
-  for(kk = 0; kk < input->nd; kk++) {
-    if (input->dimensions[kk] > 1) {
-      params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
-      if (!params[kk]) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-    }
-  }
-  switch (filter_type) {
-    case _NI_GAUSSIAN:
-      /* calculate the tables of exponentials: */
-      for (hh = 0; hh < input->nd; hh++) {
-        if (params[hh]) {
-          if (hh == axis && n >= 0) {
-            for(kk = 0; kk < input->dimensions[hh]; kk++) {
-              double tmp = parameters[hh] * kk * kk;
-              params[hh][kk] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
-            }
-          } else {
-            int jj = 0;
-            for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
-              double tmp = parameters[hh] * kk * kk;
-              params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
-            }
-            for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
-              double tmp = parameters[hh] * kk * kk;
-              params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
-            }
-          }
-        }
-      }
-      break;
-    case _NI_UNIFORM:
-      /* calculate the tables of parameters: */
-      for (hh = 0; hh < input->nd; hh++) {
-        if (params[hh]) {
-          params[hh][0] = 1.0;
-          if (hh == axis && n >= 0) {
-            double tmp = M_PI * parameters[hh] / n;
-            for(kk = 1; kk < input->dimensions[hh]; kk++)
-              params[hh][kk] = tmp > 0.0 ?
-                                      sin(tmp * kk) / (tmp * kk) : 0.0;
-          } else {
-            double tmp = M_PI * parameters[hh] / input->dimensions[hh];
-            int jj = 1;
-            for(kk = 1; kk < (input->dimensions[hh] + 1) / 2; kk++)
-              params[hh][jj++] = tmp > 0.0 ?
-                                      sin(tmp * kk) / (tmp * kk) : 0.0;
-            for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
-              params[hh][jj++] = tmp > 0.0 ?
-                                      sin(tmp * kk) / (tmp * kk) : 0.0;
-          }
-        }
-      }
-      break;
-    case _NI_ELLIPSOID:
-      /* calculate the tables of parameters: */
-      for (hh = 0; hh < input->nd; hh++) {
-        if (params[hh]) {
-          params[hh][0] = 1.0;
-          if (hh == axis && n >= 0) {
-            double tmp = M_PI * parameters[hh] / n;
-            for(kk = 0; kk < input->dimensions[hh]; kk++)
-              params[hh][kk] = (double)kk * tmp;
-          } else {
-            double tmp = M_PI * parameters[hh] / input->dimensions[hh];
-            int jj = 0;
-            for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++)
-              params[hh][jj++] = (double)kk * tmp;
-            for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
-              params[hh][jj++] = (double)kk * tmp;
-          }
-        } else if (input->dimensions[hh] > 0) {
-          params[hh][0] = 1.0;
-        }
-      }
-      if (input->nd > 1)
-        for(hh = 0; hh < input->nd; hh++)
-          for(kk = 0; kk < input->dimensions[hh]; kk++)
-            params[hh][kk] = params[hh][kk] * params[hh][kk];
-      break;
-    default:
-      break;
-  }
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* iterator over the elements: */
-  for(hh = 0; hh < size; hh++) {
-    double tmp = 1.0;
-    switch (filter_type) {
-    case _NI_GAUSSIAN:
-    case _NI_UNIFORM:
-      for(kk = 0; kk < input->nd; kk++)
-        if (params[kk])
-          tmp *= params[kk][ii.coordinates[kk]];
-      break;
-    case _NI_ELLIPSOID:
-      switch (input->nd) {
-      case 1:
-        tmp = params[0][ii.coordinates[0]];
-        tmp = tmp > 0.0 ? sin(tmp) / (tmp) : 1.0;
-        break;
-      case 2:
-        tmp = 0.0;
-        for(kk = 0; kk < 2; kk++)
-          tmp += params[kk][ii.coordinates[kk]];
-        tmp = sqrt(tmp);
-        tmp = tmp > 0.0 ? 2.0 * _bessel_j1(tmp) / tmp : 1.0;
-        break;
-      case 3:
-        {
-          double r = 0.0;
-          for(kk = 0; kk < 3; kk++)
-            r += params[kk][ii.coordinates[kk]];
-          r = sqrt(r);
-          if (r > 0.0) {
-            tmp = 3.0 * (sin(r) - r * cos(r));
-            tmp /= r * r * r;
-          } else {
-            tmp = 1.0;
-          }
-        }
-        break;
-      }
-      break;
-    default:
-      break;
-    }
-    if (input->descr->type_num == tComplex64 ||
-        input->descr->type_num == tComplex128) {
-      double tmp_r = 0.0, tmp_i = 0.0;
-      switch (input->descr->type_num) {
-        CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex64);
-        CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex128);
-      default:
-        PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-        goto exit;
-      }
-      switch (output->descr->type_num) {
-        CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex64);
-        CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex128);
-      default:
-        PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-        goto exit;
-      }
-    } else {
-      switch (input->descr->type_num) {
-        CASE_FOURIER_FILTER_RR(pi, tmp, Bool)
-        CASE_FOURIER_FILTER_RR(pi, tmp, UInt8)
-        CASE_FOURIER_FILTER_RR(pi, tmp, UInt16)
-        CASE_FOURIER_FILTER_RR(pi, tmp, UInt32)
-#if HAS_UINT64
-        CASE_FOURIER_FILTER_RR(pi, tmp, UInt64)
-#endif
-        CASE_FOURIER_FILTER_RR(pi, tmp, Int8)
-        CASE_FOURIER_FILTER_RR(pi, tmp, Int16)
-        CASE_FOURIER_FILTER_RR(pi, tmp, Int32)
-        CASE_FOURIER_FILTER_RR(pi, tmp, Int64)
-        CASE_FOURIER_FILTER_RR(pi, tmp, Float32)
-        CASE_FOURIER_FILTER_RR(pi, tmp, Float64)
-      default:
-        PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-        goto exit;
-      }
-      switch (output->descr->type_num) {
-        CASE_FOURIER_OUT_RR(po, tmp, Float32);
-        CASE_FOURIER_OUT_RR(po, tmp, Float64);
-        CASE_FOURIER_OUT_RC(po, tmp, Complex64);
-        CASE_FOURIER_OUT_RC(po, tmp, Complex128);
-      default:
-        PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-        goto exit;
-      }
-    }
-    NI_ITERATOR_NEXT2(ii, io, pi, po);
-  }
-
- exit:
-  if (parameters) free(parameters);
-  if (params) {
-    for(kk = 0; kk < input->nd; kk++)
-      if (params[kk]) free(params[kk]);
-    free(params);
-  }
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_FOURIER_SHIFT_R(_pi, _tmp, _r, _i, _cost, _sint, _type) \
-case t ## _type:                                                     \
-  _tmp = *(_type*)_pi;                                               \
-  _r = _tmp * _cost;                                                 \
-  _i = _tmp * _sint;                                                 \
-  break;
-
-#define CASE_FOURIER_SHIFT_C(_pi, _r, _i, _cost, _sint, _type)     \
-case t ## _type:                                                   \
-  _r = (*(_type*)_pi).real * _cost - (*(_type*)_pi).imag * _sint;  \
-  _i = (*(_type*)_pi).real * _sint + (*(_type*)_pi).imag * _cost;  \
-  break;
-
-int NI_FourierShift(PyArrayObject *input, PyArrayObject* shift_array,
-      maybelong n, int axis, PyArrayObject* output)
-{
-  NI_Iterator ii, io;
-  char *pi, *po;
-  double *shifts = NULL, **params = NULL;
-  maybelong kk, hh, size;
-  Float64 *ishifts = (void *)PyArray_DATA(shift_array);
-  int ll;
-
-  /* precalculate the shifts: */
-  shifts = (double*)malloc(input->nd * sizeof(double));
-  if (!shifts) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(kk = 0; kk < input->nd; kk++) {
-    /* along the direction of the real transform we must use the given
-       length of that dimensons, unless a complex transform is assumed
-       (n < 0): */
-    int shape = kk == axis ?
-            (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
-    shifts[kk] = -2.0 * M_PI * *ishifts++ / (double)shape;
-  }
-  /* allocate memory for tables: */
-  params = (double**) malloc(input->nd * sizeof(double*));
-  if (!params) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(kk = 0; kk < input->nd; kk++)
-    params[kk] = NULL;
-  for(kk = 0; kk < input->nd; kk++) {
-    if (input->dimensions[kk] > 1) {
-      params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
-      if (!params[kk]) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-    }
-  }
-  for (hh = 0; hh < input->nd; hh++) {
-    if (params[hh]) {
-      if (hh == axis && n >= 0) {
-        for(kk = 0; kk < input->dimensions[hh]; kk++)
-          params[hh][kk] = shifts[hh] * kk;
-      } else {
-        int jj = 0;
-        for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
-          params[hh][jj++] = shifts[hh] * kk;
-        }
-        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
-          params[hh][jj++] = shifts[hh] * kk;
-        }
-      }
-    }
-  }
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* iterator over the elements: */
-  for(hh = 0; hh < size; hh++) {
-    double tmp = 0.0, sint, cost, r = 0.0, i = 0.0;
-    for(kk = 0; kk < input->nd; kk++)
-      if (params[kk])
-        tmp += params[kk][ii.coordinates[kk]];
-    sint = sin(tmp);
-    cost = cos(tmp);
-    switch (input->descr->type_num) {
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Bool)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt8)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt16)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt32)
-#if HAS_UINT64
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt64)
-#endif
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int8)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int16)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int32)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int64)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float32)
-      CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float64)
-      CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex64)
-      CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex128)
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-      CASE_FOURIER_OUT_CC(po, r, i, Complex64);
-      CASE_FOURIER_OUT_CC(po, r, i, Complex128);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    NI_ITERATOR_NEXT2(ii, io, pi, po);
-  }
-
- exit:
-  if (shifts) free(shifts);
-  if (params) {
-    for(kk = 0; kk < input->nd; kk++)
-      if (params[kk]) free(params[kk]);
-    free(params);
-  }
-  return PyErr_Occurred() ? 0 : 1;
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+#if !defined(M_PI)
+#define M_PI 3.14159265358979323846
+#endif
+
+#define _NI_GAUSSIAN 0
+#define _NI_UNIFORM 1
+#define _NI_ELLIPSOID 2
+
+static double polevl(double x, const double coef[], int N)
+{
+    double ans;
+    const double *p = coef;
+    int i = N;
+
+    ans = *p++;
+    do
+        ans = ans * x + *p++;
+    while(--i);
+
+    return ans ;
+}
+
+double p1evl(double x, const double coef[], int N)
+{
+    double ans;
+    const double *p = coef;
+    int i = N - 1;
+
+    ans = x + *p++;
+    do
+        ans = ans * x + *p++;
+    while(--i);
+
+    return ans;
+}
+
+#define THPIO4 2.35619449019234492885
+#define SQ2OPI .79788456080286535588
+#define Z1 1.46819706421238932572E1
+#define Z2 4.92184563216946036703E1
+
+static double _bessel_j1(double x)
+{
+    double w, z, p, q, xn;
+    const double RP[4] = {
+        -8.99971225705559398224E8,
+        4.52228297998194034323E11,
+        -7.27494245221818276015E13,
+        3.68295732863852883286E15,
+    };
+    const double RQ[8] = {
+        6.20836478118054335476E2,
+        2.56987256757748830383E5,
+        8.35146791431949253037E7,
+        2.21511595479792499675E10,
+        4.74914122079991414898E12,
+        7.84369607876235854894E14,
+        8.95222336184627338078E16,
+        5.32278620332680085395E18,
+    };
+    const double PP[7] = {
+        7.62125616208173112003E-4,
+        7.31397056940917570436E-2,
+        1.12719608129684925192E0,
+        5.11207951146807644818E0,
+        8.42404590141772420927E0,
+        5.21451598682361504063E0,
+        1.00000000000000000254E0,
+    };
+    const double PQ[7] = {
+        5.71323128072548699714E-4,
+        6.88455908754495404082E-2,
+        1.10514232634061696926E0,
+        5.07386386128601488557E0,
+        8.39985554327604159757E0,
+        5.20982848682361821619E0,
+        9.99999999999999997461E-1,
+    };
+    const double QP[8] = {
+        5.10862594750176621635E-2,
+        4.98213872951233449420E0,
+        7.58238284132545283818E1,
+        3.66779609360150777800E2,
+        7.10856304998926107277E2,
+        5.97489612400613639965E2,
+        2.11688757100572135698E2,
+        2.52070205858023719784E1,
+    };
+    const double QQ[7] = {
+        7.42373277035675149943E1,
+        1.05644886038262816351E3,
+        4.98641058337653607651E3,
+        9.56231892404756170795E3,
+        7.99704160447350683650E3,
+        2.82619278517639096600E3,
+        3.36093607810698293419E2,
+    };
+
+    w = x;
+    if (x < 0)
+        w = -x;
+
+    if (w <= 5.0) {
+        z = x * x;
+        w = polevl(z, RP, 3) / p1evl(z, RQ, 8);
+        w = w * x * (z - Z1) * (z - Z2);
+        return w ;
+    }
+
+    w = 5.0 / x;
+    z = w * w;
+    p = polevl(z, PP, 6) / polevl(z, PQ, 6);
+    q = polevl(z, QP, 7) / p1evl(z, QQ, 7);
+    xn = x - THPIO4;
+    p = p * cos(xn) - w * q * sin(xn);
+    return p * SQ2OPI / sqrt(x);
+}
+
+#define CASE_FOURIER_OUT_RR(_po, _tmp, _type) \
+case t ## _type:                              \
+    *(_type*)_po = _tmp;                        \
+    break
+
+#define CASE_FOURIER_OUT_RC(_po, _tmp, _type) \
+case t ## _type:                              \
+    (*(_type*)_po).real = tmp;                  \
+    (*(_type*)_po).imag = 0.0;                  \
+    break
+
+#define CASE_FOURIER_OUT_CC(_po, _tmp_r, _tmp_i, _type) \
+case t ## _type:                                        \
+    (*(_type*)_po).real = _tmp_r;                         \
+    (*(_type*)_po).imag = _tmp_i;                         \
+    break
+
+#define CASE_FOURIER_FILTER_RC(_pi, _tmp, _tmp_r, _tmp_i, _type) \
+case t ## _type:                                                 \
+    _tmp_r = (*(_type*)_pi).real * _tmp;                           \
+    _tmp_i = (*(_type*)_pi).imag * _tmp;                           \
+    break;
+
+#define CASE_FOURIER_FILTER_RR(_pi, _tmp, _type) \
+case t ## _type:                                 \
+    _tmp *= *(_type*)_pi;                          \
+    break;
+
+int NI_FourierFilter(PyArrayObject *input, PyArrayObject* parameter_array,
+                        maybelong n, int axis, PyArrayObject* output, int filter_type)
+{
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *parameters = NULL, **params = NULL;
+    maybelong kk, hh, size;
+    Float64 *iparameters = (void *)PyArray_DATA(parameter_array);
+    int ll;
+
+    /* precalculate the parameters: */
+    parameters = (double*)malloc(input->nd * sizeof(double));
+    if (!parameters) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++) {
+        /* along the direction of the real transform we must use the given
+             length of that dimensons, unless a complex transform is assumed
+             (n < 0): */
+        int shape = kk == axis ?
+                        (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
+        switch (filter_type) {
+            case _NI_GAUSSIAN:
+                parameters[kk] = *iparameters++ * M_PI / (double)shape;
+                parameters[kk] = -2.0 * parameters[kk] * parameters[kk];
+                break;
+            case _NI_ELLIPSOID:
+            case _NI_UNIFORM:
+                parameters[kk] = *iparameters++;
+                break;
+        }
+    }
+    /* allocate memory for tables: */
+    params = (double**) malloc(input->nd * sizeof(double*));
+    if (!params) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++)
+        params[kk] = NULL;
+    for(kk = 0; kk < input->nd; kk++) {
+        if (input->dimensions[kk] > 1) {
+            params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
+            if (!params[kk]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+    switch (filter_type) {
+        case _NI_GAUSSIAN:
+            /* calculate the tables of exponentials: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    if (hh == axis && n >= 0) {
+                        for(kk = 0; kk < input->dimensions[hh]; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][kk] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                    } else {
+                        int jj = 0;
+                        for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                    }
+                }
+            }
+            break;
+        case _NI_UNIFORM:
+            /* calculate the tables of parameters: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    params[hh][0] = 1.0;
+                    if (hh == axis && n >= 0) {
+                        double tmp = M_PI * parameters[hh] / n;
+                        for(kk = 1; kk < input->dimensions[hh]; kk++)
+                            params[hh][kk] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                    } else {
+                        double tmp = M_PI * parameters[hh] / input->dimensions[hh];
+                        int jj = 1;
+                        for(kk = 1; kk < (input->dimensions[hh] + 1) / 2; kk++)
+                            params[hh][jj++] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
+                            params[hh][jj++] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                    }
+                }
+            }
+            break;
+        case _NI_ELLIPSOID:
+            /* calculate the tables of parameters: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    params[hh][0] = 1.0;
+                    if (hh == axis && n >= 0) {
+                        double tmp = M_PI * parameters[hh] / n;
+                        for(kk = 0; kk < input->dimensions[hh]; kk++)
+                            params[hh][kk] = (double)kk * tmp;
+                    } else {
+                        double tmp = M_PI * parameters[hh] / input->dimensions[hh];
+                        int jj = 0;
+                        for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++)
+                            params[hh][jj++] = (double)kk * tmp;
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
+                            params[hh][jj++] = (double)kk * tmp;
+                    }
+                } else if (input->dimensions[hh] > 0) {
+                    params[hh][0] = 1.0;
+                }
+            }
+            if (input->nd > 1)
+                for(hh = 0; hh < input->nd; hh++)
+                    for(kk = 0; kk < input->dimensions[hh]; kk++)
+                        params[hh][kk] = params[hh][kk] * params[hh][kk];
+            break;
+        default:
+            break;
+    }
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    for(hh = 0; hh < size; hh++) {
+        double tmp = 1.0;
+        switch (filter_type) {
+        case _NI_GAUSSIAN:
+        case _NI_UNIFORM:
+            for(kk = 0; kk < input->nd; kk++)
+                if (params[kk])
+                    tmp *= params[kk][ii.coordinates[kk]];
+            break;
+        case _NI_ELLIPSOID:
+            switch (input->nd) {
+            case 1:
+                tmp = params[0][ii.coordinates[0]];
+                tmp = tmp > 0.0 ? sin(tmp) / (tmp) : 1.0;
+                break;
+            case 2:
+                tmp = 0.0;
+                for(kk = 0; kk < 2; kk++)
+                    tmp += params[kk][ii.coordinates[kk]];
+                tmp = sqrt(tmp);
+                tmp = tmp > 0.0 ? 2.0 * _bessel_j1(tmp) / tmp : 1.0;
+                break;
+            case 3:
+                {
+                    double r = 0.0;
+                    for(kk = 0; kk < 3; kk++)
+                        r += params[kk][ii.coordinates[kk]];
+                    r = sqrt(r);
+                    if (r > 0.0) {
+                        tmp = 3.0 * (sin(r) - r * cos(r));
+                        tmp /= r * r * r;
+                    } else {
+                        tmp = 1.0;
+                    }
+                }
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+        if (input->descr->type_num == tComplex64 ||
+                input->descr->type_num == tComplex128) {
+            double tmp_r = 0.0, tmp_i = 0.0;
+            switch (input->descr->type_num) {
+                CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex64);
+                CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+            switch (output->descr->type_num) {
+                CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex64);
+                CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+        } else {
+            switch (input->descr->type_num) {
+                CASE_FOURIER_FILTER_RR(pi, tmp, Bool)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt8)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt16)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt32)
+#if HAS_UINT64
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt64)
+#endif
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int8)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int16)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int32)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int64)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Float32)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Float64)
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+            switch (output->descr->type_num) {
+                CASE_FOURIER_OUT_RR(po, tmp, Float32);
+                CASE_FOURIER_OUT_RR(po, tmp, Float64);
+                CASE_FOURIER_OUT_RC(po, tmp, Complex64);
+                CASE_FOURIER_OUT_RC(po, tmp, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+ exit:
+    if (parameters) free(parameters);
+    if (params) {
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk]) free(params[kk]);
+        free(params);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_FOURIER_SHIFT_R(_pi, _tmp, _r, _i, _cost, _sint, _type) \
+case t ## _type:                                                     \
+    _tmp = *(_type*)_pi;                                               \
+    _r = _tmp * _cost;                                                 \
+    _i = _tmp * _sint;                                                 \
+    break;
+
+#define CASE_FOURIER_SHIFT_C(_pi, _r, _i, _cost, _sint, _type)     \
+case t ## _type:                                                   \
+    _r = (*(_type*)_pi).real * _cost - (*(_type*)_pi).imag * _sint;  \
+    _i = (*(_type*)_pi).real * _sint + (*(_type*)_pi).imag * _cost;  \
+    break;
+
+int NI_FourierShift(PyArrayObject *input, PyArrayObject* shift_array,
+            maybelong n, int axis, PyArrayObject* output)
+{
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *shifts = NULL, **params = NULL;
+    maybelong kk, hh, size;
+    Float64 *ishifts = (void *)PyArray_DATA(shift_array);
+    int ll;
+
+    /* precalculate the shifts: */
+    shifts = (double*)malloc(input->nd * sizeof(double));
+    if (!shifts) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++) {
+        /* along the direction of the real transform we must use the given
+             length of that dimensons, unless a complex transform is assumed
+             (n < 0): */
+        int shape = kk == axis ?
+                        (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
+        shifts[kk] = -2.0 * M_PI * *ishifts++ / (double)shape;
+    }
+    /* allocate memory for tables: */
+    params = (double**) malloc(input->nd * sizeof(double*));
+    if (!params) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++)
+        params[kk] = NULL;
+    for(kk = 0; kk < input->nd; kk++) {
+        if (input->dimensions[kk] > 1) {
+            params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
+            if (!params[kk]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+    for (hh = 0; hh < input->nd; hh++) {
+        if (params[hh]) {
+            if (hh == axis && n >= 0) {
+                for(kk = 0; kk < input->dimensions[hh]; kk++)
+                    params[hh][kk] = shifts[hh] * kk;
+            } else {
+                int jj = 0;
+                for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
+                    params[hh][jj++] = shifts[hh] * kk;
+                }
+                for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
+                    params[hh][jj++] = shifts[hh] * kk;
+                }
+            }
+        }
+    }
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    for(hh = 0; hh < size; hh++) {
+        double tmp = 0.0, sint, cost, r = 0.0, i = 0.0;
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk])
+                tmp += params[kk][ii.coordinates[kk]];
+        sint = sin(tmp);
+        cost = cos(tmp);
+        switch (input->descr->type_num) {
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Bool)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt8)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt16)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt32)
+#if HAS_UINT64
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt64)
+#endif
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int8)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int16)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int32)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int64)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float32)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float64)
+            CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex64)
+            CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex128)
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FOURIER_OUT_CC(po, r, i, Complex64);
+            CASE_FOURIER_OUT_CC(po, r, i, Complex128);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+ exit:
+    if (shifts) free(shifts);
+    if (params) {
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk]) free(params[kk]);
+        free(params);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}

Modified: trunk/scipy/ndimage/src/ni_fourier.h
===================================================================
--- trunk/scipy/ndimage/src/ni_fourier.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_fourier.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,40 +1,40 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met: 
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
- */
-
-#ifndef NI_FOURIER_H
-#define NI_FOURIER_H
-
-int NI_FourierFilter(PyArrayObject*, PyArrayObject*, maybelong, int,
-                     PyArrayObject*, int);
-int NI_FourierShift(PyArrayObject*, PyArrayObject*, maybelong, int,
-                    PyArrayObject*);
-
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
+ */
+
+#ifndef NI_FOURIER_H
+#define NI_FOURIER_H
+
+int NI_FourierFilter(PyArrayObject*, PyArrayObject*, maybelong, int,
+                                         PyArrayObject*, int);
+int NI_FourierShift(PyArrayObject*, PyArrayObject*, maybelong, int,
+                                        PyArrayObject*);
+
+#endif

Modified: trunk/scipy/ndimage/src/ni_interpolation.c
===================================================================
--- trunk/scipy/ndimage/src/ni_interpolation.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_interpolation.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,966 +1,966 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_interpolation.h"
-#include <stdlib.h>
-#include <math.h>
-
-/* calculate the B-spline interpolation coefficients for given x: */
-static void
-spline_coefficients(double x, int order, double *result)
-{
-  int hh;
-  double y, start;
-
-  if (order & 1) {
-    start = (int)floor(x) - order / 2;
-  } else {
-    start = (int)floor(x + 0.5) - order / 2;
-  }
-
-  for(hh = 0; hh <= order; hh++)  {
-    y = fabs(start - x + hh);
-
-    switch(order) {
-    case 1:
-      result[hh] = y > 1.0 ? 0.0 : 1.0 - y;
-      break;
-    case 2:
-      if (y < 0.5) {
-        result[hh] = 0.75 - y * y;
-      } else if (y < 1.5) {
-        y = 1.5 - y;
-        result[hh] = 0.5 * y * y;
-      } else {
-        result[hh] = 0.0;
-      }
-      break;
-    case 3:
-      if (y < 1.0) {
-        result[hh] =
-          (y * y * (y - 2.0) * 3.0 + 4.0) / 6.0;
-      } else if (y < 2.0) {
-        y = 2.0 - y;
-        result[hh] = y * y * y / 6.0;
-      } else {
-        result[hh] = 0.0;
-      }
-      break;
-    case 4:
-      if (y < 0.5) {
-        y *= y;
-        result[hh] = y * (y * 0.25 - 0.625) + 115.0 / 192.0;
-      } else if (y < 1.5) {
-        result[hh] = y * (y * (y * (5.0 / 6.0 - y / 6.0) - 1.25) +
-                          5.0 / 24.0) + 55.0 / 96.0;
-      } else if (y < 2.5) {
-        y -= 2.5;
-        y *= y;
-        result[hh] = y * y / 24.0;
-      } else {
-        result[hh] = 0.0;
-      }
-      break;
-    case 5:
-      if (y < 1.0) {
-        double f = y * y;
-        result[hh] =
-          f * (f * (0.25 - y / 12.0) - 0.5) + 0.55;
-      } else if (y < 2.0) {
-        result[hh] = y * (y * (y * (y * (y / 24.0 - 0.375)
-                                    + 1.25) -  1.75) + 0.625) + 0.425;
-      } else if (y < 3.0) {
-        double f = 3.0 - y;
-        y = f * f;
-        result[hh] = f * y * y / 120.0;
-      } else {
-        result[hh] = 0.0;
-      }
-      break;
-    }
-  }
-}
-
-/* map a coordinate outside the borders, according to the requested
-   boundary condition: */
-static double
-map_coordinate(double in, maybelong len, int mode)
-{
-  if (in < 0) {
-    switch (mode) {
-    case NI_EXTEND_MIRROR:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz2 = 2 * len - 2;
-        in = sz2 * (maybelong)(-in / sz2) + in;
-        in = in <= 1 - len ? in + sz2 : -in;
-      }
-      break;
-    case NI_EXTEND_REFLECT:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz2 = 2 * len;
-        if (in < -sz2)
-          in = sz2 * (maybelong)(-in / sz2) + in;
-        in = in < -len ? in + sz2 : -in - 1;
-      }
-      break;
-    case NI_EXTEND_WRAP:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz = len - 1;
-        // Integer division of -in/sz gives (-in mod sz)
-        // Note that 'in' is negative
-        in += sz * ((maybelong)(-in / sz) + 1);
-      }
-      break;
-    case NI_EXTEND_NEAREST:
-      in = 0;
-      break;
-    case NI_EXTEND_CONSTANT:
-      in = -1;
-      break;
-    }
-  } else if (in > len-1) {
-    switch (mode) {
-    case NI_EXTEND_MIRROR:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz2 = 2 * len - 2;
-        in -= sz2 * (maybelong)(in / sz2);
-        if (in >= len)
-          in = sz2 - in;
-      }
-      break;
-    case NI_EXTEND_REFLECT:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz2 = 2 * len;
-        in -= sz2 * (maybelong)(in / sz2);
-        if (in >= len)
-          in = sz2 - in - 1;
-      }
-      break;
-    case NI_EXTEND_WRAP:
-      if (len <= 1) {
-        in = 0;
-      } else {
-        maybelong sz = len - 1;
-        in -= sz * (maybelong)(in / sz);
-      }
-      break;
-    case NI_EXTEND_NEAREST:
-      in = len - 1;
-      break;
-    case NI_EXTEND_CONSTANT:
-      in = -1;
-      break;
-    }
-  }
-
-  return in;
-}
-
-#define BUFFER_SIZE 256000
-#define TOLERANCE 1e-15
-
-/* one-dimensional spline filter: */
-int NI_SplineFilter1D(PyArrayObject *input, int order, int axis,
-                      PyArrayObject *output)
-{
-  int hh, npoles = 0, more;
-  maybelong kk, ll, lines, len;
-  double *buffer = NULL, weight, pole[2];
-  NI_LineBuffer iline_buffer, oline_buffer;
-
-  len = input->nd > 0 ? input->dimensions[axis] : 1;
-  if (len < 1)
-    goto exit;
-
-  /* these are used in the spline filter calculation below: */
-  switch (order) {
-  case 2:
-    npoles = 1;
-    pole[0] = sqrt(8.0) - 3.0;
-    break;
-  case 3:
-    npoles = 1;
-    pole[0] = sqrt(3.0) - 2.0;
-    break;
-  case 4:
-    npoles = 2;
-    pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0;
-    pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0;
-    break;
-  case 5:
-    npoles = 2;
-    pole[0] = sqrt(67.5 - sqrt(4436.25)) + sqrt(26.25) - 6.5;
-    pole[1] = sqrt(67.5 + sqrt(4436.25)) - sqrt(26.25) - 6.5;
-    break;
-  default:
-    break;
-  }
-
-  weight = 1.0;
-  for(hh = 0; hh < npoles; hh++)
-    weight *= (1.0 - pole[hh]) * (1.0 - 1.0 / pole[hh]);
-
-  /* allocate an initialize the line buffer, only a single one is used,
-     because the calculation is in-place: */
-  lines = -1;
-  if (!NI_AllocateLineBuffer(input, axis, 0, 0, &lines, BUFFER_SIZE,
-                             &buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(input, axis, 0, 0, lines, buffer,
-                         NI_EXTEND_DEFAULT, 0.0, &iline_buffer))
-    goto exit;
-  if (!NI_InitLineBuffer(output, axis, 0, 0, lines, buffer,
-                         NI_EXTEND_DEFAULT, 0.0, &oline_buffer))
-    goto exit;
-
-  /* iterate over all the array lines: */
-  do {
-    /* copy lines from array to buffer: */
-    if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-      goto exit;
-    /* iterate over the lines in the buffer: */
-    for(kk = 0; kk < lines; kk++) {
-      /* get line: */
-      double *ln = NI_GET_LINE(iline_buffer, kk);
-      /* spline filter: */
-      if (len > 1) {
-        for(ll = 0; ll < len; ll++)
-          ln[ll] *= weight;
-        for(hh = 0; hh < npoles; hh++) {
-          double p = pole[hh];
-          int max = (int)ceil(log(TOLERANCE) / log(fabs(p)));
-          if (max < len) {
-            double zn = p;
-            double sum = ln[0];
-            for(ll = 1; ll < max; ll++) {
-              sum += zn * ln[ll];
-              zn *= p;
-            }
-            ln[0] = sum;
-          } else {
-            double zn = p;
-            double iz = 1.0 / p;
-            double z2n = pow(p, (double)(len - 1));
-            double sum = ln[0] + z2n * ln[len - 1];
-            z2n *= z2n * iz;
-            for(ll = 1; ll <= len - 2; ll++) {
-              sum += (zn + z2n) * ln[ll];
-              zn *= p;
-              z2n *= iz;
-            }
-            ln[0] = sum / (1.0 - zn * zn);
-          }
-          for(ll = 1; ll < len; ll++)
-            ln[ll] += p * ln[ll - 1];
-          ln[len-1] = (p / (p * p - 1.0)) * (ln[len-1] + p * ln[len-2]);
-          for(ll = len - 2; ll >= 0; ll--)
-            ln[ll] = p * (ln[ll + 1] - ln[ll]);
-        }
-      }
-    }
-    /* copy lines from buffer to array: */
-    if (!NI_LineBufferToArray(&oline_buffer))
-      goto exit;
-  } while(more);
-
- exit:
-  if (buffer) free(buffer);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_MAP_COORDINATES(_p, _coor, _rank, _stride, _type) \
-case t ## _type:                                                    \
-{                                                              \
-  int _hh;                                                     \
-  for(_hh = 0; _hh < _rank; _hh++) {                           \
-    _coor[_hh] = *(_type*)_p;                                  \
-    _p += _stride;                                             \
-  }                                                            \
-}                                                              \
-break;
-
-#define CASE_INTERP_COEFF(_coeff, _pi, _idx, _type) \
-case t ## _type:                                    \
-  _coeff = *(_type*)(_pi + _idx);                   \
-  break;
-
-#define CASE_INTERP_OUT(_po, _t, _type) \
-case t ## _type:                        \
-  *(_type*)_po = (_type)_t;             \
-  break;
-
-#define CASE_INTERP_OUT_UINT(_po, _t, _type, type_min, type_max) \
-case t ## _type:                             \
-  _t = _t > 0 ? _t + 0.5 : 0;                \
-  _t = _t > type_max ? type_max : t;         \
-  _t = _t < type_min ? type_min : t;         \
-  *(_type*)_po = (_type)_t;                  \
-  break;
-
-#define CASE_INTERP_OUT_INT(_po, _t, _type, type_min, type_max) \
-case t ## _type:                            \
-  _t = _t > 0 ? _t + 0.5 : _t - 0.5;        \
-  _t = _t > type_max ? type_max : t;        \
-  _t = _t < type_min ? type_min : t;        \
-  *(_type*)_po = (_type)_t;                 \
-  break;
-
-int
-NI_GeometricTransform(PyArrayObject *input, int (*map)(maybelong*, double*,
-        int, int, void*), void* map_data, PyArrayObject* matrix_ar,
-        PyArrayObject* shift_ar, PyArrayObject *coordinates,
-        PyArrayObject *output, int order, int mode, double cval)
-{
-  char *po, *pi, *pc = NULL;
-  maybelong **edge_offsets = NULL, **data_offsets = NULL, filter_size;
-  maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
-  maybelong cstride = 0, kk, hh, ll, jj, *idxs = NULL;
-  maybelong size;
-  double **splvals = NULL, icoor[MAXDIM];
-  double idimensions[MAXDIM], istrides[MAXDIM];
-  NI_Iterator io, ic;
-  Float64 *matrix = matrix_ar ? (Float64*)PyArray_DATA(matrix_ar) : NULL;
-  Float64 *shift = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
-  int irank = 0, orank, qq;
-
-  for(kk = 0; kk < input->nd; kk++) {
-    idimensions[kk] = input->dimensions[kk];
-    istrides[kk] = input->strides[kk];
-  }
-  irank = input->nd;
-  orank = output->nd;
-
-  /* if the mapping is from array coordinates: */
-  if (coordinates) {
-    /* initialze a line iterator along the first axis: */
-    if (!NI_InitPointIterator(coordinates, &ic))
-      goto exit;
-    cstride = ic.strides[0];
-    if (!NI_LineIterator(&ic, 0))
-      goto exit;
-    pc = (void *)(PyArray_DATA(coordinates));
-  }
-
-  /* offsets used at the borders: */
-  edge_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
-  data_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
-  if (!edge_offsets || !data_offsets) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < irank; jj++)
-    data_offsets[jj] = NULL;
-  for(jj = 0; jj < irank; jj++) {
-    data_offsets[jj] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
-    if (!data_offsets[jj]) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  /* will hold the spline coefficients: */
-  splvals = (double**)malloc(irank * sizeof(double*));
-  if (!splvals) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < irank; jj++)
-    splvals[jj] = NULL;
-  for(jj = 0; jj < irank; jj++) {
-    splvals[jj] = (double*)malloc((order + 1) * sizeof(double));
-    if (!splvals[jj]) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-
-  filter_size = 1;
-  for(jj = 0; jj < irank; jj++)
-    filter_size *= order + 1;
-  idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
-  if (!idxs) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-
-  /* initialize output iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-
-  /* get data pointers: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-
-  /* make a table of all possible coordinates within the spline filter: */
-  fcoordinates = (maybelong*)malloc(irank * filter_size * sizeof(maybelong));
-  /* make a table of all offsets within the spline filter: */
-  foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
-  if (!fcoordinates || !foffsets) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < irank; jj++)
-    ftmp[jj] = 0;
-  kk = 0;
-  for(hh = 0; hh < filter_size; hh++) {
-    for(jj = 0; jj < irank; jj++)
-      fcoordinates[jj + hh * irank] = ftmp[jj];
-    foffsets[hh] = kk;
-    for(jj = irank - 1; jj >= 0; jj--) {
-      if (ftmp[jj] < order) {
-        ftmp[jj]++;
-        kk += istrides[jj];
-        break;
-      } else {
-        ftmp[jj] = 0;
-        kk -= istrides[jj] * order;
-      }
-    }
-  }
-
-  size = 1;
-  for(qq = 0; qq < output->nd; qq++)
-    size *= output->dimensions[qq];
-  for(kk = 0; kk < size; kk++) {
-    double t = 0.0;
-    int constant = 0, edge = 0, offset = 0;
-    if (map) {
-      /* call mappint functions: */
-      if (!map(io.coordinates, icoor, orank, irank, map_data)) {
-        if (!PyErr_Occurred())
-          PyErr_SetString(PyExc_RuntimeError,
-                          "unknown error in mapping function");
-        goto exit;
-      }
-    } else if (matrix) {
-      /* do an affine transformation: */
-      Float64 *p = matrix;
-      for(hh = 0; hh < irank; hh++) {
-        icoor[hh] = 0.0;
-        for(ll = 0; ll < orank; ll++)
-          icoor[hh] += io.coordinates[ll] * *p++;
-        icoor[hh] += shift[hh];
-      }
-    } else if (coordinates) {
-      /* mapping is from an coordinates array: */
-      char *p = pc;
-      switch(coordinates->descr->type_num) {
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Bool);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt8);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt16);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt32);
-#if HAS_UINT64
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt64);
-#endif
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int8);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int16);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int32);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int64);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float32);
-        CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float64);
-      default:
-        PyErr_SetString(PyExc_RuntimeError,
-                        "coordinate array data type not supported");
-        goto exit;
-      }
-    }
-    /* iterate over axes: */
-    for(hh = 0; hh < irank; hh++) {
-      /* if the input coordinate is outside the borders, map it: */
-      double cc = map_coordinate(icoor[hh], idimensions[hh], mode);
-      if (cc > -1.0) {
-        /* find the filter location along this axis: */
-        int start;
-        if (order & 1) {
-          start = (int)floor(cc) - order / 2;
-        } else {
-          start = (int)floor(cc + 0.5) - order / 2;
-        }
-        /* get the offset to the start of the filter: */
-        offset += istrides[hh] * start;
-        if (start < 0 || start + order >= idimensions[hh]) {
-          /* implement border mapping, if outside border: */
-          edge = 1;
-          edge_offsets[hh] = data_offsets[hh];
-          for(ll = 0; ll <= order; ll++) {
-            int idx = start + ll;
-            int len = idimensions[hh];
-            if (len <= 1) {
-              idx = 0;
-            } else {
-              int s2 = 2 * len - 2;
-              if (idx < 0) {
-                idx = s2 * (int)(-idx / s2) + idx;
-                idx = idx <= 1 - len ? idx + s2 : -idx;
-              } else if (idx >= len) {
-                idx -= s2 * (int)(idx / s2);
-                if (idx >= len)
-                  idx = s2 - idx;
-              }
-            }
-            /* calculate and store the offests at this edge: */
-            edge_offsets[hh][ll] = istrides[hh] * (idx - start);
-          }
-        } else {
-          /* we are not at the border, use precalculated offsets: */
-          edge_offsets[hh] = NULL;
-        }
-        spline_coefficients(cc, order, splvals[hh]);
-      } else {
-        /* we use the constant border condition: */
-        constant = 1;
-        break;
-      }
-    }
-
-    if (!constant) {
-      maybelong *ff = fcoordinates;
-      for(hh = 0; hh < filter_size; hh++) {
-        int idx = 0;
-        if (edge) {
-          for(ll = 0; ll < irank; ll++) {
-            if (edge_offsets[ll])
-              idx += edge_offsets[ll][ff[ll]];
-            else
-              idx += ff[ll] * istrides[ll];
-          }
-        } else {
-          idx = foffsets[hh];
-        }
-        idx += offset;
-        idxs[hh] = idx;
-        ff += irank;
-      }
-    }
-    if (!constant) {
-      maybelong *ff = fcoordinates;
-      t = 0.0;
-      for(hh = 0; hh < filter_size; hh++) {
-        double coeff = 0.0;
-        switch(input->descr->type_num) {
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
-#if HAS_UINT64
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
-#endif
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
-        default:
-          PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-          goto exit;
-        }
-        /* calculate the interpolated value: */
-        for(ll = 0; ll < irank; ll++)
-          if (order > 0)
-            coeff *= splvals[ll][ff[ll]];
-        t += coeff;
-        ff += irank;
-      }
-    } else {
-      t = cval;
-    }
-    /* store output value: */
-    switch (output->descr->type_num) {
-      CASE_INTERP_OUT(po, t, Bool);
-      CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
-      CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
-      CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
-#if HAS_UINT64
-      /* FIXME */
-      CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
-#endif
-      CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
-      CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
-      CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
-      CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
-      CASE_INTERP_OUT(po, t, Float32);
-      CASE_INTERP_OUT(po, t, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    if (coordinates) {
-      NI_ITERATOR_NEXT2(io, ic, po, pc);
-    } else {
-      NI_ITERATOR_NEXT(io, po);
-    }
-  }
-
- exit:
-  if (edge_offsets)
-    free(edge_offsets);
-  if (data_offsets) {
-    for(jj = 0; jj < irank; jj++)
-      free(data_offsets[jj]);
-    free(data_offsets);
-  }
-  if (splvals) {
-    for(jj = 0; jj < irank; jj++)
-      free(splvals[jj]);
-    free(splvals);
-  }
-  if (foffsets)
-    free(foffsets);
-  if (fcoordinates)
-    free(fcoordinates);
-  if (idxs)
-    free(idxs);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-int NI_ZoomShift(PyArrayObject *input, PyArrayObject* zoom_ar,
-                 PyArrayObject* shift_ar, PyArrayObject *output,
-                 int order, int mode, double cval)
-{
-  char *po, *pi;
-  maybelong **zeros = NULL, **offsets = NULL, ***edge_offsets = NULL;
-  maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
-  maybelong jj, hh, kk, filter_size, odimensions[MAXDIM];
-  maybelong idimensions[MAXDIM], istrides[MAXDIM], *idxs = NULL;
-  maybelong size;
-  double ***splvals = NULL;
-  NI_Iterator io;
-  Float64 *zooms = zoom_ar ? (Float64*)PyArray_DATA(zoom_ar) : NULL;
-  Float64 *shifts = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
-  int rank = 0, qq;
-
-  for(kk = 0; kk < input->nd; kk++) {
-    idimensions[kk] = input->dimensions[kk];
-    istrides[kk] = input->strides[kk];
-    odimensions[kk] = output->dimensions[kk];
-  }
-  rank = input->nd;
-
-  /* if the mode is 'constant' we need some temps later: */
-  if (mode == NI_EXTEND_CONSTANT) {
-    zeros = (maybelong**)malloc(rank * sizeof(maybelong*));
-    if (!zeros) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-    for(jj = 0; jj < rank; jj++)
-      zeros[jj] = NULL;
-    for(jj = 0; jj < rank; jj++) {
-      zeros[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
-      if(!zeros[jj]) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-    }
-  }
-
-  /* store offsets, along each axis: */
-  offsets = (maybelong**)malloc(rank * sizeof(maybelong*));
-  /* store spline coefficients, along each axis: */
-  splvals = (double***)malloc(rank * sizeof(double**));
-  /* store offsets at all edges: */
-  edge_offsets = (maybelong***)malloc(rank * sizeof(maybelong**));
-  if (!offsets || !splvals || !edge_offsets) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < rank; jj++) {
-    offsets[jj] = NULL;
-    splvals[jj] = NULL;
-    edge_offsets[jj] = NULL;
-  }
-  for(jj = 0; jj < rank; jj++) {
-    offsets[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
-    splvals[jj] = (double**)malloc(odimensions[jj] * sizeof(double*));
-    edge_offsets[jj] = (maybelong**)malloc(odimensions[jj] * sizeof(maybelong*));
-    if (!offsets[jj] || !splvals[jj] || !edge_offsets[jj]) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-    for(hh = 0; hh < odimensions[jj]; hh++) {
-      splvals[jj][hh] = NULL;
-      edge_offsets[jj][hh] = NULL;
-    }
-  }
-
-  /* precalculate offsets, and offsets at the edge: */
-  for(jj = 0; jj < rank; jj++) {
-    double shift = 0.0, zoom = 0.0;
-    if (shifts)
-      shift = shifts[jj];
-    if (zooms)
-      zoom = zooms[jj];
-    for(kk = 0; kk < odimensions[jj]; kk++) {
-      double cc = (double)kk;
-      if (shifts)
-        cc += shift;
-      if (zooms)
-        cc *= zoom;
-      cc = map_coordinate(cc, idimensions[jj], mode);
-      if (cc > -1.0) {
-        int start;
-        if (zeros && zeros[jj])
-          zeros[jj][kk] = 0;
-        if (order & 1) {
-          start = (int)floor(cc) - order / 2;
-        } else {
-          start = (int)floor(cc + 0.5) - order / 2;
-        }
-        offsets[jj][kk] = istrides[jj] * start;
-        if (start < 0 || start + order >= idimensions[jj]) {
-          edge_offsets[jj][kk] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
-          if (!edge_offsets[jj][kk]) {
-            PyErr_NoMemory();
-            goto exit;
-          }
-          for(hh = 0; hh <= order; hh++) {
-            int idx = start + hh;
-             int len = idimensions[jj];
-            if (len <= 1) {
-              idx = 0;
-            } else {
-              int s2 = 2 * len - 2;
-              if (idx < 0) {
-                idx = s2 * (int)(-idx / s2) + idx;
-                idx = idx <= 1 - len ? idx + s2 : -idx;
-              } else if (idx >= len) {
-                idx -= s2 * (int)(idx / s2);
-                if (idx >= len)
-                  idx = s2 - idx;
-              }
-            }
-            edge_offsets[jj][kk][hh] = istrides[jj] * (idx - start);
-          }
-        }
-        if (order > 0) {
-          splvals[jj][kk] = (double*)malloc((order + 1) * sizeof(double));
-          if (!splvals[jj][kk]) {
-            PyErr_NoMemory();
-            goto exit;
-          }
-          spline_coefficients(cc, order, splvals[jj][kk]);
-        }
-      } else {
-        zeros[jj][kk] = 1;
-      }
-    }
-  }
-
-  filter_size = 1;
-  for(jj = 0; jj < rank; jj++)
-    filter_size *= order + 1;
-  idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
-  if (!idxs) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-
-  /* store all coordinates and offsets with filter: */
-  fcoordinates = (maybelong*)malloc(rank * filter_size * sizeof(maybelong));
-  foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
-  if (!fcoordinates || !foffsets) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-
-  for(jj = 0; jj < rank; jj++)
-    ftmp[jj] = 0;
-  kk = 0;
-  for(hh = 0; hh < filter_size; hh++) {
-    for(jj = 0; jj < rank; jj++)
-      fcoordinates[jj + hh * rank] = ftmp[jj];
-    foffsets[hh] = kk;
-    for(jj = rank - 1; jj >= 0; jj--) {
-      if (ftmp[jj] < order) {
-        ftmp[jj]++;
-        kk += istrides[jj];
-        break;
-      } else {
-        ftmp[jj] = 0;
-        kk -= istrides[jj] * order;
-      }
-    }
-  }
-  size = 1;
-  for(qq = 0; qq < output->nd; qq++)
-    size *= output->dimensions[qq];
-  for(kk = 0; kk < size; kk++) {
-    double t = 0.0;
-    int edge = 0, oo = 0, zero = 0;
-
-    for(hh = 0; hh < rank; hh++) {
-      if (zeros && zeros[hh][io.coordinates[hh]]) {
-        /* we use constant border condition */
-        zero = 1;
-        break;
-      }
-      oo += offsets[hh][io.coordinates[hh]];
-      if (edge_offsets[hh][io.coordinates[hh]])
-        edge = 1;
-    }
-
-    if (!zero) {
-      maybelong *ff = fcoordinates;
-      for(hh = 0; hh < filter_size; hh++) {
-        int idx = 0;
-        if (edge) {
-            /* use precalculated edge offsets: */
-          for(jj = 0; jj < rank; jj++) {
-            if (edge_offsets[jj][io.coordinates[jj]])
-              idx += edge_offsets[jj][io.coordinates[jj]][ff[jj]];
-            else
-              idx += ff[jj] * istrides[jj];
-          }
-          idx += oo;
-        } else {
-          /* use normal offsets: */
-          idx += oo + foffsets[hh];
-        }
-        idxs[hh] = idx;
-        ff += rank;
-      }
-    }
-    if (!zero) {
-      maybelong *ff = fcoordinates;
-      t = 0.0;
-      for(hh = 0; hh < filter_size; hh++) {
-        double coeff = 0.0;
-        switch(input->descr->type_num) {
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
-#if HAS_UINT64
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
-#endif
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
-          CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
-        default:
-          PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-          goto exit;
-        }
-        /* calculate interpolated value: */
-        for(jj = 0; jj < rank; jj++)
-          if (order > 0)
-            coeff *= splvals[jj][io.coordinates[jj]][ff[jj]];
-        t += coeff;
-        ff += rank;
-      }
-    } else {
-      t = cval;
-    }
-    /* store output: */
-    switch (output->descr->type_num) {
-      CASE_INTERP_OUT(po, t, Bool);
-      CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
-      CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
-      CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
-#if HAS_UINT64
-      /* FIXME */
-      CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
-#endif
-      CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
-      CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
-      CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
-      CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
-      CASE_INTERP_OUT(po, t, Float32);
-      CASE_INTERP_OUT(po, t, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    NI_ITERATOR_NEXT(io, po);
-  }
-
- exit:
-  if (zeros) {
-    for(jj = 0; jj < rank; jj++)
-      if (zeros[jj])
-        free(zeros[jj]);
-    free(zeros);
-  }
-  if (offsets) {
-    for(jj = 0; jj < rank; jj++)
-      if (offsets[jj])
-        free(offsets[jj]);
-    free(offsets);
-  }
-  if (splvals) {
-    for(jj = 0; jj < rank; jj++) {
-      if (splvals[jj]) {
-        for(hh = 0; hh < odimensions[jj]; hh++)
-          if (splvals[jj][hh])
-            free(splvals[jj][hh]);
-        free(splvals[jj]);
-      }
-    }
-    free(splvals);
-  }
-  if (edge_offsets) {
-    for(jj = 0; jj < rank; jj++) {
-      if (edge_offsets[jj]) {
-        for(hh = 0; hh < odimensions[jj]; hh++)
-          if (edge_offsets[jj][hh])
-            free(edge_offsets[jj][hh]);
-        free(edge_offsets[jj]);
-      }
-    }
-    free(edge_offsets);
-  }
-  if (foffsets)
-    free(foffsets);
-  if (fcoordinates)
-    free(fcoordinates);
-  if (idxs)
-    free(idxs);
-  return PyErr_Occurred() ? 0 : 1;
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+#include "ni_interpolation.h"
+#include <stdlib.h>
+#include <math.h>
+
+/* calculate the B-spline interpolation coefficients for given x: */
+static void
+spline_coefficients(double x, int order, double *result)
+{
+    int hh;
+    double y, start;
+
+    if (order & 1) {
+        start = (int)floor(x) - order / 2;
+    } else {
+        start = (int)floor(x + 0.5) - order / 2;
+    }
+
+    for(hh = 0; hh <= order; hh++)  {
+        y = fabs(start - x + hh);
+
+        switch(order) {
+        case 1:
+            result[hh] = y > 1.0 ? 0.0 : 1.0 - y;
+            break;
+        case 2:
+            if (y < 0.5) {
+                result[hh] = 0.75 - y * y;
+            } else if (y < 1.5) {
+                y = 1.5 - y;
+                result[hh] = 0.5 * y * y;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 3:
+            if (y < 1.0) {
+                result[hh] =
+                    (y * y * (y - 2.0) * 3.0 + 4.0) / 6.0;
+            } else if (y < 2.0) {
+                y = 2.0 - y;
+                result[hh] = y * y * y / 6.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 4:
+            if (y < 0.5) {
+                y *= y;
+                result[hh] = y * (y * 0.25 - 0.625) + 115.0 / 192.0;
+            } else if (y < 1.5) {
+                result[hh] = y * (y * (y * (5.0 / 6.0 - y / 6.0) - 1.25) +
+                                                    5.0 / 24.0) + 55.0 / 96.0;
+            } else if (y < 2.5) {
+                y -= 2.5;
+                y *= y;
+                result[hh] = y * y / 24.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 5:
+            if (y < 1.0) {
+                double f = y * y;
+                result[hh] =
+                    f * (f * (0.25 - y / 12.0) - 0.5) + 0.55;
+            } else if (y < 2.0) {
+                result[hh] = y * (y * (y * (y * (y / 24.0 - 0.375)
+                                                                        + 1.25) -  1.75) + 0.625) + 0.425;
+            } else if (y < 3.0) {
+                double f = 3.0 - y;
+                y = f * f;
+                result[hh] = f * y * y / 120.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        }
+    }
+}
+
+/* map a coordinate outside the borders, according to the requested
+     boundary condition: */
+static double
+map_coordinate(double in, maybelong len, int mode)
+{
+    if (in < 0) {
+        switch (mode) {
+        case NI_EXTEND_MIRROR:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len - 2;
+                in = sz2 * (maybelong)(-in / sz2) + in;
+                in = in <= 1 - len ? in + sz2 : -in;
+            }
+            break;
+        case NI_EXTEND_REFLECT:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len;
+                if (in < -sz2)
+                    in = sz2 * (maybelong)(-in / sz2) + in;
+                in = in < -len ? in + sz2 : -in - 1;
+            }
+            break;
+        case NI_EXTEND_WRAP:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz = len - 1;
+                // Integer division of -in/sz gives (-in mod sz)
+                // Note that 'in' is negative
+                in += sz * ((maybelong)(-in / sz) + 1);
+            }
+            break;
+        case NI_EXTEND_NEAREST:
+            in = 0;
+            break;
+        case NI_EXTEND_CONSTANT:
+            in = -1;
+            break;
+        }
+    } else if (in > len-1) {
+        switch (mode) {
+        case NI_EXTEND_MIRROR:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len - 2;
+                in -= sz2 * (maybelong)(in / sz2);
+                if (in >= len)
+                    in = sz2 - in;
+            }
+            break;
+        case NI_EXTEND_REFLECT:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len;
+                in -= sz2 * (maybelong)(in / sz2);
+                if (in >= len)
+                    in = sz2 - in - 1;
+            }
+            break;
+        case NI_EXTEND_WRAP:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz = len - 1;
+                in -= sz * (maybelong)(in / sz);
+            }
+            break;
+        case NI_EXTEND_NEAREST:
+            in = len - 1;
+            break;
+        case NI_EXTEND_CONSTANT:
+            in = -1;
+            break;
+        }
+    }
+
+    return in;
+}
+
+#define BUFFER_SIZE 256000
+#define TOLERANCE 1e-15
+
+/* one-dimensional spline filter: */
+int NI_SplineFilter1D(PyArrayObject *input, int order, int axis,
+                                            PyArrayObject *output)
+{
+    int hh, npoles = 0, more;
+    maybelong kk, ll, lines, len;
+    double *buffer = NULL, weight, pole[2];
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    len = input->nd > 0 ? input->dimensions[axis] : 1;
+    if (len < 1)
+        goto exit;
+
+    /* these are used in the spline filter calculation below: */
+    switch (order) {
+    case 2:
+        npoles = 1;
+        pole[0] = sqrt(8.0) - 3.0;
+        break;
+    case 3:
+        npoles = 1;
+        pole[0] = sqrt(3.0) - 2.0;
+        break;
+    case 4:
+        npoles = 2;
+        pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0;
+        pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0;
+        break;
+    case 5:
+        npoles = 2;
+        pole[0] = sqrt(67.5 - sqrt(4436.25)) + sqrt(26.25) - 6.5;
+        pole[1] = sqrt(67.5 + sqrt(4436.25)) - sqrt(26.25) - 6.5;
+        break;
+    default:
+        break;
+    }
+
+    weight = 1.0;
+    for(hh = 0; hh < npoles; hh++)
+        weight *= (1.0 - pole[hh]) * (1.0 - 1.0 / pole[hh]);
+
+    /* allocate an initialize the line buffer, only a single one is used,
+         because the calculation is in-place: */
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, 0, 0, lines, buffer,
+                                                 NI_EXTEND_DEFAULT, 0.0, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, buffer,
+                                                 NI_EXTEND_DEFAULT, 0.0, &oline_buffer))
+        goto exit;
+
+    /* iterate over all the array lines: */
+    do {
+        /* copy lines from array to buffer: */
+        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
+            goto exit;
+        /* iterate over the lines in the buffer: */
+        for(kk = 0; kk < lines; kk++) {
+            /* get line: */
+            double *ln = NI_GET_LINE(iline_buffer, kk);
+            /* spline filter: */
+            if (len > 1) {
+                for(ll = 0; ll < len; ll++)
+                    ln[ll] *= weight;
+                for(hh = 0; hh < npoles; hh++) {
+                    double p = pole[hh];
+                    int max = (int)ceil(log(TOLERANCE) / log(fabs(p)));
+                    if (max < len) {
+                        double zn = p;
+                        double sum = ln[0];
+                        for(ll = 1; ll < max; ll++) {
+                            sum += zn * ln[ll];
+                            zn *= p;
+                        }
+                        ln[0] = sum;
+                    } else {
+                        double zn = p;
+                        double iz = 1.0 / p;
+                        double z2n = pow(p, (double)(len - 1));
+                        double sum = ln[0] + z2n * ln[len - 1];
+                        z2n *= z2n * iz;
+                        for(ll = 1; ll <= len - 2; ll++) {
+                            sum += (zn + z2n) * ln[ll];
+                            zn *= p;
+                            z2n *= iz;
+                        }
+                        ln[0] = sum / (1.0 - zn * zn);
+                    }
+                    for(ll = 1; ll < len; ll++)
+                        ln[ll] += p * ln[ll - 1];
+                    ln[len-1] = (p / (p * p - 1.0)) * (ln[len-1] + p * ln[len-2]);
+                    for(ll = len - 2; ll >= 0; ll--)
+                        ln[ll] = p * (ln[ll + 1] - ln[ll]);
+                }
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+
+ exit:
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_MAP_COORDINATES(_p, _coor, _rank, _stride, _type) \
+case t ## _type:                                                    \
+{                                                              \
+    int _hh;                                                     \
+    for(_hh = 0; _hh < _rank; _hh++) {                           \
+        _coor[_hh] = *(_type*)_p;                                  \
+        _p += _stride;                                             \
+    }                                                            \
+}                                                              \
+break;
+
+#define CASE_INTERP_COEFF(_coeff, _pi, _idx, _type) \
+case t ## _type:                                    \
+    _coeff = *(_type*)(_pi + _idx);                   \
+    break;
+
+#define CASE_INTERP_OUT(_po, _t, _type) \
+case t ## _type:                        \
+    *(_type*)_po = (_type)_t;             \
+    break;
+
+#define CASE_INTERP_OUT_UINT(_po, _t, _type, type_min, type_max) \
+case t ## _type:                             \
+    _t = _t > 0 ? _t + 0.5 : 0;                \
+    _t = _t > type_max ? type_max : t;         \
+    _t = _t < type_min ? type_min : t;         \
+    *(_type*)_po = (_type)_t;                  \
+    break;
+
+#define CASE_INTERP_OUT_INT(_po, _t, _type, type_min, type_max) \
+case t ## _type:                            \
+    _t = _t > 0 ? _t + 0.5 : _t - 0.5;        \
+    _t = _t > type_max ? type_max : t;        \
+    _t = _t < type_min ? type_min : t;        \
+    *(_type*)_po = (_type)_t;                 \
+    break;
+
+int
+NI_GeometricTransform(PyArrayObject *input, int (*map)(maybelong*, double*,
+                int, int, void*), void* map_data, PyArrayObject* matrix_ar,
+                PyArrayObject* shift_ar, PyArrayObject *coordinates,
+                PyArrayObject *output, int order, int mode, double cval)
+{
+    char *po, *pi, *pc = NULL;
+    maybelong **edge_offsets = NULL, **data_offsets = NULL, filter_size;
+    maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
+    maybelong cstride = 0, kk, hh, ll, jj, *idxs = NULL;
+    maybelong size;
+    double **splvals = NULL, icoor[MAXDIM];
+    double idimensions[MAXDIM], istrides[MAXDIM];
+    NI_Iterator io, ic;
+    Float64 *matrix = matrix_ar ? (Float64*)PyArray_DATA(matrix_ar) : NULL;
+    Float64 *shift = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
+    int irank = 0, orank, qq;
+
+    for(kk = 0; kk < input->nd; kk++) {
+        idimensions[kk] = input->dimensions[kk];
+        istrides[kk] = input->strides[kk];
+    }
+    irank = input->nd;
+    orank = output->nd;
+
+    /* if the mapping is from array coordinates: */
+    if (coordinates) {
+        /* initialze a line iterator along the first axis: */
+        if (!NI_InitPointIterator(coordinates, &ic))
+            goto exit;
+        cstride = ic.strides[0];
+        if (!NI_LineIterator(&ic, 0))
+            goto exit;
+        pc = (void *)(PyArray_DATA(coordinates));
+    }
+
+    /* offsets used at the borders: */
+    edge_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
+    data_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
+    if (!edge_offsets || !data_offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        data_offsets[jj] = NULL;
+    for(jj = 0; jj < irank; jj++) {
+        data_offsets[jj] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
+        if (!data_offsets[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    /* will hold the spline coefficients: */
+    splvals = (double**)malloc(irank * sizeof(double*));
+    if (!splvals) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        splvals[jj] = NULL;
+    for(jj = 0; jj < irank; jj++) {
+        splvals[jj] = (double*)malloc((order + 1) * sizeof(double));
+        if (!splvals[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    filter_size = 1;
+    for(jj = 0; jj < irank; jj++)
+        filter_size *= order + 1;
+    idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
+    if (!idxs) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    /* initialize output iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+
+    /* get data pointers: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+
+    /* make a table of all possible coordinates within the spline filter: */
+    fcoordinates = (maybelong*)malloc(irank * filter_size * sizeof(maybelong));
+    /* make a table of all offsets within the spline filter: */
+    foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
+    if (!fcoordinates || !foffsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        ftmp[jj] = 0;
+    kk = 0;
+    for(hh = 0; hh < filter_size; hh++) {
+        for(jj = 0; jj < irank; jj++)
+            fcoordinates[jj + hh * irank] = ftmp[jj];
+        foffsets[hh] = kk;
+        for(jj = irank - 1; jj >= 0; jj--) {
+            if (ftmp[jj] < order) {
+                ftmp[jj]++;
+                kk += istrides[jj];
+                break;
+            } else {
+                ftmp[jj] = 0;
+                kk -= istrides[jj] * order;
+            }
+        }
+    }
+
+    size = 1;
+    for(qq = 0; qq < output->nd; qq++)
+        size *= output->dimensions[qq];
+    for(kk = 0; kk < size; kk++) {
+        double t = 0.0;
+        int constant = 0, edge = 0, offset = 0;
+        if (map) {
+            /* call mappint functions: */
+            if (!map(io.coordinates, icoor, orank, irank, map_data)) {
+                if (!PyErr_Occurred())
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "unknown error in mapping function");
+                goto exit;
+            }
+        } else if (matrix) {
+            /* do an affine transformation: */
+            Float64 *p = matrix;
+            for(hh = 0; hh < irank; hh++) {
+                icoor[hh] = 0.0;
+                for(ll = 0; ll < orank; ll++)
+                    icoor[hh] += io.coordinates[ll] * *p++;
+                icoor[hh] += shift[hh];
+            }
+        } else if (coordinates) {
+            /* mapping is from an coordinates array: */
+            char *p = pc;
+            switch(coordinates->descr->type_num) {
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Bool);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt8);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt16);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt32);
+#if HAS_UINT64
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt64);
+#endif
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int8);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int16);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int32);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int64);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float32);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float64);
+            default:
+                PyErr_SetString(PyExc_RuntimeError,
+                                                "coordinate array data type not supported");
+                goto exit;
+            }
+        }
+        /* iterate over axes: */
+        for(hh = 0; hh < irank; hh++) {
+            /* if the input coordinate is outside the borders, map it: */
+            double cc = map_coordinate(icoor[hh], idimensions[hh], mode);
+            if (cc > -1.0) {
+                /* find the filter location along this axis: */
+                int start;
+                if (order & 1) {
+                    start = (int)floor(cc) - order / 2;
+                } else {
+                    start = (int)floor(cc + 0.5) - order / 2;
+                }
+                /* get the offset to the start of the filter: */
+                offset += istrides[hh] * start;
+                if (start < 0 || start + order >= idimensions[hh]) {
+                    /* implement border mapping, if outside border: */
+                    edge = 1;
+                    edge_offsets[hh] = data_offsets[hh];
+                    for(ll = 0; ll <= order; ll++) {
+                        int idx = start + ll;
+                        int len = idimensions[hh];
+                        if (len <= 1) {
+                            idx = 0;
+                        } else {
+                            int s2 = 2 * len - 2;
+                            if (idx < 0) {
+                                idx = s2 * (int)(-idx / s2) + idx;
+                                idx = idx <= 1 - len ? idx + s2 : -idx;
+                            } else if (idx >= len) {
+                                idx -= s2 * (int)(idx / s2);
+                                if (idx >= len)
+                                    idx = s2 - idx;
+                            }
+                        }
+                        /* calculate and store the offests at this edge: */
+                        edge_offsets[hh][ll] = istrides[hh] * (idx - start);
+                    }
+                } else {
+                    /* we are not at the border, use precalculated offsets: */
+                    edge_offsets[hh] = NULL;
+                }
+                spline_coefficients(cc, order, splvals[hh]);
+            } else {
+                /* we use the constant border condition: */
+                constant = 1;
+                break;
+            }
+        }
+
+        if (!constant) {
+            maybelong *ff = fcoordinates;
+            for(hh = 0; hh < filter_size; hh++) {
+                int idx = 0;
+                if (edge) {
+                    for(ll = 0; ll < irank; ll++) {
+                        if (edge_offsets[ll])
+                            idx += edge_offsets[ll][ff[ll]];
+                        else
+                            idx += ff[ll] * istrides[ll];
+                    }
+                } else {
+                    idx = foffsets[hh];
+                }
+                idx += offset;
+                idxs[hh] = idx;
+                ff += irank;
+            }
+        }
+        if (!constant) {
+            maybelong *ff = fcoordinates;
+            t = 0.0;
+            for(hh = 0; hh < filter_size; hh++) {
+                double coeff = 0.0;
+                switch(input->descr->type_num) {
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
+#if HAS_UINT64
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
+#endif
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
+                default:
+                    PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                    goto exit;
+                }
+                /* calculate the interpolated value: */
+                for(ll = 0; ll < irank; ll++)
+                    if (order > 0)
+                        coeff *= splvals[ll][ff[ll]];
+                t += coeff;
+                ff += irank;
+            }
+        } else {
+            t = cval;
+        }
+        /* store output value: */
+        switch (output->descr->type_num) {
+            CASE_INTERP_OUT(po, t, Bool);
+            CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
+            CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
+            CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
+#if HAS_UINT64
+            /* FIXME */
+            CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
+#endif
+            CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
+            CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
+            CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
+            CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
+            CASE_INTERP_OUT(po, t, Float32);
+            CASE_INTERP_OUT(po, t, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        if (coordinates) {
+            NI_ITERATOR_NEXT2(io, ic, po, pc);
+        } else {
+            NI_ITERATOR_NEXT(io, po);
+        }
+    }
+
+ exit:
+    if (edge_offsets)
+        free(edge_offsets);
+    if (data_offsets) {
+        for(jj = 0; jj < irank; jj++)
+            free(data_offsets[jj]);
+        free(data_offsets);
+    }
+    if (splvals) {
+        for(jj = 0; jj < irank; jj++)
+            free(splvals[jj]);
+        free(splvals);
+    }
+    if (foffsets)
+        free(foffsets);
+    if (fcoordinates)
+        free(fcoordinates);
+    if (idxs)
+        free(idxs);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int NI_ZoomShift(PyArrayObject *input, PyArrayObject* zoom_ar,
+                                 PyArrayObject* shift_ar, PyArrayObject *output,
+                                 int order, int mode, double cval)
+{
+    char *po, *pi;
+    maybelong **zeros = NULL, **offsets = NULL, ***edge_offsets = NULL;
+    maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
+    maybelong jj, hh, kk, filter_size, odimensions[MAXDIM];
+    maybelong idimensions[MAXDIM], istrides[MAXDIM], *idxs = NULL;
+    maybelong size;
+    double ***splvals = NULL;
+    NI_Iterator io;
+    Float64 *zooms = zoom_ar ? (Float64*)PyArray_DATA(zoom_ar) : NULL;
+    Float64 *shifts = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
+    int rank = 0, qq;
+
+    for(kk = 0; kk < input->nd; kk++) {
+        idimensions[kk] = input->dimensions[kk];
+        istrides[kk] = input->strides[kk];
+        odimensions[kk] = output->dimensions[kk];
+    }
+    rank = input->nd;
+
+    /* if the mode is 'constant' we need some temps later: */
+    if (mode == NI_EXTEND_CONSTANT) {
+        zeros = (maybelong**)malloc(rank * sizeof(maybelong*));
+        if (!zeros) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(jj = 0; jj < rank; jj++)
+            zeros[jj] = NULL;
+        for(jj = 0; jj < rank; jj++) {
+            zeros[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
+            if(!zeros[jj]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+
+    /* store offsets, along each axis: */
+    offsets = (maybelong**)malloc(rank * sizeof(maybelong*));
+    /* store spline coefficients, along each axis: */
+    splvals = (double***)malloc(rank * sizeof(double**));
+    /* store offsets at all edges: */
+    edge_offsets = (maybelong***)malloc(rank * sizeof(maybelong**));
+    if (!offsets || !splvals || !edge_offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < rank; jj++) {
+        offsets[jj] = NULL;
+        splvals[jj] = NULL;
+        edge_offsets[jj] = NULL;
+    }
+    for(jj = 0; jj < rank; jj++) {
+        offsets[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
+        splvals[jj] = (double**)malloc(odimensions[jj] * sizeof(double*));
+        edge_offsets[jj] = (maybelong**)malloc(odimensions[jj] * sizeof(maybelong*));
+        if (!offsets[jj] || !splvals[jj] || !edge_offsets[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(hh = 0; hh < odimensions[jj]; hh++) {
+            splvals[jj][hh] = NULL;
+            edge_offsets[jj][hh] = NULL;
+        }
+    }
+
+    /* precalculate offsets, and offsets at the edge: */
+    for(jj = 0; jj < rank; jj++) {
+        double shift = 0.0, zoom = 0.0;
+        if (shifts)
+            shift = shifts[jj];
+        if (zooms)
+            zoom = zooms[jj];
+        for(kk = 0; kk < odimensions[jj]; kk++) {
+            double cc = (double)kk;
+            if (shifts)
+                cc += shift;
+            if (zooms)
+                cc *= zoom;
+            cc = map_coordinate(cc, idimensions[jj], mode);
+            if (cc > -1.0) {
+                int start;
+                if (zeros && zeros[jj])
+                    zeros[jj][kk] = 0;
+                if (order & 1) {
+                    start = (int)floor(cc) - order / 2;
+                } else {
+                    start = (int)floor(cc + 0.5) - order / 2;
+                }
+                offsets[jj][kk] = istrides[jj] * start;
+                if (start < 0 || start + order >= idimensions[jj]) {
+                    edge_offsets[jj][kk] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
+                    if (!edge_offsets[jj][kk]) {
+                        PyErr_NoMemory();
+                        goto exit;
+                    }
+                    for(hh = 0; hh <= order; hh++) {
+                        int idx = start + hh;
+                         int len = idimensions[jj];
+                        if (len <= 1) {
+                            idx = 0;
+                        } else {
+                            int s2 = 2 * len - 2;
+                            if (idx < 0) {
+                                idx = s2 * (int)(-idx / s2) + idx;
+                                idx = idx <= 1 - len ? idx + s2 : -idx;
+                            } else if (idx >= len) {
+                                idx -= s2 * (int)(idx / s2);
+                                if (idx >= len)
+                                    idx = s2 - idx;
+                            }
+                        }
+                        edge_offsets[jj][kk][hh] = istrides[jj] * (idx - start);
+                    }
+                }
+                if (order > 0) {
+                    splvals[jj][kk] = (double*)malloc((order + 1) * sizeof(double));
+                    if (!splvals[jj][kk]) {
+                        PyErr_NoMemory();
+                        goto exit;
+                    }
+                    spline_coefficients(cc, order, splvals[jj][kk]);
+                }
+            } else {
+                zeros[jj][kk] = 1;
+            }
+        }
+    }
+
+    filter_size = 1;
+    for(jj = 0; jj < rank; jj++)
+        filter_size *= order + 1;
+    idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
+    if (!idxs) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+
+    /* store all coordinates and offsets with filter: */
+    fcoordinates = (maybelong*)malloc(rank * filter_size * sizeof(maybelong));
+    foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
+    if (!fcoordinates || !foffsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    for(jj = 0; jj < rank; jj++)
+        ftmp[jj] = 0;
+    kk = 0;
+    for(hh = 0; hh < filter_size; hh++) {
+        for(jj = 0; jj < rank; jj++)
+            fcoordinates[jj + hh * rank] = ftmp[jj];
+        foffsets[hh] = kk;
+        for(jj = rank - 1; jj >= 0; jj--) {
+            if (ftmp[jj] < order) {
+                ftmp[jj]++;
+                kk += istrides[jj];
+                break;
+            } else {
+                ftmp[jj] = 0;
+                kk -= istrides[jj] * order;
+            }
+        }
+    }
+    size = 1;
+    for(qq = 0; qq < output->nd; qq++)
+        size *= output->dimensions[qq];
+    for(kk = 0; kk < size; kk++) {
+        double t = 0.0;
+        int edge = 0, oo = 0, zero = 0;
+
+        for(hh = 0; hh < rank; hh++) {
+            if (zeros && zeros[hh][io.coordinates[hh]]) {
+                /* we use constant border condition */
+                zero = 1;
+                break;
+            }
+            oo += offsets[hh][io.coordinates[hh]];
+            if (edge_offsets[hh][io.coordinates[hh]])
+                edge = 1;
+        }
+
+        if (!zero) {
+            maybelong *ff = fcoordinates;
+            for(hh = 0; hh < filter_size; hh++) {
+                int idx = 0;
+                if (edge) {
+                        /* use precalculated edge offsets: */
+                    for(jj = 0; jj < rank; jj++) {
+                        if (edge_offsets[jj][io.coordinates[jj]])
+                            idx += edge_offsets[jj][io.coordinates[jj]][ff[jj]];
+                        else
+                            idx += ff[jj] * istrides[jj];
+                    }
+                    idx += oo;
+                } else {
+                    /* use normal offsets: */
+                    idx += oo + foffsets[hh];
+                }
+                idxs[hh] = idx;
+                ff += rank;
+            }
+        }
+        if (!zero) {
+            maybelong *ff = fcoordinates;
+            t = 0.0;
+            for(hh = 0; hh < filter_size; hh++) {
+                double coeff = 0.0;
+                switch(input->descr->type_num) {
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
+#if HAS_UINT64
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
+#endif
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
+                default:
+                    PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                    goto exit;
+                }
+                /* calculate interpolated value: */
+                for(jj = 0; jj < rank; jj++)
+                    if (order > 0)
+                        coeff *= splvals[jj][io.coordinates[jj]][ff[jj]];
+                t += coeff;
+                ff += rank;
+            }
+        } else {
+            t = cval;
+        }
+        /* store output: */
+        switch (output->descr->type_num) {
+            CASE_INTERP_OUT(po, t, Bool);
+            CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
+            CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
+            CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
+#if HAS_UINT64
+            /* FIXME */
+            CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
+#endif
+            CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
+            CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
+            CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
+            CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
+            CASE_INTERP_OUT(po, t, Float32);
+            CASE_INTERP_OUT(po, t, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT(io, po);
+    }
+
+ exit:
+    if (zeros) {
+        for(jj = 0; jj < rank; jj++)
+            if (zeros[jj])
+                free(zeros[jj]);
+        free(zeros);
+    }
+    if (offsets) {
+        for(jj = 0; jj < rank; jj++)
+            if (offsets[jj])
+                free(offsets[jj]);
+        free(offsets);
+    }
+    if (splvals) {
+        for(jj = 0; jj < rank; jj++) {
+            if (splvals[jj]) {
+                for(hh = 0; hh < odimensions[jj]; hh++)
+                    if (splvals[jj][hh])
+                        free(splvals[jj][hh]);
+                free(splvals[jj]);
+            }
+        }
+        free(splvals);
+    }
+    if (edge_offsets) {
+        for(jj = 0; jj < rank; jj++) {
+            if (edge_offsets[jj]) {
+                for(hh = 0; hh < odimensions[jj]; hh++)
+                    if (edge_offsets[jj][hh])
+                        free(edge_offsets[jj][hh]);
+                free(edge_offsets[jj]);
+            }
+        }
+        free(edge_offsets);
+    }
+    if (foffsets)
+        free(foffsets);
+    if (fcoordinates)
+        free(fcoordinates);
+    if (idxs)
+        free(idxs);
+    return PyErr_Occurred() ? 0 : 1;
+}

Modified: trunk/scipy/ndimage/src/ni_interpolation.h
===================================================================
--- trunk/scipy/ndimage/src/ni_interpolation.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_interpolation.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,43 +1,43 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef NI_INTERPOLATION_H
-#define NI_INTERPOLATION_H
-
-int NI_SplineFilter1D(PyArrayObject*, int, int, PyArrayObject*);
-int NI_GeometricTransform(PyArrayObject*, int (*)(maybelong*, double*, int, int,
-                          void*), void*, PyArrayObject*, PyArrayObject*,
-                          PyArrayObject*, PyArrayObject*, int, int,
-                          double);
-int NI_ZoomShift(PyArrayObject*, PyArrayObject*, PyArrayObject*,
-                 PyArrayObject*, int, int, double);
-
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NI_INTERPOLATION_H
+#define NI_INTERPOLATION_H
+
+int NI_SplineFilter1D(PyArrayObject*, int, int, PyArrayObject*);
+int NI_GeometricTransform(PyArrayObject*, int (*)(maybelong*, double*, int, int,
+                                                    void*), void*, PyArrayObject*, PyArrayObject*,
+                                                    PyArrayObject*, PyArrayObject*, int, int,
+                                                    double);
+int NI_ZoomShift(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                 PyArrayObject*, int, int, double);
+
+#endif

Modified: trunk/scipy/ndimage/src/ni_measure.c
===================================================================
--- trunk/scipy/ndimage/src/ni_measure.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_measure.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,1197 +1,1197 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_measure.h"
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
-#include <assert.h>
-
-typedef struct {
-  Int32 index1, index2;
-  void* next;
-} _index_pair;
-
-#define CASE_LABEL(_p, _pi, _type) \
-case t ## _type:                   \
-  *_p = *(_type*)_pi ? -1 : 0;     \
-  break
-
-int NI_Label(PyArrayObject* input, PyArrayObject* strct,
-             maybelong *max_label, PyArrayObject* output)
-{
-  int kk;
-  maybelong jj, ll, ssize, size, filter_size, *offsets = NULL;
-  maybelong mask_value, *oo;
-  Bool *ps, *footprint = NULL;
-  char *pi, *po;
-  Int32 index = 0, *index_map = NULL;
-  NI_FilterIterator fi;
-  NI_Iterator ii, io;
-  _index_pair *pairs = NULL;
-
-  /* structure size */
-  ssize = 1;
-  for(kk = 0; kk < strct->nd; kk++)
-    ssize *= strct->dimensions[kk];
-  /* we only use the first half of the structure data, so we make a
-     temporary structure for use with the filter functions: */
-  footprint = (Bool*)malloc(ssize * sizeof(Bool));
-  if (!footprint) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  ps = (Bool*)PyArray_DATA(strct);
-  filter_size = 0;
-  for(jj = 0; jj < ssize / 2; jj++) {
-    footprint[jj] = ps[jj];
-    if (ps[jj])
-      ++filter_size;
-  }
-  for(jj = ssize / 2; jj < ssize; jj++)
-    footprint[jj] = 0;
-  /* get data and size */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(kk = 0; kk < output->nd; kk++)
-    size *= output->dimensions[kk];
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* set all elements in the output corresponding to non-zero elements
-     in input to -1: */
-  for(jj = 0; jj < size; jj++) {
-    Int32 *p = (Int32*)po;
-    switch (input->descr->type_num) {
-    CASE_LABEL(p, pi, Bool);
-    CASE_LABEL(p, pi, UInt8);
-    CASE_LABEL(p, pi, UInt16);
-    CASE_LABEL(p, pi, UInt32);
-#if HAS_UINT64
-    CASE_LABEL(p, pi, UInt64);
-#endif
-    CASE_LABEL(p, pi, Int8);
-    CASE_LABEL(p, pi, Int16);
-    CASE_LABEL(p, pi, Int32);
-    CASE_LABEL(p, pi, Int64);
-    CASE_LABEL(p, pi, Float32);
-    CASE_LABEL(p, pi, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    NI_ITERATOR_NEXT2(ii, io, pi, po);
-  }
-
-  /* calculate the filter offsets: */
-  if (!NI_InitFilterOffsets(output, footprint, strct->dimensions, NULL,
-                          NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, strct->dimensions, filter_size,
-                                           input->dimensions, NULL, &fi))
-    goto exit;
-  /* reset output iterator: */
-  NI_ITERATOR_RESET(io);
-  po = (void *)PyArray_DATA(output);
-  /* iterator over the elements: */
-  oo = offsets;
-  for(jj = 0; jj < size; jj++) {
-    if (*(Int32*)po < 0) {
-      Int32 neighbor = 0;
-      /* iterate over structuring element: */
-      for(ll = 0; ll < filter_size; ll++) {
-        int offset = oo[ll];
-        if (offset != mask_value) {
-          Int32 tt = *(Int32*)(po + offset);
-          if (tt > 0) {
-            /* this element is next to an already found object: */
-            if (neighbor && neighbor != tt) {
-              /* we have two objects that must be merged later: */
-              _index_pair* tp = (_index_pair*)malloc(sizeof(_index_pair));
-              if (!tp) {
-                PyErr_NoMemory();
-                goto exit;
-              }
-              tp->next = pairs;
-              /* the pairs must be ordered: */
-              if (neighbor < tt) {
-                tp->index1 = neighbor;
-                tp->index2 = tt;
-              } else {
-                tp->index1 = tt;
-                tp->index2 = neighbor;
-              }
-              pairs = tp;
-            } else {
-              neighbor = tt;
-            }
-          }
-        }
-      }
-      if (neighbor) {
-        /* this point belongs to an existing object */
-        *(Int32*)po = neighbor;
-      } else {
-        /* this may be a new object: */
-        *(Int32*)po = ++index;
-      }
-    }
-    NI_FILTER_NEXT(fi, io, oo, po);
-  }
-  *max_label = index;
-  /* merge any touching objects: */
-  if (pairs) {
-    Int32 counter;
-    index_map = (Int32*)malloc(index * sizeof(Int32));
-    if (!index_map) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-    for(jj = 0; jj < index; jj++)
-      index_map[jj] = (Int32)jj;
-    while (pairs) {
-      Int32 idx1 = pairs->index1 - 1;
-      Int32 idx2 = pairs->index2 - 1;
-      if (index_map[idx2] == idx1 || index_map[idx2] == idx2) {
-        /* if this pair was already processed, or if idx2 was not
-           mapped yet, we delete this pair and map idx2 to idx1: */
-        _index_pair *tp = pairs;
-        pairs = tp->next;
-        free(tp);
-        index_map[idx2] = idx1;
-      } else {
-        /* idx2 was already mapped, therefore we find what it was
-           mapped to and change the current pair to the result of that
-           and idx1. Since the pair is not destroyed, it will be
-           re-processed with the adapted values.  */
-        idx2 = index_map[idx2];
-        /* keep the pairs ordered: */
-        if (idx1 < idx2) {
-          pairs->index1 = idx1 + 1;
-          pairs->index2 = idx2 + 1;
-        } else {
-          pairs->index1 = idx2 + 1;
-          pairs->index2 = idx1 + 1;
-        }
-      }
-    }
-    for(jj = 0; jj < index; jj++) {
-      /* if the current index maps to a index that is also mapped,
-         change it to map to that index. Since an index always maps to
-         a lower index or to itself, this will make sure that at the
-         end all indices map to an unmapped index. */
-      if (index_map[index_map[jj]] < index_map[jj])
-        index_map[jj] = index_map[index_map[jj]];
-    }
-    /* renumber the indices that are not mapped: */
-    counter = 0;
-    for(jj = 0; jj < index; jj++)
-      if (index_map[jj] == jj)
-        index_map[jj] = ++counter;
-      else
-        index_map[jj] = index_map[index_map[jj]];
-  }
-
-  /* relabel the output if we merged some objects: */
-  if (index_map) {
-    *max_label = 0;
-    NI_ITERATOR_RESET(io);
-    po = (void *)PyArray_DATA(output);
-    for(jj = 0; jj < size; jj++) {
-      Int32 p = *(Int32*)po;
-      if (p > 0 )
-        *(Int32*)po = index_map[p - 1];
-      if (*(Int32*)po > *max_label)
-        *max_label = *(Int32*)po;
-      NI_ITERATOR_NEXT(io, po);
-    }
-  }
- exit:
-  if (offsets) free(offsets);
-  if (index_map) free(index_map);
-  while (pairs) {
-    _index_pair *tp = pairs;
-    pairs = (_index_pair*)pairs->next;
-    free(tp);
-  }
-  if (footprint)
-    free(footprint);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_FIND_OBJECT_POINT(_pi, _regions, _rank, _dimensions, \
-                               _max_label, _ii, _type)            \
-case t ## _type:                                                  \
-{                                                                 \
-  int _kk;                                                        \
-  maybelong _sindex = *(_type*)_pi - 1;                           \
-  if (_sindex >= 0 && _sindex < _max_label) {                     \
-    if (_rank > 0) {                                              \
-      _sindex *= 2 * _rank;                                       \
-      if (_regions[_sindex] < 0) {                                \
-        for(_kk = 0; _kk < _rank; _kk++) {                        \
-          maybelong _cc = _ii.coordinates[_kk];                   \
-          _regions[_sindex + _kk] = _cc;                          \
-          _regions[_sindex + _kk + _rank] = _cc + 1;              \
-        }                                                         \
-      } else {                                                    \
-        for(_kk = 0; _kk < _rank; _kk++) {                        \
-          maybelong _cc = _ii.coordinates[_kk];                   \
-          if (_cc < _regions[_sindex + _kk])                      \
-            _regions[_sindex + _kk] = _cc;                        \
-          if (_cc + 1 > _regions[_sindex + _kk + _rank])          \
-            _regions[_sindex + _kk + _rank] = _cc + 1;            \
-        }                                                         \
-      }                                                           \
-    } else {                                                      \
-      _regions[_sindex] = 1;                                      \
-    }                                                             \
-  }                                                               \
-}                                                                 \
-break
-
-int NI_FindObjects(PyArrayObject* input, maybelong max_label,
-                   maybelong* regions)
-{
-  int kk;
-  maybelong size, jj;
-  NI_Iterator ii;
-  char *pi;
-
-  /* get input data, size and iterator: */
-  pi = (void *)PyArray_DATA(input);
-  size = 1;
-  for(kk = 0; kk < input->nd; kk++)
-    size *= input->dimensions[kk];
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  if (input->nd > 0) {
-    for(jj = 0; jj < 2 * input->nd * max_label; jj++)
-      regions[jj] = -1;
-  } else {
-    for(jj = 0; jj < max_label; jj++)
-      regions[jj] = -1;
-  }
-  /* iterate over all points: */
-  for(jj = 0 ; jj < size; jj++) {
-    switch (input->descr->type_num) {
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii,  Bool);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, UInt8);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, UInt16);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, UInt32);
-#if HAS_UINT64
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, UInt64);
-#endif
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, Int8);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, Int16);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, Int32);
-    CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
-                           max_label, ii, Int64);
-      break;
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    NI_ITERATOR_NEXT(ii, pi);
-  }
- exit:
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-
-/* macro to get input value: */
-#if HAS_UINT64
-#define NI_GET_VALUE(_pi, _v, _type)                                  \
-{                                                                     \
-  switch(_type) {                                                     \
-  case tBool:                                                         \
-    _v = (*(Bool*)_pi) != 0;                                          \
-    break;                                                            \
-  case tUInt8:                                                        \
-    _v = *(UInt8*)_pi;                                                \
-    break;                                                            \
-  case tUInt16:                                                       \
-    _v = *(UInt16*)_pi;                                               \
-    break;                                                            \
-  case tUInt32:                                                       \
-    _v = *(UInt32*)_pi;                                               \
-    break;                                                            \
-  case tInt8:                                                         \
-    _v = *(Int8*)_pi;                                                 \
-    break;                                                            \
-  case tInt16:                                                        \
-    _v = *(Int16*)_pi;                                                \
-    break;                                                            \
-  case tInt32:                                                        \
-    _v = *(Int32*)_pi;                                                \
-    break;                                                            \
-  case tInt64:                                                        \
-    _v = *(Int64*)_pi;                                                \
-    break;                                                            \
-  case tUInt64:                                                       \
-    _v = *(UInt64*)_pi;                                               \
-    break;                                                            \
-  case tFloat32:                                                      \
-    _v = *(Float32*)_pi;                                              \
-    break;                                                            \
-  case tFloat64:                                                      \
-    _v = *(Float64*)_pi;                                              \
-    break;                                                            \
-  default:                                                            \
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
-      return 0;                                                       \
-  }                                                                   \
-}
-#else
-#define NI_GET_VALUE(_pi, _v, _type)                                  \
-{                                                                     \
-  switch(_type) {                                                     \
-  case tBool:                                                         \
-    _v = (*(Bool*)_pi) != 0;                                          \
-    break;                                                            \
-  case tUInt8:                                                        \
-    _v = *(UInt8*)_pi;                                                \
-    break;                                                            \
-  case tUInt16:                                                       \
-    _v = *(UInt16*)_pi;                                               \
-    break;                                                            \
-  case tUInt32:                                                       \
-    _v = *(UInt32*)_pi;                                               \
-    break;                                                            \
-  case tInt8:                                                         \
-    _v = *(Int8*)_pi;                                                 \
-    break;                                                            \
-  case tInt16:                                                        \
-    _v = *(Int16*)_pi;                                                \
-    break;                                                            \
-  case tInt32:                                                        \
-    _v = *(Int32*)_pi;                                                \
-    break;                                                            \
-  case tInt64:                                                        \
-    _v = *(Int64*)_pi;                                                \
-    break;                                                            \
-  case tFloat32:                                                      \
-    _v = *(Float32*)_pi;                                              \
-    break;                                                            \
-  case tFloat64:                                                      \
-    _v = *(Float64*)_pi;                                              \
-    break;                                                            \
-  default:                                                            \
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
-      return 0;                                                       \
-  }                                                                   \
-}
-#endif
-
-/* macro to get label value: */
-#if HAS_UINT64
-#define NI_GET_LABEL(_pm, _label, _type)                              \
-{                                                                     \
-  if (_pm) {                                                          \
-    switch(_type) {                                                   \
-    case tBool:                                                       \
-      _label = *(Bool*)_pm;                                           \
-      break;                                                          \
-    case tUInt8:                                                      \
-      _label = *(UInt8*)_pm;                                          \
-      break;                                                          \
-    case tUInt16:                                                     \
-      _label = *(UInt16*)_pm;                                         \
-      break;                                                          \
-    case tUInt32:                                                     \
-      _label = *(UInt32*)_pm;                                         \
-      break;                                                          \
-    case tUInt64:                                                     \
-      _label = *(UInt64*)_pm;                                         \
-      break;                                                          \
-    case tInt8:                                                       \
-      _label = *(Int8*)_pm;                                           \
-      break;                                                          \
-    case tInt16:                                                      \
-      _label = *(Int16*)_pm;                                          \
-      break;                                                          \
-    case tInt32:                                                      \
-      _label = *(Int32*)_pm;                                          \
-       break;                                                         \
-    case tInt64:                                                      \
-      _label = *(Int64*)_pm;                                          \
-       break;                                                         \
-    case tFloat32:                                                    \
-      _label = *(Float32*)_pm;                                        \
-      break;                                                          \
-    case tFloat64:                                                    \
-      _label = *(Float64*)_pm;                                        \
-      break;                                                          \
-    default:                                                          \
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
-      return 0;                                                       \
-    }                                                                 \
-  }                                                                   \
-}
-#else
-#define NI_GET_LABEL(_pm, _label, _type)                              \
-{                                                                     \
-  if (_pm) {                                                          \
-    switch(_type) {                                                   \
-    case tBool:                                                       \
-      _label = *(Bool*)_pm;                                           \
-      break;                                                          \
-    case tUInt8:                                                      \
-      _label = *(UInt8*)_pm;                                          \
-      break;                                                          \
-    case tUInt16:                                                     \
-      _label = *(UInt16*)_pm;                                         \
-      break;                                                          \
-    case tUInt32:                                                     \
-      _label = *(UInt32*)_pm;                                         \
-      break;                                                          \
-    case tInt8:                                                       \
-      _label = *(Int8*)_pm;                                           \
-      break;                                                          \
-    case tInt16:                                                      \
-      _label = *(Int16*)_pm;                                          \
-      break;                                                          \
-    case tInt32:                                                      \
-      _label = *(Int32*)_pm;                                          \
-       break;                                                         \
-    case tInt64:                                                      \
-      _label = *(Int64*)_pm;                                          \
-       break;                                                         \
-    case tFloat32:                                                    \
-      _label = *(Float32*)_pm;                                        \
-      break;                                                          \
-    case tFloat64:                                                    \
-      _label = *(Float64*)_pm;                                        \
-      break;                                                          \
-    default:                                                          \
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
-      return 0;                                                       \
-    }                                                                 \
-  }                                                                   \
-}
-#endif
-
-int NI_Statistics(PyArrayObject *input, PyArrayObject *labels,
-  maybelong min_label, maybelong max_label, maybelong *indices,
-  maybelong n_results, double *sum, maybelong *total, double *variance,
-  double *minimum, double *maximum, maybelong* min_pos, maybelong* max_pos)
-{
-  char *pi = NULL, *pm = NULL;
-  NI_Iterator ii, mi;
-  maybelong jj, size, idx = 0, label = 1, doit = 1;
-  int qq;
-
-  /* input iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    return 0;
-  /* input data: */
-  pi = (void *)PyArray_DATA(input);
-  if (labels) {
-    if (!NI_InitPointIterator(labels, &mi))
-      return 0;
-    pm = (void *)PyArray_DATA(labels);
-  }
-  /* input size: */
-  size = 1;
-  for(qq = 0; qq < input->nd; qq++)
-    size *= input->dimensions[qq];
-  for(jj = 0; jj < n_results; jj++) {
-    if (sum)
-      sum[jj] = 0.0;
-    if (total)
-      total[jj] = 0;
-    if (variance)
-      variance[jj] = 0;
-    if (minimum)
-      minimum[jj] = DBL_MAX;
-    if (maximum)
-      maximum[jj] = -DBL_MAX;
-    if (min_pos)
-      min_pos[jj] = 0;
-    if (max_pos)
-      max_pos[jj] = 0;
-  }
-  /* iterate over array: */
-  for(jj = 0; jj < size; jj++) {
-    NI_GET_LABEL(pm, label, labels->descr->type_num);
-    if (min_label >= 0) {
-      if (label >= min_label && label <= max_label) {
-        idx = indices[label - min_label];
-        doit = idx >= 0;
-      } else {
-        doit = 0;
-      }
-    } else {
-      doit = label != 0;
-    }
-    if (doit) {
-      double val;
-      NI_GET_VALUE(pi, val, input->descr->type_num);
-      if (sum)
-        sum[idx] += val;
-      if (total)
-        total[idx]++;
-      if (minimum && val < minimum[idx]) {
-        minimum[idx] = val;
-        if (min_pos)
-          min_pos[idx] = jj;
-      }
-      if (maximum && (val > maximum[idx])) {
-        maximum[idx] = val;
-        if (max_pos)
-          max_pos[idx] = jj;
-      }
-    }
-    if (labels) {
-      NI_ITERATOR_NEXT2(ii, mi, pi, pm);
-    } else {
-      NI_ITERATOR_NEXT(ii, pi);
-    }
-  }
-  if (minimum) {
-    for(jj = 0; jj < n_results; jj++) {
-      if (!(minimum[jj] < DBL_MAX))
-        minimum[jj] = 0.0;
-    }
-  }
-  if (maximum) {
-    for(jj = 0; jj < n_results; jj++) {
-      if (!(maximum[jj] > -DBL_MAX))
-        maximum[jj] = 0.0;
-    }
-  }
-  if (variance) {
-    int do_var = 0;
-    for(jj = 0; jj < n_results; jj++)
-      if (total[jj] > 1) {
-        do_var = 1;
-        break;
-      }
-    if (do_var) {
-      /* reset input iterator: */
-      NI_ITERATOR_RESET(ii);
-      pi = (void *)PyArray_DATA(input);
-      if (labels) {
-        /* reset label iterator: */
-        NI_ITERATOR_RESET(mi);
-        pm = (void *)PyArray_DATA(labels);
-      }
-      for(jj = 0; jj < size; jj++) {
-        NI_GET_LABEL(pm, label, labels->descr->type_num);
-        if (min_label >= 0) {
-          if (label >= min_label && label <= max_label) {
-            idx = indices[label - min_label];
-            doit = idx >= 0;
-          } else {
-            doit = 0;
-          }
-        } else {
-          doit = label != 0;
-        }
-        if (doit) {
-          double val;
-          NI_GET_VALUE(pi, val, input->descr->type_num);
-          val = val - sum[idx] / total[idx];
-          variance[idx] += val * val;
-        }
-        if (labels) {
-          NI_ITERATOR_NEXT2(ii, mi, pi, pm);
-        } else {
-          NI_ITERATOR_NEXT(ii, pi);
-        }
-      }
-      for(jj = 0; jj < n_results; jj++)
-        variance[jj] = (total[jj] > 1 ?
-                        variance[jj] / (total[jj] - 1) : 0.0);
-    }
-  }
-  return 1;
-}
-
-
-int NI_CenterOfMass(PyArrayObject *input, PyArrayObject *labels,
-              maybelong min_label, maybelong max_label, maybelong *indices,
-              maybelong n_results, double *center_of_mass)
-{
-  char *pi = NULL, *pm = NULL;
-  NI_Iterator ii, mi;
-  maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
-  double *sum = NULL;
-  int qq;
-
-  /* input iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* input data: */
-  pi = (void *)PyArray_DATA(input);
-  if (labels) {
-    if (!NI_InitPointIterator(labels, &mi))
-      goto exit;
-    pm = (void *)PyArray_DATA(labels);
-  }
-  /* input size: */
-  size = 1;
-  for(qq = 0; qq < input->nd; qq++)
-    size *= input->dimensions[qq];
-  sum = (double*)malloc(n_results * sizeof(double));
-  if (!sum) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < n_results; jj++) {
-    sum[jj] = 0.0;
-    for(kk = 0; kk < input->nd; kk++)
-      center_of_mass[jj * input->nd + kk] = 0.0;
-  }
-  /* iterate over array: */
-  for(jj = 0; jj < size; jj++) {
-    NI_GET_LABEL(pm, label, labels->descr->type_num);
-    if (min_label >= 0) {
-      if (label >= min_label && label <= max_label) {
-        idx = indices[label - min_label];
-        doit = idx >= 0;
-      } else {
-        doit = 0;
-      }
-    } else {
-      doit = label != 0;
-    }
-    if (doit) {
-      double val;
-      NI_GET_VALUE(pi, val, input->descr->type_num);
-      sum[idx] += val;
-      for(kk = 0; kk < input->nd; kk++)
-        center_of_mass[idx * input->nd + kk] += val * ii.coordinates[kk];
-    }
-    if (labels) {
-      NI_ITERATOR_NEXT2(ii, mi, pi, pm);
-    } else {
-      NI_ITERATOR_NEXT(ii, pi);
-    }
-  }
-  for(jj = 0; jj < n_results; jj++)
-    for(kk = 0; kk < input->nd; kk++)
-      center_of_mass[jj * input->nd + kk] /= sum[jj];
- exit:
-  if (sum)
-    free(sum);
-  return  PyErr_Occurred() == NULL;
-}
-
-
-int NI_Histogram(PyArrayObject *input, PyArrayObject *labels,
-              maybelong min_label, maybelong max_label, maybelong *indices,
-              maybelong n_results, PyArrayObject **histograms,
-              double min, double max, maybelong nbins)
-{
-  char *pi = NULL, *pm = NULL;
-  NI_Iterator ii, mi;
-  maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
-  Int32 **ph = NULL;
-  double bsize;
-  int qq;
-
-  /* input iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* input data: */
-  pi = (void *)PyArray_DATA(input);
-  if (labels) {
-    if (!NI_InitPointIterator(labels, &mi))
-      goto exit;
-    pm = (void *)PyArray_DATA(labels);
-  }
-  ph = (Int32**)malloc(n_results * sizeof(Int32*));
-  if (!ph) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < n_results; jj++) {
-      ph[jj] = (Int32*)PyArray_DATA(histograms[jj]);
-      for(kk = 0; kk < nbins; kk++)
-          ph[jj][kk] = 0;
-  }
-  bsize = (max - min) / (double)nbins;
-  /* input size: */
-  size = 1;
-  for(qq = 0; qq < input->nd; qq++)
-    size *= input->dimensions[qq];
-  /* iterate over array: */
-  for(jj = 0; jj < size; jj++) {
-    NI_GET_LABEL(pm, label, labels->descr->type_num);
-    if (min_label >= 0) {
-      if (label >= min_label && label <= max_label) {
-        idx = indices[label - min_label];
-        doit = idx >= 0;
-      } else {
-        doit = 0;
-      }
-    } else {
-      doit = label != 0;
-    }
-    if (doit) {
-      int bin;
-      double val;
-      NI_GET_VALUE(pi, val, input->descr->type_num);
-      if (val >= min && val < max) {
-        bin = (int)((val - min) / bsize);
-        ++(ph[idx][bin]);
-      }
-    }
-    if (labels) {
-      NI_ITERATOR_NEXT2(ii, mi, pi, pm);
-    } else {
-      NI_ITERATOR_NEXT(ii, pi);
-    }
-  }
- exit:
-  if (ph)
-    free(ph);
-  return  PyErr_Occurred() == NULL;
-}
-
-#define WS_GET_INDEX(_index, _c_strides, _b_strides, _rank, _out, \
-                     _contiguous, _type)                          \
-do {                                                              \
-  if (_contiguous) {                                              \
-    _out = _index * sizeof(_type);                                \
-  } else {                                                        \
-    int _qq;                                                      \
-    maybelong _cc, _idx = _index;                                 \
-    _out = 0;                                                     \
-    for (_qq = 0; _qq < _rank; _qq++) {                           \
-      _cc = _idx / _c_strides[_qq];                               \
-      _idx -= _cc * _c_strides[_qq];                              \
-      _out += _b_strides[_qq] * _cc;                              \
-    }                                                             \
-  }                                                               \
-} while(0)
-
-#define CASE_GET_INPUT(_ival, _pi, _type) \
-case t ## _type:                          \
-  _ival = *((_type*)_pi);                 \
-  break
-
-#define CASE_GET_LABEL(_label, _pm, _type) \
-case t ## _type:                           \
-  _label = *(_type*)_pm;                   \
-  break
-
-#define CASE_PUT_LABEL(_label, _pl, _type) \
-case t ## _type:                           \
-  *((_type*)_pl) = _label;                 \
-  break
-
-#define CASE_WINDEX1(_v_index, _p_index, _strides, _istrides, _irank,  \
-                     _icont, _p_idx, _v_idx, _pi, _vval, _pval, _type) \
-case t ## _type:                                                       \
-  WS_GET_INDEX(_v_index, _strides, _istrides, _irank, _p_idx, _icont,  \
-               _type);                                                 \
-  WS_GET_INDEX(_p_index, _strides, _istrides, _irank, _v_idx, _icont,  \
-               _type);                                                 \
-  _vval = *(_type*)(_pi + _v_idx);                                     \
-  _pval = *(_type*)(_pi + _p_idx);                                     \
-  break
-
-#define CASE_WINDEX2(_v_index, _strides, _ostrides, _irank, _idx, \
-                     _ocont, _label, _pl, _type)                  \
-case t ## _type:                                                  \
-  WS_GET_INDEX(_v_index, _strides, _ostrides, _irank, _idx,       \
-               _ocont, _type);                                    \
-  _label = *(_type*)(_pl + _idx);                                 \
-  break
-
-#define CASE_WINDEX3(_p_index, _strides, _ostrides, _irank, _idx, \
-                     _ocont, _label, _pl, _type)                  \
-case t ## _type:                                                  \
-  WS_GET_INDEX(_p_index, _strides, _ostrides, _irank, _idx,       \
-               _ocont, _type);                                    \
-  *(_type*)(_pl + _idx) = _label;                                 \
-break
-
-#define DONE_TYPE UInt8
-#define COST_TYPE UInt16
-#define WS_MAXDIM 7
-
-typedef struct {
-  maybelong index;
-  COST_TYPE cost;
-  void *next, *prev;
-  DONE_TYPE done;
-} NI_WatershedElement;
-
-int NI_WatershedIFT(PyArrayObject* input, PyArrayObject* markers,
-                    PyArrayObject* strct, PyArrayObject* output)
-{
-  char *pl, *pm, *pi;
-  int ll;
-  maybelong size, jj, hh, kk, maxval;
-  maybelong strides[WS_MAXDIM], coordinates[WS_MAXDIM];
-  maybelong *nstrides = NULL, nneigh, ssize;
-  int i_contiguous, o_contiguous;
-  NI_WatershedElement *temp = NULL, **first = NULL, **last = NULL;
-  Bool *ps = NULL;
-  NI_Iterator mi, ii, li;
-
-  i_contiguous = PyArray_ISCONTIGUOUS(input);
-  o_contiguous = PyArray_ISCONTIGUOUS(output);
-  ssize = 1;
-  for(ll = 0; ll < strct->nd; ll++)
-    ssize *= strct->dimensions[ll];
-  if (input->nd > WS_MAXDIM) {
-    PyErr_SetString(PyExc_RuntimeError, "too many dimensions");
-    goto exit;
-  }
-  size = 1;
-  for(ll = 0; ll < input->nd; ll++)
-    size *= input->dimensions[ll];
-  /* Storage for the temporary queue data. */
-  temp = (NI_WatershedElement*)malloc(size * sizeof(NI_WatershedElement));
-  if (!temp) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  pi = (void *)PyArray_DATA(input);
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* Initialization and find the maximum of the input. */
-  maxval = 0;
-  for(jj = 0; jj < size; jj++) {
-    int ival = 0;
-    switch(input->descr->type_num) {
-    CASE_GET_INPUT(ival, pi, UInt8);
-    CASE_GET_INPUT(ival, pi, UInt16);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    temp[jj].index = jj;
-    temp[jj].done = 0;
-    if (ival > maxval)
-      maxval = ival;
-    NI_ITERATOR_NEXT(ii, pi);
-  }
-  pi = (void *)PyArray_DATA(input);
-  /* Allocate and initialize the storage for the queue. */
-  first = (NI_WatershedElement**)malloc((maxval + 1) *
-                                        sizeof(NI_WatershedElement*));
-  last = (NI_WatershedElement**)malloc((maxval + 1) *
-                                       sizeof(NI_WatershedElement*));
-  if (!first || !last) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(hh = 0; hh <= maxval; hh++) {
-    first[hh] = NULL;
-    last[hh] = NULL;
-  }
-  if (!NI_InitPointIterator(markers, &mi))
-    goto exit;
-  if (!NI_InitPointIterator(output, &li))
-    goto exit;
-  pm = (void *)PyArray_DATA(markers);
-  pl = (void *)PyArray_DATA(output);
-  /* initialize all nodes */
-  for(ll = 0; ll < input->nd; ll++)
-    coordinates[ll] = 0;
-  for(jj = 0; jj < size; jj++) {
-    /* get marker */
-    int label = 0;
-    switch(markers->descr->type_num) {
-    CASE_GET_LABEL(label, pm, UInt8);
-    CASE_GET_LABEL(label, pm, UInt16);
-    CASE_GET_LABEL(label, pm, UInt32);
-#if HAS_UINT64
-    CASE_GET_LABEL(label, pm, UInt64);
-#endif
-    CASE_GET_LABEL(label, pm, Int8);
-    CASE_GET_LABEL(label, pm, Int16);
-    CASE_GET_LABEL(label, pm, Int32);
-    CASE_GET_LABEL(label, pm, Int64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    switch(output->descr->type_num) {
-    CASE_PUT_LABEL(label, pl, UInt8);
-    CASE_PUT_LABEL(label, pl, UInt16);
-    CASE_PUT_LABEL(label, pl, UInt32);
-#if HAS_UINT64
-    CASE_PUT_LABEL(label, pl, UInt64);
-#endif
-    CASE_PUT_LABEL(label, pl, Int8);
-    CASE_PUT_LABEL(label, pl, Int16);
-    CASE_PUT_LABEL(label, pl, Int32);
-    CASE_PUT_LABEL(label, pl, Int64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    NI_ITERATOR_NEXT2(mi, li, pm, pl);
-    if (label != 0) {
-      /* This node is a marker */
-      temp[jj].cost = 0;
-      if (!first[0]) {
-        first[0] = &(temp[jj]);
-        first[0]->next = NULL;
-        first[0]->prev = NULL;
-        last[0] = first[0];
-      } else {
-        if (label > 0) {
-          /* object markers are enqueued at the beginning, so they are
-             processed first. */
-          temp[jj].next = first[0];
-          temp[jj].prev = NULL;
-          first[0]->prev = &(temp[jj]);
-          first[0] = &(temp[jj]);
-        } else {
-          /* background markers are enqueued at the end, so they are
-             processed after the object markers. */
-          temp[jj].next = NULL;
-          temp[jj].prev = last[0];
-          last[0]->next = &(temp[jj]);
-          last[0] = &(temp[jj]);
-        }
-      }
-    } else {
-      /* This node is not a marker */
-      temp[jj].cost = maxval + 1;
-      temp[jj].next = NULL;
-      temp[jj].prev = NULL;
-    }
-    for(ll = input->nd - 1; ll >= 0; ll--)
-      if (coordinates[ll] < input->dimensions[ll] - 1) {
-        coordinates[ll]++;
-        break;
-      } else {
-        coordinates[ll] = 0;
-      }
-  }
-
-  pl = (void *)PyArray_DATA(output);
-  ps = (Bool*)PyArray_DATA(strct);
-  nneigh = 0;
-  for (kk = 0; kk < ssize; kk++)
-    if (ps[kk] && kk != (ssize / 2))
-      ++nneigh;
-  nstrides = (maybelong*)malloc(nneigh * sizeof(maybelong));
-  if (!nstrides) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  strides[input->nd - 1] = 1;
-  for(ll = input->nd - 2; ll >= 0; ll--)
-    strides[ll] = input->dimensions[ll + 1] * strides[ll + 1];
-  for(ll = 0; ll < input->nd; ll++)
-    coordinates[ll] = -1;
-  for(kk = 0; kk < nneigh; kk++)
-    nstrides[kk] = 0;
-  jj = 0;
-  for(kk = 0; kk < ssize; kk++) {
-    if (ps[kk]) {
-      int offset = 0;
-      for(ll = 0; ll < input->nd; ll++)
-        offset += coordinates[ll] * strides[ll];
-      if (offset != 0)
-        nstrides[jj++] += offset;
-    }
-    for(ll = input->nd - 1; ll >= 0; ll--)
-      if (coordinates[ll] < 1) {
-        coordinates[ll]++;
-        break;
-      } else {
-        coordinates[ll] = -1;
-      }
-  }
-  /* Propagation phase: */
-  for(jj = 0; jj <= maxval; jj++) {
-    while (first[jj]) {
-      /* dequeue first element: */
-      NI_WatershedElement *v = first[jj];
-      first[jj] = first[jj]->next;
-      if (first[jj])
-        first[jj]->prev = NULL;
-      v->prev = NULL;
-      v->next = NULL;
-      /* Mark element as done: */
-      v->done = 1;
-      /* Iterate over the neighbors of the element: */
-      for(hh = 0; hh < nneigh; hh++) {
-        maybelong v_index = v->index, p_index = v->index, idx, cc;
-        int qq, outside = 0;
-        p_index += nstrides[hh];
-        /* check if the neighbor is within the extent of the array: */
-        idx = p_index;
-        for (qq = 0; qq < input->nd; qq++) {
-          cc = idx / strides[qq];
-          if (cc < 0 || cc >= input->dimensions[qq]) {
-            outside = 1;
-            break;
-          }
-          idx -= cc * strides[qq];
-        }
-        if (!outside) {
-          NI_WatershedElement *p = &(temp[p_index]);
-          if (!(p->done)) {
-            /* If the neighbor was not processed yet: */
-            int max, pval, vval, wvp, pcost, label, p_idx, v_idx;
-            switch(input->descr->type_num) {
-            CASE_WINDEX1(v_index, p_index, strides, input->strides,
-                         input->nd, i_contiguous, p_idx, v_idx, pi,
-                         vval, pval, UInt8);
-            CASE_WINDEX1(v_index, p_index, strides, input->strides,
-                         input->nd, i_contiguous, p_idx, v_idx, pi,
-                         vval, pval, UInt16);
-            default:
-              PyErr_SetString(PyExc_RuntimeError,
-                              "data type not supported");
-              goto exit;
-            }
-            /* Calculate cost: */
-            wvp = pval - vval;
-            if (wvp < 0)
-              wvp = -wvp;
-            /* Find the maximum of this cost and the current
-               element cost: */
-            pcost = p->cost;
-            max = v->cost > wvp ? v->cost : wvp;
-            if (max < pcost) {
-              /* If this maximum is less than the neighbors cost,
-                 adapt the cost and the label of the neighbor: */
-              int idx;
-              p->cost = max;
-              switch(output->descr->type_num) {
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt8);
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt16);
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt32);
-#if HAS_UINT64
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt64);
-#endif
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int8);
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int16);
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int32);
-              CASE_WINDEX2(v_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int64);
-              default:
-                PyErr_SetString(PyExc_RuntimeError,
-                                "data type not supported");
-                goto exit;
-              }
-              switch(output->descr->type_num) {
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt8);
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt16);
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt32);
-#if HAS_UINT64
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, UInt64);
-#endif
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int8);
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int16);
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int32);
-              CASE_WINDEX3(p_index, strides, output->strides, input->nd,
-                           idx, o_contiguous, label, pl, Int64);
-              default:
-                PyErr_SetString(PyExc_RuntimeError,
-                                "data type not supported");
-                goto exit;
-              }
-              /* If the neighbor is in a queue, remove it: */
-              if (p->next || p->prev) {
-                NI_WatershedElement *prev = p->prev, *next = p->next;
-                if (first[pcost] == p)
-                  first[pcost] = next;
-                if (last[pcost] == p)
-                  last[pcost] = prev;
-                if (prev)
-                  prev->next = next;
-                if (next)
-                  next->prev = prev;
-              }
-              /* Insert the neighbor in the appropiate queue: */
-              if (label < 0) {
-                p->prev = last[max];
-                p->next = NULL;
-                if (last[max])
-                  last[max]->next = p;
-                last[max] = p;
-                if (!first[max])
-                  first[max] = p;
-              } else {
-                p->next = first[max];
-                p->prev = NULL;
-                if (first[max])
-                  first[max]->prev = p;
-                first[max] = p;
-                if (!last[max])
-                  last[max] = p;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
- exit:
-  if (temp)
-    free(temp);
-  if (first)
-    free(first);
-  if (last)
-    free(last);
-  if (nstrides)
-    free(nstrides);
-  return PyErr_Occurred() ? 0 : 1;
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+#include "ni_measure.h"
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <assert.h>
+
+typedef struct {
+    Int32 index1, index2;
+    void* next;
+} _index_pair;
+
+#define CASE_LABEL(_p, _pi, _type) \
+case t ## _type:                   \
+    *_p = *(_type*)_pi ? -1 : 0;     \
+    break
+
+int NI_Label(PyArrayObject* input, PyArrayObject* strct,
+                         maybelong *max_label, PyArrayObject* output)
+{
+    int kk;
+    maybelong jj, ll, ssize, size, filter_size, *offsets = NULL;
+    maybelong mask_value, *oo;
+    Bool *ps, *footprint = NULL;
+    char *pi, *po;
+    Int32 index = 0, *index_map = NULL;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    _index_pair *pairs = NULL;
+
+    /* structure size */
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    /* we only use the first half of the structure data, so we make a
+         temporary structure for use with the filter functions: */
+    footprint = (Bool*)malloc(ssize * sizeof(Bool));
+    if (!footprint) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    ps = (Bool*)PyArray_DATA(strct);
+    filter_size = 0;
+    for(jj = 0; jj < ssize / 2; jj++) {
+        footprint[jj] = ps[jj];
+        if (ps[jj])
+            ++filter_size;
+    }
+    for(jj = ssize / 2; jj < ssize; jj++)
+        footprint[jj] = 0;
+    /* get data and size */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(kk = 0; kk < output->nd; kk++)
+        size *= output->dimensions[kk];
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* set all elements in the output corresponding to non-zero elements
+         in input to -1: */
+    for(jj = 0; jj < size; jj++) {
+        Int32 *p = (Int32*)po;
+        switch (input->descr->type_num) {
+        CASE_LABEL(p, pi, Bool);
+        CASE_LABEL(p, pi, UInt8);
+        CASE_LABEL(p, pi, UInt16);
+        CASE_LABEL(p, pi, UInt32);
+#if HAS_UINT64
+        CASE_LABEL(p, pi, UInt64);
+#endif
+        CASE_LABEL(p, pi, Int8);
+        CASE_LABEL(p, pi, Int16);
+        CASE_LABEL(p, pi, Int32);
+        CASE_LABEL(p, pi, Int64);
+        CASE_LABEL(p, pi, Float32);
+        CASE_LABEL(p, pi, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(output, footprint, strct->dimensions, NULL,
+                                                    NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, strct->dimensions, filter_size,
+                                                                                     input->dimensions, NULL, &fi))
+        goto exit;
+    /* reset output iterator: */
+    NI_ITERATOR_RESET(io);
+    po = (void *)PyArray_DATA(output);
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        if (*(Int32*)po < 0) {
+            Int32 neighbor = 0;
+            /* iterate over structuring element: */
+            for(ll = 0; ll < filter_size; ll++) {
+                int offset = oo[ll];
+                if (offset != mask_value) {
+                    Int32 tt = *(Int32*)(po + offset);
+                    if (tt > 0) {
+                        /* this element is next to an already found object: */
+                        if (neighbor && neighbor != tt) {
+                            /* we have two objects that must be merged later: */
+                            _index_pair* tp = (_index_pair*)malloc(sizeof(_index_pair));
+                            if (!tp) {
+                                PyErr_NoMemory();
+                                goto exit;
+                            }
+                            tp->next = pairs;
+                            /* the pairs must be ordered: */
+                            if (neighbor < tt) {
+                                tp->index1 = neighbor;
+                                tp->index2 = tt;
+                            } else {
+                                tp->index1 = tt;
+                                tp->index2 = neighbor;
+                            }
+                            pairs = tp;
+                        } else {
+                            neighbor = tt;
+                        }
+                    }
+                }
+            }
+            if (neighbor) {
+                /* this point belongs to an existing object */
+                *(Int32*)po = neighbor;
+            } else {
+                /* this may be a new object: */
+                *(Int32*)po = ++index;
+            }
+        }
+        NI_FILTER_NEXT(fi, io, oo, po);
+    }
+    *max_label = index;
+    /* merge any touching objects: */
+    if (pairs) {
+        Int32 counter;
+        index_map = (Int32*)malloc(index * sizeof(Int32));
+        if (!index_map) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(jj = 0; jj < index; jj++)
+            index_map[jj] = (Int32)jj;
+        while (pairs) {
+            Int32 idx1 = pairs->index1 - 1;
+            Int32 idx2 = pairs->index2 - 1;
+            if (index_map[idx2] == idx1 || index_map[idx2] == idx2) {
+                /* if this pair was already processed, or if idx2 was not
+                     mapped yet, we delete this pair and map idx2 to idx1: */
+                _index_pair *tp = pairs;
+                pairs = tp->next;
+                free(tp);
+                index_map[idx2] = idx1;
+            } else {
+                /* idx2 was already mapped, therefore we find what it was
+                     mapped to and change the current pair to the result of that
+                     and idx1. Since the pair is not destroyed, it will be
+                     re-processed with the adapted values.  */
+                idx2 = index_map[idx2];
+                /* keep the pairs ordered: */
+                if (idx1 < idx2) {
+                    pairs->index1 = idx1 + 1;
+                    pairs->index2 = idx2 + 1;
+                } else {
+                    pairs->index1 = idx2 + 1;
+                    pairs->index2 = idx1 + 1;
+                }
+            }
+        }
+        for(jj = 0; jj < index; jj++) {
+            /* if the current index maps to a index that is also mapped,
+                 change it to map to that index. Since an index always maps to
+                 a lower index or to itself, this will make sure that at the
+                 end all indices map to an unmapped index. */
+            if (index_map[index_map[jj]] < index_map[jj])
+                index_map[jj] = index_map[index_map[jj]];
+        }
+        /* renumber the indices that are not mapped: */
+        counter = 0;
+        for(jj = 0; jj < index; jj++)
+            if (index_map[jj] == jj)
+                index_map[jj] = ++counter;
+            else
+                index_map[jj] = index_map[index_map[jj]];
+    }
+
+    /* relabel the output if we merged some objects: */
+    if (index_map) {
+        *max_label = 0;
+        NI_ITERATOR_RESET(io);
+        po = (void *)PyArray_DATA(output);
+        for(jj = 0; jj < size; jj++) {
+            Int32 p = *(Int32*)po;
+            if (p > 0 )
+                *(Int32*)po = index_map[p - 1];
+            if (*(Int32*)po > *max_label)
+                *max_label = *(Int32*)po;
+            NI_ITERATOR_NEXT(io, po);
+        }
+    }
+ exit:
+    if (offsets) free(offsets);
+    if (index_map) free(index_map);
+    while (pairs) {
+        _index_pair *tp = pairs;
+        pairs = (_index_pair*)pairs->next;
+        free(tp);
+    }
+    if (footprint)
+        free(footprint);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_FIND_OBJECT_POINT(_pi, _regions, _rank, _dimensions, \
+                                                             _max_label, _ii, _type)            \
+case t ## _type:                                                  \
+{                                                                 \
+    int _kk;                                                        \
+    maybelong _sindex = *(_type*)_pi - 1;                           \
+    if (_sindex >= 0 && _sindex < _max_label) {                     \
+        if (_rank > 0) {                                              \
+            _sindex *= 2 * _rank;                                       \
+            if (_regions[_sindex] < 0) {                                \
+                for(_kk = 0; _kk < _rank; _kk++) {                        \
+                    maybelong _cc = _ii.coordinates[_kk];                   \
+                    _regions[_sindex + _kk] = _cc;                          \
+                    _regions[_sindex + _kk + _rank] = _cc + 1;              \
+                }                                                         \
+            } else {                                                    \
+                for(_kk = 0; _kk < _rank; _kk++) {                        \
+                    maybelong _cc = _ii.coordinates[_kk];                   \
+                    if (_cc < _regions[_sindex + _kk])                      \
+                        _regions[_sindex + _kk] = _cc;                        \
+                    if (_cc + 1 > _regions[_sindex + _kk + _rank])          \
+                        _regions[_sindex + _kk + _rank] = _cc + 1;            \
+                }                                                         \
+            }                                                           \
+        } else {                                                      \
+            _regions[_sindex] = 1;                                      \
+        }                                                             \
+    }                                                               \
+}                                                                 \
+break
+
+int NI_FindObjects(PyArrayObject* input, maybelong max_label,
+                                     maybelong* regions)
+{
+    int kk;
+    maybelong size, jj;
+    NI_Iterator ii;
+    char *pi;
+
+    /* get input data, size and iterator: */
+    pi = (void *)PyArray_DATA(input);
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    if (input->nd > 0) {
+        for(jj = 0; jj < 2 * input->nd * max_label; jj++)
+            regions[jj] = -1;
+    } else {
+        for(jj = 0; jj < max_label; jj++)
+            regions[jj] = -1;
+    }
+    /* iterate over all points: */
+    for(jj = 0 ; jj < size; jj++) {
+        switch (input->descr->type_num) {
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii,  Bool);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt8);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt16);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt32);
+#if HAS_UINT64
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt64);
+#endif
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int8);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int16);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int32);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int64);
+            break;
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+ exit:
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+/* macro to get input value: */
+#if HAS_UINT64
+#define NI_GET_VALUE(_pi, _v, _type)                                  \
+{                                                                     \
+    switch(_type) {                                                     \
+    case tBool:                                                         \
+        _v = (*(Bool*)_pi) != 0;                                          \
+        break;                                                            \
+    case tUInt8:                                                        \
+        _v = *(UInt8*)_pi;                                                \
+        break;                                                            \
+    case tUInt16:                                                       \
+        _v = *(UInt16*)_pi;                                               \
+        break;                                                            \
+    case tUInt32:                                                       \
+        _v = *(UInt32*)_pi;                                               \
+        break;                                                            \
+    case tInt8:                                                         \
+        _v = *(Int8*)_pi;                                                 \
+        break;                                                            \
+    case tInt16:                                                        \
+        _v = *(Int16*)_pi;                                                \
+        break;                                                            \
+    case tInt32:                                                        \
+        _v = *(Int32*)_pi;                                                \
+        break;                                                            \
+    case tInt64:                                                        \
+        _v = *(Int64*)_pi;                                                \
+        break;                                                            \
+    case tUInt64:                                                       \
+        _v = *(UInt64*)_pi;                                               \
+        break;                                                            \
+    case tFloat32:                                                      \
+        _v = *(Float32*)_pi;                                              \
+        break;                                                            \
+    case tFloat64:                                                      \
+        _v = *(Float64*)_pi;                                              \
+        break;                                                            \
+    default:                                                            \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+    }                                                                   \
+}
+#else
+#define NI_GET_VALUE(_pi, _v, _type)                                  \
+{                                                                     \
+    switch(_type) {                                                     \
+    case tBool:                                                         \
+        _v = (*(Bool*)_pi) != 0;                                          \
+        break;                                                            \
+    case tUInt8:                                                        \
+        _v = *(UInt8*)_pi;                                                \
+        break;                                                            \
+    case tUInt16:                                                       \
+        _v = *(UInt16*)_pi;                                               \
+        break;                                                            \
+    case tUInt32:                                                       \
+        _v = *(UInt32*)_pi;                                               \
+        break;                                                            \
+    case tInt8:                                                         \
+        _v = *(Int8*)_pi;                                                 \
+        break;                                                            \
+    case tInt16:                                                        \
+        _v = *(Int16*)_pi;                                                \
+        break;                                                            \
+    case tInt32:                                                        \
+        _v = *(Int32*)_pi;                                                \
+        break;                                                            \
+    case tInt64:                                                        \
+        _v = *(Int64*)_pi;                                                \
+        break;                                                            \
+    case tFloat32:                                                      \
+        _v = *(Float32*)_pi;                                              \
+        break;                                                            \
+    case tFloat64:                                                      \
+        _v = *(Float64*)_pi;                                              \
+        break;                                                            \
+    default:                                                            \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+    }                                                                   \
+}
+#endif
+
+/* macro to get label value: */
+#if HAS_UINT64
+#define NI_GET_LABEL(_pm, _label, _type)                              \
+{                                                                     \
+    if (_pm) {                                                          \
+        switch(_type) {                                                   \
+        case tBool:                                                       \
+            _label = *(Bool*)_pm;                                           \
+            break;                                                          \
+        case tUInt8:                                                      \
+            _label = *(UInt8*)_pm;                                          \
+            break;                                                          \
+        case tUInt16:                                                     \
+            _label = *(UInt16*)_pm;                                         \
+            break;                                                          \
+        case tUInt32:                                                     \
+            _label = *(UInt32*)_pm;                                         \
+            break;                                                          \
+        case tUInt64:                                                     \
+            _label = *(UInt64*)_pm;                                         \
+            break;                                                          \
+        case tInt8:                                                       \
+            _label = *(Int8*)_pm;                                           \
+            break;                                                          \
+        case tInt16:                                                      \
+            _label = *(Int16*)_pm;                                          \
+            break;                                                          \
+        case tInt32:                                                      \
+            _label = *(Int32*)_pm;                                          \
+             break;                                                         \
+        case tInt64:                                                      \
+            _label = *(Int64*)_pm;                                          \
+             break;                                                         \
+        case tFloat32:                                                    \
+            _label = *(Float32*)_pm;                                        \
+            break;                                                          \
+        case tFloat64:                                                    \
+            _label = *(Float64*)_pm;                                        \
+            break;                                                          \
+        default:                                                          \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+        }                                                                 \
+    }                                                                   \
+}
+#else
+#define NI_GET_LABEL(_pm, _label, _type)                              \
+{                                                                     \
+    if (_pm) {                                                          \
+        switch(_type) {                                                   \
+        case tBool:                                                       \
+            _label = *(Bool*)_pm;                                           \
+            break;                                                          \
+        case tUInt8:                                                      \
+            _label = *(UInt8*)_pm;                                          \
+            break;                                                          \
+        case tUInt16:                                                     \
+            _label = *(UInt16*)_pm;                                         \
+            break;                                                          \
+        case tUInt32:                                                     \
+            _label = *(UInt32*)_pm;                                         \
+            break;                                                          \
+        case tInt8:                                                       \
+            _label = *(Int8*)_pm;                                           \
+            break;                                                          \
+        case tInt16:                                                      \
+            _label = *(Int16*)_pm;                                          \
+            break;                                                          \
+        case tInt32:                                                      \
+            _label = *(Int32*)_pm;                                          \
+             break;                                                         \
+        case tInt64:                                                      \
+            _label = *(Int64*)_pm;                                          \
+             break;                                                         \
+        case tFloat32:                                                    \
+            _label = *(Float32*)_pm;                                        \
+            break;                                                          \
+        case tFloat64:                                                    \
+            _label = *(Float64*)_pm;                                        \
+            break;                                                          \
+        default:                                                          \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+        }                                                                 \
+    }                                                                   \
+}
+#endif
+
+int NI_Statistics(PyArrayObject *input, PyArrayObject *labels,
+    maybelong min_label, maybelong max_label, maybelong *indices,
+    maybelong n_results, double *sum, maybelong *total, double *variance,
+    double *minimum, double *maximum, maybelong* min_pos, maybelong* max_pos)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, size, idx = 0, label = 1, doit = 1;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        return 0;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    for(jj = 0; jj < n_results; jj++) {
+        if (sum)
+            sum[jj] = 0.0;
+        if (total)
+            total[jj] = 0;
+        if (variance)
+            variance[jj] = 0;
+        if (minimum)
+            minimum[jj] = DBL_MAX;
+        if (maximum)
+            maximum[jj] = -DBL_MAX;
+        if (min_pos)
+            min_pos[jj] = 0;
+        if (max_pos)
+            max_pos[jj] = 0;
+    }
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            if (sum)
+                sum[idx] += val;
+            if (total)
+                total[idx]++;
+            if (minimum && val < minimum[idx]) {
+                minimum[idx] = val;
+                if (min_pos)
+                    min_pos[idx] = jj;
+            }
+            if (maximum && (val > maximum[idx])) {
+                maximum[idx] = val;
+                if (max_pos)
+                    max_pos[idx] = jj;
+            }
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+    if (minimum) {
+        for(jj = 0; jj < n_results; jj++) {
+            if (!(minimum[jj] < DBL_MAX))
+                minimum[jj] = 0.0;
+        }
+    }
+    if (maximum) {
+        for(jj = 0; jj < n_results; jj++) {
+            if (!(maximum[jj] > -DBL_MAX))
+                maximum[jj] = 0.0;
+        }
+    }
+    if (variance) {
+        int do_var = 0;
+        for(jj = 0; jj < n_results; jj++)
+            if (total[jj] > 1) {
+                do_var = 1;
+                break;
+            }
+        if (do_var) {
+            /* reset input iterator: */
+            NI_ITERATOR_RESET(ii);
+            pi = (void *)PyArray_DATA(input);
+            if (labels) {
+                /* reset label iterator: */
+                NI_ITERATOR_RESET(mi);
+                pm = (void *)PyArray_DATA(labels);
+            }
+            for(jj = 0; jj < size; jj++) {
+                NI_GET_LABEL(pm, label, labels->descr->type_num);
+                if (min_label >= 0) {
+                    if (label >= min_label && label <= max_label) {
+                        idx = indices[label - min_label];
+                        doit = idx >= 0;
+                    } else {
+                        doit = 0;
+                    }
+                } else {
+                    doit = label != 0;
+                }
+                if (doit) {
+                    double val;
+                    NI_GET_VALUE(pi, val, input->descr->type_num);
+                    val = val - sum[idx] / total[idx];
+                    variance[idx] += val * val;
+                }
+                if (labels) {
+                    NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+                } else {
+                    NI_ITERATOR_NEXT(ii, pi);
+                }
+            }
+            for(jj = 0; jj < n_results; jj++)
+                variance[jj] = (total[jj] > 1 ?
+                                                variance[jj] / (total[jj] - 1) : 0.0);
+        }
+    }
+    return 1;
+}
+
+
+int NI_CenterOfMass(PyArrayObject *input, PyArrayObject *labels,
+                            maybelong min_label, maybelong max_label, maybelong *indices,
+                            maybelong n_results, double *center_of_mass)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
+    double *sum = NULL;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            goto exit;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    sum = (double*)malloc(n_results * sizeof(double));
+    if (!sum) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+        sum[jj] = 0.0;
+        for(kk = 0; kk < input->nd; kk++)
+            center_of_mass[jj * input->nd + kk] = 0.0;
+    }
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            sum[idx] += val;
+            for(kk = 0; kk < input->nd; kk++)
+                center_of_mass[idx * input->nd + kk] += val * ii.coordinates[kk];
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+    for(jj = 0; jj < n_results; jj++)
+        for(kk = 0; kk < input->nd; kk++)
+            center_of_mass[jj * input->nd + kk] /= sum[jj];
+ exit:
+    if (sum)
+        free(sum);
+    return  PyErr_Occurred() == NULL;
+}
+
+
+int NI_Histogram(PyArrayObject *input, PyArrayObject *labels,
+                            maybelong min_label, maybelong max_label, maybelong *indices,
+                            maybelong n_results, PyArrayObject **histograms,
+                            double min, double max, maybelong nbins)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
+    Int32 **ph = NULL;
+    double bsize;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            goto exit;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    ph = (Int32**)malloc(n_results * sizeof(Int32*));
+    if (!ph) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+            ph[jj] = (Int32*)PyArray_DATA(histograms[jj]);
+            for(kk = 0; kk < nbins; kk++)
+                    ph[jj][kk] = 0;
+    }
+    bsize = (max - min) / (double)nbins;
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            int bin;
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            if (val >= min && val < max) {
+                bin = (int)((val - min) / bsize);
+                ++(ph[idx][bin]);
+            }
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+ exit:
+    if (ph)
+        free(ph);
+    return  PyErr_Occurred() == NULL;
+}
+
+#define WS_GET_INDEX(_index, _c_strides, _b_strides, _rank, _out, \
+                                         _contiguous, _type)                          \
+do {                                                              \
+    if (_contiguous) {                                              \
+        _out = _index * sizeof(_type);                                \
+    } else {                                                        \
+        int _qq;                                                      \
+        maybelong _cc, _idx = _index;                                 \
+        _out = 0;                                                     \
+        for (_qq = 0; _qq < _rank; _qq++) {                           \
+            _cc = _idx / _c_strides[_qq];                               \
+            _idx -= _cc * _c_strides[_qq];                              \
+            _out += _b_strides[_qq] * _cc;                              \
+        }                                                             \
+    }                                                               \
+} while(0)
+
+#define CASE_GET_INPUT(_ival, _pi, _type) \
+case t ## _type:                          \
+    _ival = *((_type*)_pi);                 \
+    break
+
+#define CASE_GET_LABEL(_label, _pm, _type) \
+case t ## _type:                           \
+    _label = *(_type*)_pm;                   \
+    break
+
+#define CASE_PUT_LABEL(_label, _pl, _type) \
+case t ## _type:                           \
+    *((_type*)_pl) = _label;                 \
+    break
+
+#define CASE_WINDEX1(_v_index, _p_index, _strides, _istrides, _irank,  \
+                                         _icont, _p_idx, _v_idx, _pi, _vval, _pval, _type) \
+case t ## _type:                                                       \
+    WS_GET_INDEX(_v_index, _strides, _istrides, _irank, _p_idx, _icont,  \
+                             _type);                                                 \
+    WS_GET_INDEX(_p_index, _strides, _istrides, _irank, _v_idx, _icont,  \
+                             _type);                                                 \
+    _vval = *(_type*)(_pi + _v_idx);                                     \
+    _pval = *(_type*)(_pi + _p_idx);                                     \
+    break
+
+#define CASE_WINDEX2(_v_index, _strides, _ostrides, _irank, _idx, \
+                                         _ocont, _label, _pl, _type)                  \
+case t ## _type:                                                  \
+    WS_GET_INDEX(_v_index, _strides, _ostrides, _irank, _idx,       \
+                             _ocont, _type);                                    \
+    _label = *(_type*)(_pl + _idx);                                 \
+    break
+
+#define CASE_WINDEX3(_p_index, _strides, _ostrides, _irank, _idx, \
+                                         _ocont, _label, _pl, _type)                  \
+case t ## _type:                                                  \
+    WS_GET_INDEX(_p_index, _strides, _ostrides, _irank, _idx,       \
+                             _ocont, _type);                                    \
+    *(_type*)(_pl + _idx) = _label;                                 \
+break
+
+#define DONE_TYPE UInt8
+#define COST_TYPE UInt16
+#define WS_MAXDIM 7
+
+typedef struct {
+    maybelong index;
+    COST_TYPE cost;
+    void *next, *prev;
+    DONE_TYPE done;
+} NI_WatershedElement;
+
+int NI_WatershedIFT(PyArrayObject* input, PyArrayObject* markers,
+                                        PyArrayObject* strct, PyArrayObject* output)
+{
+    char *pl, *pm, *pi;
+    int ll;
+    maybelong size, jj, hh, kk, maxval;
+    maybelong strides[WS_MAXDIM], coordinates[WS_MAXDIM];
+    maybelong *nstrides = NULL, nneigh, ssize;
+    int i_contiguous, o_contiguous;
+    NI_WatershedElement *temp = NULL, **first = NULL, **last = NULL;
+    Bool *ps = NULL;
+    NI_Iterator mi, ii, li;
+
+    i_contiguous = PyArray_ISCONTIGUOUS(input);
+    o_contiguous = PyArray_ISCONTIGUOUS(output);
+    ssize = 1;
+    for(ll = 0; ll < strct->nd; ll++)
+        ssize *= strct->dimensions[ll];
+    if (input->nd > WS_MAXDIM) {
+        PyErr_SetString(PyExc_RuntimeError, "too many dimensions");
+        goto exit;
+    }
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* Storage for the temporary queue data. */
+    temp = (NI_WatershedElement*)malloc(size * sizeof(NI_WatershedElement));
+    if (!temp) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    pi = (void *)PyArray_DATA(input);
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* Initialization and find the maximum of the input. */
+    maxval = 0;
+    for(jj = 0; jj < size; jj++) {
+        int ival = 0;
+        switch(input->descr->type_num) {
+        CASE_GET_INPUT(ival, pi, UInt8);
+        CASE_GET_INPUT(ival, pi, UInt16);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        temp[jj].index = jj;
+        temp[jj].done = 0;
+        if (ival > maxval)
+            maxval = ival;
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+    pi = (void *)PyArray_DATA(input);
+    /* Allocate and initialize the storage for the queue. */
+    first = (NI_WatershedElement**)malloc((maxval + 1) *
+                                                                                sizeof(NI_WatershedElement*));
+    last = (NI_WatershedElement**)malloc((maxval + 1) *
+                                                                             sizeof(NI_WatershedElement*));
+    if (!first || !last) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(hh = 0; hh <= maxval; hh++) {
+        first[hh] = NULL;
+        last[hh] = NULL;
+    }
+    if (!NI_InitPointIterator(markers, &mi))
+        goto exit;
+    if (!NI_InitPointIterator(output, &li))
+        goto exit;
+    pm = (void *)PyArray_DATA(markers);
+    pl = (void *)PyArray_DATA(output);
+    /* initialize all nodes */
+    for(ll = 0; ll < input->nd; ll++)
+        coordinates[ll] = 0;
+    for(jj = 0; jj < size; jj++) {
+        /* get marker */
+        int label = 0;
+        switch(markers->descr->type_num) {
+        CASE_GET_LABEL(label, pm, UInt8);
+        CASE_GET_LABEL(label, pm, UInt16);
+        CASE_GET_LABEL(label, pm, UInt32);
+#if HAS_UINT64
+        CASE_GET_LABEL(label, pm, UInt64);
+#endif
+        CASE_GET_LABEL(label, pm, Int8);
+        CASE_GET_LABEL(label, pm, Int16);
+        CASE_GET_LABEL(label, pm, Int32);
+        CASE_GET_LABEL(label, pm, Int64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch(output->descr->type_num) {
+        CASE_PUT_LABEL(label, pl, UInt8);
+        CASE_PUT_LABEL(label, pl, UInt16);
+        CASE_PUT_LABEL(label, pl, UInt32);
+#if HAS_UINT64
+        CASE_PUT_LABEL(label, pl, UInt64);
+#endif
+        CASE_PUT_LABEL(label, pl, Int8);
+        CASE_PUT_LABEL(label, pl, Int16);
+        CASE_PUT_LABEL(label, pl, Int32);
+        CASE_PUT_LABEL(label, pl, Int64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(mi, li, pm, pl);
+        if (label != 0) {
+            /* This node is a marker */
+            temp[jj].cost = 0;
+            if (!first[0]) {
+                first[0] = &(temp[jj]);
+                first[0]->next = NULL;
+                first[0]->prev = NULL;
+                last[0] = first[0];
+            } else {
+                if (label > 0) {
+                    /* object markers are enqueued at the beginning, so they are
+                         processed first. */
+                    temp[jj].next = first[0];
+                    temp[jj].prev = NULL;
+                    first[0]->prev = &(temp[jj]);
+                    first[0] = &(temp[jj]);
+                } else {
+                    /* background markers are enqueued at the end, so they are
+                         processed after the object markers. */
+                    temp[jj].next = NULL;
+                    temp[jj].prev = last[0];
+                    last[0]->next = &(temp[jj]);
+                    last[0] = &(temp[jj]);
+                }
+            }
+        } else {
+            /* This node is not a marker */
+            temp[jj].cost = maxval + 1;
+            temp[jj].next = NULL;
+            temp[jj].prev = NULL;
+        }
+        for(ll = input->nd - 1; ll >= 0; ll--)
+            if (coordinates[ll] < input->dimensions[ll] - 1) {
+                coordinates[ll]++;
+                break;
+            } else {
+                coordinates[ll] = 0;
+            }
+    }
+
+    pl = (void *)PyArray_DATA(output);
+    ps = (Bool*)PyArray_DATA(strct);
+    nneigh = 0;
+    for (kk = 0; kk < ssize; kk++)
+        if (ps[kk] && kk != (ssize / 2))
+            ++nneigh;
+    nstrides = (maybelong*)malloc(nneigh * sizeof(maybelong));
+    if (!nstrides) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    strides[input->nd - 1] = 1;
+    for(ll = input->nd - 2; ll >= 0; ll--)
+        strides[ll] = input->dimensions[ll + 1] * strides[ll + 1];
+    for(ll = 0; ll < input->nd; ll++)
+        coordinates[ll] = -1;
+    for(kk = 0; kk < nneigh; kk++)
+        nstrides[kk] = 0;
+    jj = 0;
+    for(kk = 0; kk < ssize; kk++) {
+        if (ps[kk]) {
+            int offset = 0;
+            for(ll = 0; ll < input->nd; ll++)
+                offset += coordinates[ll] * strides[ll];
+            if (offset != 0)
+                nstrides[jj++] += offset;
+        }
+        for(ll = input->nd - 1; ll >= 0; ll--)
+            if (coordinates[ll] < 1) {
+                coordinates[ll]++;
+                break;
+            } else {
+                coordinates[ll] = -1;
+            }
+    }
+    /* Propagation phase: */
+    for(jj = 0; jj <= maxval; jj++) {
+        while (first[jj]) {
+            /* dequeue first element: */
+            NI_WatershedElement *v = first[jj];
+            first[jj] = first[jj]->next;
+            if (first[jj])
+                first[jj]->prev = NULL;
+            v->prev = NULL;
+            v->next = NULL;
+            /* Mark element as done: */
+            v->done = 1;
+            /* Iterate over the neighbors of the element: */
+            for(hh = 0; hh < nneigh; hh++) {
+                maybelong v_index = v->index, p_index = v->index, idx, cc;
+                int qq, outside = 0;
+                p_index += nstrides[hh];
+                /* check if the neighbor is within the extent of the array: */
+                idx = p_index;
+                for (qq = 0; qq < input->nd; qq++) {
+                    cc = idx / strides[qq];
+                    if (cc < 0 || cc >= input->dimensions[qq]) {
+                        outside = 1;
+                        break;
+                    }
+                    idx -= cc * strides[qq];
+                }
+                if (!outside) {
+                    NI_WatershedElement *p = &(temp[p_index]);
+                    if (!(p->done)) {
+                        /* If the neighbor was not processed yet: */
+                        int max, pval, vval, wvp, pcost, label, p_idx, v_idx;
+                        switch(input->descr->type_num) {
+                        CASE_WINDEX1(v_index, p_index, strides, input->strides,
+                                                 input->nd, i_contiguous, p_idx, v_idx, pi,
+                                                 vval, pval, UInt8);
+                        CASE_WINDEX1(v_index, p_index, strides, input->strides,
+                                                 input->nd, i_contiguous, p_idx, v_idx, pi,
+                                                 vval, pval, UInt16);
+                        default:
+                            PyErr_SetString(PyExc_RuntimeError,
+                                                            "data type not supported");
+                            goto exit;
+                        }
+                        /* Calculate cost: */
+                        wvp = pval - vval;
+                        if (wvp < 0)
+                            wvp = -wvp;
+                        /* Find the maximum of this cost and the current
+                             element cost: */
+                        pcost = p->cost;
+                        max = v->cost > wvp ? v->cost : wvp;
+                        if (max < pcost) {
+                            /* If this maximum is less than the neighbors cost,
+                                 adapt the cost and the label of the neighbor: */
+                            int idx;
+                            p->cost = max;
+                            switch(output->descr->type_num) {
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt8);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt16);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt32);
+#if HAS_UINT64
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt64);
+#endif
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int8);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int16);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int32);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int64);
+                            default:
+                                PyErr_SetString(PyExc_RuntimeError,
+                                                                "data type not supported");
+                                goto exit;
+                            }
+                            switch(output->descr->type_num) {
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt8);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt16);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt32);
+#if HAS_UINT64
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt64);
+#endif
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int8);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int16);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int32);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int64);
+                            default:
+                                PyErr_SetString(PyExc_RuntimeError,
+                                                                "data type not supported");
+                                goto exit;
+                            }
+                            /* If the neighbor is in a queue, remove it: */
+                            if (p->next || p->prev) {
+                                NI_WatershedElement *prev = p->prev, *next = p->next;
+                                if (first[pcost] == p)
+                                    first[pcost] = next;
+                                if (last[pcost] == p)
+                                    last[pcost] = prev;
+                                if (prev)
+                                    prev->next = next;
+                                if (next)
+                                    next->prev = prev;
+                            }
+                            /* Insert the neighbor in the appropiate queue: */
+                            if (label < 0) {
+                                p->prev = last[max];
+                                p->next = NULL;
+                                if (last[max])
+                                    last[max]->next = p;
+                                last[max] = p;
+                                if (!first[max])
+                                    first[max] = p;
+                            } else {
+                                p->next = first[max];
+                                p->prev = NULL;
+                                if (first[max])
+                                    first[max]->prev = p;
+                                first[max] = p;
+                                if (!last[max])
+                                    last[max] = p;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+ exit:
+    if (temp)
+        free(temp);
+    if (first)
+        free(first);
+    if (last)
+        free(last);
+    if (nstrides)
+        free(nstrides);
+    return PyErr_Occurred() ? 0 : 1;
+}

Modified: trunk/scipy/ndimage/src/ni_measure.h
===================================================================
--- trunk/scipy/ndimage/src/ni_measure.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_measure.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,59 +1,59 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met: 
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
- */
-
-#ifndef NI_MEASURE_H
-#define NI_MEASURE_H
-
-#include "nd_image.h"
-
-/* structure for array regions to find objects: */
-typedef struct {
-  int start[NI_MAXDIM], end[NI_MAXDIM];
-} NI_ObjectRegion;
-
-int NI_Label(PyArrayObject*, PyArrayObject*, maybelong*, PyArrayObject*);
-
-int NI_FindObjects(PyArrayObject*, maybelong, maybelong*);
-
-int NI_CenterOfMass(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
-                    maybelong*, maybelong, double*);
-
-int NI_Histogram(PyArrayObject*, PyArrayObject*, maybelong, maybelong, 
-       maybelong*, maybelong,  PyArrayObject**, double, double, maybelong);
-
-int NI_Statistics(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
-                  maybelong*, maybelong, double*, maybelong*, double*, 
-                  double*, double*, maybelong*, maybelong*);
-
-int NI_WatershedIFT(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
-                    PyArrayObject*);
-
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
+ */
+
+#ifndef NI_MEASURE_H
+#define NI_MEASURE_H
+
+#include "nd_image.h"
+
+/* structure for array regions to find objects: */
+typedef struct {
+    int start[NI_MAXDIM], end[NI_MAXDIM];
+} NI_ObjectRegion;
+
+int NI_Label(PyArrayObject*, PyArrayObject*, maybelong*, PyArrayObject*);
+
+int NI_FindObjects(PyArrayObject*, maybelong, maybelong*);
+
+int NI_CenterOfMass(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
+                                        maybelong*, maybelong, double*);
+
+int NI_Histogram(PyArrayObject*, PyArrayObject*, maybelong, maybelong, 
+             maybelong*, maybelong,  PyArrayObject**, double, double, maybelong);
+
+int NI_Statistics(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
+                                    maybelong*, maybelong, double*, maybelong*, double*, 
+                                    double*, double*, maybelong*, maybelong*);
+
+int NI_WatershedIFT(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
+                                        PyArrayObject*);
+
+#endif

Modified: trunk/scipy/ndimage/src/ni_morphology.c
===================================================================
--- trunk/scipy/ndimage/src/ni_morphology.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_morphology.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,955 +1,955 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_morphology.h"
-#include <stdlib.h>
-#include <math.h>
-#include <limits.h>
-#include <float.h>
-
-#define LIST_SIZE 100000
-
-#define CASE_GET_MASK(_msk_value, _pm, _type) \
-case t ## _type:                              \
-  _msk_value = *(_type*)_pm ? 1 : 0;          \
-  break
-
-#define CASE_OUTPUT(_po, _out, _type) \
-case t ## _type:                      \
-  *(_type*)_po = (_type)_out;         \
-  break
-
-#define CASE_NI_ERODE_POINT(_pi, _out, _offsets, _filter_size, _type, \
-                            _mv,  _border_value, _bv, _center_is_true,\
-                            _true, _false, _changed)                  \
-case t ## _type:                                                      \
-{                                                                     \
-  maybelong _ii, _oo;                                                 \
-  int _in = *(_type*)_pi ? 1 : 0;                                     \
-  if (_mv) {                                                          \
-    if (_center_is_true && _in == false) {                            \
-      _changed = 0;                                                   \
-      _out = _in;                                                     \
-    } else {                                                          \
-      _out = _true;                                                   \
-      for(_ii = 0; _ii < _filter_size; _ii++) {                       \
-        _oo = _offsets[_ii];                                          \
-        if (_oo == _bv) {                                             \
-          if (!_border_value) {                                       \
-            _out = _false;                                            \
-            break;                                                    \
-          }                                                           \
-        } else {                                                      \
-          int _nn = *(_type*)(_pi + _oo) ? _true : _false;            \
-          if (!_nn) {                                                 \
-            _out = _false;                                            \
-            break;                                                    \
-          }                                                           \
-        }                                                             \
-      }                                                               \
-      _changed = _out != _in;                                         \
-    }                                                                 \
-  } else {                                                            \
-    _out = _in;                                                       \
-  }                                                                   \
-}                                                                     \
-break
-
-int NI_BinaryErosion(PyArrayObject* input, PyArrayObject* strct,
-        PyArrayObject* mask, PyArrayObject* output, int bdr_value,
-        maybelong *origins, int invert, int center_is_true, int* changed,
-        NI_CoordinateList **coordinate_list)
-{
-  maybelong struct_size = 0, *offsets = NULL, size, *oo, jj;
-  maybelong ssize, block_size = 0, *current = NULL, border_flag_value;
-  int kk, true, false, msk_value;
-  NI_Iterator ii, io, mi;
-  NI_FilterIterator fi;
-  Bool *ps, out = 0;
-  char *pi, *po, *pm = NULL;
-  NI_CoordinateBlock *block = NULL;
-
-  ps = (Bool*)PyArray_DATA(strct);
-  ssize = 1;
-  for(kk = 0; kk < strct->nd; kk++)
-    ssize *= strct->dimensions[kk];
-  for(jj = 0; jj < ssize; jj++)
-    if (ps[jj]) ++struct_size;
-  if (mask) {
-    if (!NI_InitPointIterator(mask, &mi))
-      return 0;
-    pm = (void *)PyArray_DATA(mask);
-  }
-  /* calculate the filter offsets: */
-  if (!NI_InitFilterOffsets(input, ps, strct->dimensions, origins,
-                  NI_EXTEND_CONSTANT, &offsets, &border_flag_value, NULL))
-    goto exit;
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-  /* initialize output element iterator: */
-  if (!NI_InitPointIterator(output, &io))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(input->nd, strct->dimensions, struct_size,
-                             input->dimensions, origins, &fi))
-    goto exit;
-
-  /* get data pointers an size: */
-  pi = (void *)PyArray_DATA(input);
-  po = (void *)PyArray_DATA(output);
-  size = 1;
-  for(kk = 0; kk < input->nd; kk++)
-    size *= input->dimensions[kk];
-  if (invert) {
-    bdr_value = bdr_value ? 0 : 1;
-    true = 0;
-    false = 1;
-  } else {
-    bdr_value = bdr_value ? 1 : 0;
-    true = 1;
-    false = 0;
-  }
-  if (coordinate_list) {
-    block_size = LIST_SIZE / input->nd / sizeof(int);
-    if (block_size < 1)
-      block_size = 1;
-    if (block_size > size)
-      block_size = size;
-    *coordinate_list = NI_InitCoordinateList(block_size, input->nd);
-    if (!*coordinate_list)
-      goto exit;
-  }
-  /* iterator over the elements: */
-  oo = offsets;
-  *changed = 0;
-  msk_value = 1;
-  for(jj = 0; jj < size; jj++) {
-    int pchange = 0;
-    if (mask) {
-      switch(mask->descr->type_num) {
-      CASE_GET_MASK(msk_value, pm, Bool);
-      CASE_GET_MASK(msk_value, pm, UInt8);
-      CASE_GET_MASK(msk_value, pm, UInt16);
-      CASE_GET_MASK(msk_value, pm, UInt32);
-#if HAS_UINT64
-      CASE_GET_MASK(msk_value, pm, UInt64);
-#endif
-      CASE_GET_MASK(msk_value, pm, Int8);
-      CASE_GET_MASK(msk_value, pm, Int16);
-      CASE_GET_MASK(msk_value, pm, Int32);
-      CASE_GET_MASK(msk_value, pm, Int64);
-      CASE_GET_MASK(msk_value, pm, Float32);
-      CASE_GET_MASK(msk_value, pm, Float64);
-      default:
-        PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-        return 0;
-      }
-    }
-    switch (input->descr->type_num) {
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Bool, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt8, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt16, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt32, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-#if HAS_UINT64
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt64, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-#endif
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int8, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int16, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int32, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int64, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float32, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float64, msk_value,
-                        bdr_value, border_flag_value, center_is_true,
-                        true, false, pchange);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    switch (output->descr->type_num) {
-    CASE_OUTPUT(po, out, Bool);
-    CASE_OUTPUT(po, out, UInt8);
-    CASE_OUTPUT(po, out, UInt16);
-    CASE_OUTPUT(po, out, UInt32);
-#if HAS_UINT64
-    CASE_OUTPUT(po, out, UInt64);
-#endif
-    CASE_OUTPUT(po, out, Int8);
-    CASE_OUTPUT(po, out, Int16);
-    CASE_OUTPUT(po, out, Int32);
-    CASE_OUTPUT(po, out, Int64);
-    CASE_OUTPUT(po, out, Float32);
-    CASE_OUTPUT(po, out, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-    if (pchange) {
-      *changed = 1;
-      if (coordinate_list) {
-        if (block == NULL ||  block->size == block_size) {
-          block = NI_CoordinateListAddBlock(*coordinate_list);
-          current = block->coordinates;
-        }
-        for(kk = 0; kk < input->nd; kk++)
-          *current++ = ii.coordinates[kk];
-        block->size++;
-      }
-    }
-    if (mask) {
-      NI_FILTER_NEXT3(fi, ii, io, mi, oo, pi, po, pm);
-    } else {
-      NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
-    }
-  }
-
- exit:
-  if (offsets)
-    free(offsets);
-  if (PyErr_Occurred()) {
-    if (coordinate_list) {
-      NI_FreeCoordinateList(*coordinate_list);
-      *coordinate_list = NULL;
-    }
-    return 0;
-  } else {
-    return 1;
-  }
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_ERODE_POINT2(_struct_size, _offsets, _coordinate_offsets, \
-                          _pi, _oo, _irank, _list1, _list2,            \
-                          _current_coors1, _current_coors2, _block1,   \
-                          _block2, _bf_value, _true, _false, _type,    \
-                          _mklist)                                     \
-case t ## _type:                                                       \
-{                                                                      \
-  maybelong _hh, _kk;                                                  \
-  for(_hh = 0; _hh < _struct_size; _hh++) {                            \
-    maybelong _to = _offsets[_oo + _hh];                               \
-    if (_to != _bf_value && *(_type*)(_pi + _to) == _true) {           \
-      if (_mklist) {                                                   \
-        maybelong *_tc = &(_coordinate_offsets[(_oo + _hh) * _irank]); \
-        if (_block2 == NULL || _block2->size == _list2->block_size) {  \
-          _block2 = NI_CoordinateListAddBlock(_list2);                 \
-          _current_coors2 = _block2->coordinates;                      \
-        }                                                              \
-        for(_kk = 0; _kk < _irank; _kk++)                              \
-          *_current_coors2++ = _current_coors1[_kk] + _tc[_kk];        \
-        _block2->size++;                                               \
-      }                                                                \
-      *(_type*)(_pi + _to) = _false;                                   \
-    }                                                                  \
-  }                                                                    \
-}                                                                      \
-break
-
-int NI_BinaryErosion2(PyArrayObject* array, PyArrayObject* strct,
-                      PyArrayObject* mask, int niter, maybelong *origins,
-                      int invert, NI_CoordinateList **iclist)
-{
-  maybelong struct_size = 0, *offsets = NULL, oo, jj, ssize;
-  maybelong *coordinate_offsets = NULL, size = 0;
-  maybelong *current_coordinates1 = NULL, *current_coordinates2 = NULL;
-  maybelong kk, border_flag_value, current = 0;
-  int true, false;
-  NI_Iterator ii, mi;
-  NI_FilterIterator fi, ci;
-  Bool *ps;
-  char *pi, *ibase, *pm = NULL;
-  NI_CoordinateBlock *block1 = NULL, *block2 = NULL;
-  NI_CoordinateList *list1 = NULL, *list2 = NULL;
-
-  ps = (Bool*)PyArray_DATA(strct);
-  ssize = 1;
-  for(kk = 0; kk < strct->nd; kk++)
-    ssize *= strct->dimensions[kk];
-  for(jj = 0; jj < ssize; jj++)
-    if (ps[jj]) ++struct_size;
-
-  /* calculate the filter offsets: */
-  if (!NI_InitFilterOffsets(array, ps, strct->dimensions, origins,
-                            NI_EXTEND_CONSTANT, &offsets,
-                            &border_flag_value, &coordinate_offsets))
-    goto exit;
-
-  /* initialize input element iterator: */
-  if (!NI_InitPointIterator(array, &ii))
-    goto exit;
-
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(array->nd, strct->dimensions, struct_size,
-                             array->dimensions, origins, &fi))
-    goto exit;
-  if (!NI_InitFilterIterator(array->nd, strct->dimensions,
-                             struct_size * array->nd, array->dimensions,
-                             origins, &ci))
-    goto exit;
-
-  /* get data pointers and size: */
-  ibase = pi = (void *)PyArray_DATA(array);
-
-  if (invert) {
-    true = 0;
-    false = 1;
-  } else {
-    true = 1;
-    false = 0;
-  }
-
-  if (mask) {
-    /* iterator, data pointer and type of mask array: */
-    if (!NI_InitPointIterator(mask, &mi))
-      return 0;
-    pm = (void *)PyArray_DATA(mask);
-
-    size = 1;
-    for(kk = 0; kk < array->nd; kk++)
-      size *= array->dimensions[kk];
-
-    for(jj = 0; jj < size; jj++) {
-      if (*(Int8*)pm) {
-        *(Int8*)pm = -1;
-      } else {
-        *(Int8*)pm = (Int8)*(Bool*)pi;
-        *(Bool*)pi = false;
-      }
-      NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
-    }
-    NI_ITERATOR_RESET(ii)
-        pi = (void *)PyArray_DATA(array);
-  }
-
-  list1 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
-  list2 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
-  if (!list1 || !list2)
-    goto exit;
-  if (NI_CoordinateListStealBlocks(list2, *iclist))
-    goto exit;
-  block2 = list2->blocks;
-  jj = 0;
-  while(block1 || block2) {
-    int mklist = 1;
-    if (!block1) {
-      if (niter <= 0 || jj < niter) {
-        if (NI_CoordinateListStealBlocks(list1, list2))
-          goto exit;
-        block1 = list1->blocks;
-        block2 = NULL;
-        current_coordinates1 = block1->coordinates;
-        current = 0;
-        ++jj;
-        mklist = niter <= 0 || jj < niter;
-      } else {
-        break;
-      }
-    }
-    NI_ITERATOR_GOTO(ii, current_coordinates1, ibase, pi);
-    NI_FILTER_GOTO(fi, ii, 0, oo);
-
-    switch (array->descr->type_num) {
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Bool, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, UInt8, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, UInt16, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, UInt32, mklist);
-#if HAS_UINT64
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, UInt64, mklist);
-#endif
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Int8, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Int16, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Int32, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Int64, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Float32, mklist);
-    CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
-                      oo, array->nd, list1, list2, current_coordinates1,
-                      current_coordinates2, block1, block2,
-                      border_flag_value, true, false, Float64, mklist);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "data type not supported");
-      goto exit;
-    }
-
-    ++current;
-    if (current == block1->size) {
-      block1 = NI_CoordinateListDeleteBlock(list1);
-      if (block1) {
-        current_coordinates1 = block1->coordinates;
-        current = 0;
-      }
-    } else {
-      current_coordinates1 += array->nd;
-    }
-  }
-
-  if (mask) {
-    NI_ITERATOR_RESET(ii)
-    NI_ITERATOR_RESET(mi)
-    pi = (void *)PyArray_DATA(array);
-    pm = (void *)PyArray_DATA(mask);
-    for(jj = 0; jj < size; jj++) {
-      int value = *(Int8*)pm;
-      if (value >= 0)
-        *(Bool*)pi = value;
-      NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
-    }
-  }
-
- exit:
-  if (offsets)
-    free(offsets);
-  if (coordinate_offsets)
-    free(coordinate_offsets);
-  NI_FreeCoordinateList(list1);
-  NI_FreeCoordinateList(list2);
-  if (PyErr_Occurred()) {
-    return 0;
-  } else {
-    return 1;
-  }
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-
-#define NI_DISTANCE_EUCLIDIAN  1
-#define NI_DISTANCE_CITY_BLOCK 2
-#define NI_DISTANCE_CHESSBOARD 3
-
-typedef struct {
-  maybelong *coordinates;
-  maybelong index;
-  void *next;
-} NI_BorderElement;
-
-int NI_DistanceTransformBruteForce(PyArrayObject* input, int metric,
-                                   PyArrayObject *sampling_arr,
-                                   PyArrayObject* distances,
-                                   PyArrayObject* features)
-{
-  maybelong size, jj, min_index = 0;
-  int kk;
-  NI_BorderElement *border_elements = NULL, *temp;
-  NI_Iterator ii, di, fi;
-  char *pi, *pd = NULL, *pf = NULL;
-  Float64 *sampling = sampling_arr ? (void *)PyArray_DATA(sampling_arr) : NULL;
-
-  /* check the output arrays: */
-  if (distances) {
-      pd = (void *)PyArray_DATA(distances);
-    if (!NI_InitPointIterator(distances, &di))
-      goto exit;
-  }
-
-  if (features) {
-      pf = (void *)PyArray_DATA(features);
-    if (!NI_InitPointIterator(features, &fi))
-      goto exit;
-  }
-
-  size = 1;
-  for(kk = 0; kk < input->nd; kk++)
-    size *= input->dimensions[kk];
-  pi = (void *)PyArray_DATA(input);
-
-  if (!NI_InitPointIterator(input, &ii))
-    goto exit;
-
-  for(jj = 0; jj < size; jj++) {
-    if (*(Int8*)pi < 0) {
-      temp = (NI_BorderElement*)malloc(sizeof(NI_BorderElement));
-      if (!temp) {
-        PyErr_NoMemory();
-        goto exit;
-      }
-      temp->next = border_elements;
-      border_elements = temp;
-      temp->index = jj;
-      temp->coordinates = (maybelong*)malloc(input->nd * sizeof(maybelong));
-      for(kk = 0; kk < input->nd; kk++)
-          temp->coordinates[kk] = ii.coordinates[kk];
-    }
-    NI_ITERATOR_NEXT(ii, pi);
-  }
-
-  NI_ITERATOR_RESET(ii);
-  pi = (void *)PyArray_DATA(input);
-
-  switch(metric) {
-  case NI_DISTANCE_EUCLIDIAN:
-    for(jj = 0; jj < size; jj++) {
-      if (*(Int8*)pi > 0) {
-        double distance = DBL_MAX;
-        temp = border_elements;
-        while(temp) {
-          double d = 0.0, t;
-          for(kk = 0; kk < input->nd; kk++) {
-            t = ii.coordinates[kk] - temp->coordinates[kk];
-            if (sampling)
-              t *= sampling[kk];
-            d += t * t;
-          }
-          if (d < distance) {
-            distance = d;
-            if (features)
-              min_index = temp->index;
-          }
-          temp = temp->next;
-        }
-        if (distances)
-          *(Float64*)pd = sqrt(distance);
-        if (features)
-          *(Int32*)pf = min_index;
-      } else {
-        if (distances)
-          *(Float64*)pd = 0.0;
-        if (features)
-          *(Int32*)pf = jj;
-      }
-      if (features && distances) {
-        NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
-      } else if (distances) {
-        NI_ITERATOR_NEXT2(ii, di, pi, pd);
-      } else {
-        NI_ITERATOR_NEXT2(ii, fi, pi, pf);
-      }
-    }
-    break;
-  case NI_DISTANCE_CITY_BLOCK:
-  case NI_DISTANCE_CHESSBOARD:
-    for(jj = 0; jj < size; jj++) {
-      if (*(Int8*)pi > 0) {
-        unsigned long distance = ULONG_MAX;
-        temp = border_elements;
-        while(temp) {
-          unsigned int d = 0;
-          maybelong t;
-          for(kk = 0; kk < input->nd; kk++) {
-            t = ii.coordinates[kk] - temp->coordinates[kk];
-            if (t < 0)
-              t = -t;
-            if (metric == NI_DISTANCE_CITY_BLOCK) {
-              d += t;
-            } else {
-              if ((unsigned int)t > d)
-                d = t;
-            }
-          }
-          if (d < distance) {
-            distance = d;
-            if (features)
-              min_index = temp->index;
-          }
-          temp = temp->next;
-        }
-        if (distances)
-          *(UInt32*)pd = distance;
-        if (features)
-          *(Int32*)pf = min_index;
-      } else {
-        if (distances)
-          *(UInt32*)pd = 0;
-        if (features)
-          *(Int32*)pf = jj;
-      }
-      if (features && distances) {
-        NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
-      } else if (distances) {
-        NI_ITERATOR_NEXT2(ii, di, pi, pd);
-      } else {
-         NI_ITERATOR_NEXT2(ii, fi, pi, pf);
-      }
-    }
-    break;
-  default:
-    PyErr_SetString(PyExc_RuntimeError,  "distance metric not supported");
-    goto exit;
-  }
-
- exit:
-  while (border_elements) {
-    temp = border_elements;
-    border_elements = border_elements->next;
-    if (temp->coordinates)
-      free(temp->coordinates);
-    free(temp);
-  }
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-
-int NI_DistanceTransformOnePass(PyArrayObject *strct,
-                        PyArrayObject* distances, PyArrayObject *features)
-{
-  int kk;
-  maybelong jj, ii, ssize, size, filter_size, mask_value, *oo;
-  maybelong *foffsets = NULL, *foo = NULL, *offsets = NULL;
-  Bool *ps, *pf = NULL, *footprint = NULL;
-  char *pd;
-  NI_FilterIterator si, ti;
-  NI_Iterator di, fi;
-
-  ssize = 1;
-  for(kk = 0; kk < strct->nd; kk++)
-    ssize *= strct->dimensions[kk];
-
-  /* we only use the first half of the structure data, so we make a
-     temporary structure for use with the filter functions: */
-  footprint = (Bool*)malloc(ssize * sizeof(Bool));
-  if (!footprint) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  ps = (Bool*)PyArray_DATA(strct);
-  filter_size = 0;
-  for(jj = 0; jj < ssize / 2; jj++) {
-    footprint[jj] = ps[jj];
-    if (ps[jj])
-      ++filter_size;
-  }
-  for(jj = ssize / 2; jj < ssize; jj++)
-    footprint[jj] = 0;
-  /* get data and size */
-  pd = (void *)PyArray_DATA(distances);
-  size = 1;
-  for(kk = 0; kk < distances->nd; kk++)
-    size *= distances->dimensions[kk];
-  if (!NI_InitPointIterator(distances, &di))
-    goto exit;
-  /* calculate the filter offsets: */
-  if (!NI_InitFilterOffsets(distances, footprint, strct->dimensions, NULL,
-                          NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
-    goto exit;
-  /* initialize filter iterator: */
-  if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
-                          filter_size, distances->dimensions, NULL, &si))
-    goto exit;
-
-  if (features) {
-    maybelong dummy;
-    /* initialize point iterator: */
-    pf = (void *)PyArray_DATA(features);
-    if (!NI_InitPointIterator(features, &fi))
-      goto exit;
-    /* calculate the filter offsets: */
-    if (!NI_InitFilterOffsets(features, footprint, strct->dimensions,
-                        NULL, NI_EXTEND_CONSTANT, &foffsets, &dummy, NULL))
-      goto exit;
-    /* initialize filter iterator: */
-    if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
-                           filter_size, distances->dimensions, NULL, &ti))
-      goto exit;
-  }
-  /* iterator over the elements: */
-  oo = offsets;
-  if (features)
-    foo = foffsets;
-  for(jj = 0; jj < size; jj++) {
-    Int32 value = *(Int32*)pd;
-    if (value != 0) {
-      Int32 min = value;
-      maybelong min_offset = 0;
-      /* iterate over structuring element: */
-      for(ii = 0; ii < filter_size; ii++) {
-        maybelong offset = oo[ii];
-        Int32 tt = -1;
-        if (offset < mask_value)
-          tt = *(Int32*)(pd + offset);
-        if (tt >= 0) {
-          if ((min < 0) || (tt + 1 < min)) {
-            min = tt + 1;
-            if (features)
-              min_offset = foo[ii];
-          }
-        }
-      }
-      *(Int32*)pd = min;
-      if (features)
-        *(Int32*)pf = *(Int32*)(pf + min_offset);
-    }
-    if (features) {
-      NI_FILTER_NEXT(ti, fi, foo, pf);
-    }
-    NI_FILTER_NEXT(si, di, oo, pd);
-  }
-
- exit:
-  if (offsets) free(offsets);
-  if (foffsets) free(foffsets);
-  if (footprint)
-    free(footprint);
-  return PyErr_Occurred() ? 0 : 1;
-}
-
-static void _VoronoiFT(char *pf, maybelong len, maybelong *coor, int rank,
-                       int d, maybelong stride, maybelong cstride,
-                       maybelong **f, maybelong *g, Float64 *sampling)
-{
-  maybelong l = -1, ii, maxl, idx1, idx2;
-  int jj;
-
-  for(ii = 0; ii < len; ii++)
-    for(jj = 0; jj < rank; jj++)
-      f[ii][jj] = *(Int32*)(pf + ii * stride + cstride * jj);
-  for(ii = 0; ii < len; ii++) {
-    if (*(Int32*)(pf + ii * stride) >= 0) {
-      double fd = f[ii][d];
-      double wR = 0.0;
-      for(jj = 0; jj < rank; jj++) {
-        if (jj != d) {
-          double tw = f[ii][jj] - coor[jj];
-          if (sampling)
-            tw *= sampling[jj];
-          wR += tw * tw;
-        }
-      }
-      while(l >= 1) {
-        double a, b, c, uR = 0.0, vR = 0.0, f1;
-        idx1 = g[l];
-        f1 = f[idx1][d];
-        idx2 = g[l - 1];
-        a = f1 - f[idx2][d];
-        b = fd - f1;
-        if (sampling) {
-          a *= sampling[d];
-          b *= sampling[d];
-        }
-        c = a + b;
-        for(jj = 0; jj < rank; jj++) {
-          if (jj != d) {
-            double cc = coor[jj];
-            double tu = f[idx2][jj] - cc;
-            double tv = f[idx1][jj] - cc;
-            if (sampling) {
-              tu *= sampling[jj];
-              tv *= sampling[jj];
-            }
-            uR += tu * tu;
-            vR += tv * tv;
-          }
-        }
-        if (c * vR - b * uR - a * wR - a * b * c <= 0.0)
-          break;
-        --l;
-      }
-      ++l;
-      g[l] = ii;
-    }
-  }
-  maxl = l;
-  if (maxl >= 0) {
-    l = 0;
-    for (ii = 0; ii < len; ii++) {
-      double delta1 = 0.0, t;
-      for(jj = 0; jj < rank; jj++) {
-        t = jj == d ? f[g[l]][jj] - ii : f[g[l]][jj] - coor[jj];
-        if (sampling)
-          t *= sampling[jj];
-        delta1 += t * t;
-      }
-      while (l < maxl) {
-        double delta2 = 0.0;
-        for(jj = 0; jj < rank; jj++) {
-          t = jj == d ? f[g[l + 1]][jj] - ii : f[g[l + 1]][jj] - coor[jj];
-          if (sampling)
-            t *= sampling[jj];
-          delta2 += t * t;
-        }
-        if (delta1 <= delta2)
-          break;
-        delta1 = delta2;
-        ++l;
-      }
-      idx1 = g[l];
-      for(jj = 0; jj < rank; jj++)
-        *(Int32*)(pf + ii * stride + jj * cstride) = f[idx1][jj];
-    }
-  }
-}
-
-
-/* Recursive feature transform */
-static void _ComputeFT(char *pi, char *pf, maybelong *ishape,
-                       maybelong *istrides, maybelong *fstrides, int rank,
-                       int d, maybelong *coor, maybelong **f, maybelong *g,
-                       PyArrayObject *features, Float64 *sampling)
-{
-  int kk;
-  maybelong jj;
-
-  if (d == 0) {
-    char *tf1 = pf;
-    for(jj = 0; jj < ishape[0]; jj++) {
-      if (*(Int8*)pi) {
-        *(Int32*)tf1 = -1;
-      } else {
-        char *tf2 = tf1;
-        *(Int32*)tf2 = jj;
-        for(kk = 1; kk < rank; kk++) {
-          tf2 += fstrides[0];
-          *(Int32*)tf2 = coor[kk];
-        }
-      }
-      pi += istrides[0];
-      tf1 += fstrides[1];
-    }
-    _VoronoiFT(pf, ishape[0], coor, rank, 0, fstrides[1], fstrides[0], f,
-               g, sampling);
-  } else {
-    UInt32 axes = 0;
-    char *tf = pf;
-    maybelong size = 1;
-    NI_Iterator ii;
-
-    for(jj = 0; jj < ishape[d]; jj++) {
-      coor[d] = jj;
-      _ComputeFT(pi, tf, ishape, istrides, fstrides, rank, d - 1, coor, f,
-                 g, features, sampling);
-      pi += istrides[d];
-      tf += fstrides[d + 1];
-    }
-
-    for(jj = 0; jj < d; jj++) {
-      axes |= (UInt32)1 << (jj + 1);
-      size *= ishape[jj];
-    }
-    NI_InitPointIterator(features, &ii);
-    NI_SubspaceIterator(&ii, axes);
-    tf = pf;
-    for(jj = 0; jj < size; jj++) {
-      for(kk = 0; kk < d; kk++)
-        coor[kk] = ii.coordinates[kk];
-      _VoronoiFT(tf, ishape[d], coor, rank, d, fstrides[d + 1],
-                 fstrides[0], f, g, sampling);
-      NI_ITERATOR_NEXT(ii, tf);
-    }
-    for(kk = 0; kk < d; kk++)
-      coor[kk] = 0;
-  }
-}
-
-/* Exact euclidean feature transform, as described in: C. R. Maurer,
-   Jr., R. Qi, V. Raghavan, "A linear time algorithm for computing
-   exact euclidean distance transforms of binary images in arbitrary
-   dimensions. IEEE Trans. PAMI 25, 265-270, 2003. */
-int NI_EuclideanFeatureTransform(PyArrayObject* input,
-                                 PyArrayObject *sampling_arr,
-                                 PyArrayObject* features)
-{
-  int ii;
-  maybelong coor[NI_MAXDIM], mx = 0, jj;
-  maybelong *tmp = NULL, **f = NULL, *g = NULL;
-  char *pi, *pf;
-  Float64 *sampling = sampling_arr ? ((void *)PyArray_DATA(sampling_arr)) : NULL;
-
-  pi = (void *)PyArray_DATA(input);
-  pf = (void *)PyArray_DATA(features);
-  for(ii = 0; ii < input->nd; ii++) {
-    coor[ii] = 0;
-    if (input->dimensions[ii] > mx)
-      mx = input->dimensions[ii];
-  }
-
-  /* Some temporaries */
-  f = (maybelong**)malloc(mx * sizeof(maybelong*));
-  g = (maybelong*)malloc(mx * sizeof(maybelong));
-  tmp = (maybelong*)malloc(mx * input->nd * sizeof(maybelong));
-  if (!f || !g || !tmp) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  for(jj = 0; jj < mx; jj++)
-    f[jj] = tmp + jj * input->nd;
-
-  /* First call of recursive feature transform */
-  _ComputeFT(pi, pf, input->dimensions, input->strides, features->strides,
-             input->nd, input->nd - 1, coor, f, g, features, sampling);
-
- exit:
-  if (f)
-    free(f);
-  if (g)
-    free(g);
-  if (tmp)
-    free(tmp);
-
-  return PyErr_Occurred() ? 0 : 1;
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+#include "ni_morphology.h"
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+
+#define LIST_SIZE 100000
+
+#define CASE_GET_MASK(_msk_value, _pm, _type) \
+case t ## _type:                              \
+    _msk_value = *(_type*)_pm ? 1 : 0;          \
+    break
+
+#define CASE_OUTPUT(_po, _out, _type) \
+case t ## _type:                      \
+    *(_type*)_po = (_type)_out;         \
+    break
+
+#define CASE_NI_ERODE_POINT(_pi, _out, _offsets, _filter_size, _type, \
+                                                        _mv,  _border_value, _bv, _center_is_true,\
+                                                        _true, _false, _changed)                  \
+case t ## _type:                                                      \
+{                                                                     \
+    maybelong _ii, _oo;                                                 \
+    int _in = *(_type*)_pi ? 1 : 0;                                     \
+    if (_mv) {                                                          \
+        if (_center_is_true && _in == false) {                            \
+            _changed = 0;                                                   \
+            _out = _in;                                                     \
+        } else {                                                          \
+            _out = _true;                                                   \
+            for(_ii = 0; _ii < _filter_size; _ii++) {                       \
+                _oo = _offsets[_ii];                                          \
+                if (_oo == _bv) {                                             \
+                    if (!_border_value) {                                       \
+                        _out = _false;                                            \
+                        break;                                                    \
+                    }                                                           \
+                } else {                                                      \
+                    int _nn = *(_type*)(_pi + _oo) ? _true : _false;            \
+                    if (!_nn) {                                                 \
+                        _out = _false;                                            \
+                        break;                                                    \
+                    }                                                           \
+                }                                                             \
+            }                                                               \
+            _changed = _out != _in;                                         \
+        }                                                                 \
+    } else {                                                            \
+        _out = _in;                                                       \
+    }                                                                   \
+}                                                                     \
+break
+
+int NI_BinaryErosion(PyArrayObject* input, PyArrayObject* strct,
+                PyArrayObject* mask, PyArrayObject* output, int bdr_value,
+                maybelong *origins, int invert, int center_is_true, int* changed,
+                NI_CoordinateList **coordinate_list)
+{
+    maybelong struct_size = 0, *offsets = NULL, size, *oo, jj;
+    maybelong ssize, block_size = 0, *current = NULL, border_flag_value;
+    int kk, true, false, msk_value;
+    NI_Iterator ii, io, mi;
+    NI_FilterIterator fi;
+    Bool *ps, out = 0;
+    char *pi, *po, *pm = NULL;
+    NI_CoordinateBlock *block = NULL;
+
+    ps = (Bool*)PyArray_DATA(strct);
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    for(jj = 0; jj < ssize; jj++)
+        if (ps[jj]) ++struct_size;
+    if (mask) {
+        if (!NI_InitPointIterator(mask, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(mask);
+    }
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(input, ps, strct->dimensions, origins,
+                                    NI_EXTEND_CONSTANT, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, strct->dimensions, struct_size,
+                                                         input->dimensions, origins, &fi))
+        goto exit;
+
+    /* get data pointers an size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    if (invert) {
+        bdr_value = bdr_value ? 0 : 1;
+        true = 0;
+        false = 1;
+    } else {
+        bdr_value = bdr_value ? 1 : 0;
+        true = 1;
+        false = 0;
+    }
+    if (coordinate_list) {
+        block_size = LIST_SIZE / input->nd / sizeof(int);
+        if (block_size < 1)
+            block_size = 1;
+        if (block_size > size)
+            block_size = size;
+        *coordinate_list = NI_InitCoordinateList(block_size, input->nd);
+        if (!*coordinate_list)
+            goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    *changed = 0;
+    msk_value = 1;
+    for(jj = 0; jj < size; jj++) {
+        int pchange = 0;
+        if (mask) {
+            switch(mask->descr->type_num) {
+            CASE_GET_MASK(msk_value, pm, Bool);
+            CASE_GET_MASK(msk_value, pm, UInt8);
+            CASE_GET_MASK(msk_value, pm, UInt16);
+            CASE_GET_MASK(msk_value, pm, UInt32);
+#if HAS_UINT64
+            CASE_GET_MASK(msk_value, pm, UInt64);
+#endif
+            CASE_GET_MASK(msk_value, pm, Int8);
+            CASE_GET_MASK(msk_value, pm, Int16);
+            CASE_GET_MASK(msk_value, pm, Int32);
+            CASE_GET_MASK(msk_value, pm, Int64);
+            CASE_GET_MASK(msk_value, pm, Float32);
+            CASE_GET_MASK(msk_value, pm, Float64);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                return 0;
+            }
+        }
+        switch (input->descr->type_num) {
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Bool, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt8, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt16, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+#if HAS_UINT64
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+#endif
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int8, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int16, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+        CASE_OUTPUT(po, out, Bool);
+        CASE_OUTPUT(po, out, UInt8);
+        CASE_OUTPUT(po, out, UInt16);
+        CASE_OUTPUT(po, out, UInt32);
+#if HAS_UINT64
+        CASE_OUTPUT(po, out, UInt64);
+#endif
+        CASE_OUTPUT(po, out, Int8);
+        CASE_OUTPUT(po, out, Int16);
+        CASE_OUTPUT(po, out, Int32);
+        CASE_OUTPUT(po, out, Int64);
+        CASE_OUTPUT(po, out, Float32);
+        CASE_OUTPUT(po, out, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        if (pchange) {
+            *changed = 1;
+            if (coordinate_list) {
+                if (block == NULL ||  block->size == block_size) {
+                    block = NI_CoordinateListAddBlock(*coordinate_list);
+                    current = block->coordinates;
+                }
+                for(kk = 0; kk < input->nd; kk++)
+                    *current++ = ii.coordinates[kk];
+                block->size++;
+            }
+        }
+        if (mask) {
+            NI_FILTER_NEXT3(fi, ii, io, mi, oo, pi, po, pm);
+        } else {
+            NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+        }
+    }
+
+ exit:
+    if (offsets)
+        free(offsets);
+    if (PyErr_Occurred()) {
+        if (coordinate_list) {
+            NI_FreeCoordinateList(*coordinate_list);
+            *coordinate_list = NULL;
+        }
+        return 0;
+    } else {
+        return 1;
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_ERODE_POINT2(_struct_size, _offsets, _coordinate_offsets, \
+                                                    _pi, _oo, _irank, _list1, _list2,            \
+                                                    _current_coors1, _current_coors2, _block1,   \
+                                                    _block2, _bf_value, _true, _false, _type,    \
+                                                    _mklist)                                     \
+case t ## _type:                                                       \
+{                                                                      \
+    maybelong _hh, _kk;                                                  \
+    for(_hh = 0; _hh < _struct_size; _hh++) {                            \
+        maybelong _to = _offsets[_oo + _hh];                               \
+        if (_to != _bf_value && *(_type*)(_pi + _to) == _true) {           \
+            if (_mklist) {                                                   \
+                maybelong *_tc = &(_coordinate_offsets[(_oo + _hh) * _irank]); \
+                if (_block2 == NULL || _block2->size == _list2->block_size) {  \
+                    _block2 = NI_CoordinateListAddBlock(_list2);                 \
+                    _current_coors2 = _block2->coordinates;                      \
+                }                                                              \
+                for(_kk = 0; _kk < _irank; _kk++)                              \
+                    *_current_coors2++ = _current_coors1[_kk] + _tc[_kk];        \
+                _block2->size++;                                               \
+            }                                                                \
+            *(_type*)(_pi + _to) = _false;                                   \
+        }                                                                  \
+    }                                                                    \
+}                                                                      \
+break
+
+int NI_BinaryErosion2(PyArrayObject* array, PyArrayObject* strct,
+                                            PyArrayObject* mask, int niter, maybelong *origins,
+                                            int invert, NI_CoordinateList **iclist)
+{
+    maybelong struct_size = 0, *offsets = NULL, oo, jj, ssize;
+    maybelong *coordinate_offsets = NULL, size = 0;
+    maybelong *current_coordinates1 = NULL, *current_coordinates2 = NULL;
+    maybelong kk, border_flag_value, current = 0;
+    int true, false;
+    NI_Iterator ii, mi;
+    NI_FilterIterator fi, ci;
+    Bool *ps;
+    char *pi, *ibase, *pm = NULL;
+    NI_CoordinateBlock *block1 = NULL, *block2 = NULL;
+    NI_CoordinateList *list1 = NULL, *list2 = NULL;
+
+    ps = (Bool*)PyArray_DATA(strct);
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    for(jj = 0; jj < ssize; jj++)
+        if (ps[jj]) ++struct_size;
+
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(array, ps, strct->dimensions, origins,
+                                                        NI_EXTEND_CONSTANT, &offsets,
+                                                        &border_flag_value, &coordinate_offsets))
+        goto exit;
+
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(array, &ii))
+        goto exit;
+
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(array->nd, strct->dimensions, struct_size,
+                                                         array->dimensions, origins, &fi))
+        goto exit;
+    if (!NI_InitFilterIterator(array->nd, strct->dimensions,
+                                                         struct_size * array->nd, array->dimensions,
+                                                         origins, &ci))
+        goto exit;
+
+    /* get data pointers and size: */
+    ibase = pi = (void *)PyArray_DATA(array);
+
+    if (invert) {
+        true = 0;
+        false = 1;
+    } else {
+        true = 1;
+        false = 0;
+    }
+
+    if (mask) {
+        /* iterator, data pointer and type of mask array: */
+        if (!NI_InitPointIterator(mask, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(mask);
+
+        size = 1;
+        for(kk = 0; kk < array->nd; kk++)
+            size *= array->dimensions[kk];
+
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pm) {
+                *(Int8*)pm = -1;
+            } else {
+                *(Int8*)pm = (Int8)*(Bool*)pi;
+                *(Bool*)pi = false;
+            }
+            NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
+        }
+        NI_ITERATOR_RESET(ii)
+                pi = (void *)PyArray_DATA(array);
+    }
+
+    list1 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
+    list2 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
+    if (!list1 || !list2)
+        goto exit;
+    if (NI_CoordinateListStealBlocks(list2, *iclist))
+        goto exit;
+    block2 = list2->blocks;
+    jj = 0;
+    while(block1 || block2) {
+        int mklist = 1;
+        if (!block1) {
+            if (niter <= 0 || jj < niter) {
+                if (NI_CoordinateListStealBlocks(list1, list2))
+                    goto exit;
+                block1 = list1->blocks;
+                block2 = NULL;
+                current_coordinates1 = block1->coordinates;
+                current = 0;
+                ++jj;
+                mklist = niter <= 0 || jj < niter;
+            } else {
+                break;
+            }
+        }
+        NI_ITERATOR_GOTO(ii, current_coordinates1, ibase, pi);
+        NI_FILTER_GOTO(fi, ii, 0, oo);
+
+        switch (array->descr->type_num) {
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Bool, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt8, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt16, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt32, mklist);
+#if HAS_UINT64
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt64, mklist);
+#endif
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int8, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int16, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int32, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int64, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Float32, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Float64, mklist);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+
+        ++current;
+        if (current == block1->size) {
+            block1 = NI_CoordinateListDeleteBlock(list1);
+            if (block1) {
+                current_coordinates1 = block1->coordinates;
+                current = 0;
+            }
+        } else {
+            current_coordinates1 += array->nd;
+        }
+    }
+
+    if (mask) {
+        NI_ITERATOR_RESET(ii)
+        NI_ITERATOR_RESET(mi)
+        pi = (void *)PyArray_DATA(array);
+        pm = (void *)PyArray_DATA(mask);
+        for(jj = 0; jj < size; jj++) {
+            int value = *(Int8*)pm;
+            if (value >= 0)
+                *(Bool*)pi = value;
+            NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
+        }
+    }
+
+ exit:
+    if (offsets)
+        free(offsets);
+    if (coordinate_offsets)
+        free(coordinate_offsets);
+    NI_FreeCoordinateList(list1);
+    NI_FreeCoordinateList(list2);
+    if (PyErr_Occurred()) {
+        return 0;
+    } else {
+        return 1;
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+#define NI_DISTANCE_EUCLIDIAN  1
+#define NI_DISTANCE_CITY_BLOCK 2
+#define NI_DISTANCE_CHESSBOARD 3
+
+typedef struct {
+    maybelong *coordinates;
+    maybelong index;
+    void *next;
+} NI_BorderElement;
+
+int NI_DistanceTransformBruteForce(PyArrayObject* input, int metric,
+                                                                     PyArrayObject *sampling_arr,
+                                                                     PyArrayObject* distances,
+                                                                     PyArrayObject* features)
+{
+    maybelong size, jj, min_index = 0;
+    int kk;
+    NI_BorderElement *border_elements = NULL, *temp;
+    NI_Iterator ii, di, fi;
+    char *pi, *pd = NULL, *pf = NULL;
+    Float64 *sampling = sampling_arr ? (void *)PyArray_DATA(sampling_arr) : NULL;
+
+    /* check the output arrays: */
+    if (distances) {
+            pd = (void *)PyArray_DATA(distances);
+        if (!NI_InitPointIterator(distances, &di))
+            goto exit;
+    }
+
+    if (features) {
+            pf = (void *)PyArray_DATA(features);
+        if (!NI_InitPointIterator(features, &fi))
+            goto exit;
+    }
+
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    pi = (void *)PyArray_DATA(input);
+
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+
+    for(jj = 0; jj < size; jj++) {
+        if (*(Int8*)pi < 0) {
+            temp = (NI_BorderElement*)malloc(sizeof(NI_BorderElement));
+            if (!temp) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            temp->next = border_elements;
+            border_elements = temp;
+            temp->index = jj;
+            temp->coordinates = (maybelong*)malloc(input->nd * sizeof(maybelong));
+            for(kk = 0; kk < input->nd; kk++)
+                    temp->coordinates[kk] = ii.coordinates[kk];
+        }
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+
+    NI_ITERATOR_RESET(ii);
+    pi = (void *)PyArray_DATA(input);
+
+    switch(metric) {
+    case NI_DISTANCE_EUCLIDIAN:
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pi > 0) {
+                double distance = DBL_MAX;
+                temp = border_elements;
+                while(temp) {
+                    double d = 0.0, t;
+                    for(kk = 0; kk < input->nd; kk++) {
+                        t = ii.coordinates[kk] - temp->coordinates[kk];
+                        if (sampling)
+                            t *= sampling[kk];
+                        d += t * t;
+                    }
+                    if (d < distance) {
+                        distance = d;
+                        if (features)
+                            min_index = temp->index;
+                    }
+                    temp = temp->next;
+                }
+                if (distances)
+                    *(Float64*)pd = sqrt(distance);
+                if (features)
+                    *(Int32*)pf = min_index;
+            } else {
+                if (distances)
+                    *(Float64*)pd = 0.0;
+                if (features)
+                    *(Int32*)pf = jj;
+            }
+            if (features && distances) {
+                NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
+            } else if (distances) {
+                NI_ITERATOR_NEXT2(ii, di, pi, pd);
+            } else {
+                NI_ITERATOR_NEXT2(ii, fi, pi, pf);
+            }
+        }
+        break;
+    case NI_DISTANCE_CITY_BLOCK:
+    case NI_DISTANCE_CHESSBOARD:
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pi > 0) {
+                unsigned long distance = ULONG_MAX;
+                temp = border_elements;
+                while(temp) {
+                    unsigned int d = 0;
+                    maybelong t;
+                    for(kk = 0; kk < input->nd; kk++) {
+                        t = ii.coordinates[kk] - temp->coordinates[kk];
+                        if (t < 0)
+                            t = -t;
+                        if (metric == NI_DISTANCE_CITY_BLOCK) {
+                            d += t;
+                        } else {
+                            if ((unsigned int)t > d)
+                                d = t;
+                        }
+                    }
+                    if (d < distance) {
+                        distance = d;
+                        if (features)
+                            min_index = temp->index;
+                    }
+                    temp = temp->next;
+                }
+                if (distances)
+                    *(UInt32*)pd = distance;
+                if (features)
+                    *(Int32*)pf = min_index;
+            } else {
+                if (distances)
+                    *(UInt32*)pd = 0;
+                if (features)
+                    *(Int32*)pf = jj;
+            }
+            if (features && distances) {
+                NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
+            } else if (distances) {
+                NI_ITERATOR_NEXT2(ii, di, pi, pd);
+            } else {
+                 NI_ITERATOR_NEXT2(ii, fi, pi, pf);
+            }
+        }
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError,  "distance metric not supported");
+        goto exit;
+    }
+
+ exit:
+    while (border_elements) {
+        temp = border_elements;
+        border_elements = border_elements->next;
+        if (temp->coordinates)
+            free(temp->coordinates);
+        free(temp);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+int NI_DistanceTransformOnePass(PyArrayObject *strct,
+                                                PyArrayObject* distances, PyArrayObject *features)
+{
+    int kk;
+    maybelong jj, ii, ssize, size, filter_size, mask_value, *oo;
+    maybelong *foffsets = NULL, *foo = NULL, *offsets = NULL;
+    Bool *ps, *pf = NULL, *footprint = NULL;
+    char *pd;
+    NI_FilterIterator si, ti;
+    NI_Iterator di, fi;
+
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+
+    /* we only use the first half of the structure data, so we make a
+         temporary structure for use with the filter functions: */
+    footprint = (Bool*)malloc(ssize * sizeof(Bool));
+    if (!footprint) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    ps = (Bool*)PyArray_DATA(strct);
+    filter_size = 0;
+    for(jj = 0; jj < ssize / 2; jj++) {
+        footprint[jj] = ps[jj];
+        if (ps[jj])
+            ++filter_size;
+    }
+    for(jj = ssize / 2; jj < ssize; jj++)
+        footprint[jj] = 0;
+    /* get data and size */
+    pd = (void *)PyArray_DATA(distances);
+    size = 1;
+    for(kk = 0; kk < distances->nd; kk++)
+        size *= distances->dimensions[kk];
+    if (!NI_InitPointIterator(distances, &di))
+        goto exit;
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(distances, footprint, strct->dimensions, NULL,
+                                                    NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
+                                                    filter_size, distances->dimensions, NULL, &si))
+        goto exit;
+
+    if (features) {
+        maybelong dummy;
+        /* initialize point iterator: */
+        pf = (void *)PyArray_DATA(features);
+        if (!NI_InitPointIterator(features, &fi))
+            goto exit;
+        /* calculate the filter offsets: */
+        if (!NI_InitFilterOffsets(features, footprint, strct->dimensions,
+                                                NULL, NI_EXTEND_CONSTANT, &foffsets, &dummy, NULL))
+            goto exit;
+        /* initialize filter iterator: */
+        if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
+                                                     filter_size, distances->dimensions, NULL, &ti))
+            goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    if (features)
+        foo = foffsets;
+    for(jj = 0; jj < size; jj++) {
+        Int32 value = *(Int32*)pd;
+        if (value != 0) {
+            Int32 min = value;
+            maybelong min_offset = 0;
+            /* iterate over structuring element: */
+            for(ii = 0; ii < filter_size; ii++) {
+                maybelong offset = oo[ii];
+                Int32 tt = -1;
+                if (offset < mask_value)
+                    tt = *(Int32*)(pd + offset);
+                if (tt >= 0) {
+                    if ((min < 0) || (tt + 1 < min)) {
+                        min = tt + 1;
+                        if (features)
+                            min_offset = foo[ii];
+                    }
+                }
+            }
+            *(Int32*)pd = min;
+            if (features)
+                *(Int32*)pf = *(Int32*)(pf + min_offset);
+        }
+        if (features) {
+            NI_FILTER_NEXT(ti, fi, foo, pf);
+        }
+        NI_FILTER_NEXT(si, di, oo, pd);
+    }
+
+ exit:
+    if (offsets) free(offsets);
+    if (foffsets) free(foffsets);
+    if (footprint)
+        free(footprint);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static void _VoronoiFT(char *pf, maybelong len, maybelong *coor, int rank,
+                                             int d, maybelong stride, maybelong cstride,
+                                             maybelong **f, maybelong *g, Float64 *sampling)
+{
+    maybelong l = -1, ii, maxl, idx1, idx2;
+    int jj;
+
+    for(ii = 0; ii < len; ii++)
+        for(jj = 0; jj < rank; jj++)
+            f[ii][jj] = *(Int32*)(pf + ii * stride + cstride * jj);
+    for(ii = 0; ii < len; ii++) {
+        if (*(Int32*)(pf + ii * stride) >= 0) {
+            double fd = f[ii][d];
+            double wR = 0.0;
+            for(jj = 0; jj < rank; jj++) {
+                if (jj != d) {
+                    double tw = f[ii][jj] - coor[jj];
+                    if (sampling)
+                        tw *= sampling[jj];
+                    wR += tw * tw;
+                }
+            }
+            while(l >= 1) {
+                double a, b, c, uR = 0.0, vR = 0.0, f1;
+                idx1 = g[l];
+                f1 = f[idx1][d];
+                idx2 = g[l - 1];
+                a = f1 - f[idx2][d];
+                b = fd - f1;
+                if (sampling) {
+                    a *= sampling[d];
+                    b *= sampling[d];
+                }
+                c = a + b;
+                for(jj = 0; jj < rank; jj++) {
+                    if (jj != d) {
+                        double cc = coor[jj];
+                        double tu = f[idx2][jj] - cc;
+                        double tv = f[idx1][jj] - cc;
+                        if (sampling) {
+                            tu *= sampling[jj];
+                            tv *= sampling[jj];
+                        }
+                        uR += tu * tu;
+                        vR += tv * tv;
+                    }
+                }
+                if (c * vR - b * uR - a * wR - a * b * c <= 0.0)
+                    break;
+                --l;
+            }
+            ++l;
+            g[l] = ii;
+        }
+    }
+    maxl = l;
+    if (maxl >= 0) {
+        l = 0;
+        for (ii = 0; ii < len; ii++) {
+            double delta1 = 0.0, t;
+            for(jj = 0; jj < rank; jj++) {
+                t = jj == d ? f[g[l]][jj] - ii : f[g[l]][jj] - coor[jj];
+                if (sampling)
+                    t *= sampling[jj];
+                delta1 += t * t;
+            }
+            while (l < maxl) {
+                double delta2 = 0.0;
+                for(jj = 0; jj < rank; jj++) {
+                    t = jj == d ? f[g[l + 1]][jj] - ii : f[g[l + 1]][jj] - coor[jj];
+                    if (sampling)
+                        t *= sampling[jj];
+                    delta2 += t * t;
+                }
+                if (delta1 <= delta2)
+                    break;
+                delta1 = delta2;
+                ++l;
+            }
+            idx1 = g[l];
+            for(jj = 0; jj < rank; jj++)
+                *(Int32*)(pf + ii * stride + jj * cstride) = f[idx1][jj];
+        }
+    }
+}
+
+
+/* Recursive feature transform */
+static void _ComputeFT(char *pi, char *pf, maybelong *ishape,
+                                             maybelong *istrides, maybelong *fstrides, int rank,
+                                             int d, maybelong *coor, maybelong **f, maybelong *g,
+                                             PyArrayObject *features, Float64 *sampling)
+{
+    int kk;
+    maybelong jj;
+
+    if (d == 0) {
+        char *tf1 = pf;
+        for(jj = 0; jj < ishape[0]; jj++) {
+            if (*(Int8*)pi) {
+                *(Int32*)tf1 = -1;
+            } else {
+                char *tf2 = tf1;
+                *(Int32*)tf2 = jj;
+                for(kk = 1; kk < rank; kk++) {
+                    tf2 += fstrides[0];
+                    *(Int32*)tf2 = coor[kk];
+                }
+            }
+            pi += istrides[0];
+            tf1 += fstrides[1];
+        }
+        _VoronoiFT(pf, ishape[0], coor, rank, 0, fstrides[1], fstrides[0], f,
+                             g, sampling);
+    } else {
+        UInt32 axes = 0;
+        char *tf = pf;
+        maybelong size = 1;
+        NI_Iterator ii;
+
+        for(jj = 0; jj < ishape[d]; jj++) {
+            coor[d] = jj;
+            _ComputeFT(pi, tf, ishape, istrides, fstrides, rank, d - 1, coor, f,
+                                 g, features, sampling);
+            pi += istrides[d];
+            tf += fstrides[d + 1];
+        }
+
+        for(jj = 0; jj < d; jj++) {
+            axes |= (UInt32)1 << (jj + 1);
+            size *= ishape[jj];
+        }
+        NI_InitPointIterator(features, &ii);
+        NI_SubspaceIterator(&ii, axes);
+        tf = pf;
+        for(jj = 0; jj < size; jj++) {
+            for(kk = 0; kk < d; kk++)
+                coor[kk] = ii.coordinates[kk];
+            _VoronoiFT(tf, ishape[d], coor, rank, d, fstrides[d + 1],
+                                 fstrides[0], f, g, sampling);
+            NI_ITERATOR_NEXT(ii, tf);
+        }
+        for(kk = 0; kk < d; kk++)
+            coor[kk] = 0;
+    }
+}
+
+/* Exact euclidean feature transform, as described in: C. R. Maurer,
+     Jr., R. Qi, V. Raghavan, "A linear time algorithm for computing
+     exact euclidean distance transforms of binary images in arbitrary
+     dimensions. IEEE Trans. PAMI 25, 265-270, 2003. */
+int NI_EuclideanFeatureTransform(PyArrayObject* input,
+                                                                 PyArrayObject *sampling_arr,
+                                                                 PyArrayObject* features)
+{
+    int ii;
+    maybelong coor[NI_MAXDIM], mx = 0, jj;
+    maybelong *tmp = NULL, **f = NULL, *g = NULL;
+    char *pi, *pf;
+    Float64 *sampling = sampling_arr ? ((void *)PyArray_DATA(sampling_arr)) : NULL;
+
+    pi = (void *)PyArray_DATA(input);
+    pf = (void *)PyArray_DATA(features);
+    for(ii = 0; ii < input->nd; ii++) {
+        coor[ii] = 0;
+        if (input->dimensions[ii] > mx)
+            mx = input->dimensions[ii];
+    }
+
+    /* Some temporaries */
+    f = (maybelong**)malloc(mx * sizeof(maybelong*));
+    g = (maybelong*)malloc(mx * sizeof(maybelong));
+    tmp = (maybelong*)malloc(mx * input->nd * sizeof(maybelong));
+    if (!f || !g || !tmp) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < mx; jj++)
+        f[jj] = tmp + jj * input->nd;
+
+    /* First call of recursive feature transform */
+    _ComputeFT(pi, pf, input->dimensions, input->strides, features->strides,
+                         input->nd, input->nd - 1, coor, f, g, features, sampling);
+
+ exit:
+    if (f)
+        free(f);
+    if (g)
+        free(g);
+    if (tmp)
+        free(tmp);
+
+    return PyErr_Occurred() ? 0 : 1;
+}

Modified: trunk/scipy/ndimage/src/ni_morphology.h
===================================================================
--- trunk/scipy/ndimage/src/ni_morphology.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_morphology.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,46 +1,46 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met: 
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
- */
-
-#ifndef NI_MORPHOLOGY_H
-#define NI_MORPHOLOGY_H
-
-int NI_BinaryErosion(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
-     PyArrayObject*, int, maybelong*, int, int, int*, NI_CoordinateList**);
-int NI_BinaryErosion2(PyArrayObject*, PyArrayObject*, PyArrayObject*,
-                      int, maybelong*, int, NI_CoordinateList**);
-int NI_DistanceTransformBruteForce(PyArrayObject*, int, PyArrayObject*,
-                                   PyArrayObject*, PyArrayObject*);
-int NI_DistanceTransformOnePass(PyArrayObject*, PyArrayObject *,
-                                PyArrayObject*);
-int NI_EuclideanFeatureTransform(PyArrayObject*, PyArrayObject*, 
-                                 PyArrayObject*);
-
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      
+ */
+
+#ifndef NI_MORPHOLOGY_H
+#define NI_MORPHOLOGY_H
+
+int NI_BinaryErosion(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
+         PyArrayObject*, int, maybelong*, int, int, int*, NI_CoordinateList**);
+int NI_BinaryErosion2(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                            int, maybelong*, int, NI_CoordinateList**);
+int NI_DistanceTransformBruteForce(PyArrayObject*, int, PyArrayObject*,
+                                                                     PyArrayObject*, PyArrayObject*);
+int NI_DistanceTransformOnePass(PyArrayObject*, PyArrayObject *,
+                                                                PyArrayObject*);
+int NI_EuclideanFeatureTransform(PyArrayObject*, PyArrayObject*, 
+                                                                 PyArrayObject*);
+
+#endif

Modified: trunk/scipy/ndimage/src/ni_support.c
===================================================================
--- trunk/scipy/ndimage/src/ni_support.c	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_support.c	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,751 +1,751 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-
-/* initialize iterations over single array elements: */
-int NI_InitPointIterator(PyArrayObject *array, NI_Iterator *iterator)
-{
-  int ii;
-
-  iterator->rank_m1 = array->nd - 1;
-  for(ii = 0; ii < array->nd; ii++) {
-    /* adapt dimensions for use in the macros: */
-    iterator->dimensions[ii] = array->dimensions[ii] - 1;
-    /* initialize coordinates: */
-    iterator->coordinates[ii] = 0;
-    /* initialize strides: */
-    iterator->strides[ii] = array->strides[ii];
-    /* calculate the strides to move back at the end of an axis: */
-    iterator->backstrides[ii] =
-        array->strides[ii] * iterator->dimensions[ii];
-  }
-  return 1;
-}
-
-
-/* initialize iteration over a lower sub-space: */
-int NI_SubspaceIterator(NI_Iterator *iterator, UInt32 axes)
-{
-  int ii, last = 0;
-
-  for(ii = 0; ii <= iterator->rank_m1; ii++) {
-    if (axes & (((UInt32)1) << ii)) {
-      if (last != ii) {
-        iterator->dimensions[last] = iterator->dimensions[ii];
-        iterator->strides[last] = iterator->strides[ii];
-        iterator->backstrides[last] = iterator->backstrides[ii];
-      }
-      ++last;
-    }
-  }
-  iterator->rank_m1 = last - 1;
-  return 1;
-}
-
-/* initialize iteration over array lines: */
-int NI_LineIterator(NI_Iterator *iterator, int axis)
-{
-  UInt32 axes = ((UInt32)1) << axis;
-  return NI_SubspaceIterator(iterator, ~axes);
-}
-
-
-/******************************************************************/
-/* Line buffers */
-/******************************************************************/
-
-/* Allocate line buffer data */
-int NI_AllocateLineBuffer(PyArrayObject* array, int axis, maybelong size1,
-    maybelong size2, maybelong *lines, maybelong max_size, double **buffer)
-{
-  maybelong line_size, max_lines;
-  int ii;
-
-  /* the number of lines of the array is an upper limit for the
-     number of lines in the buffer: */
-  max_lines = 1;
-  for(ii = 0; ii < array->nd; ii++)
-    max_lines *= array->dimensions[ii];
-  if (array->nd > 0 && array->dimensions[axis] > 0)
-    max_lines /= array->dimensions[axis];
-  /* calculate the space needed for one line, including space to
-     support the boundary conditions: */
-  line_size = sizeof(double) * (array->dimensions[axis] + size1 + size2);
-  /* if *lines < 1, no number of lines is proposed, so we calculate it
-     from the maximum size allowed: */
-  if (*lines < 1) {
-    *lines = line_size > 0 ? max_size / line_size : 0;
-    if (*lines < 1)
-      *lines = 1;
-  }
-  /* no need to allocate too many lines: */
-  if (*lines > max_lines)
-    *lines = max_lines;
-  /* allocate data for the buffer: */
-  *buffer = (double*)malloc(*lines * line_size);
-  if (!*buffer) {
-    PyErr_NoMemory();
-    return 0;
-  }
-  return 1;
-}
-
-/* Initialize a line buffer */
-int NI_InitLineBuffer(PyArrayObject *array, int axis, maybelong size1,
-    maybelong size2, maybelong buffer_lines, double *buffer_data,
-    NI_ExtendMode extend_mode, double extend_value, NI_LineBuffer *buffer)
-{
-  maybelong line_length = 0, array_lines = 0, size;
-  int ii;
-
-  size = 1;
-  for(ii = 0; ii < array->nd; ii++)
-    size *= array->dimensions[ii];
-  /* check if the buffer is big enough: */
-  if (size > 0 && buffer_lines < 1) {
-    PyErr_SetString(PyExc_RuntimeError, "buffer too small");
-    return 0;
-  }
-  /* Initialize a line iterator to move over the array: */
-  if (!NI_InitPointIterator(array, &(buffer->iterator)))
-    return 0;
-  if (!NI_LineIterator(&(buffer->iterator), axis))
-    return 0;
-  line_length = array->nd > 0 ? array->dimensions[axis] : 1;
-  if (line_length > 0)
-    array_lines = line_length > 0 ? size / line_length : 1;
-  /* initialize the buffer structure: */
-  buffer->array_data = (void *)PyArray_DATA(array);
-  buffer->buffer_data = buffer_data;
-  buffer->buffer_lines = buffer_lines;
-  buffer->array_type = array->descr->type_num;
-  buffer->array_lines = array_lines;
-  buffer->next_line = 0;
-  buffer->size1 = size1;
-  buffer->size2 = size2;
-  buffer->line_length = line_length;
-  buffer->line_stride = array->nd > 0 ? array->strides[axis] : 0;
-  buffer->extend_mode = extend_mode;
-  buffer->extend_value = extend_value;
-  return 1;
-}
-
-/* Extend a line in memory to implement boundary conditions: */
-int NI_ExtendLine(double *line, maybelong length, maybelong size1,
-                maybelong size2, NI_ExtendMode mode, double constant_value)
-{
-  maybelong ii, jj, length1, nextend, rextend;
-  double *l1, *l2, *l3, val;
-
-  switch (mode) {
-  case NI_EXTEND_WRAP:
-    nextend = size1 / length;
-    rextend = size1 - nextend * length;
-    l1 = line + size1 + length - rextend;
-    l2 = line;
-    for(ii = 0; ii < rextend; ii++)
-      *l2++ = *l1++;
-    for(ii = 0; ii < nextend; ii++) {
-      l1 = line + size1;
-      for(jj = 0; jj < length; jj++)
-        *l2++ = *l1++;
-    }
-    nextend = size2 / length;
-    rextend = size2 - nextend * length;
-    l1 = line + size1;
-    l2 = line + size1 + length;
-    for(ii = 0; ii < nextend; ii++) {
-      l3 = l1;
-      for(jj = 0; jj < length; jj++)
-        *l2++ = *l3++;
-    }
-    for(ii = 0; ii < rextend; ii++)
-      *l2++ = *l1++;
-    break;
-  case NI_EXTEND_MIRROR:
-    if (length == 1) {
-      l1 = line;
-      val = line[size1];
-      for(ii = 0; ii < size1; ii++)
-        *l1++ = val;
-      l1 = line + size1 + length;
-      val = line[size1 + length - 1];
-      for(ii = 0; ii < size2; ii++)
-        *l1++ = val;
-    } else {
-      length1 = length - 1;
-      nextend = size1 / length1;
-      rextend = size1 - nextend * length1;
-      l1 = line + size1 + 1;
-      l2 = l1 - 2;
-      for(ii = 0; ii < nextend; ii++) {
-        l3 = l1;
-        for(jj = 0; jj < length1; jj++)
-          *l2-- = *l3++;
-        l1 -= length1;
-      }
-      for(ii = 0; ii < rextend; ii++)
-        *l2-- = *l1++;
-      nextend = size2 / length1;
-      rextend = size2 - nextend * length1;
-      l1 = line + size1 + length1 - 1;
-      l2 = l1 + 2;
-      for(ii = 0; ii < nextend; ii++) {
-        l3 = l1;
-        for(jj = 0; jj < length1; jj++)
-          *l2++ = *l3--;
-        l1 += length1;
-      }
-      for(ii = 0; ii < rextend; ii++)
-        *l2++ = *l1--;
-    }
-    break;
-  case NI_EXTEND_REFLECT:
-    nextend = size1 / length;
-    rextend = size1 - nextend * length;
-    l1 = line + size1;
-    l2 = l1 - 1;
-    for(ii = 0; ii < nextend; ii++) {
-      l3 = l1;
-      for(jj = 0; jj < length; jj++)
-        *l2-- = *l3++;
-      l1 -= length;
-    }
-    l3 = l1;
-    for(ii = 0; ii < rextend; ii++)
-      *l2-- = *l3++;
-    nextend = size2 / length;
-    rextend = size2 - nextend * length;
-    l1 = line + size1 + length - 1;
-    l2 = l1 + 1;
-    for(ii = 0; ii < nextend; ii++) {
-      l3 = l1;
-      for(jj = 0; jj < length; jj++)
-        *l2++ = *l3--;
-      l1 += length;
-    }
-    for(ii = 0; ii < rextend; ii++)
-      *l2++ = *l1--;
-    break;
-  case NI_EXTEND_NEAREST:
-    l1 = line;
-    val = line[size1];
-    for(ii = 0; ii < size1; ii++)
-      *l1++ = val;
-    l1 = line + size1 + length;
-    val = line[size1 + length - 1];
-    for(ii = 0; ii < size2; ii++)
-      *l1++ = val;
-    break;
-  case NI_EXTEND_CONSTANT:
-    l1 = line;
-    for(ii = 0; ii < size1; ii++)
-      *l1++ = constant_value;
-    l1 = line + size1 + length;
-    for(ii = 0; ii < size2; ii++)
-      *l1++ = constant_value;
-    break;
-  default:
-    PyErr_SetString(PyExc_RuntimeError, "mode not supported");
-    return 0;
-  }
-  return 1;
-}
-
-
-#define CASE_COPY_DATA_TO_LINE(_pi, _po, _length, _stride, _type) \
-case t ## _type:                                                  \
-{                                                                 \
-  maybelong _ii;                                                  \
-  for(_ii = 0; _ii < _length; _ii++) {                            \
-    _po[_ii] = (double)*(_type*)_pi;                              \
-    _pi += _stride;                                               \
-  }                                                               \
-}                                                                 \
-break
-
-
-/* Copy a line from an array to a buffer: */
-int NI_ArrayToLineBuffer(NI_LineBuffer *buffer,
-                         maybelong *number_of_lines, int *more)
-{
-  double *pb = buffer->buffer_data;
-  char *pa;
-  maybelong length = buffer->line_length;
-
-  pb += buffer->size1;
-  *number_of_lines = 0;
-  /* fill until all lines in the array have been processed, or until
-     the buffer is full: */
-  while (buffer->next_line < buffer->array_lines &&
-         *number_of_lines < buffer->buffer_lines) {
-    pa = buffer->array_data;
-    /* copy the data from the array to the buffer: */
-    switch (buffer->array_type) {
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Bool);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt8);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt16);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt32);
-#if HAS_UINT64
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt64);
-#endif
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int8);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int16);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int32);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int64);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float32);
-      CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float64);
-    default:
-      PyErr_Format(PyExc_RuntimeError, "array type %d not supported", buffer->array_type);
-      return 0;
-    }
-    /* goto next line in the array: */
-    NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
-    /* implement boundary conditions to the line: */
-    if (buffer->size1 + buffer->size2 > 0)
-      if (!NI_ExtendLine(pb - buffer->size1, length, buffer->size1,
-                         buffer->size2, buffer->extend_mode,
-                         buffer->extend_value))
-        return 0;
-    /* The number of the array lines copied: */
-    ++(buffer->next_line);
-    /* keep track of (and return) the number of lines in the buffer: */
-    ++(*number_of_lines);
-    pb += buffer->line_length + buffer->size1 + buffer->size2;
-  }
-  /* if not all array lines were processed, *more is set true: */
-  *more = buffer->next_line < buffer->array_lines;
-  return 1;
-}
-
-#define CASE_COPY_LINE_TO_DATA(_pi, _po, _length, _stride, _type) \
-case t ## _type:                                                  \
-{                                                                 \
-  maybelong _ii;                                                  \
-  for(_ii = 0; _ii < _length; _ii++) {                            \
-    *(_type*)_po = (_type)_pi[_ii];                               \
-    _po += _stride;                                               \
-  }                                                               \
-}                                                                 \
-break
-
-/* Copy a line from a buffer to an array: */
-int NI_LineBufferToArray(NI_LineBuffer *buffer)
-{
-  double *pb = buffer->buffer_data;
-  char *pa;
-  maybelong jj, length = buffer->line_length;
-
-  pb += buffer->size1;
-  for(jj = 0; jj < buffer->buffer_lines; jj++) {
-    /* if all array lines are copied return: */
-    if (buffer->next_line == buffer->array_lines)
-      break;
-    pa = buffer->array_data;
-    /* copy data from the buffer to the array: */
-    switch (buffer->array_type) {
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Bool);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt8);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt16);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt32);
-#if HAS_UINT64
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt64);
-#endif
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int8);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int16);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int32);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int64);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float32);
-      CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float64);
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "array type not supported");
-      return 0;
-    }
-    /* move to the next line in the array: */
-    NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
-    /* number of lines copied: */
-    ++(buffer->next_line);
-    /* move the buffer data pointer to the next line: */
-    pb += buffer->line_length + buffer->size1 + buffer->size2;
-  }
-  return 1;
-}
-
-/******************************************************************/
-/* Multi-dimensional filter support functions */
-/******************************************************************/
-
-/* Initialize a filter iterator: */
-int
-NI_InitFilterIterator(int rank, maybelong *filter_shape,
-          maybelong filter_size, maybelong *array_shape,
-          maybelong *origins, NI_FilterIterator *iterator)
-{
-  int ii;
-  maybelong fshape[MAXDIM], forigins[MAXDIM];
-
-  for(ii = 0; ii < rank; ii++) {
-    fshape[ii] = *filter_shape++;
-    forigins[ii] = origins ? *origins++ : 0;
-  }
-  /* calculate the strides, used to move the offsets pointer through
-     the offsets table: */
-  if (rank > 0) {
-    iterator->strides[rank - 1] = filter_size;
-    for(ii = rank - 2; ii >= 0; ii--) {
-      maybelong step = array_shape[ii + 1] < fshape[ii + 1] ?
-                                     array_shape[ii + 1] : fshape[ii + 1];
-      iterator->strides[ii] =  iterator->strides[ii + 1] * step;
-    }
-  }
-  for(ii = 0; ii < rank; ii++) {
-    maybelong step = array_shape[ii] < fshape[ii] ?
-                                             array_shape[ii] : fshape[ii];
-    maybelong orgn = fshape[ii] / 2 + forigins[ii];
-    /* stride for stepping back to previous offsets: */
-    iterator->backstrides[ii] = (step - 1) * iterator->strides[ii];
-    /* initialize boundary extension sizes: */
-    iterator->bound1[ii] = orgn;
-    iterator->bound2[ii] = array_shape[ii] - fshape[ii] + orgn;
-  }
-  return 1;
-}
-
-/* Calculate the offsets to the filter points, for all border regions and
-   the interior of the array: */
-int NI_InitFilterOffsets(PyArrayObject *array, Bool *footprint,
-     maybelong *filter_shape, maybelong* origins,
-     NI_ExtendMode mode, maybelong **offsets, maybelong *border_flag_value,
-     maybelong **coordinate_offsets)
-{
-  int rank, ii;
-  maybelong kk, ll, filter_size = 1, offsets_size = 1, max_size = 0;
-  maybelong max_stride = 0, *ashape = NULL, *astrides = NULL;
-  maybelong footprint_size = 0, coordinates[MAXDIM], position[MAXDIM];
-  maybelong fshape[MAXDIM], forigins[MAXDIM], *po, *pc = NULL;
-
-  rank = array->nd;
-  ashape = array->dimensions;
-  astrides = array->strides;
-  for(ii = 0; ii < rank; ii++) {
-    fshape[ii] = *filter_shape++;
-    forigins[ii] = origins ? *origins++ : 0.0;
-  }
-  /* the size of the footprint array: */
-  for(ii = 0; ii < rank; ii++)
-    filter_size *= fshape[ii];
-  /* calculate the number of non-zero elements in the footprint: */
-  if (footprint) {
-    for(kk = 0; kk < filter_size; kk++)
-      if (footprint[kk])
-        ++footprint_size;
-  } else {
-    footprint_size = filter_size;
-  }
-  /* calculate how many sets of offsets must be stored: */
-  for(ii = 0; ii < rank; ii++)
-    offsets_size *= (ashape[ii] < fshape[ii] ? ashape[ii] : fshape[ii]);
-  /* allocate offsets data: */
-  *offsets = (maybelong*)malloc(offsets_size * footprint_size *
-                                                        sizeof(maybelong));
-  if (!*offsets) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  if (coordinate_offsets) {
-    *coordinate_offsets = (maybelong*)malloc(offsets_size * rank *
-                                       footprint_size * sizeof(maybelong));
-    if (!*coordinate_offsets) {
-      PyErr_NoMemory();
-      goto exit;
-    }
-  }
-  for(ii = 0; ii < rank; ii++) {
-    maybelong stride;
-    /* find maximum axis size: */
-    if (ashape[ii] > max_size)
-      max_size = ashape[ii];
-    /* find maximum stride: */
-    stride = astrides[ii] < 0 ? -astrides[ii] : astrides[ii];
-    if (stride > max_stride)
-      max_stride = stride;
-    /* coordinates for iterating over the kernel elements: */
-    coordinates[ii] = 0;
-    /* keep track of the kernel position: */
-    position[ii] = 0;
-  }
-  /* the flag to indicate that we are outside the border must have a
-     value that is larger than any possible offset: */
-  *border_flag_value = max_size * max_stride + 1;
-  /* calculate all possible offsets to elements in the filter kernel,
-     for all regions in the array (interior and border regions): */
-  po = *offsets;
-  if (coordinate_offsets) {
-    pc = *coordinate_offsets;
-  }
-  /* iterate over all regions: */
-  for(ll = 0; ll < offsets_size; ll++) {
-    /* iterate over the elements in the footprint array: */
-    for(kk = 0; kk < filter_size; kk++) {
-      maybelong offset = 0;
-      /* only calculate an offset if the footprint is 1: */
-      if (!footprint || footprint[kk]) {
-        /* find offsets along all axes: */
-        for(ii = 0; ii < rank; ii++) {
-          maybelong orgn = fshape[ii] / 2 + forigins[ii];
-          maybelong cc = coordinates[ii] - orgn + position[ii];
-          maybelong len = ashape[ii];
-          /* apply boundary conditions, if necessary: */
-          switch (mode) {
-          case NI_EXTEND_MIRROR:
-            if (cc < 0) {
-              if (len <= 1) {
-                cc = 0;
-              } else {
-                int sz2 = 2 * len - 2;
-                cc = sz2 * (int)(-cc / sz2) + cc;
-                cc = cc <= 1 - len ? cc + sz2 : -cc;
-              }
-            } else if (cc >= len) {
-              if (len <= 1) {
-                cc = 0;
-              } else {
-                int sz2 = 2 * len - 2;
-                cc -= sz2 * (int)(cc / sz2);
-                if (cc >= len)
-                  cc = sz2 - cc;
-              }
-            }
-            break;
-          case NI_EXTEND_REFLECT:
-            if (cc < 0) {
-              if (len <= 1) {
-                cc = 0;
-              } else {
-                int sz2 = 2 * len;
-                if (cc < -sz2)
-                  cc = sz2 * (int)(-cc / sz2) + cc;
-                cc = cc < -len ? cc + sz2 : -cc - 1;
-              }
-            } else if (cc >= len) {
-              if (len <= 1) {cc = 0;
-              } else {
-                int sz2 = 2 * len;
-                cc -= sz2 * (int)(cc / sz2);
-                if (cc >= len)
-                  cc = sz2 - cc - 1;
-              }
-            }
-            break;
-          case NI_EXTEND_WRAP:
-            if (cc < 0) {
-              if (len <= 1) {
-                cc = 0;
-              } else {
-                int sz = len;
-                cc += sz * (int)(-cc / sz);
-                if (cc < 0)
-                  cc += sz;
-              }
-            } else if (cc >= len) {
-              if (len <= 1) {
-                cc = 0;
-              } else {
-                int sz = len;
-                cc -= sz * (int)(cc / sz);
-              }
-            }
-            break;
-          case NI_EXTEND_NEAREST:
-            if (cc < 0) {
-              cc = 0;
-            } else if (cc >= len) {
-              cc = len - 1;
-            }
-            break;
-          case NI_EXTEND_CONSTANT:
-            if (cc < 0 || cc >= len)
-              cc = *border_flag_value;
-            break;
-          default:
-          PyErr_SetString(PyExc_RuntimeError,
-                                          "boundary mode not supported");
-            goto exit;
-          }
-
-          /* calculate offset along current axis: */
-          if (cc == *border_flag_value) {
-            /* just flag that we are outside the border */
-            offset = *border_flag_value;
-            if (coordinate_offsets)
-              pc[ii] = 0;
-            break;
-          } else {
-            /* use an offset that is possibly mapped from outside the
-               border: */
-            cc = cc - position[ii];
-            offset += astrides[ii] * cc;
-            if (coordinate_offsets)
-              pc[ii] = cc;
-          }
-        }
-        /* store the offset */
-        *po++ = offset;
-        if (coordinate_offsets)
-          pc += rank;
-      }
-      /* next point in the filter: */
-      for(ii = rank - 1; ii >= 0; ii--) {
-        if (coordinates[ii] < fshape[ii] - 1) {
-          coordinates[ii]++;
-          break;
-        } else {
-          coordinates[ii] = 0;
-        }
-      }
-    }
-
-    /* move to the next array region: */
-    for(ii = rank - 1; ii >= 0; ii--) {
-      int orgn = fshape[ii] / 2 + forigins[ii];
-      if (position[ii] == orgn) {
-        position[ii] += ashape[ii] - fshape[ii] + 1;
-        if (position[ii] <= orgn)
-          position[ii] = orgn + 1;
-      } else {
-        position[ii]++;
-      }
-      if (position[ii] < ashape[ii]) {
-        break;
-      } else {
-        position[ii] = 0;
-      }
-    }
-  }
-
- exit:
-  if (PyErr_Occurred()) {
-    if (*offsets)
-      free(*offsets);
-    if (coordinate_offsets && *coordinate_offsets)
-      free(*coordinate_offsets);
-    return 0;
-  } else {
-    return 1;
-  }
-}
-
-NI_CoordinateList* NI_InitCoordinateList(int size, int rank)
-{
-  NI_CoordinateList *list = \
-    (NI_CoordinateList*)malloc(sizeof(NI_CoordinateList));
-  if (!list) {
-    PyErr_NoMemory();
-    return NULL;
-  }
-  list->block_size = size;
-  list->rank = rank;
-  list->blocks = NULL;
-  return list;
-}
-
-int NI_CoordinateListStealBlocks(NI_CoordinateList *list1,
-                                 NI_CoordinateList *list2)
-{
-  if (list1->block_size != list2->block_size ||
-      list1->rank != list2->rank) {
-    PyErr_SetString(PyExc_RuntimeError, "coordinate lists not compatible");
-    return 1;
-  }
-  if (list1->blocks) {
-    PyErr_SetString(PyExc_RuntimeError, "first is list not empty");
-    return 1;
-  }
-  list1->blocks = list2->blocks;
-  list2->blocks = NULL;
-  return 0;
-}
-
-NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList *list)
-{
-  NI_CoordinateBlock* block = NULL;
-  block = (NI_CoordinateBlock*)malloc(sizeof(NI_CoordinateBlock));
-  if (!block) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  block->coordinates = (maybelong*)malloc(list->block_size * list->rank *
-					  sizeof(maybelong));
-  if (!block->coordinates) {
-    PyErr_NoMemory();
-    goto exit;
-  }
-  block->next = list->blocks;
-  list->blocks = block;
-  block->size = 0;
-
-exit:
-  if (PyErr_Occurred()) {
-    if (block)
-      free(block);
-    return NULL;
-  }
-  return block;
-}
-
-NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList *list)
-{
-  NI_CoordinateBlock* block = list->blocks;
-  if (block) {
-    list->blocks = block->next;
-    if (block->coordinates)
-      free(block->coordinates);
-    free(block);
-  }
-  return list->blocks;
-}
-
-void NI_FreeCoordinateList(NI_CoordinateList *list)
-{
-  if (list) {
-    NI_CoordinateBlock *block = list->blocks;
-    while (block) {
-      NI_CoordinateBlock *tmp = block;
-      block = block->next;
-      if (tmp->coordinates)
-        free(tmp->coordinates);
-      free(tmp);
-    }
-    list->blocks = NULL;
-    free(list);
-  }
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ni_support.h"
+
+/* initialize iterations over single array elements: */
+int NI_InitPointIterator(PyArrayObject *array, NI_Iterator *iterator)
+{
+    int ii;
+
+    iterator->rank_m1 = array->nd - 1;
+    for(ii = 0; ii < array->nd; ii++) {
+        /* adapt dimensions for use in the macros: */
+        iterator->dimensions[ii] = array->dimensions[ii] - 1;
+        /* initialize coordinates: */
+        iterator->coordinates[ii] = 0;
+        /* initialize strides: */
+        iterator->strides[ii] = array->strides[ii];
+        /* calculate the strides to move back at the end of an axis: */
+        iterator->backstrides[ii] =
+                array->strides[ii] * iterator->dimensions[ii];
+    }
+    return 1;
+}
+
+
+/* initialize iteration over a lower sub-space: */
+int NI_SubspaceIterator(NI_Iterator *iterator, UInt32 axes)
+{
+    int ii, last = 0;
+
+    for(ii = 0; ii <= iterator->rank_m1; ii++) {
+        if (axes & (((UInt32)1) << ii)) {
+            if (last != ii) {
+                iterator->dimensions[last] = iterator->dimensions[ii];
+                iterator->strides[last] = iterator->strides[ii];
+                iterator->backstrides[last] = iterator->backstrides[ii];
+            }
+            ++last;
+        }
+    }
+    iterator->rank_m1 = last - 1;
+    return 1;
+}
+
+/* initialize iteration over array lines: */
+int NI_LineIterator(NI_Iterator *iterator, int axis)
+{
+    UInt32 axes = ((UInt32)1) << axis;
+    return NI_SubspaceIterator(iterator, ~axes);
+}
+
+
+/******************************************************************/
+/* Line buffers */
+/******************************************************************/
+
+/* Allocate line buffer data */
+int NI_AllocateLineBuffer(PyArrayObject* array, int axis, maybelong size1,
+        maybelong size2, maybelong *lines, maybelong max_size, double **buffer)
+{
+    maybelong line_size, max_lines;
+    int ii;
+
+    /* the number of lines of the array is an upper limit for the
+         number of lines in the buffer: */
+    max_lines = 1;
+    for(ii = 0; ii < array->nd; ii++)
+        max_lines *= array->dimensions[ii];
+    if (array->nd > 0 && array->dimensions[axis] > 0)
+        max_lines /= array->dimensions[axis];
+    /* calculate the space needed for one line, including space to
+         support the boundary conditions: */
+    line_size = sizeof(double) * (array->dimensions[axis] + size1 + size2);
+    /* if *lines < 1, no number of lines is proposed, so we calculate it
+         from the maximum size allowed: */
+    if (*lines < 1) {
+        *lines = line_size > 0 ? max_size / line_size : 0;
+        if (*lines < 1)
+            *lines = 1;
+    }
+    /* no need to allocate too many lines: */
+    if (*lines > max_lines)
+        *lines = max_lines;
+    /* allocate data for the buffer: */
+    *buffer = (double*)malloc(*lines * line_size);
+    if (!*buffer) {
+        PyErr_NoMemory();
+        return 0;
+    }
+    return 1;
+}
+
+/* Initialize a line buffer */
+int NI_InitLineBuffer(PyArrayObject *array, int axis, maybelong size1,
+        maybelong size2, maybelong buffer_lines, double *buffer_data,
+        NI_ExtendMode extend_mode, double extend_value, NI_LineBuffer *buffer)
+{
+    maybelong line_length = 0, array_lines = 0, size;
+    int ii;
+
+    size = 1;
+    for(ii = 0; ii < array->nd; ii++)
+        size *= array->dimensions[ii];
+    /* check if the buffer is big enough: */
+    if (size > 0 && buffer_lines < 1) {
+        PyErr_SetString(PyExc_RuntimeError, "buffer too small");
+        return 0;
+    }
+    /* Initialize a line iterator to move over the array: */
+    if (!NI_InitPointIterator(array, &(buffer->iterator)))
+        return 0;
+    if (!NI_LineIterator(&(buffer->iterator), axis))
+        return 0;
+    line_length = array->nd > 0 ? array->dimensions[axis] : 1;
+    if (line_length > 0)
+        array_lines = line_length > 0 ? size / line_length : 1;
+    /* initialize the buffer structure: */
+    buffer->array_data = (void *)PyArray_DATA(array);
+    buffer->buffer_data = buffer_data;
+    buffer->buffer_lines = buffer_lines;
+    buffer->array_type = array->descr->type_num;
+    buffer->array_lines = array_lines;
+    buffer->next_line = 0;
+    buffer->size1 = size1;
+    buffer->size2 = size2;
+    buffer->line_length = line_length;
+    buffer->line_stride = array->nd > 0 ? array->strides[axis] : 0;
+    buffer->extend_mode = extend_mode;
+    buffer->extend_value = extend_value;
+    return 1;
+}
+
+/* Extend a line in memory to implement boundary conditions: */
+int NI_ExtendLine(double *line, maybelong length, maybelong size1,
+                                maybelong size2, NI_ExtendMode mode, double constant_value)
+{
+    maybelong ii, jj, length1, nextend, rextend;
+    double *l1, *l2, *l3, val;
+
+    switch (mode) {
+    case NI_EXTEND_WRAP:
+        nextend = size1 / length;
+        rextend = size1 - nextend * length;
+        l1 = line + size1 + length - rextend;
+        l2 = line;
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1++;
+        for(ii = 0; ii < nextend; ii++) {
+            l1 = line + size1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l1++;
+        }
+        nextend = size2 / length;
+        rextend = size2 - nextend * length;
+        l1 = line + size1;
+        l2 = line + size1 + length;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l3++;
+        }
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1++;
+        break;
+    case NI_EXTEND_MIRROR:
+        if (length == 1) {
+            l1 = line;
+            val = line[size1];
+            for(ii = 0; ii < size1; ii++)
+                *l1++ = val;
+            l1 = line + size1 + length;
+            val = line[size1 + length - 1];
+            for(ii = 0; ii < size2; ii++)
+                *l1++ = val;
+        } else {
+            length1 = length - 1;
+            nextend = size1 / length1;
+            rextend = size1 - nextend * length1;
+            l1 = line + size1 + 1;
+            l2 = l1 - 2;
+            for(ii = 0; ii < nextend; ii++) {
+                l3 = l1;
+                for(jj = 0; jj < length1; jj++)
+                    *l2-- = *l3++;
+                l1 -= length1;
+            }
+            for(ii = 0; ii < rextend; ii++)
+                *l2-- = *l1++;
+            nextend = size2 / length1;
+            rextend = size2 - nextend * length1;
+            l1 = line + size1 + length1 - 1;
+            l2 = l1 + 2;
+            for(ii = 0; ii < nextend; ii++) {
+                l3 = l1;
+                for(jj = 0; jj < length1; jj++)
+                    *l2++ = *l3--;
+                l1 += length1;
+            }
+            for(ii = 0; ii < rextend; ii++)
+                *l2++ = *l1--;
+        }
+        break;
+    case NI_EXTEND_REFLECT:
+        nextend = size1 / length;
+        rextend = size1 - nextend * length;
+        l1 = line + size1;
+        l2 = l1 - 1;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2-- = *l3++;
+            l1 -= length;
+        }
+        l3 = l1;
+        for(ii = 0; ii < rextend; ii++)
+            *l2-- = *l3++;
+        nextend = size2 / length;
+        rextend = size2 - nextend * length;
+        l1 = line + size1 + length - 1;
+        l2 = l1 + 1;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l3--;
+            l1 += length;
+        }
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1--;
+        break;
+    case NI_EXTEND_NEAREST:
+        l1 = line;
+        val = line[size1];
+        for(ii = 0; ii < size1; ii++)
+            *l1++ = val;
+        l1 = line + size1 + length;
+        val = line[size1 + length - 1];
+        for(ii = 0; ii < size2; ii++)
+            *l1++ = val;
+        break;
+    case NI_EXTEND_CONSTANT:
+        l1 = line;
+        for(ii = 0; ii < size1; ii++)
+            *l1++ = constant_value;
+        l1 = line + size1 + length;
+        for(ii = 0; ii < size2; ii++)
+            *l1++ = constant_value;
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError, "mode not supported");
+        return 0;
+    }
+    return 1;
+}
+
+
+#define CASE_COPY_DATA_TO_LINE(_pi, _po, _length, _stride, _type) \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii;                                                  \
+    for(_ii = 0; _ii < _length; _ii++) {                            \
+        _po[_ii] = (double)*(_type*)_pi;                              \
+        _pi += _stride;                                               \
+    }                                                               \
+}                                                                 \
+break
+
+
+/* Copy a line from an array to a buffer: */
+int NI_ArrayToLineBuffer(NI_LineBuffer *buffer,
+                                                 maybelong *number_of_lines, int *more)
+{
+    double *pb = buffer->buffer_data;
+    char *pa;
+    maybelong length = buffer->line_length;
+
+    pb += buffer->size1;
+    *number_of_lines = 0;
+    /* fill until all lines in the array have been processed, or until
+         the buffer is full: */
+    while (buffer->next_line < buffer->array_lines &&
+                 *number_of_lines < buffer->buffer_lines) {
+        pa = buffer->array_data;
+        /* copy the data from the array to the buffer: */
+        switch (buffer->array_type) {
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Bool);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt8);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt16);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt32);
+#if HAS_UINT64
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt64);
+#endif
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int8);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int16);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int32);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int64);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float32);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float64);
+        default:
+            PyErr_Format(PyExc_RuntimeError, "array type %d not supported", buffer->array_type);
+            return 0;
+        }
+        /* goto next line in the array: */
+        NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
+        /* implement boundary conditions to the line: */
+        if (buffer->size1 + buffer->size2 > 0)
+            if (!NI_ExtendLine(pb - buffer->size1, length, buffer->size1,
+                                                 buffer->size2, buffer->extend_mode,
+                                                 buffer->extend_value))
+                return 0;
+        /* The number of the array lines copied: */
+        ++(buffer->next_line);
+        /* keep track of (and return) the number of lines in the buffer: */
+        ++(*number_of_lines);
+        pb += buffer->line_length + buffer->size1 + buffer->size2;
+    }
+    /* if not all array lines were processed, *more is set true: */
+    *more = buffer->next_line < buffer->array_lines;
+    return 1;
+}
+
+#define CASE_COPY_LINE_TO_DATA(_pi, _po, _length, _stride, _type) \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii;                                                  \
+    for(_ii = 0; _ii < _length; _ii++) {                            \
+        *(_type*)_po = (_type)_pi[_ii];                               \
+        _po += _stride;                                               \
+    }                                                               \
+}                                                                 \
+break
+
+/* Copy a line from a buffer to an array: */
+int NI_LineBufferToArray(NI_LineBuffer *buffer)
+{
+    double *pb = buffer->buffer_data;
+    char *pa;
+    maybelong jj, length = buffer->line_length;
+
+    pb += buffer->size1;
+    for(jj = 0; jj < buffer->buffer_lines; jj++) {
+        /* if all array lines are copied return: */
+        if (buffer->next_line == buffer->array_lines)
+            break;
+        pa = buffer->array_data;
+        /* copy data from the buffer to the array: */
+        switch (buffer->array_type) {
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Bool);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt8);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt16);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt32);
+#if HAS_UINT64
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt64);
+#endif
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int8);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int16);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int32);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int64);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float32);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            return 0;
+        }
+        /* move to the next line in the array: */
+        NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
+        /* number of lines copied: */
+        ++(buffer->next_line);
+        /* move the buffer data pointer to the next line: */
+        pb += buffer->line_length + buffer->size1 + buffer->size2;
+    }
+    return 1;
+}
+
+/******************************************************************/
+/* Multi-dimensional filter support functions */
+/******************************************************************/
+
+/* Initialize a filter iterator: */
+int
+NI_InitFilterIterator(int rank, maybelong *filter_shape,
+                    maybelong filter_size, maybelong *array_shape,
+                    maybelong *origins, NI_FilterIterator *iterator)
+{
+    int ii;
+    maybelong fshape[MAXDIM], forigins[MAXDIM];
+
+    for(ii = 0; ii < rank; ii++) {
+        fshape[ii] = *filter_shape++;
+        forigins[ii] = origins ? *origins++ : 0;
+    }
+    /* calculate the strides, used to move the offsets pointer through
+         the offsets table: */
+    if (rank > 0) {
+        iterator->strides[rank - 1] = filter_size;
+        for(ii = rank - 2; ii >= 0; ii--) {
+            maybelong step = array_shape[ii + 1] < fshape[ii + 1] ?
+                                                                         array_shape[ii + 1] : fshape[ii + 1];
+            iterator->strides[ii] =  iterator->strides[ii + 1] * step;
+        }
+    }
+    for(ii = 0; ii < rank; ii++) {
+        maybelong step = array_shape[ii] < fshape[ii] ?
+                                                                                         array_shape[ii] : fshape[ii];
+        maybelong orgn = fshape[ii] / 2 + forigins[ii];
+        /* stride for stepping back to previous offsets: */
+        iterator->backstrides[ii] = (step - 1) * iterator->strides[ii];
+        /* initialize boundary extension sizes: */
+        iterator->bound1[ii] = orgn;
+        iterator->bound2[ii] = array_shape[ii] - fshape[ii] + orgn;
+    }
+    return 1;
+}
+
+/* Calculate the offsets to the filter points, for all border regions and
+     the interior of the array: */
+int NI_InitFilterOffsets(PyArrayObject *array, Bool *footprint,
+         maybelong *filter_shape, maybelong* origins,
+         NI_ExtendMode mode, maybelong **offsets, maybelong *border_flag_value,
+         maybelong **coordinate_offsets)
+{
+    int rank, ii;
+    maybelong kk, ll, filter_size = 1, offsets_size = 1, max_size = 0;
+    maybelong max_stride = 0, *ashape = NULL, *astrides = NULL;
+    maybelong footprint_size = 0, coordinates[MAXDIM], position[MAXDIM];
+    maybelong fshape[MAXDIM], forigins[MAXDIM], *po, *pc = NULL;
+
+    rank = array->nd;
+    ashape = array->dimensions;
+    astrides = array->strides;
+    for(ii = 0; ii < rank; ii++) {
+        fshape[ii] = *filter_shape++;
+        forigins[ii] = origins ? *origins++ : 0.0;
+    }
+    /* the size of the footprint array: */
+    for(ii = 0; ii < rank; ii++)
+        filter_size *= fshape[ii];
+    /* calculate the number of non-zero elements in the footprint: */
+    if (footprint) {
+        for(kk = 0; kk < filter_size; kk++)
+            if (footprint[kk])
+                ++footprint_size;
+    } else {
+        footprint_size = filter_size;
+    }
+    /* calculate how many sets of offsets must be stored: */
+    for(ii = 0; ii < rank; ii++)
+        offsets_size *= (ashape[ii] < fshape[ii] ? ashape[ii] : fshape[ii]);
+    /* allocate offsets data: */
+    *offsets = (maybelong*)malloc(offsets_size * footprint_size *
+                                                                                                                sizeof(maybelong));
+    if (!*offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    if (coordinate_offsets) {
+        *coordinate_offsets = (maybelong*)malloc(offsets_size * rank *
+                                                                             footprint_size * sizeof(maybelong));
+        if (!*coordinate_offsets) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    for(ii = 0; ii < rank; ii++) {
+        maybelong stride;
+        /* find maximum axis size: */
+        if (ashape[ii] > max_size)
+            max_size = ashape[ii];
+        /* find maximum stride: */
+        stride = astrides[ii] < 0 ? -astrides[ii] : astrides[ii];
+        if (stride > max_stride)
+            max_stride = stride;
+        /* coordinates for iterating over the kernel elements: */
+        coordinates[ii] = 0;
+        /* keep track of the kernel position: */
+        position[ii] = 0;
+    }
+    /* the flag to indicate that we are outside the border must have a
+         value that is larger than any possible offset: */
+    *border_flag_value = max_size * max_stride + 1;
+    /* calculate all possible offsets to elements in the filter kernel,
+         for all regions in the array (interior and border regions): */
+    po = *offsets;
+    if (coordinate_offsets) {
+        pc = *coordinate_offsets;
+    }
+    /* iterate over all regions: */
+    for(ll = 0; ll < offsets_size; ll++) {
+        /* iterate over the elements in the footprint array: */
+        for(kk = 0; kk < filter_size; kk++) {
+            maybelong offset = 0;
+            /* only calculate an offset if the footprint is 1: */
+            if (!footprint || footprint[kk]) {
+                /* find offsets along all axes: */
+                for(ii = 0; ii < rank; ii++) {
+                    maybelong orgn = fshape[ii] / 2 + forigins[ii];
+                    maybelong cc = coordinates[ii] - orgn + position[ii];
+                    maybelong len = ashape[ii];
+                    /* apply boundary conditions, if necessary: */
+                    switch (mode) {
+                    case NI_EXTEND_MIRROR:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len - 2;
+                                cc = sz2 * (int)(-cc / sz2) + cc;
+                                cc = cc <= 1 - len ? cc + sz2 : -cc;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len - 2;
+                                cc -= sz2 * (int)(cc / sz2);
+                                if (cc >= len)
+                                    cc = sz2 - cc;
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_REFLECT:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len;
+                                if (cc < -sz2)
+                                    cc = sz2 * (int)(-cc / sz2) + cc;
+                                cc = cc < -len ? cc + sz2 : -cc - 1;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {cc = 0;
+                            } else {
+                                int sz2 = 2 * len;
+                                cc -= sz2 * (int)(cc / sz2);
+                                if (cc >= len)
+                                    cc = sz2 - cc - 1;
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_WRAP:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz = len;
+                                cc += sz * (int)(-cc / sz);
+                                if (cc < 0)
+                                    cc += sz;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz = len;
+                                cc -= sz * (int)(cc / sz);
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_NEAREST:
+                        if (cc < 0) {
+                            cc = 0;
+                        } else if (cc >= len) {
+                            cc = len - 1;
+                        }
+                        break;
+                    case NI_EXTEND_CONSTANT:
+                        if (cc < 0 || cc >= len)
+                            cc = *border_flag_value;
+                        break;
+                    default:
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                                                    "boundary mode not supported");
+                        goto exit;
+                    }
+
+                    /* calculate offset along current axis: */
+                    if (cc == *border_flag_value) {
+                        /* just flag that we are outside the border */
+                        offset = *border_flag_value;
+                        if (coordinate_offsets)
+                            pc[ii] = 0;
+                        break;
+                    } else {
+                        /* use an offset that is possibly mapped from outside the
+                             border: */
+                        cc = cc - position[ii];
+                        offset += astrides[ii] * cc;
+                        if (coordinate_offsets)
+                            pc[ii] = cc;
+                    }
+                }
+                /* store the offset */
+                *po++ = offset;
+                if (coordinate_offsets)
+                    pc += rank;
+            }
+            /* next point in the filter: */
+            for(ii = rank - 1; ii >= 0; ii--) {
+                if (coordinates[ii] < fshape[ii] - 1) {
+                    coordinates[ii]++;
+                    break;
+                } else {
+                    coordinates[ii] = 0;
+                }
+            }
+        }
+
+        /* move to the next array region: */
+        for(ii = rank - 1; ii >= 0; ii--) {
+            int orgn = fshape[ii] / 2 + forigins[ii];
+            if (position[ii] == orgn) {
+                position[ii] += ashape[ii] - fshape[ii] + 1;
+                if (position[ii] <= orgn)
+                    position[ii] = orgn + 1;
+            } else {
+                position[ii]++;
+            }
+            if (position[ii] < ashape[ii]) {
+                break;
+            } else {
+                position[ii] = 0;
+            }
+        }
+    }
+
+ exit:
+    if (PyErr_Occurred()) {
+        if (*offsets)
+            free(*offsets);
+        if (coordinate_offsets && *coordinate_offsets)
+            free(*coordinate_offsets);
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+NI_CoordinateList* NI_InitCoordinateList(int size, int rank)
+{
+    NI_CoordinateList *list = \
+        (NI_CoordinateList*)malloc(sizeof(NI_CoordinateList));
+    if (!list) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    list->block_size = size;
+    list->rank = rank;
+    list->blocks = NULL;
+    return list;
+}
+
+int NI_CoordinateListStealBlocks(NI_CoordinateList *list1,
+                                                                 NI_CoordinateList *list2)
+{
+    if (list1->block_size != list2->block_size ||
+            list1->rank != list2->rank) {
+        PyErr_SetString(PyExc_RuntimeError, "coordinate lists not compatible");
+        return 1;
+    }
+    if (list1->blocks) {
+        PyErr_SetString(PyExc_RuntimeError, "first is list not empty");
+        return 1;
+    }
+    list1->blocks = list2->blocks;
+    list2->blocks = NULL;
+    return 0;
+}
+
+NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList *list)
+{
+    NI_CoordinateBlock* block = NULL;
+    block = (NI_CoordinateBlock*)malloc(sizeof(NI_CoordinateBlock));
+    if (!block) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    block->coordinates = (maybelong*)malloc(list->block_size * list->rank *
+					  sizeof(maybelong));
+    if (!block->coordinates) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    block->next = list->blocks;
+    list->blocks = block;
+    block->size = 0;
+
+exit:
+    if (PyErr_Occurred()) {
+        if (block)
+            free(block);
+        return NULL;
+    }
+    return block;
+}
+
+NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList *list)
+{
+    NI_CoordinateBlock* block = list->blocks;
+    if (block) {
+        list->blocks = block->next;
+        if (block->coordinates)
+            free(block->coordinates);
+        free(block);
+    }
+    return list->blocks;
+}
+
+void NI_FreeCoordinateList(NI_CoordinateList *list)
+{
+    if (list) {
+        NI_CoordinateBlock *block = list->blocks;
+        while (block) {
+            NI_CoordinateBlock *tmp = block;
+            block = block->next;
+            if (tmp->coordinates)
+                free(tmp->coordinates);
+            free(tmp);
+        }
+        list->blocks = NULL;
+        free(list);
+    }
+}

Modified: trunk/scipy/ndimage/src/ni_support.h
===================================================================
--- trunk/scipy/ndimage/src/ni_support.h	2008-07-24 21:13:18 UTC (rev 4561)
+++ trunk/scipy/ndimage/src/ni_support.h	2008-07-25 16:26:25 UTC (rev 4562)
@@ -1,323 +1,323 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef NI_SUPPORT_H
-#define NI_SUPPORT_H
-
-#include "nd_image.h"
-#include <stdlib.h>
-#include <float.h>
-#include <limits.h>
-#include <assert.h>
-
-/* The different boundary conditions. The mirror condition is not used
-   by the python code, but C code is kept around in case we might wish
-   to add it. */
-typedef enum {
-  NI_EXTEND_FIRST = 0,
-  NI_EXTEND_NEAREST = 0,
-  NI_EXTEND_WRAP = 1,
-  NI_EXTEND_REFLECT = 2,
-  NI_EXTEND_MIRROR = 3,
-  NI_EXTEND_CONSTANT = 4,
-  NI_EXTEND_LAST = NI_EXTEND_CONSTANT,
-  NI_EXTEND_DEFAULT = NI_EXTEND_MIRROR
-} NI_ExtendMode;
-
-/******************************************************************/
-/* Iterators */
-/******************************************************************/
-
-/******************************************************************/
-/* Iterators */
-/******************************************************************/
-
-/* the iterator structure: */
-typedef struct {
-  int rank_m1;
-  maybelong dimensions[MAXDIM];
-  maybelong coordinates[MAXDIM];
-  maybelong strides[MAXDIM];
-  maybelong backstrides[MAXDIM];
-} NI_Iterator;
-
-/* initialize iterations over single array elements: */
-int NI_InitPointIterator(PyArrayObject*, NI_Iterator*);
-
-/* initialize iterations over an arbritrary sub-space: */
-int NI_SubspaceIterator(NI_Iterator*, UInt32);
-
-/* initialize iteration over array lines: */
-int NI_LineIterator(NI_Iterator*, int);
-
-/* reset an iterator */
-#define NI_ITERATOR_RESET(iterator)              \
-{                                                \
-  int _ii;                                       \
-  for(_ii = 0; _ii <= (iterator).rank_m1; _ii++) \
-    (iterator).coordinates[_ii] = 0;             \
-}
-
-/* go to the next point in a single array */
-#define NI_ITERATOR_NEXT(iterator, pointer)                         \
-{                                                                   \
-  int _ii;                                                          \
-  for(_ii = (iterator).rank_m1; _ii >= 0; _ii--)                    \
-    if ((iterator).coordinates[_ii] < (iterator).dimensions[_ii]) { \
-      (iterator).coordinates[_ii]++;                                \
-      pointer += (iterator).strides[_ii];                           \
-      break;                                                        \
-    } else {                                                        \
-      (iterator).coordinates[_ii] = 0;                              \
-      pointer -= (iterator).backstrides[_ii];                       \
-    }                                                               \
-}
-
-/* go to the next point in two arrays of the same size */
-#define NI_ITERATOR_NEXT2(iterator1, iterator2,  pointer1, pointer2)  \
-{                                                                     \
-  int _ii;                                                            \
-  for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
-    if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
-      (iterator1).coordinates[_ii]++;                                 \
-      pointer1 += (iterator1).strides[_ii];                           \
-      pointer2 += (iterator2).strides[_ii];                           \
-      break;                                                          \
-    } else {                                                          \
-      (iterator1).coordinates[_ii] = 0;                               \
-      pointer1 -= (iterator1).backstrides[_ii];                       \
-      pointer2 -= (iterator2).backstrides[_ii];                       \
-    }                                                                 \
-}
-
-/* go to the next point in three arrays of the same size */
-#define NI_ITERATOR_NEXT3(iterator1, iterator2,  iterator3,           \
-                          pointer1, pointer2, pointer3)               \
-{                                                                     \
-  int _ii;                                                            \
-  for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
-    if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
-      (iterator1).coordinates[_ii]++;                                 \
-      pointer1 += (iterator1).strides[_ii];                           \
-      pointer2 += (iterator2).strides[_ii];                           \
-      pointer3 += (iterator3).strides[_ii];                           \
-      break;                                                          \
-    } else {                                                          \
-      (iterator1).coordinates[_ii] = 0;                               \
-      pointer1 -= (iterator1).backstrides[_ii];                       \
-      pointer2 -= (iterator2).backstrides[_ii];                       \
-      pointer3 -= (iterator3).backstrides[_ii];                       \
-    }                                                                 \
-}
-
-/* go to an arbitrary point in a single array */
-#define NI_ITERATOR_GOTO(iterator, destination, base, pointer) \
-{                                                              \
-  int _ii;                                                     \
-  pointer = base;                                              \
-  for(_ii = (iterator).rank_m1; _ii >= 0; _ii--) {             \
-    pointer += destination[_ii] * (iterator).strides[_ii];     \
-    (iterator).coordinates[_ii] = destination[_ii];            \
-  }                                                            \
-}
-
-/******************************************************************/
-/* Line buffers */
-/******************************************************************/
-
-/* the linebuffer structure: */
-typedef struct {
-  double *buffer_data;
-  maybelong buffer_lines, line_length, line_stride;
-  maybelong size1, size2, array_lines, next_line;
-  NI_Iterator iterator;
-  char* array_data;
-  NumarrayType array_type;
-  NI_ExtendMode extend_mode;
-  double extend_value;
-} NI_LineBuffer;
-
-/* Get the next line being processed: */
-#define NI_GET_LINE(_buffer, _line)                                      \
-  ((_buffer).buffer_data + (_line) * ((_buffer).line_length +            \
-                                      (_buffer).size1 + (_buffer).size2))
-/* Allocate line buffer data */
-int NI_AllocateLineBuffer(PyArrayObject*, int, maybelong, maybelong,
-                          maybelong*, maybelong, double**);
-
-/* Initialize a line buffer */
-int NI_InitLineBuffer(PyArrayObject*, int, maybelong, maybelong, maybelong,
-                      double*, NI_ExtendMode, double, NI_LineBuffer*);
-
-/* Extend a line in memory to implement boundary conditions: */
-int NI_ExtendLine(double*, maybelong, maybelong, maybelong, NI_ExtendMode, double);
-
-/* Copy a line from an array to a buffer: */
-int NI_ArrayToLineBuffer(NI_LineBuffer*, maybelong*, int*);
-
-/* Copy a line from a buffer to an array: */
-int NI_LineBufferToArray(NI_LineBuffer*);
-
-/******************************************************************/
-/* Multi-dimensional filter support functions */
-/******************************************************************/
-
-/* the filter iterator structure: */
-typedef struct {
-  maybelong strides[MAXDIM], backstrides[MAXDIM];
-  maybelong bound1[MAXDIM], bound2[MAXDIM];
-} NI_FilterIterator;
-
-/* Initialize a filter iterator: */
-int NI_InitFilterIterator(int, maybelong*, maybelong, maybelong*,
-                                          maybelong*, NI_FilterIterator*);
-
-/* Calculate the offsets to the filter points, for all border regions and
-   the interior of the array: */
-int NI_InitFilterOffsets(PyArrayObject*, Bool*, maybelong*,
-          maybelong*, NI_ExtendMode, maybelong**, maybelong*, maybelong**);
-
-/* Move to the next point in an array, possible changing the filter
-   offsets, to adapt to boundary conditions: */
-#define NI_FILTER_NEXT(iteratorf, iterator1, pointerf, pointer1)  \
-{                                                                 \
-  int _ii;                                                        \
-  for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {               \
-    maybelong _pp = (iterator1).coordinates[_ii];                 \
-    if (_pp < (iterator1).dimensions[_ii]) {                      \
-      if (_pp < (iteratorf).bound1[_ii] ||                        \
-                                  _pp >= (iteratorf).bound2[_ii]) \
-        pointerf += (iteratorf).strides[_ii];                     \
-      (iterator1).coordinates[_ii]++;                             \
-      pointer1 += (iterator1).strides[_ii];                       \
-      break;                                                      \
-    } else {                                                      \
-      (iterator1).coordinates[_ii] = 0;                           \
-      pointer1 -= (iterator1).backstrides[_ii];                   \
-      pointerf -= (iteratorf).backstrides[_ii];                   \
-    }                                                             \
-  }                                                               \
-}
-
-/* Move to the next point in two arrays, possible changing the pointer
-   to the filter offsets when moving into a different region in the
-   array: */
-#define NI_FILTER_NEXT2(iteratorf, iterator1, iterator2,    \
-                        pointerf, pointer1, pointer2)       \
-{                                                           \
-  int _ii;                                                  \
-  for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {         \
-    maybelong _pp = (iterator1).coordinates[_ii];           \
-    if (_pp < (iterator1).dimensions[_ii]) {                \
-      if (_pp < (iteratorf).bound1[_ii] ||                  \
-                            _pp >= (iteratorf).bound2[_ii]) \
-        pointerf += (iteratorf).strides[_ii];               \
-      (iterator1).coordinates[_ii]++;                       \
-      pointer1 += (iterator1).strides[_ii];                 \
-      pointer2 += (iterator2).strides[_ii];                 \
-      break;                                                \
-    } else {                                                \
-      (iterator1).coordinates[_ii] = 0;                     \
-      pointer1 -= (iterator1).backstrides[_ii];             \
-      pointer2 -= (iterator2).backstrides[_ii];             \
-      pointerf -= (iteratorf).backstrides[_ii];             \
-    }                                                       \
-  }                                                         \
-}
-
-/* Move to the next point in three arrays, possible changing the pointer
-   to the filter offsets when moving into a different region in the
-   array: */
-#define NI_FILTER_NEXT3(iteratorf, iterator1, iterator2, iterator3,  \
-                        pointerf, pointer1, pointer2, pointer3)      \
-{                                                                    \
-  int _ii;                                                           \
-  for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {                  \
-    maybelong _pp = (iterator1).coordinates[_ii];                    \
-    if (_pp < (iterator1).dimensions[_ii]) {                         \
-      if (_pp < (iteratorf).bound1[_ii] ||                           \
-                                     _pp >= (iteratorf).bound2[_ii]) \
-        pointerf += (iteratorf).strides[_ii];                        \
-      (iterator1).coordinates[_ii]++;                                \
-      pointer1 += (iterator1).strides[_ii];                          \
-      pointer2 += (iterator2).strides[_ii];                          \
-      pointer3 += (iterator3).strides[_ii];                          \
-      break;                                                         \
-    } else {                                                         \
-      (iterator1).coordinates[_ii] = 0;                              \
-      pointer1 -= (iterator1).backstrides[_ii];                      \
-      pointer2 -= (iterator2).backstrides[_ii];                      \
-      pointer3 -= (iterator3).backstrides[_ii];                      \
-      pointerf -= (iteratorf).backstrides[_ii];                      \
-    }                                                                \
-  }                                                                  \
-}
-
-/* Move the pointer to the filter offsets according to the given
-  coordinates: */
-#define NI_FILTER_GOTO(iteratorf, iterator, fbase, pointerf) \
-{                                                            \
-  int _ii;                                                   \
-  maybelong _jj;                                             \
-  pointerf = fbase;                                          \
-  for(_ii = iterator.rank_m1; _ii >= 0; _ii--) {             \
-    maybelong _pp = iterator.coordinates[_ii];               \
-    maybelong b1 = (iteratorf).bound1[_ii];                  \
-    maybelong b2 = (iteratorf).bound2[_ii];                  \
-    if (_pp < b1) {                                          \
-        _jj = _pp;                                           \
-    } else if (_pp > b2 && b2 >= b1) {                       \
-        _jj = _pp + b1 - b2;                                 \
-    } else {                                                 \
-        _jj = b1;                                            \
-    }                                                        \
-    pointerf += (iteratorf).strides[_ii] * _jj;              \
-  }                                                          \
-}
-
-typedef struct {
-    maybelong *coordinates;
-    int size;
-    void *next;
-} NI_CoordinateBlock;
-
-typedef struct {
-    int block_size, rank;
-    void *blocks;
-} NI_CoordinateList;
-
-NI_CoordinateList* NI_InitCoordinateList(int, int);
-int NI_CoordinateListStealBlocks(NI_CoordinateList*, NI_CoordinateList*);
-NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList*);
-NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList*);
-void NI_FreeCoordinateList(NI_CoordinateList*);
-
-#endif
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NI_SUPPORT_H
+#define NI_SUPPORT_H
+
+#include "nd_image.h"
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <assert.h>
+
+/* The different boundary conditions. The mirror condition is not used
+     by the python code, but C code is kept around in case we might wish
+     to add it. */
+typedef enum {
+    NI_EXTEND_FIRST = 0,
+    NI_EXTEND_NEAREST = 0,
+    NI_EXTEND_WRAP = 1,
+    NI_EXTEND_REFLECT = 2,
+    NI_EXTEND_MIRROR = 3,
+    NI_EXTEND_CONSTANT = 4,
+    NI_EXTEND_LAST = NI_EXTEND_CONSTANT,
+    NI_EXTEND_DEFAULT = NI_EXTEND_MIRROR
+} NI_ExtendMode;
+
+/******************************************************************/
+/* Iterators */
+/******************************************************************/
+
+/******************************************************************/
+/* Iterators */
+/******************************************************************/
+
+/* the iterator structure: */
+typedef struct {
+    int rank_m1;
+    maybelong dimensions[MAXDIM];
+    maybelong coordinates[MAXDIM];
+    maybelong strides[MAXDIM];
+    maybelong backstrides[MAXDIM];
+} NI_Iterator;
+
+/* initialize iterations over single array elements: */
+int NI_InitPointIterator(PyArrayObject*, NI_Iterator*);
+
+/* initialize iterations over an arbritrary sub-space: */
+int NI_SubspaceIterator(NI_Iterator*, UInt32);
+
+/* initialize iteration over array lines: */
+int NI_LineIterator(NI_Iterator*, int);
+
+/* reset an iterator */
+#define NI_ITERATOR_RESET(iterator)              \
+{                                                \
+    int _ii;                                       \
+    for(_ii = 0; _ii <= (iterator).rank_m1; _ii++) \
+        (iterator).coordinates[_ii] = 0;             \
+}
+
+/* go to the next point in a single array */
+#define NI_ITERATOR_NEXT(iterator, pointer)                         \
+{                                                                   \
+    int _ii;                                                          \
+    for(_ii = (iterator).rank_m1; _ii >= 0; _ii--)                    \
+        if ((iterator).coordinates[_ii] < (iterator).dimensions[_ii]) { \
+            (iterator).coordinates[_ii]++;                                \
+            pointer += (iterator).strides[_ii];                           \
+            break;                                                        \
+        } else {                                                        \
+            (iterator).coordinates[_ii] = 0;                              \
+            pointer -= (iterator).backstrides[_ii];                       \
+        }                                                               \
+}
+
+/* go to the next point in two arrays of the same size */
+#define NI_ITERATOR_NEXT2(iterator1, iterator2,  pointer1, pointer2)  \
+{                                                                     \
+    int _ii;                                                            \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
+        if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
+            (iterator1).coordinates[_ii]++;                                 \
+            pointer1 += (iterator1).strides[_ii];                           \
+            pointer2 += (iterator2).strides[_ii];                           \
+            break;                                                          \
+        } else {                                                          \
+            (iterator1).coordinates[_ii] = 0;                               \
+            pointer1 -= (iterator1).backstrides[_ii];                       \
+            pointer2 -= (iterator2).backstrides[_ii];                       \
+        }                                                                 \
+}
+
+/* go to the next point in three arrays of the same size */
+#define NI_ITERATOR_NEXT3(iterator1, iterator2,  iterator3,           \
+                                                    pointer1, pointer2, pointer3)               \
+{                                                                     \
+    int _ii;                                                            \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
+        if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
+            (iterator1).coordinates[_ii]++;                                 \
+            pointer1 += (iterator1).strides[_ii];                           \
+            pointer2 += (iterator2).strides[_ii];                           \
+            pointer3 += (iterator3).strides[_ii];                           \
+            break;                                                          \
+        } else {                                                          \
+            (iterator1).coordinates[_ii] = 0;                               \
+            pointer1 -= (iterator1).backstrides[_ii];                       \
+            pointer2 -= (iterator2).backstrides[_ii];                       \
+            pointer3 -= (iterator3).backstrides[_ii];                       \
+        }                                                                 \
+}
+
+/* go to an arbitrary point in a single array */
+#define NI_ITERATOR_GOTO(iterator, destination, base, pointer) \
+{                                                              \
+    int _ii;                                                     \
+    pointer = base;                                              \
+    for(_ii = (iterator).rank_m1; _ii >= 0; _ii--) {             \
+        pointer += destination[_ii] * (iterator).strides[_ii];     \
+        (iterator).coordinates[_ii] = destination[_ii];            \
+    }                                                            \
+}
+
+/******************************************************************/
+/* Line buffers */
+/******************************************************************/
+
+/* the linebuffer structure: */
+typedef struct {
+    double *buffer_data;
+    maybelong buffer_lines, line_length, line_stride;
+    maybelong size1, size2, array_lines, next_line;
+    NI_Iterator iterator;
+    char* array_data;
+    NumarrayType array_type;
+    NI_ExtendMode extend_mode;
+    double extend_value;
+} NI_LineBuffer;
+
+/* Get the next line being processed: */
+#define NI_GET_LINE(_buffer, _line)                                      \
+    ((_buffer).buffer_data + (_line) * ((_buffer).line_length +            \
+                                                                            (_buffer).size1 + (_buffer).size2))
+/* Allocate line buffer data */
+int NI_AllocateLineBuffer(PyArrayObject*, int, maybelong, maybelong,
+                                                    maybelong*, maybelong, double**);
+
+/* Initialize a line buffer */
+int NI_InitLineBuffer(PyArrayObject*, int, maybelong, maybelong, maybelong,
+                                            double*, NI_ExtendMode, double, NI_LineBuffer*);
+
+/* Extend a line in memory to implement boundary conditions: */
+int NI_ExtendLine(double*, maybelong, maybelong, maybelong, NI_ExtendMode, double);
+
+/* Copy a line from an array to a buffer: */
+int NI_ArrayToLineBuffer(NI_LineBuffer*, maybelong*, int*);
+
+/* Copy a line from a buffer to an array: */
+int NI_LineBufferToArray(NI_LineBuffer*);
+
+/******************************************************************/
+/* Multi-dimensional filter support functions */
+/******************************************************************/
+
+/* the filter iterator structure: */
+typedef struct {
+    maybelong strides[MAXDIM], backstrides[MAXDIM];
+    maybelong bound1[MAXDIM], bound2[MAXDIM];
+} NI_FilterIterator;
+
+/* Initialize a filter iterator: */
+int NI_InitFilterIterator(int, maybelong*, maybelong, maybelong*,
+                                                                                    maybelong*, NI_FilterIterator*);
+
+/* Calculate the offsets to the filter points, for all border regions and
+     the interior of the array: */
+int NI_InitFilterOffsets(PyArrayObject*, Bool*, maybelong*,
+                    maybelong*, NI_ExtendMode, maybelong**, maybelong*, maybelong**);
+
+/* Move to the next point in an array, possible changing the filter
+     offsets, to adapt to boundary conditions: */
+#define NI_FILTER_NEXT(iteratorf, iterator1, pointerf, pointer1)  \
+{                                                                 \
+    int _ii;                                                        \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {               \
+        maybelong _pp = (iterator1).coordinates[_ii];                 \
+        if (_pp < (iterator1).dimensions[_ii]) {                      \
+            if (_pp < (iteratorf).bound1[_ii] ||                        \
+                                                                    _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];                     \
+            (iterator1).coordinates[_ii]++;                             \
+            pointer1 += (iterator1).strides[_ii];                       \
+            break;                                                      \
+        } else {                                                      \
+            (iterator1).coordinates[_ii] = 0;                           \
+            pointer1 -= (iterator1).backstrides[_ii];                   \
+            pointerf -= (iteratorf).backstrides[_ii];                   \
+        }                                                             \
+    }                                                               \
+}
+
+/* Move to the next point in two arrays, possible changing the pointer
+     to the filter offsets when moving into a different region in the
+     array: */
+#define NI_FILTER_NEXT2(iteratorf, iterator1, iterator2,    \
+                                                pointerf, pointer1, pointer2)       \
+{                                                           \
+    int _ii;                                                  \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {         \
+        maybelong _pp = (iterator1).coordinates[_ii];           \
+        if (_pp < (iterator1).dimensions[_ii]) {                \
+            if (_pp < (iteratorf).bound1[_ii] ||                  \
+                                                        _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];               \
+            (iterator1).coordinates[_ii]++;                       \
+            pointer1 += (iterator1).strides[_ii];                 \
+            pointer2 += (iterator2).strides[_ii];                 \
+            break;                                                \
+        } else {                                                \
+            (iterator1).coordinates[_ii] = 0;                     \
+            pointer1 -= (iterator1).backstrides[_ii];             \
+            pointer2 -= (iterator2).backstrides[_ii];             \
+            pointerf -= (iteratorf).backstrides[_ii];             \
+        }                                                       \
+    }                                                         \
+}
+
+/* Move to the next point in three arrays, possible changing the pointer
+     to the filter offsets when moving into a different region in the
+     array: */
+#define NI_FILTER_NEXT3(iteratorf, iterator1, iterator2, iterator3,  \
+                                                pointerf, pointer1, pointer2, pointer3)      \
+{                                                                    \
+    int _ii;                                                           \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {                  \
+        maybelong _pp = (iterator1).coordinates[_ii];                    \
+        if (_pp < (iterator1).dimensions[_ii]) {                         \
+            if (_pp < (iteratorf).bound1[_ii] ||                           \
+                                                                         _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];                        \
+            (iterator1).coordinates[_ii]++;                                \
+            pointer1 += (iterator1).strides[_ii];                          \
+            pointer2 += (iterator2).strides[_ii];                          \
+            pointer3 += (iterator3).strides[_ii];                          \
+            break;                                                         \
+        } else {                                                         \
+            (iterator1).coordinates[_ii] = 0;                              \
+            pointer1 -= (iterator1).backstrides[_ii];                      \
+            pointer2 -= (iterator2).backstrides[_ii];                      \
+            pointer3 -= (iterator3).backstrides[_ii];                      \
+            pointerf -= (iteratorf).backstrides[_ii];                      \
+        }                                                                \
+    }                                                                  \
+}
+
+/* Move the pointer to the filter offsets according to the given
+    coordinates: */
+#define NI_FILTER_GOTO(iteratorf, iterator, fbase, pointerf) \
+{                                                            \
+    int _ii;                                                   \
+    maybelong _jj;                                             \
+    pointerf = fbase;                                          \
+    for(_ii = iterator.rank_m1; _ii >= 0; _ii--) {             \
+        maybelong _pp = iterator.coordinates[_ii];               \
+        maybelong b1 = (iteratorf).bound1[_ii];                  \
+        maybelong b2 = (iteratorf).bound2[_ii];                  \
+        if (_pp < b1) {                                          \
+                _jj = _pp;                                           \
+        } else if (_pp > b2 && b2 >= b1) {                       \
+                _jj = _pp + b1 - b2;                                 \
+        } else {                                                 \
+                _jj = b1;                                            \
+        }                                                        \
+        pointerf += (iteratorf).strides[_ii] * _jj;              \
+    }                                                          \
+}
+
+typedef struct {
+        maybelong *coordinates;
+        int size;
+        void *next;
+} NI_CoordinateBlock;
+
+typedef struct {
+        int block_size, rank;
+        void *blocks;
+} NI_CoordinateList;
+
+NI_CoordinateList* NI_InitCoordinateList(int, int);
+int NI_CoordinateListStealBlocks(NI_CoordinateList*, NI_CoordinateList*);
+NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList*);
+NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList*);
+void NI_FreeCoordinateList(NI_CoordinateList*);
+
+#endif



More information about the Scipy-svn mailing list