/*============================================================================ WCSLIB 4.3 - an implementation of the FITS WCS standard. Copyright (C) 1995-2007, Mark Calabretta This file is part of WCSLIB. WCSLIB is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with WCSLIB. If not, see . Correspondence concerning WCSLIB may be directed to: Internet email: mcalabre@atnf.csiro.au Postal address: Dr. Mark Calabretta Australia Telescope National Facility, CSIRO PO Box 76 Epping NSW 1710 AUSTRALIA Author: Mark Calabretta, Australia Telescope National Facility http://www.atnf.csiro.au/~mcalabre/index.html $Id: tab.c,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *===========================================================================*/ #include #include #include #include #include "wcsmath.h" #include "tab.h" const int TABSET = 137; /* Map status return value to message. */ const char *tab_errmsg[] = { "Success", "Null tabprm pointer passed", "Memory allocation failed", "Invalid tabular parameters", "One or more of the x coordinates were invalid", "One or more of the world coordinates were invalid"}; /*--------------------------------------------------------------------------*/ int tabini(int alloc, int M, const int K[], struct tabprm *tab) { int k, m, N; double *dp; if (tab == 0x0) return 1; if (M <= 0) { return 3; } /* Determine the total number of elements in the coordinate array. */ if (K) { N = M; for (m = 0; m < M; m++) { if (K[m] < 0) { return 3; } N *= K[m]; } } else { /* Axis lengths as yet unknown. */ N = 0; } /* Initialize memory management. */ if (tab->flag == -1 || tab->m_flag != TABSET) { tab->m_flag = 0; tab->m_M = 0; tab->m_N = 0; tab->m_K = 0x0; tab->m_map = 0x0; tab->m_crval = 0x0; tab->m_index = 0x0; tab->m_indxs = 0x0; tab->m_coord = 0x0; } else { /* Clear any outstanding signals set by wcstab(). */ for (m = 0; m < tab->m_M; m++) { if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0; } if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0; } if (tab->flag == -1) { tab->sense = 0x0; tab->p0 = 0x0; tab->delta = 0x0; tab->extrema = 0x0; tab->set_M = 0; } /* Allocate memory for arrays if required. */ if (alloc || tab->K == 0x0 || tab->map == 0x0 || tab->crval == 0x0 || tab->index == 0x0 || tab->coord == 0x0) { /* Was sufficient allocated previously? */ if (tab->m_flag == TABSET && (tab->m_M < M || tab->m_N < N)) { /* No, free it. */ tabfree(tab); } if (alloc || tab->K == 0x0) { if (tab->m_K) { /* In case the caller fiddled with it. */ tab->K = tab->m_K; } else { if (!(tab->K = calloc(M, sizeof(int)))) { return 2; } tab->m_flag = TABSET; tab->m_M = M; tab->m_K = tab->K; } } if (alloc || tab->map == 0x0) { if (tab->m_map) { /* In case the caller fiddled with it. */ tab->map = tab->m_map; } else { if (!(tab->map = calloc(M, sizeof(int)))) { return 2; } tab->m_flag = TABSET; tab->m_M = M; tab->m_map = tab->map; } } if (alloc || tab->crval == 0x0) { if (tab->m_crval) { /* In case the caller fiddled with it. */ tab->crval = tab->m_crval; } else { if (!(tab->crval = calloc(M, sizeof(double)))) { return 2; } tab->m_flag = TABSET; tab->m_M = M; tab->m_crval = tab->crval; } } if (alloc || tab->index == 0x0) { if (tab->m_index) { /* In case the caller fiddled with it. */ tab->index = tab->m_index; } else { if (!(tab->index = calloc(M, sizeof(double *)))) { return 2; } tab->m_flag = TABSET; tab->m_M = M; tab->m_N = N; tab->m_index = tab->index; if (!(tab->m_indxs = calloc(M, sizeof(double *)))) { return 2; } /* Recall that calloc() initializes these pointers to zero. */ if (K) { for (m = 0; m < M; m++) { if (K[m]) { if (!(tab->index[m] = calloc(K[m], sizeof(double)))) { return 2; } tab->m_indxs[m] = tab->index[m]; } } } } } if (alloc || tab->coord == 0x0) { if (tab->m_coord) { /* In case the caller fiddled with it. */ tab->coord = tab->m_coord; } else if (N) { if (!(tab->coord = calloc(N, sizeof(double)))) { return 2; } tab->m_flag = TABSET; tab->m_M = M; tab->m_N = N; tab->m_coord = tab->coord; } } } tab->flag = 0; tab->M = M; /* Set defaults. */ for (m = 0; m < M; m++) { tab->map[m] = -1; tab->crval[m] = 0.0; if (K) { tab->K[m] = K[m]; if ((dp = tab->index[m])) { for (k = 0; k < K[m]; k++) { *(dp++) = k; } } } else { tab->K[m] = 0; } } /* Initialize the coordinate array. */ for (dp = tab->coord; dp < tab->coord + N; dp++) { *dp = UNDEFINED; } return 0; } /*--------------------------------------------------------------------------*/ int tabmem(struct tabprm *tab) { int m, M, N; if (tab == 0x0) return 1; if (tab->M == 0 || tab->K == 0x0) { /* Should have been set by this time. */ return 2; } N = M = tab->M; for (m = 0; m < M; m++) { if (tab->K[m] < 0) { return 3; } N *= tab->K[m]; } if (tab->m_M == 0) { tab->m_M = M; } else if (tab->m_M < M) { /* Only possible if the user changed M. */ return 2; } if (tab->m_N == 0) { tab->m_N = N; } else if (tab->m_N < N) { /* Only possible if the user changed K[]. */ return 2; } if (tab->m_K == 0x0) { if ((tab->m_K = tab->K)) { tab->m_flag = TABSET; } } if (tab->m_map == 0x0) { if ((tab->m_map = tab->map)) { tab->m_flag = TABSET; } } if (tab->m_crval == 0x0) { if ((tab->m_crval = tab->crval)) { tab->m_flag = TABSET; } } if (tab->m_index == 0x0) { if ((tab->m_index = tab->index)) { tab->m_flag = TABSET; } } for (m = 0; m < tab->m_M; m++) { if (tab->m_indxs[m] == 0x0 || tab->m_indxs[m] == (double *)0x1) { if ((tab->m_indxs[m] = tab->index[m])) { tab->m_flag = TABSET; } } } if (tab->m_coord == 0x0 || tab->m_coord == (double *)0x1) { if ((tab->m_coord = tab->coord)) { tab->m_flag = TABSET; } } tab->flag = 0; return 0; } /*--------------------------------------------------------------------------*/ int tabcpy(int alloc, const struct tabprm *tabsrc, struct tabprm *tabdst) { int k, m, M, n, N, status; double *dstp, *srcp; if (tabsrc == 0x0) return 1; M = tabsrc->M; if (M <= 0) { return 2; } if ((status = tabini(alloc, M, tabsrc->K, tabdst))) { return status; } N = M; for (m = 0; m < M; m++) { tabdst->map[m] = tabsrc->map[m]; tabdst->crval[m] = tabsrc->crval[m]; N *= tabsrc->K[m]; } for (m = 0; m < M; m++) { if ((srcp = tabsrc->index[m])) { dstp = tabdst->index[m]; for (k = 0; k < tabsrc->K[m]; k++) { *(dstp++) = *(srcp++); } } } srcp = tabsrc->coord; dstp = tabdst->coord; for (n = 0; n < N; n++) { *(dstp++) = *(srcp++); } return 0; } /*--------------------------------------------------------------------------*/ int tabfree(struct tabprm *tab) { int m; if (tab == 0x0) return 1; if (tab->flag != -1) { /* Clear any outstanding signals set by wcstab(). */ for (m = 0; m < tab->m_M; m++) { if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0; } if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0; /* Free memory allocated by tabini(). */ if (tab->m_flag == TABSET) { if (tab->K == tab->m_K) tab->K = 0x0; if (tab->map == tab->m_map) tab->map = 0x0; if (tab->crval == tab->m_crval) tab->crval = 0x0; if (tab->index == tab->m_index) tab->index = 0x0; if (tab->coord == tab->m_coord) tab->coord = 0x0; if (tab->m_K) free(tab->m_K); if (tab->m_map) free(tab->m_map); if (tab->m_crval) free(tab->m_crval); if (tab->m_index) { for (m = 0; m < tab->m_M; m++) { if (tab->m_indxs[m]) free(tab->m_indxs[m]); } free(tab->m_index); free(tab->m_indxs); } if (tab->m_coord) free(tab->m_coord); } /* Free memory allocated by tabset(). */ if (tab->sense) free(tab->sense); if (tab->p0) free(tab->p0); if (tab->delta) free(tab->delta); if (tab->extrema) free(tab->extrema); } tab->m_flag = 0; tab->m_M = 0; tab->m_N = 0; tab->m_K = 0x0; tab->m_map = 0x0; tab->m_crval = 0x0; tab->m_index = 0x0; tab->m_indxs = 0x0; tab->m_coord = 0x0; tab->sense = 0x0; tab->p0 = 0x0; tab->delta = 0x0; tab->extrema = 0x0; tab->set_M = 0; tab->flag = 0; return 0; } /*--------------------------------------------------------------------------*/ int tabprt(const struct tabprm *tab) { char *cp, text[128]; int j, k, m, n, nd; double *dp; if (tab == 0x0) return 1; if (tab->flag != TABSET) { printf("The tabprm struct is UNINITIALIZED.\n"); return 0; } printf(" flag: %d\n", tab->flag); printf(" M: %d\n", tab->M); /* Array dimensions. */ printf(" K: %p\n", (void *)tab->K); printf(" "); for (m = 0; m < tab->M; m++) { printf("%6d", tab->K[m]); } printf("\n"); /* Map vector. */ printf(" map: %p\n", (void *)tab->map); printf(" "); for (m = 0; m < tab->M; m++) { printf("%6d", tab->map[m]); } printf("\n"); /* Reference index value. */ printf(" crval: %p\n", (void *)tab->crval); printf(" "); for (m = 0; m < tab->M; m++) { printf(" %- 11.5g", tab->crval[m]); } printf("\n"); /* Index vectors. */ printf(" index: %p\n", (void *)tab->index); for (m = 0; m < tab->M; m++) { printf(" index[%d]: %p", m, (void *)tab->index[m]); if (tab->index[m]) { for (k = 0; k < tab->K[m]; k++) { if (k%5 == 0) { printf("\n "); } printf(" %- 11.5g", tab->index[m][k]); } printf("\n"); } } /* Coordinate array. */ printf(" coord: %p\n", (void *)tab->coord); dp = tab->coord; for (n = 0; n < tab->nc; n++) { /* Array index. */ j = n; cp = text; for (m = 0; m < tab->M; m++) { nd = (tab->K[m] < 10) ? 1 : 2; sprintf(cp, ",%*d", nd, j % tab->K[m] + 1); j /= tab->K[m]; cp += strlen(cp); } printf(" (*%s)", text); for (m = 0; m < tab->M; m++) { printf(" %- 11.5g", *(dp++)); } printf("\n"); } printf(" nc: %d\n", tab->nc); if (tab->sense == 0x0) { printf(" sense: (nil)\n"); } else { printf(" sense: %p\n", (void *)tab->sense); printf(" "); for (m = 0; m < tab->M; m++) { printf("%6d", tab->sense[m]); } printf("\n"); } if (tab->p0 == 0x0) { printf(" p0: (nil)\n"); } else { printf(" p0: %p\n", (void *)tab->p0); printf(" "); for (m = 0; m < tab->M; m++) { printf("%6d", tab->p0[m]); } printf("\n"); } if (tab->delta == 0x0) { printf(" delta: (nil)\n"); } else { printf(" delta: %p\n", (void *)tab->delta); printf(" "); for (m = 0; m < tab->M; m++) { printf(" %- 11.5g", tab->delta[m]); } printf("\n"); } printf(" extrema: %p\n", (void *)tab->extrema); dp = tab->extrema; for (n = 0; n < tab->nc/tab->K[0]; n++) { /* Array index. */ j = n; cp = text; *cp = '\0'; for (m = 1; m < tab->M; m++) { nd = (tab->K[m] < 10) ? 1 : 2; sprintf(cp, ",%*d", nd, j % tab->K[m] + 1); j /= tab->K[m]; cp += strlen(cp); } printf(" (*,*%s)", text); for (m = 0; m < 2*tab->M; m++) { if (m == tab->M) printf("-> "); printf(" %- 11.5g", *(dp++)); } printf("\n"); } /* Memory management. */ printf(" m_flag: %d\n", tab->m_flag); printf(" m_M: %d\n", tab->m_M); printf(" m_N: %d\n", tab->m_N); printf(" m_K: %p", (void *)tab->m_K); if (tab->m_K == tab->K) printf(" (= K)"); printf("\n"); printf(" m_map: %p", (void *)tab->m_map); if (tab->m_map == tab->map) printf(" (= map)"); printf("\n"); printf(" m_crval: %p", (void *)tab->m_crval); if (tab->m_crval == tab->crval) printf(" (= crval)"); printf("\n"); printf(" m_index: %p", (void *)tab->m_index); if (tab->m_index == tab->index) printf(" (= index)"); printf("\n"); for (m = 0; m < tab->M; m++) { printf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]); if (tab->m_indxs[m] == tab->index[m]) printf(" (= index[%d])", m); printf("\n"); } printf(" m_coord: %p", (void *)tab->m_coord); if (tab->m_coord == tab->coord) printf(" (= coord)"); printf("\n"); return 0; } /*--------------------------------------------------------------------------*/ int tabset(struct tabprm *tab) { int i, ic, k, *Km, m, M, ne; double *dcrd, *dmax, *dmin, *Psi; if (tab == 0x0) return 1; /* Check the number of tabular coordinate axes. */ if ((M = tab->M) < 1) { return 3; } /* Check the axis lengths. */ if (!tab->K) { return 2; } tab->nc = 1; for (m = 0; m < M; m++) { if (tab->K[m] < 1) { return 3; } /* Number of coordinate vectors in the coordinate array. */ tab->nc *= tab->K[m]; } /* Check that the map vector is sensible. */ if (!tab->map) { return 2; } for (m = 0; m < M; m++) { i = tab->map[m]; if (i < 0) { return 3; } } /* Check memory allocation for the remaining vectors. */ if (!tab->crval || !tab->index || !tab->coord) { return 2; } /* Take memory if signalled to by wcstab(). */ for (m = 0; m < tab->m_M; m++) { if (tab->m_indxs[m] == (double *)0x1 && (tab->m_indxs[m] = tab->index[m])) { tab->m_flag = TABSET; } } if (tab->m_coord == (double *)0x1 && (tab->m_coord = tab->coord)) { tab->m_flag = TABSET; } /* Allocate memory for work vectors. */ if (tab->flag != TABSET || tab->set_M < M) { /* Free memory that may have been allocated previously. */ if (tab->sense) free(tab->sense); if (tab->p0) free(tab->p0); if (tab->delta) free(tab->delta); if (tab->extrema) free(tab->extrema); /* Allocate memory for internal arrays. */ if (!(tab->sense = calloc(M, sizeof(int)))) { return 2; } if (!(tab->p0 = calloc(M, sizeof(int)))) { free(tab->sense); return 2; } if (!(tab->delta = calloc(M, sizeof(double)))) { free(tab->sense); free(tab->p0); return 2; } ne = M * tab->nc * 2 / tab->K[0]; if (!(tab->extrema = calloc(ne, sizeof(double)))) { free(tab->sense); free(tab->p0); free(tab->delta); return 2; } tab->set_M = M; } /* Check that the index vectors are monotonic. */ Km = tab->K; for (m = 0; m < M; m++, Km++) { tab->sense[m] = 0; if (*Km > 1) { if ((Psi = tab->index[m]) == 0) { /* Default indexing. */ tab->sense[m] = 1; } else { for (k = 0; k < *Km-1; k++) { switch (tab->sense[m]) { case 0: if (Psi[k] < Psi[k+1]) { /* Monotonic increasing. */ tab->sense[m] = 1; } else if (Psi[k] > Psi[k+1]) { /* Monotonic decreasing. */ tab->sense[m] = -1; } break; case 1: if (Psi[k] > Psi[k+1]) { /* Should be monotonic increasing. */ free(tab->sense); free(tab->p0); free(tab->delta); free(tab->extrema); return 3; } break; case -1: if (Psi[k] < Psi[k+1]) { /* Should be monotonic decreasing. */ free(tab->sense); free(tab->p0); free(tab->delta); free(tab->extrema); return 3; } break; } } } if (tab->sense[m] == 0) { free(tab->sense); free(tab->p0); free(tab->delta); free(tab->extrema); return 3; } } } /* Deduce the extremal values of the coordinate elements in each row. */ dcrd = tab->coord; dmin = tab->extrema; dmax = tab->extrema + M; for (ic = 0; ic < tab->nc; ic += tab->K[0]) { for (m = 0; m < M; m++, dcrd++) { *(dmax+m) = *(dmin+m) = *dcrd; } for (i = 1; i < tab->K[0]; i++) { for (m = 0; m < M; m++, dcrd++) { if (*(dmax+m) < *dcrd) *(dmax+m) = *dcrd; if (*(dmin+m) > *dcrd) *(dmin+m) = *dcrd; } } dmin += 2*M; dmax += 2*M; } tab->flag = TABSET; return 0; } /*--------------------------------------------------------------------------*/ int tabx2s( struct tabprm *tab, int ncoord, int nelem, const double x[], double world[], int stat[]) { int i, iv, k, *Km, m, M, n, nv, offset, p0, status; double *coord, *Psi, psi_m, upsilon, wgt; register int *statp; register const double *xp; register double *wp; /* Initialize if required. */ if (tab == 0x0) return 1; if (tab->flag != TABSET) { if ((status = tabset(tab))) return status; } /* This is used a lot. */ M = tab->M; status = 0; xp = x; wp = world; statp = stat; for (n = 0; n < ncoord; n++) { /* Determine the indexes. */ Km = tab->K; for (m = 0; m < M; m++, Km++) { i = tab->map[m]; psi_m = *(xp+i) + tab->crval[m]; if ((Psi = tab->index[m]) == 0) { /* Default indexing is simple. */ upsilon = psi_m; } else { if (*Km == 1) { /* Index vector is degenerate. */ if (Psi[0]-0.5 <= psi_m && psi_m <= Psi[0]+0.5) { upsilon = psi_m; } else { *statp = 1; status = 4; goto next; } } else { /* Interpolate in the indexing vector. */ if (tab->sense[m] == 1) { /* Monotonic increasing index values. */ if (psi_m < Psi[0]) { if (Psi[0] - 0.5*(Psi[1]-Psi[0]) <= psi_m) { /* Allow minor extrapolation. */ k = 0; } else { /* Index is out of range. */ *statp = 1; status = 4; goto next; } } else if (Psi[*Km-1] < psi_m) { if (psi_m <= Psi[*Km-1] + 0.5*(Psi[*Km-1]-Psi[*Km-2])) { /* Allow minor extrapolation. */ k = *Km - 2; } else { /* Index is out of range. */ *statp = 1; status = 4; goto next; } } else { for (k = 0; k < *Km-1; k++) { if (psi_m < Psi[k]) { continue; } if (Psi[k] == psi_m && psi_m < Psi[k+1]) { break; } if (Psi[k] < psi_m && psi_m <= Psi[k+1]) { break; } } } } else { /* Monotonic decreasing index values. */ if (psi_m > Psi[0]) { if (Psi[0] + 0.5*(Psi[0]-Psi[1]) >= psi_m) { /* Allow minor extrapolation. */ k = 0; } else { /* Index is out of range. */ *statp = 1; status = 4; goto next; } } else if (psi_m < Psi[*Km-1]) { if (Psi[*Km-1] - 0.5*(Psi[*Km-2]-Psi[*Km-1]) <= psi_m) { /* Allow minor extrapolation. */ k = *Km - 2; } else { /* Index is out of range. */ *statp = 1; status = 4; goto next; } } else { for (k = 0; k < *Km-1; k++) { if (psi_m > Psi[k]) { continue; } if (Psi[k] == psi_m && psi_m > Psi[k+1]) { break; } if (Psi[k] > psi_m && psi_m >= Psi[k+1]) { break; } } } } upsilon = k + (psi_m - Psi[k]) / (Psi[k+1] - Psi[k]); } } if (upsilon < -0.5 || upsilon > *Km - 0.5) { /* Index out of range. */ *statp = 1; status = 4; goto next; } /* Fiducial array indices and fractional offset. */ p0 = (int)floor(upsilon); tab->p0[m] = p0; tab->delta[m] = upsilon - p0; if (p0 == -1) { tab->p0[m] += 1; tab->delta[m] -= 1.0; } else if (p0 == *Km-1 && *Km > 1) { tab->p0[m] -= 1; tab->delta[m] += 1.0; } } /* Now interpolate in the coordinate array; the M-dimensional linear */ /* interpolation algorithm is described in Sect. 3.4 of WCS Paper IV. */ for (m = 0; m < M; m++) { i = tab->map[m]; *(wp+i) = 0.0; } /* Loop over the 2^M vertices surrounding P. */ nv = 1 << M; for (iv = 0; iv < nv; iv++) { /* Locate vertex in the coordinate array and compute its weight. */ offset = 0; wgt = 1.0; for (m = M-1; m >= 0; m--) { offset *= tab->K[m]; offset += tab->p0[m]; if (iv & (1 << m)) { if (tab->K[m] > 1) offset++; wgt *= tab->delta[m]; } else { wgt *= 1.0 - tab->delta[m]; } } if (wgt == 0.0) continue; /* Add the contribution from this vertex to each element. */ coord = tab->coord + offset*M; for (m = 0; m < M; m++) { i = tab->map[m]; *(wp+i) += *(coord++) * wgt; } if (wgt == 1.0) break; } *statp = 0; next: xp += nelem; wp += nelem; statp++; } return status; } /*--------------------------------------------------------------------------*/ int tabs2x( struct tabprm* tab, int ncoord, int nelem, const double world[], double x[], int stat[]) { int tabedge(struct tabprm *); int tabrow(struct tabprm *, const double *); int tabvox(struct tabprm *, const double *, int, unsigned int *); int edge, i, ic, k, *Km, M, m, n, status; double *Psi, psi_m, upsilon; register int *statp; register const double *wp; register double *xp; /* Initialize if required. */ if (tab == 0x0) return 1; if (tab->flag != TABSET) { if ((status = tabset(tab))) return status; } /* This is used a lot. */ M = tab->M; status = 0; wp = world; xp = x; statp = stat; for (n = 0; n < ncoord; n++) { /* Locate this coordinate in the coordinate array. */ edge = 0; for (m = 0; m < M; m++) { tab->p0[m] = 0; } for (ic = 0; ic < tab->nc; ic++) { if (tab->p0[0] == 0) { /* New row, could it contain a solution? */ if (edge || tabrow(tab, wp)) { /* No, skip it. */ ic += tab->K[0] - 1; tab->p0[1]++; edge = tabedge(tab); continue; } } if (M == 1) { /* Deal with the one-dimensional case separately. */ if (*wp == tab->coord[0]) { tab->p0[0] = 0; tab->delta[0] = 0.0; break; } else if (ic < tab->nc - 1) { if (((tab->coord[ic] <= *wp && *wp <= tab->coord[ic+1]) || (tab->coord[ic] >= *wp && *wp >= tab->coord[ic+1])) && (tab->index[0] == 0 || tab->index[0][ic] != tab->index[0][ic+1])) { tab->p0[0] = ic; tab->delta[0] = (*wp - tab->coord[ic]) / (tab->coord[ic+1] - tab->coord[ic]); break; } } } else { /* Multi-dimensional tables are much harder. */ if (!edge && tabvox(tab, wp, 0, 0) == 0) { /* Found a solution. */ break; } /* Next voxel. */ tab->p0[0]++; edge = tabedge(tab); } } if (ic == tab->nc) { /* Coordinate not found. */ *statp = 1; status = 5; } else { /* Determine the intermediate world coordinates. */ Km = tab->K; for (m = 0; m < M; m++, Km++) { upsilon = tab->p0[m] + tab->delta[m]; if (upsilon < -0.5 || upsilon > *Km - 0.5) { /* Index out of range. */ *statp = 1; status = 5; } else { /* Do inverse lookup of the index vector. */ if ((Psi = tab->index[m]) == 0) { /* Default indexing. */ psi_m = upsilon; } else { if (*Km == 1) { /* Degenerate index vector. */ psi_m = Psi[0]; } else { k = (int)upsilon; psi_m = Psi[k]; if (k < *Km-1) { psi_m += (upsilon - k) * (Psi[k+1] - Psi[k]); } } } i = tab->map[m]; xp[i] = psi_m - tab->crval[m]; } } *statp = 0; } wp += nelem; xp += nelem; statp++; } return status; } /*--------------------------------------------------------------------------*/ int tabedge(tab) struct tabprm* tab; { int edge, *Km, m; edge = 0; Km = tab->K; for (m = 0; m < tab->M; m++, Km++) { if (tab->p0[m] == *Km) { tab->p0[m] = 0; tab->p0[m+1]++; } else if (tab->p0[m] == *Km - 1 && *Km > 1) { /* Edge effects? */ edge = 1; } } return edge; } /*--------------------------------------------------------------------------*/ int tabrow(tab, wp) struct tabprm* tab; const double *wp; { int iv, M, m, nv, offset; unsigned int eq, et, gt, lt; const double tol = 1.0e-10; double *cp, w; M = tab->M; /* Could the coordinate lie somewhere along this row of voxels? */ lt = 0; gt = 0; eq = 0; nv = 1 << M; for (iv = 0; iv < nv; iv++) { /* Find the extrema at this end of the row. */ offset = 0; for (m = M-1; m > 0; m--) { offset *= tab->K[m]; offset += tab->p0[m]; if (iv & (1 << m)) { if (tab->K[m] > 1) offset++; } } offset *= 2; offset += tab->p0[0]; if (iv & 1 && tab->K[0] > 1) offset++; et = 0; cp = tab->extrema + offset*M; for (m = 0; m < M; m++, cp++) { w = wp[tab->map[m]]; if (fabs(*cp - w) < tol) { et |= (1 << m); } else if (*cp < w) { lt |= (1 << m); } else if (*cp > w) { gt |= (1 << m); } } if (et == nv-1) { /* Solution found in a corner. */ return 0; } eq |= et; } if ((lt | eq) == nv-1 && (gt | eq) == nv-1) { /* A solution could lie within this row of voxels. */ return 0; } /* No solution in this row. */ return 1; } /*--------------------------------------------------------------------------*/ int tabvox(tab, wp, level, vox) struct tabprm* tab; const double *wp; int level; unsigned int *vox; { int i, iv, jv, M, m, nv, offset; unsigned int eq, et, gt, lt, vox2[16]; const double tol = 1.0e-10; double coord[16], *cp, dv, w, wgt; M = tab->M; dv = 1.0; for (i = 0; i < level; i++) { dv /= 2.0; } /* Could the coordinate lie within this voxel? */ lt = 0; gt = 0; eq = 0; nv = 1 << M; for (iv = 0; iv < nv; iv++) { /* Compute the coordinates of this corner of the voxel. */ for (m = 0; m < M; m++) { coord[m] = 0.0; tab->delta[m] = level ? dv*vox[m] : 0.0; if (iv & (1 << m)) { tab->delta[m] += dv; } } for (jv = 0; jv < nv; jv++) { offset = 0; wgt = 1.0; for (m = M-1; m >= 0; m--) { offset *= tab->K[m]; offset += tab->p0[m]; if (jv & (1 << m)) { if (tab->K[m] > 1) offset++; wgt *= tab->delta[m]; } else { wgt *= 1.0 - tab->delta[m]; } } if (wgt == 0.0) continue; cp = tab->coord + offset*M; for (m = 0; m < M; m++) { coord[m] += *(cp++) * wgt; } if (wgt == 1.0) break; } /* Coordinate elements are minimal or maximal in a corner. */ et = 0; for (m = 0; m < M; m++) { w = wp[tab->map[m]]; if (fabs(coord[m] - w) < tol) { et |= (1 << m); } else if (coord[m] < w) { lt |= (1 << m); } else if (coord[m] > w) { gt |= (1 << m); } } if (et == nv-1) { /* Solution found in a corner. */ return 0; } eq |= et; } if ((lt | eq) == nv-1 && (gt | eq) == nv-1) { /* The coordinate could lie within this voxel, but does it? */ if (level == 31) { /* Stop the recursion. */ dv /= 2.0; for (m = 0; m < M; m++) { tab->delta[m] = dv * (2.0*vox[m] + 1.0); } return 0; } /* Subdivide and try again. */ for (iv = 0; iv < nv; iv++) { for (m = 0; m < M; m++) { vox2[m] = level ? 2*vox[m] : 0; if (iv & (1 << m)) { vox2[m]++; } } if (tabvox(tab, wp, level+1, vox2) == 0) { return 0; } } } /* No solution in this voxel. */ return 1; }