Exemplo n.º 1
0
/*
** _nrrdApply2DSetUp()
**
** some error checking and initializing needed for 2D LUTS and regular
** maps.  The intent is that if this succeeds, then there is no need
** for any further error checking.
**
** The only thing this function DOES is allocate the output nrrd, and
** set meta information.  The rest is just error checking.
**
** The given NrrdRange has to be fleshed out by the caller: it can't
** be NULL, and both range->min and range->max must exist.
*/
int
_nrrdApply2DSetUp(Nrrd *nout, const Nrrd *nin,
                  const NrrdRange *range0, const NrrdRange *range1,
                  const Nrrd *nmap, int kind, int typeOut,
                  int rescale0, int rescale1) {
  char me[]="_nrrdApply2DSetUp", err[BIFF_STRLEN], *mapcnt;
  char nounStr[][AIR_STRLEN_SMALL]={"2D lut",
                                    "2D regular map"};
  char verbStr[][AIR_STRLEN_SMALL]={"lut2",
                                    "rmap2"};
  int mapAxis, copyMapAxis0=AIR_FALSE, axisMap[NRRD_DIM_MAX];
  unsigned int dim, entLen;
  size_t size[NRRD_DIM_MAX];
  double domMin, domMax;

  if (nout == nin) {
    sprintf(err, "%s: due to laziness, nout==nin always disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (airEnumValCheck(nrrdType, typeOut)) {
    sprintf(err, "%s: invalid requested output type %d", me, typeOut);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == typeOut) {
    sprintf(err, "%s: input or requested output type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (!(2 == nin->axis[0].size)) {
    sprintf(err, "%s: input axis[0] must have size 2 (not " 
            _AIR_SIZE_T_CNV ")", me, nin->axis[0].size);
    biffAdd(NRRD, err); return 1;
  }
  if (!(nin->dim > 1)) {
    sprintf(err, "%s: input dimension must be > 1 (not %u)", me, nin->dim);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale0 && !(range0
                    && AIR_EXISTS(range0->min) 
                    && AIR_EXISTS(range0->max))) {
    sprintf(err, "%s: want axis 0 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale1 && !(range1
                    && AIR_EXISTS(range1->min) 
                    && AIR_EXISTS(range1->max))) {
    sprintf(err, "%s: want axis 1 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  mapAxis = nmap->dim - 2;
  if (!(0 == mapAxis || 1 == mapAxis)) {
    sprintf(err, "%s: dimension of %s should be 2 or 3, not %d", 
            me, nounStr[kind], nmap->dim);
    biffAdd(NRRD, err); return 1;
  }
  copyMapAxis0 = (1 == mapAxis);
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis+1);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis+1);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis+1, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdHasNonExist(nmap)) {
    sprintf(err, "%s: %s nrrd has non-existent values",
            me, nounStr[kind]);
    biffAdd(NRRD, err); return 1;
  }
  entLen = mapAxis ? nmap->axis[0].size : 1;
  if (mapAxis + nin->dim - 1 > NRRD_DIM_MAX) {
    sprintf(err, "%s: input nrrd dim %d through non-scalar %s exceeds "
            "NRRD_DIM_MAX %d",
            me, nin->dim, nounStr[kind], NRRD_DIM_MAX);
    biffAdd(NRRD, err); return 1;
  }
  if (mapAxis) {
    size[0] = entLen;
    axisMap[0] = -1;
  }
  for (dim=1; dim<nin->dim; dim++) {
    size[dim-1+mapAxis] = nin->axis[dim].size;
    axisMap[dim-1+mapAxis] = dim;
  }
  /*
  fprintf(stderr, "##%s: pre maybe alloc: nout->data = %p\n", me, nout->data);
  for (dim=0; dim<mapAxis + nin->dim - 1; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)size[dim]);
  }
  fprintf(stderr, "   nout->dim = %u; nout->type = %d = %s; sizes = %u,%u\n", 
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type),
          AIR_CAST(unsigned int, nout->axis[0].size),
          AIR_CAST(unsigned int, nout->axis[1].size));
  fprintf(stderr, "   typeOut = %d = %s\n", typeOut,
          airEnumStr(nrrdType, typeOut));
  */
  if (nrrdMaybeAlloc_nva(nout, typeOut, nin->dim - 1 + mapAxis, size)) {
    sprintf(err, "%s: couldn't allocate output nrrd", me);
    biffAdd(NRRD, err); return 1;
  }
  /*
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s\n",
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type));
  for (dim=0; dim<nout->dim; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)nout->axis[dim].size);
  }
  fprintf(stderr, "##%s: post maybe alloc: nout->data = %p\n", me, nout->data);
  */
  if (nrrdAxisInfoCopy(nout, nin, axisMap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: trouble copying axis info", me);
    biffAdd(NRRD, err); return 1;
  }
  if (copyMapAxis0) {
    _nrrdAxisInfoCopy(nout->axis + 0, nmap->axis + 0,
                      NRRD_AXIS_INFO_SIZE_BIT);
  }

  mapcnt = _nrrdContentGet(nmap);
  if (nrrdContentSet_va(nout, verbStr[kind], nin, "%s", mapcnt)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); free(mapcnt); return 1;
  }
  free(mapcnt); 
  nrrdBasicInfoInit(nout, (NRRD_BASIC_INFO_DATA_BIT
                           | NRRD_BASIC_INFO_TYPE_BIT
                           | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                           | NRRD_BASIC_INFO_DIMENSION_BIT
                           | NRRD_BASIC_INFO_CONTENT_BIT));
  return 0;
}
Exemplo n.º 2
0
/*
** _nrrdApply1DSetUp()
**
** some error checking and initializing needed for 1D LUTS, regular,
** and irregular maps.  The intent is that if this succeeds, then
** there is no need for any further error checking.
**
** The only thing this function DOES is allocate the output nrrd, and
** set meta information.  The rest is just error checking.
**
** The given NrrdRange has to be fleshed out by the caller: it can't
** be NULL, and both range->min and range->max must exist.
*/
int
_nrrdApply1DSetUp(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, 
                  const Nrrd *nmap, int kind, int typeOut,
                  int rescale, int multi) {
  char me[]="_nrrdApply1DSetUp", err[BIFF_STRLEN], *mapcnt;
  char nounStr[][AIR_STRLEN_SMALL]={"lut",
                                    "regular map",
                                    "irregular map"};
  char mnounStr[][AIR_STRLEN_SMALL]={"multi lut",
                                     "multi regular map",
                                     "multi irregular map"}; 
                                      /* wishful thinking */
  char verbStr[][AIR_STRLEN_SMALL]={"lut",
                                    "rmap",
                                    "imap"};
  char mverbStr[][AIR_STRLEN_SMALL]={"mlut",
                                     "mrmap",
                                     "mimap"}; /* wishful thinking */
  int mapAxis, copyMapAxis0=AIR_FALSE, axisMap[NRRD_DIM_MAX];
  unsigned int ax, dim, entLen;
  size_t size[NRRD_DIM_MAX];
  double domMin, domMax;

  if (nout == nin) {
    sprintf(err, "%s: due to laziness, nout==nin always disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (airEnumValCheck(nrrdType, typeOut)) {
    sprintf(err, "%s: invalid requested output type %d", me, typeOut);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == typeOut) {
    sprintf(err, "%s: input or requested output type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (rescale && !(range
                   && AIR_EXISTS(range->min) 
                   && AIR_EXISTS(range->max))) {
    sprintf(err, "%s: want rescaling but didn't get a range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  if (kindLut == kind || kindRmap == kind) {
    if (!multi) {
      mapAxis = nmap->dim - 1;
      if (!(0 == mapAxis || 1 == mapAxis)) {
        sprintf(err, "%s: dimension of %s should be 1 or 2, not %d", 
                me, nounStr[kind], nmap->dim);
        biffAdd(NRRD, err); return 1;
      }
      copyMapAxis0 = (1 == mapAxis);
    } else {
      mapAxis = nmap->dim - nin->dim - 1;
      if (!(0 == mapAxis || 1 == mapAxis)) {
        sprintf(err, "%s: dimension of %s should be %d or %d, not %d", 
                me, mnounStr[kind],
                nin->dim + 1, nin->dim + 2, nmap->dim);
        biffAdd(NRRD, err); return 1;
      }
      copyMapAxis0 = (1 == mapAxis);
      /* need to make sure the relevant sizes match */
      for (ax=0; ax<nin->dim; ax++) {
        if (nin->axis[ax].size != nmap->axis[mapAxis + 1 + ax].size) {
          sprintf(err, "%s: input and mmap don't have compatible sizes: "
                  "nin->axis[%d].size (" _AIR_SIZE_T_CNV ") "
                  "!= nmap->axis[%d].size (" _AIR_SIZE_T_CNV "): ",
                  me, ax, nin->axis[ax].size, 
                  mapAxis + 1 + ax, nmap->axis[mapAxis + 1 + ax].size);
          biffAdd(NRRD, err); return 1;
        }
      }
    }
    domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis);
    domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis);
    if (!( domMin < domMax )) {
      sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
              mapAxis, domMin, domMax);
      biffAdd(NRRD, err); return 1;
    }
    if (nrrdHasNonExist(nmap)) {
      sprintf(err, "%s: %s nrrd has non-existent values",
              me, multi ? mnounStr[kind] : nounStr[kind]);
      biffAdd(NRRD, err); return 1;
    }
    entLen = mapAxis ? nmap->axis[0].size : 1;
  } else {
    if (multi) {
      sprintf(err, "%s: sorry, multi irregular maps not implemented", me);
      biffAdd(NRRD, err); return 1;
    }
    /* its an irregular map */
    if (nrrd1DIrregMapCheck(nmap)) {
      sprintf(err, "%s: problem with irregular map", me);
      biffAdd(NRRD, err); return 1;
    }
    /* mapAxis has no meaning for irregular maps, but we'll pretend ... */
    mapAxis = nmap->axis[0].size == 2 ? 0 : 1;
    copyMapAxis0 = AIR_TRUE;
    entLen = nmap->axis[0].size-1;
  }
  if (mapAxis + nin->dim > NRRD_DIM_MAX) {
    sprintf(err, "%s: input nrrd dim %d through non-scalar %s exceeds "
            "NRRD_DIM_MAX %d",
            me, nin->dim,
            multi ? mnounStr[kind] : nounStr[kind], NRRD_DIM_MAX);
    biffAdd(NRRD, err); return 1;
  }
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size+mapAxis);
  if (mapAxis) {
    size[0] = entLen;
    axisMap[0] = -1;
  }
  for (dim=0; dim<nin->dim; dim++) {
    axisMap[dim+mapAxis] = dim;
  }
  /*
  fprintf(stderr, "##%s: pre maybe alloc: nout->data = %p\n", me, nout->data);
  for (dim=0; dim<mapAxis + nin->dim; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", d, (int)size[d]);
  }
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s; sizes = %d,%d\n", 
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type));
  fprintf(stderr, "   typeOut = %d = %s\n", typeOut,
          airEnumStr(nrrdType, typeOut));
  */
  if (nrrdMaybeAlloc_nva(nout, typeOut, mapAxis + nin->dim, size)) {
    sprintf(err, "%s: couldn't allocate output nrrd", me);
    biffAdd(NRRD, err); return 1;
  }
  /*
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s\n",
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type),
          nout->axis[0].size, nout->axis[1].size);
  for (d=0; d<nout->dim; d++) {
    fprintf(stderr, "    size[%d] = %d\n", d, (int)nout->axis[d].size);
  }
  fprintf(stderr, "##%s: post maybe alloc: nout->data = %p\n", me, nout->data);
  */
  if (nrrdAxisInfoCopy(nout, nin, axisMap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: trouble copying axis info", me);
    biffAdd(NRRD, err); return 1;
  }
  if (copyMapAxis0) {
    _nrrdAxisInfoCopy(nout->axis + 0, nmap->axis + 0,
                      NRRD_AXIS_INFO_SIZE_BIT);
  }

  mapcnt = _nrrdContentGet(nmap);
  if (nrrdContentSet_va(nout, multi ? mverbStr[kind] : verbStr[kind],
                        nin, "%s", mapcnt)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); free(mapcnt); return 1;
  }
  free(mapcnt); 
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); return 1;
  }
  return 0;
}
Exemplo n.º 3
0
/*
** _nrrdApply2DLutOrRegMap()
**
** the guts of nrrdApply2DLut and nrrdApply2DRegMap
**
** yikes, does NOT use biff, since we're only supposed to be called
** after copious error checking.  
**
** FOR INSTANCE, this allows nout == nin, which could be a big
** problem if mapAxis == 1.
**
** we don't need a typeOut arg because nout has already been allocated
** as some specific type; we'll look at that.
**
** NOTE: non-existant values get passed through regular maps and luts
** "unchanged".  However, if the output type is integral, the results
** are probaby undefined.  HEY: there is currently no warning message
** or error handling based on nrrdStateDisallowIntegerNonExist, but
** there really should be.
*/
int
_nrrdApply2DLutOrRegMap(Nrrd *nout, const Nrrd *nin,
                        const NrrdRange *range0, const NrrdRange *range1,
                        const Nrrd *nmap, int ramps,
                        int rescale0, int rescale1) {
  char me[]="_nrrdApply2DLutOrRegMap";
  char *inData, *outData, *mapData, *entData;
  size_t N, I;
  double (*inLoad)(const void *v), (*mapLup)(const void *v, size_t I),
    (*outInsert)(void *v, size_t I, double d),
    val0, val1, domMin0, domMax0, domMin1, domMax1;
  unsigned int i, mapAxis, mapLen0, mapLen1, mapIdx0, mapIdx1,
    entSize, entLen, inSize, outSize;

  mapAxis = nmap->dim - 2;             /* axis of nmap containing entries */
  mapData = (char *)nmap->data;        /* map data, as char* */
                                       /* low end of map domain */
  domMin0 = _nrrdApplyDomainMin(nmap, ramps, mapAxis + 0);
  domMin1 = _nrrdApplyDomainMin(nmap, ramps, mapAxis + 1);
                                       /* high end of map domain */
  domMax0 = _nrrdApplyDomainMax(nmap, ramps, mapAxis + 0);
  domMax1 = _nrrdApplyDomainMax(nmap, ramps, mapAxis + 1);
  mapLen0 = nmap->axis[mapAxis+0].size;   /* number of entries in map axis 0 */
  mapLen1 = nmap->axis[mapAxis+1].size;   /* number of entries in map axis 1 */
  mapLup = nrrdDLookup[nmap->type];    /* how to get doubles out of map */
  inData = (char *)nin->data;          /* input data, as char* */
  inLoad = nrrdDLoad[nin->type];       /* how to get doubles out of nin */
  inSize = nrrdElementSize(nin);       /* size of one input value */
  outData = (char *)nout->data;        /* output data, as char* */
  outInsert = nrrdDInsert[nout->type]; /* putting doubles into output */
  entLen = (mapAxis                    /* number of elements in one entry */
            ? nmap->axis[0].size
            : 1);
  outSize = entLen*nrrdElementSize(nout); /* size of entry in output */
  entSize = entLen*nrrdElementSize(nmap); /* size of entry in map */

  /*
  fprintf(stderr, "!%s: entLen = %u, mapLen = %u,%u\n", me,
          entLen, mapLen0, mapLen1);
  */

  N = nrrdElementNumber(nin)/2;       /* number of value pairs to be mapped */
  /* _VV = 1; */
  if (ramps) {
    fprintf(stderr, "%s: PANIC: unimplemented\n", me);
    exit(1);
  } else {
    /* lookup table */
    for (I=0; I<N; I++) {
      val0 = inLoad(inData + 0*inSize);
      val1 = inLoad(inData + 1*inSize);
      if (rescale0) {
        val0 = AIR_AFFINE(range0->min, val0, range0->max, domMin0, domMax0);
      }
      if (rescale1) {
        val1 = AIR_AFFINE(range1->min, val1, range1->max, domMin1, domMax1);
      }
      if (AIR_EXISTS(val0) && AIR_EXISTS(val1)) {
        mapIdx0 = airIndexClamp(domMin0, val0, domMax0, mapLen0);
        mapIdx1 = airIndexClamp(domMin1, val1, domMax1, mapLen1);
        entData = mapData + entSize*(mapIdx0 + mapLen0*mapIdx1);
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, mapLup(entData, i));
        }
      } else {
        /* copy non-existant values from input to output */
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, val0 + val1);  /* HEY this is weird */
        }
      }
      inData += 2*inSize;
      outData += outSize;
    }
  }

  return 0;
}
Exemplo n.º 4
0
/*
** _nrrdApply1DLutOrRegMap()
**
** the guts of nrrdApply1DLut and nrrdApply1DRegMap
**
** yikes, does NOT use biff, since we're only supposed to be called
** after copious error checking.  
**
** FOR INSTANCE, this allows nout == nin, which could be a big
** problem if mapAxis == 1.
**
** we don't need a typeOut arg because nout has already been allocated
** as some specific type; we'll look at that.
**
** NOTE: non-existant values get passed through regular maps and luts
** "unchanged".  However, if the output type is integral, the results
** are probaby undefined.  HEY: there is currently no warning message
** or error handling based on nrrdStateDisallowIntegerNonExist, but
** there really should be.
*/
int
_nrrdApply1DLutOrRegMap(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, 
                        const Nrrd *nmap, int ramps, int rescale, int multi) {
  /* char me[]="_nrrdApply1DLutOrRegMap"; */
  char *inData, *outData, *mapData, *entData0, *entData1;
  size_t N, I;
  double (*inLoad)(const void *v), (*mapLup)(const void *v, size_t I),
    (*outInsert)(void *v, size_t I, double d),
    val, mapIdxFrac, domMin, domMax;
  unsigned int i, mapAxis, mapLen, mapIdx, entSize, entLen, inSize, outSize;

  if (!multi) {
    mapAxis = nmap->dim - 1;           /* axis of nmap containing entries */
  } else {
    mapAxis = nmap->dim - nin->dim - 1;
  }
  mapData = (char *)nmap->data;        /* map data, as char* */
                                       /* low end of map domain */
  domMin = _nrrdApplyDomainMin(nmap, ramps, mapAxis);
                                       /* high end of map domain */
  domMax = _nrrdApplyDomainMax(nmap, ramps, mapAxis);
  mapLen = nmap->axis[mapAxis].size;   /* number of entries in map */
  mapLup = nrrdDLookup[nmap->type];    /* how to get doubles out of map */
  inData = (char *)nin->data;          /* input data, as char* */
  inLoad = nrrdDLoad[nin->type];       /* how to get doubles out of nin */
  inSize = nrrdElementSize(nin);       /* size of one input value */
  outData = (char *)nout->data;        /* output data, as char* */
  outInsert = nrrdDInsert[nout->type]; /* putting doubles into output */
  entLen = (mapAxis                    /* number of elements in one entry */
            ? nmap->axis[0].size
            : 1);
  outSize = entLen*nrrdElementSize(nout); /* size of entry in output */
  entSize = entLen*nrrdElementSize(nmap); /* size of entry in map */

  N = nrrdElementNumber(nin);       /* the number of values to be mapped */
  if (ramps) {
    /* regular map */
    for (I=0; I<N; I++) {
      /* ...
      if (!(I % 100)) fprintf(stderr, "I = %d\n", (int)I);
      ... */
      val = inLoad(inData);
      /* ...
      fprintf(stderr, "##%s: val = \na% 31.15f --> ", me, val);
      ... */
      if (rescale) {
        val = AIR_AFFINE(range->min, val, range->max, domMin, domMax);
        /* ...
        fprintf(stderr, "\nb% 31.15f (min,max = %g,%g)--> ", val,
                range->min, range->max);
        ... */
      }
      /* ...
      fprintf(stderr, "\nc% 31.15f --> clamp(%g,%g), %d --> ",
              val, domMin, domMax, mapLen);
      ... */
      if (AIR_EXISTS(val)) {
        val = AIR_CLAMP(domMin, val, domMax);
        mapIdxFrac = AIR_AFFINE(domMin, val, domMax, 0, mapLen-1);
        /* ...
        fprintf(stderr, "mapIdxFrac = \nd% 31.15f --> ",
                mapIdxFrac);
        ... */
        mapIdx = (unsigned int)mapIdxFrac;
        mapIdx -= mapIdx == mapLen-1;
        mapIdxFrac -= mapIdx;
        /* ...
        fprintf(stderr, "%s: (%d,\ne% 31.15f) --> \n",
                me, mapIdx, mapIdxFrac); 
        ... */
        entData0 = mapData + mapIdx*entSize;
        entData1 = mapData + (mapIdx+1)*entSize;
        for (i=0; i<entLen; i++) {
          val = ((1-mapIdxFrac)*mapLup(entData0, i) + 
                 mapIdxFrac*mapLup(entData1, i));
          outInsert(outData, i, val);
          /* ...
          fprintf(stderr, "f% 31.15f\n", val); 
          ... */
        }
      } else {
        /* copy non-existant values from input to output */
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, val);
        }
      }
      inData += inSize;
      outData += outSize;
      if (multi) {
        mapData += mapLen*entSize;
      }
    }    
  } else {
    /* lookup table */
    for (I=0; I<N; I++) {
      val = inLoad(inData);
      if (rescale) {
        val = AIR_AFFINE(range->min, val, range->max, domMin, domMax);
      }
      if (AIR_EXISTS(val)) {
        mapIdx = airIndexClamp(domMin, val, domMax, mapLen);
        entData0 = mapData + mapIdx*entSize;
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, mapLup(entData0, i));
        }
      } else {
        /* copy non-existant values from input to output */
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, val);
        }
      }
      inData += inSize;
      outData += outSize;
      if (multi) {
        mapData += mapLen*entSize;
      }
    }
  }

  return 0;
}