/*
******** nrrdApply1DIrregMap()
**
** Linear interpolation between irregularly spaced control points.
** Obviously, the location of the control point has to be given
** explicitly.  The map nrrd must have dimension 2, and each 
** control point is represented by a scanline along axis 0.  The
** first value is the position of the control point, and the remaining
** value(s) are linearly weighted according to the position of the
** input value among the control point locations.
**
** To allow "coloring" of non-existant values -inf, NaN, and +inf, if
** the very first value of the map (the location of the first control
** point) is non-existant, then the first three control point locations
** must be -inf, NaN, and +inf, in that order, and the information
** about these points will be used for corresponding input values.
** Doing this makes everything slower, however, because airFPClass_f()
** is called on every single value.
**
** This assumes that nrrd1DIrregMapCheck has been called on "nmap",
** and that nrrd1DIrregAclCheck has been called on "nacl" (if it is
** non-NULL).
*/
int
nrrdApply1DIrregMap(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range,
                    const Nrrd *nmap, const Nrrd *nacl,
                    int typeOut, int rescale) {
  char me[]="nrrdApply1DIrregMap", err[BIFF_STRLEN];
  size_t N, I;
  int i, *acl, entLen, posLen, aclLen, mapIdx, aclIdx,
    entSize, colSize, inSize, lo, hi, baseI;
  double val, *pos, domMin, domMax, mapIdxFrac,
    (*mapLup)(const void *v, size_t I),
    (*inLoad)(const void *v), (*outInsert)(void *v, size_t I, double d);
  char *inData, *outData, *entData0, *entData1;
  NrrdRange *range;
  airArray *mop;

  if (!(nout && nmap && nin)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  mop = airMopNew();
  if (_range) {
    range = nrrdRangeCopy(_range);
    nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState);
  } else {
    range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState);
  }
  airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways);
  if (_nrrdApply1DSetUp(nout, nin, range, nmap,
                        kindImap, typeOut, rescale, AIR_FALSE)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  if (nacl && nrrd1DIrregAclCheck(nacl)) {
    sprintf(err, "%s: given acl isn't valid", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  
  if (nacl) {
    acl = (int *)nacl->data;
    aclLen = nacl->axis[1].size;
  } else {
    acl = NULL;
    aclLen = 0;
  }
  pos = _nrrd1DIrregMapDomain(&posLen, &baseI, nmap);
  if (!pos) {
    sprintf(err, "%s: couldn't determine domain", me); 
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  airMopAdd(mop, pos, airFree, airMopAlways);
  mapLup = nrrdDLookup[nmap->type];
  
  inData = (char *)nin->data;
  inLoad = nrrdDLoad[nin->type];
  inSize = nrrdElementSize(nin);
  mapLup = nrrdDLookup[nmap->type];
  entLen = nmap->axis[0].size;    /* entLen is really 1 + entry length */
  entSize = entLen*nrrdElementSize(nmap);
  colSize = (entLen-1)*nrrdTypeSize[typeOut];
  outData = (char *)nout->data;
  outInsert = nrrdDInsert[nout->type];
  domMin = pos[0];
  domMax = pos[posLen-1];
  
  N = nrrdElementNumber(nin);
  for (I=0;
       I<N;
       I++, inData += inSize, outData += colSize) {
    val = inLoad(inData);
    /* _VV = ( (AIR_EXISTS(val) && (21 == (int)(-val))) 
       || 22400 < I ); */
    /* if (_VV)
       fprintf(stderr, "##%s: (%d) val = % 31.15f\n", me, (int)I, val); */
    if (!AIR_EXISTS(val)) {
      /* got a non-existant value */
      if (baseI) {
        /* and we know how to deal with them */
        switch (airFPClass_d(val)) {
        case airFP_NEG_INF:
          mapIdx = 0;
          break;
        case airFP_SNAN:
        case airFP_QNAN:
          mapIdx = 1;
          break;
        case airFP_POS_INF:
          mapIdx = 2;
          break;
        default:
          mapIdx = 0;
          fprintf(stderr, "%s: PANIC: non-existant value/class %g/%d "
                  "not handled\n",
                  me, val, airFPClass_d(val));
          exit(1);
        }
        entData0 = (char*)(nmap->data) + mapIdx*entSize;
        for (i=1; i<entLen; i++) {
          outInsert(outData, i-1, mapLup(entData0, i));
        }
        continue;  /* we're done! (with this value) */
      } else {
        /* we don't know how to properly deal with this non-existant value:
           we use the first entry, and then fall through to code below */
        mapIdx = 0;
        mapIdxFrac = 0.0;
      }
    } else {
      /* we have an existant value */
      if (rescale) {
        val = AIR_AFFINE(range->min, val, range->max, domMin, domMax);
        /* if (_VV) fprintf(stderr, "   rescaled --> % 31.15f\n", val); */
      }
      val = AIR_CLAMP(domMin, val, domMax);
      if (acl) {
        aclIdx = airIndex(domMin, val, domMax, aclLen);
        lo = acl[0 + 2*aclIdx];
        hi = acl[1 + 2*aclIdx];
      } else {
        lo = 0;
        hi = posLen-2;
      }
      if (lo < hi) {
        mapIdx = _nrrd1DIrregFindInterval(pos, val, lo, hi);
      } else {
        /* acl did its job ==> lo == hi */
        mapIdx = lo;
      }
    }
    mapIdxFrac = AIR_AFFINE(pos[mapIdx], val, pos[mapIdx+1], 0.0, 1.0);
    /* if (_VV) fprintf(stderr, "##%s: val=\n% 31.15f --> "
                     "mapIdx,frac = %d,\n% 31.15f\n",
                     me, val, mapIdx, mapIdxFrac); */
    entData0 = (char*)(nmap->data) + (baseI+mapIdx)*entSize;
    entData1 = (char*)(nmap->data) + (baseI+mapIdx+1)*entSize;
    /* if (_VV) fprintf(stderr, "##%s: 2; %d/\n% 31.15f --> entLen=%d "
                     "baseI=%d -->\n",
                     me, mapIdx, mapIdxFrac, entLen, baseI); */
    for (i=1; i<entLen; i++) {
      val = ((1-mapIdxFrac)*mapLup(entData0, i) +
             mapIdxFrac*mapLup(entData1, i));
      /* if (_VV) fprintf(stderr, "% 31.15f\n", val); */
      outInsert(outData, i-1, val);
    }
    /* if (_VV) fprintf(stderr, "##%s: 3\n", me); */
  }
  airMopOkay(mop);
  return 0;
}
Exemple #2
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;
}
/*
** _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;
}