/* 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 #include /* 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; in += sz * (maybelong)(-in / sz); if (in < 0) in += sz; } break; case NI_EXTEND_NEAREST: in = 0; break; case NI_EXTEND_CONSTANT: in = -1; break; } } else if (in >= len) { 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; 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) \ case t ## _type: \ _t = _t > 0 ? _t + 0.5 : 0; \ *(_type*)_po = (_type)_t; \ break; #define CASE_INTERP_OUT_INT(_po, _t, _type) \ case t ## _type: \ _t = _t > 0 ? _t + 0.5 : _t - 0.5; \ *(_type*)_po = (_type)_t; \ break; int NI_GeometricTransform(PyArrayObject *input, int (*map)(int*, 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*)NA_OFFSETDATA(matrix_ar) : NULL; Float64 *shift = shift_ar ? (Float64*)NA_OFFSETDATA(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 = NA_OFFSETDATA(coordinates); } /* offsets used at the borders: */ edge_offsets = (int**)malloc(irank * sizeof(int*)); data_offsets = (int**)malloc(irank * sizeof(int*)); 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] = (int*)malloc((order + 1) * sizeof(int)); 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 = NA_OFFSETDATA(input); po = NA_OFFSETDATA(output); /* make a table of all possible coordinates within the spline filter: */ fcoordinates = (int*)malloc(irank * filter_size * sizeof(int)); /* make a table of all offsets within the spline filter: */ foffsets = (int*)malloc(filter_size * sizeof(int)); 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) { int *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) { int *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); CASE_INTERP_OUT_UINT(po, t, UInt16); CASE_INTERP_OUT_UINT(po, t, UInt32); #if HAS_UINT64 CASE_INTERP_OUT_UINT(po, t, UInt64); #endif CASE_INTERP_OUT_INT(po, t, Int8); CASE_INTERP_OUT_INT(po, t, Int16); CASE_INTERP_OUT_INT(po, t, Int32); CASE_INTERP_OUT_INT(po, t, 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*)NA_OFFSETDATA(zoom_ar) : NULL; Float64 *shifts = shift_ar ? (Float64*)NA_OFFSETDATA(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 = (int**)malloc(rank * sizeof(int*)); if (!zeros) { PyErr_NoMemory(); goto exit; } for(jj = 0; jj < rank; jj++) zeros[jj] = NULL; for(jj = 0; jj < rank; jj++) { zeros[jj] = (int*)malloc(odimensions[jj] * sizeof(int)); if(!zeros[jj]) { PyErr_NoMemory(); goto exit; } } } /* store offsets, along each axis: */ offsets = (int**)malloc(rank * sizeof(int*)); /* store spline coefficients, along each axis: */ splvals = (double***)malloc(rank * sizeof(double**)); /* store offsets at all edges: */ edge_offsets = (int***)malloc(rank * sizeof(int**)); 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] = (int*)malloc(odimensions[jj] * sizeof(int)); splvals[jj] = (double**)malloc(odimensions[jj] * sizeof(double*)); edge_offsets[jj] = (int**)malloc(odimensions[jj] * sizeof(double*)); 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] = (int*)malloc((order + 1) * sizeof(int)); 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 = NA_OFFSETDATA(input); po = NA_OFFSETDATA(output); /* store all coordinates and offsets with filter: */ fcoordinates = (int*)malloc(rank * filter_size * sizeof(int)); foffsets = (int*)malloc(filter_size * sizeof(int)); 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) { int *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) { int *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); CASE_INTERP_OUT_UINT(po, t, UInt16); CASE_INTERP_OUT_UINT(po, t, UInt32); #if HAS_UINT64 CASE_INTERP_OUT_UINT(po, t, UInt64); #endif CASE_INTERP_OUT_INT(po, t, Int8); CASE_INTERP_OUT_INT(po, t, Int16); CASE_INTERP_OUT_INT(po, t, Int32); CASE_INTERP_OUT_INT(po, t, 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); return PyErr_Occurred() ? 0 : 1; }