/* ******** nrrdContentSet ** ** Kind of like sprintf, but for the content string of the nrrd. ** ** Whether or not we write a new content for an old nrrd ("nin") with ** NULL content is decided here, according to ** nrrdStateAlwaysSetContent. ** ** Does the string allocation and some attempts at error detection. ** Does allow nout==nin, which requires some care. */ int nrrdContentSet_va(Nrrd *nout, const char *func, const Nrrd *nin, const char *format, ...) { static const char me[]="nrrdContentSet_va"; va_list ap; char *content; if (!(nout && func && nin && format)) { biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nrrdStateDisableContent) { /* we kill content always */ nout->content = (char *)airFree(nout->content); return 0; } if (!nin->content && !nrrdStateAlwaysSetContent) { /* there's no input content, and we're not supposed to invent any content, so after freeing nout's content we're done */ nout->content = (char *)airFree(nout->content); return 0; } /* we copy the input nrrd content first, before blowing away the output content, in case nout == nin */ content = _nrrdContentGet(nin); va_start(ap, format); if (_nrrdContentSet_nva(nout, func, content, format, ap)) { biffAddf(NRRD, "%s:", me); va_end(ap); free(content); return 1; } va_end(ap); free(content); return 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; }
/* ******** nrrdSplice() ** ** (opposite of nrrdSlice): replaces one slice of a nrrd with ** another nrrd. Will allocate memory for output only if nout != nin. */ int nrrdSplice(Nrrd *nout, const Nrrd *nin, const Nrrd *nslice, unsigned int axis, size_t pos) { char me[]="nrrdSplice", func[]="splice", err[BIFF_STRLEN]; size_t I, rowLen, /* length of segment */ colStep, /* distance between start of each segment */ colLen; /* number of periods */ unsigned int ai; char *src, *dest, *sliceCont; if (!(nin && nout && nslice)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (nout == nslice) { sprintf(err, "%s: nout==nslice disallowed", me); biffAdd(NRRD, err); return 1; } /* check that desired slice location is legit */ if (!( axis < nin->dim )) { sprintf(err, "%s: slice axis %d out of bounds (0 to %d)", me, axis, nin->dim-1); biffAdd(NRRD, err); return 1; } if (!( pos < nin->axis[axis].size )) { sprintf(err, "%s: position " _AIR_SIZE_T_CNV " out of bounds (0 to " _AIR_SIZE_T_CNV ")", me, pos, nin->axis[axis].size-1); biffAdd(NRRD, err); return 1; } /* check that slice will fit in nin */ if (nrrdCheck(nslice) || nrrdCheck(nin)) { sprintf(err, "%s: input or slice not valid nrrd", me); biffAdd(NRRD, err); return 1; } if (!( nin->dim-1 == nslice->dim )) { sprintf(err, "%s: dim of slice (%d) not one less than dim of input (%d)", me, nslice->dim, nin->dim); biffAdd(NRRD, err); return 1; } if (!( nin->type == nslice->type )) { sprintf(err, "%s: type of slice (%s) != type of input (%s)", me, airEnumStr(nrrdType, nslice->type), airEnumStr(nrrdType, nin->type)); biffAdd(NRRD, err); return 1; } if (nrrdTypeBlock == nin->type) { if (!( nin->blockSize == nslice->blockSize )) { sprintf(err, "%s: input's blockSize (" _AIR_SIZE_T_CNV ") != subvolume's blockSize (" _AIR_SIZE_T_CNV ")", me, nin->blockSize, nslice->blockSize); biffAdd(NRRD, err); return 1; } } for (ai=0; ai<nslice->dim; ai++) { if (!( nin->axis[ai + (ai >= axis)].size == nslice->axis[ai].size )) { sprintf(err, "%s: input's axis %d size (" _AIR_SIZE_T_CNV ") != slices axis %d size (" _AIR_SIZE_T_CNV ")", me, ai + (ai >= axis), nin->axis[ai + (ai >= axis)].size, ai, nslice->axis[ai].size); biffAdd(NRRD, err); return 1; } } if (nout != nin) { if (nrrdCopy(nout, nin)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } } /* else we're going to splice in place */ /* the following was copied from nrrdSlice() */ /* set up control variables */ rowLen = colLen = 1; for (ai=0; ai<nin->dim; ai++) { if (ai < axis) { rowLen *= nin->axis[ai].size; } else if (ai > axis) { colLen *= nin->axis[ai].size; } } rowLen *= nrrdElementSize(nin); colStep = rowLen*nin->axis[axis].size; /* the skinny */ src = (char *)nout->data; /* switched src,dest from nrrdSlice() */ dest = (char *)nslice->data; src += rowLen*pos; for (I=0; I<colLen; I++) { /* HEY: replace with AIR_MEMCPY() or similar, when applicable */ memcpy(src, dest, rowLen); /* switched src,dest from nrrdSlice() */ src += colStep; dest += rowLen; } sliceCont = _nrrdContentGet(nslice); if (nrrdContentSet_va(nout, func, nin, "%s,%d," _AIR_SIZE_T_CNV, sliceCont, axis, pos)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); free(sliceCont); return 1; } free(sliceCont); /* basic info copied by nrrdCopy above */ return 0; }
/* ******** nrrdInset() ** ** (opposite of nrrdCrop()) replace some sub-volume inside a nrrd with ** another given nrrd. ** */ int nrrdInset(Nrrd *nout, const Nrrd *nin, const Nrrd *nsub, const size_t *min) { char me[]="nrrdInset", func[] = "inset", err[BIFF_STRLEN], buff1[NRRD_DIM_MAX*30], buff2[AIR_STRLEN_SMALL]; unsigned int ai; size_t I, lineSize, /* #bytes in one scanline to be copied */ typeSize, /* size of data type */ cIn[NRRD_DIM_MAX], /* coords for line start, in input */ cOut[NRRD_DIM_MAX], /* coords for line start, in output */ szIn[NRRD_DIM_MAX], szOut[NRRD_DIM_MAX], idxIn, idxOut, /* linear indices for input and output */ numLines; /* number of scanlines in output nrrd */ char *dataIn, *dataOut, *subCont; /* errors */ if (!(nout && nin && nsub && min)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (nout == nsub) { sprintf(err, "%s: nout==nsub disallowed", me); biffAdd(NRRD, err); return 1; } if (nrrdCheck(nin)) { sprintf(err, "%s: input not valid nrrd", me); biffAdd(NRRD, err); return 1; } if (nrrdCheck(nsub)) { sprintf(err, "%s: subvolume not valid nrrd", me); biffAdd(NRRD, err); return 1; } if (!( nin->dim == nsub->dim )) { sprintf(err, "%s: input's dim (%d) != subvolume's dim (%d)", me, nin->dim, nsub->dim); biffAdd(NRRD, err); return 1; } if (!( nin->type == nsub->type )) { sprintf(err, "%s: input's type (%s) != subvolume's type (%s)", me, airEnumStr(nrrdType, nin->type), airEnumStr(nrrdType, nsub->type)); biffAdd(NRRD, err); return 1; } if (nrrdTypeBlock == nin->type) { if (!( nin->blockSize == nsub->blockSize )) { sprintf(err, "%s: input's blockSize (" _AIR_SIZE_T_CNV ") != subvolume's blockSize (" _AIR_SIZE_T_CNV ")", me, nin->blockSize, nsub->blockSize); biffAdd(NRRD, err); return 1; } } for (ai=0; ai<nin->dim; ai++) { if (!( min[ai] + nsub->axis[ai].size - 1 <= nin->axis[ai].size - 1)) { sprintf(err, "%s: axis %d range of inset indices [" _AIR_SIZE_T_CNV "," _AIR_SIZE_T_CNV "] not within " "input indices [0," _AIR_SIZE_T_CNV "]", me, ai, min[ai], min[ai] + nsub->axis[ai].size - 1, nin->axis[ai].size - 1); biffAdd(NRRD, err); return 1; } } if (nout != nin) { if (nrrdCopy(nout, nin)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } } /* else we're going to inset in place */ /* WARNING: following code copied/modified from nrrdCrop(), so the meanings of "in"/"out", "src"/"dest" are all messed up */ nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn); nrrdAxisInfoGet_nva(nsub, nrrdAxisInfoSize, szOut); numLines = 1; for (ai=1; ai<nin->dim; ai++) { numLines *= szOut[ai]; } lineSize = szOut[0]*nrrdElementSize(nin); /* the skinny */ typeSize = nrrdElementSize(nin); dataIn = (char *)nout->data; dataOut = (char *)nsub->data; for (ai=0; ai<NRRD_DIM_MAX; ai++) { cOut[ai] = 0; } for (I=0; I<numLines; I++) { for (ai=0; ai<nin->dim; ai++) { cIn[ai] = cOut[ai] + min[ai]; } NRRD_INDEX_GEN(idxOut, cOut, szOut, nin->dim); NRRD_INDEX_GEN(idxIn, cIn, szIn, nin->dim); memcpy(dataIn + idxIn*typeSize, dataOut + idxOut*typeSize, lineSize); /* the lowest coordinate in cOut[] will stay zero, since we are copying one (1-D) scanline at a time */ NRRD_COORD_INCR(cOut, szOut, nin->dim, 1); } /* HEY: before Teem version 2.0 figure out nrrdKind stuff here */ strcpy(buff1, "["); for (ai=0; ai<nin->dim; ai++) { sprintf(buff2, "%s" _AIR_SIZE_T_CNV, (ai ? "," : ""), min[ai]); strcat(buff1, buff2); } strcat(buff1, "]"); subCont = _nrrdContentGet(nsub); if (nrrdContentSet_va(nout, func, nin, "%s,%s", subCont, buff1)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); free(subCont); return 1; } free(subCont); /* basic info copied by nrrdCopy above */ return 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; }
/* ******** nrrdArithTerneryOp ** ** HEY: UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED ** ** this is a simplified version of nrrdArithIterTernaryOp, written after ** that, in a hurry, to operate directly on three nrrds, instead with ** the NrrdIter nonsense */ int nrrdArithTernaryOp(Nrrd *nout, int op, const Nrrd *ninA, const Nrrd *ninB, const Nrrd *ninC) { static const char me[]="nrrdArithTernaryOp"; char *contA, *contB, *contC; size_t N, I, size[NRRD_DIM_MAX]; double (*ins)(void *v, size_t I, double d), (*lupA)(const void *v, size_t I), (*lupB)(const void *v, size_t I), (*lupC)(const void *v, size_t I), (*top)(double a, double b, double c), valA, valB, valC; if (!( nout && !nrrdCheck(ninA) && !nrrdCheck(ninB) && !nrrdCheck(ninC) )) { biffAddf(NRRD, "%s: NULL pointer or invalid args", me); return 1; } if (!( nrrdSameSize(ninA, ninB, AIR_TRUE) && nrrdSameSize(ninA, ninC, AIR_TRUE) )) { biffAddf(NRRD, "%s: size mismatch between arguments", me); return 1; } if (airEnumValCheck(nrrdTernaryOp, op)) { biffAddf(NRRD, "%s: ternary op %d invalid", me, op); return 1; } nrrdAxisInfoGet_nva(ninA, nrrdAxisInfoSize, size); if (!( nout == ninA || nout == ninB || nout == ninC)) { if (_nrrdMaybeAllocMaybeZero_nva(nout, ninA->type, ninA->dim, size, AIR_FALSE /* zero when no realloc */)) { biffAddf(NRRD, "%s: couldn't allocate output nrrd", me); return 1; } if (nrrdAxisInfoCopy(nout, ninA, NULL, NRRD_AXIS_INFO_NONE)) { biffAddf(NRRD, "%s:", me); return 1; } nrrdBasicInfoCopy(nout, ninA, (NRRD_BASIC_INFO_DATA_BIT | NRRD_BASIC_INFO_TYPE_BIT | NRRD_BASIC_INFO_DIMENSION_BIT | NRRD_BASIC_INFO_CONTENT_BIT | NRRD_BASIC_INFO_COMMENTS_BIT | (nrrdStateKeyValuePairsPropagate ? 0 : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))); } nrrdBasicInfoInit(nout, NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT | NRRD_BASIC_INFO_OLDMAX_BIT)); top = _nrrdTernaryOp[op]; N = nrrdElementNumber(ninA); lupA = nrrdDLookup[ninA->type]; lupB = nrrdDLookup[ninB->type]; lupC = nrrdDLookup[ninC->type]; ins = nrrdDInsert[nout->type]; for (I=0; I<N; I++) { /* HEY: there is a loss of precision issue here with 64-bit ints */ valA = lupA(ninA->data, I); valB = lupB(ninB->data, I); valC = lupC(ninC->data, I); ins(nout->data, I, top(valA, valB, valC)); } contA = _nrrdContentGet(ninA); contB = _nrrdContentGet(ninB); contC = _nrrdContentGet(ninC); if (_nrrdContentSet_va(nout, airEnumStr(nrrdTernaryOp, op), contA, "%s,%s", contB, contC)) { biffAddf(NRRD, "%s:", me); free(contA); free(contB); free(contC); return 1; } free(contA); free(contB); free(contC); return 0; }