/* ** _nrrd1DIrregMapDomain() ** ** ALLOCATES an array of doubles storing the existant control point ** locations, and sets its length in *poslenP. If there are the three ** points with non-existant locations, these are ignored. ** ** Assumes that nrrd1DIrregMapCheck has been called on "nmap". */ double * _nrrd1DIrregMapDomain(int *posLenP, int *baseIP, const Nrrd *nmap) { char me[]="_nrrd1DIrregMapDomain", err[BIFF_STRLEN]; int i, entLen, baseI, posLen; double *pos, (*mapLup)(const void *v, size_t I); mapLup = nrrdDLookup[nmap->type]; baseI = AIR_EXISTS(mapLup(nmap->data, 0)) ? 0 : 3; if (baseIP) { *baseIP = baseI; } entLen = nmap->axis[0].size; posLen = nmap->axis[1].size - baseI; if (posLenP) { *posLenP = posLen; } pos = (double*)malloc(posLen * sizeof(double)); if (!pos) { sprintf(err, "%s: couldn't allocate %d doubles\n", me, posLen); biffAdd(NRRD, err); return NULL; } for (i=0; i<posLen; i++) { pos[i] = mapLup(nmap->data, (baseI+i)*entLen); } return pos; }
/* ** _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; }
/* ******** 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; }
/* ******** nrrd1DIrregMapCheck() ** ** return zero only for the valid forms of 1D irregular map. ** imap must be 2D, both sizes >= 2, non-block-type, no non-existant ** values in range. If the first point's position is non-existant, ** than the first three points positions must be -inf, NaN, and +inf, ** and none of the other points locations can be non-existant, and ** they must increase monotonically. There must be at least two ** points with existant positions. */ int nrrd1DIrregMapCheck(const Nrrd *nmap) { char me[]="nrrd1DIrregMapCheck", err[BIFF_STRLEN]; double (*mapLup)(const void *v, size_t I); int i, entLen, mapLen, baseI; size_t min[2], max[2]; Nrrd *nrange; if (!nmap) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (nrrdCheck(nmap)) { sprintf(err, "%s: ", me); biffAdd(NRRD, err); return 1; } if (nrrdTypeBlock == nmap->type) { sprintf(err, "%s: map is %s type, need scalar", me, airEnumStr(nrrdType, nrrdTypeBlock)); biffAdd(NRRD, err); return 1; } if (2 != nmap->dim) { sprintf(err, "%s: map needs to have dimension 2, not %d", me, nmap->dim); biffAdd(NRRD, err); return 1; } entLen = nmap->axis[0].size; mapLen = nmap->axis[1].size; if (!( entLen >= 2 && mapLen >= 2 )) { sprintf(err, "%s: both map's axes sizes should be >= 2 (not %d,%d)", me, entLen, mapLen); biffAdd(NRRD, err); return 1; } min[0] = 1; max[0] = nmap->axis[0].size-1; min[1] = 0; max[1] = nmap->axis[1].size-1; if (nrrdCrop(nrange=nrrdNew(), nmap, min, max)) { sprintf(err, "%s: couldn't crop to isolate range of map", me); biffAdd(NRRD, err); nrrdNuke(nrange); return 1; } if (nrrdHasNonExist(nrange)) { sprintf(err, "%s: map has non-existent values in its range", me); biffAdd(NRRD, err); nrrdNuke(nrange); return 1; } nrrdNuke(nrange); mapLup = nrrdDLookup[nmap->type]; if (AIR_EXISTS(mapLup(nmap->data, 0))) { baseI = 0; } else { baseI = 3; if (!( mapLen >= 5 )) { sprintf(err, "%s: length of map w/ non-existant locations must " "be >= 5 (not %d)", me, mapLen); biffAdd(NRRD, err); return 1; } if (!( airFP_NEG_INF == airFPClass_d(mapLup(nmap->data, 0*entLen)) && airFP_QNAN == airFPClass_d(mapLup(nmap->data, 1*entLen)) && airFP_POS_INF == airFPClass_d(mapLup(nmap->data, 2*entLen)) )) { sprintf(err, "%s: 1st entry's position non-existant, but position " "of 1st three entries not -inf, NaN, and +inf", me); biffAdd(NRRD, err); return 1; } } for (i=baseI; i<mapLen; i++) { if (!AIR_EXISTS(mapLup(nmap->data, i*entLen))) { sprintf(err, "%s: entry %d has non-existant position", me, i); biffAdd(NRRD, err); return 1; } } for (i=baseI; i<mapLen-1; i++) { if (!( mapLup(nmap->data, i*entLen) < mapLup(nmap->data, (i+1)*entLen) )) { sprintf(err, "%s: map entry %d pos (%g) not < entry %d pos (%g)", me, i, mapLup(nmap->data, i*entLen), i+1, mapLup(nmap->data, (i+1)*entLen)); biffAdd(NRRD, err); return 1; } } 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; }