int baneInputCheck (Nrrd *nin, baneHVolParm *hvp) { char me[]="baneInputCheck", err[BIFF_STRLEN]; int i; if (nrrdCheck(nin)) { sprintf(err, "%s: basic nrrd validity check failed", me); biffMove(BANE, err, NRRD); return 1; } if (3 != nin->dim) { sprintf(err, "%s: need a 3-dimensional nrrd (not %d)", me, nin->dim); biffAdd(BANE, err); return 1; } if (nrrdTypeBlock == nin->type) { sprintf(err, "%s: can't operate on block type", me); biffAdd(BANE, err); return 1; } if (!( AIR_EXISTS(nin->axis[0].spacing) && nin->axis[0].spacing != 0 && AIR_EXISTS(nin->axis[1].spacing) && nin->axis[1].spacing != 0 && AIR_EXISTS(nin->axis[2].spacing) && nin->axis[2].spacing != 0 )) { sprintf(err, "%s: must have non-zero existant spacing for all 3 axes", me); biffAdd(BANE, err); return 1; } for (i=0; i<=2; i++) { if (_baneAxisCheck(hvp->axis + i)) { sprintf(err, "%s: trouble with axis %d", me, i); biffAdd(BANE, err); return 1; } } if (!hvp->clip) { sprintf(err, "%s: got NULL baneClip", me); biffAdd(BANE, err); return 1; } /* all okay */ return 0; }
/* ** so that you can see if a given volume will work as the given kind */ int gageKindVolumeCheck(const gageKind *kind, const Nrrd *nrrd) { static const char me[]="gageKindVolumeCheck"; if (!(kind && nrrd)) { biffAddf(GAGE, "%s: got NULL pointer", me); return 1; } if (nrrdCheck(nrrd)) { biffMovef(GAGE, NRRD, "%s: problem with nrrd", me); return 1; } if (!(nrrd->dim == 3 + kind->baseDim)) { biffAddf(GAGE, "%s: nrrd should be %u-D, not %u-D", me, 3 + kind->baseDim, nrrd->dim); return 1; } if (nrrdTypeBlock == nrrd->type) { biffAddf(GAGE, "%s: can't handle %s-type volumes", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (1 == kind->baseDim && (kind->valLen != nrrd->axis[0].size)) { biffAddf(GAGE, "%s: kind requires %u axis 0 values, not " _AIR_SIZE_T_CNV, me, kind->valLen, nrrd->axis[0].size); return 1; } /* this eventually calls _gageShapeSet(), which, for purely historical reasons, does the brunt of the error checking, some of which is almost certainly redundant with checks above ... */ if (gageVolumeCheck(NULL, nrrd, kind)) { biffAddf(GAGE, "%s: trouble", me); return 1; } return 0; }
/* ** _nrrdWrite ** ** Write a nrrd to given file or string (allocated by nrrd), using the ** format and and encoding indicated in nio. Cleverness should be ** isolated and collected here: by the time nio->format->write() is ** called, all writing parameters must be given explicitly, and their ** appropriateness is explicitly tested */ int _nrrdWrite(FILE *file, char **stringP, const Nrrd *nrrd, NrrdIoState *_nio) { char me[]="_nrrdWrite", err[BIFF_STRLEN]; NrrdIoState *nio; airArray *mop; if (!((file || stringP) && nrrd)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (file && stringP) { sprintf(err, "%s: can't write to both file and string", me); biffAdd(NRRD, err); return 1; } if (nrrdCheck(nrrd)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } mop = airMopNew(); if (_nio) { nio = _nio; } else { nio = nrrdIoStateNew(); if (!nio) { sprintf(err, "%s: couldn't alloc local NrrdIoState", me); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways); } if (_nrrdEncodingMaybeSet(nio) || _nrrdFormatMaybeSet(nio)) { sprintf(err, "%s: ", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (nio->byteSkip || nio->lineSkip) { /* NOTE: unu make bypasses this by calling nrrdFormatNRRD->write() directly */ sprintf(err, "%s: can't generate line or byte skips on data write", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (stringP) { if (nrrdFormatNRRD != nio->format) { sprintf(err, "%s: sorry, can only write %s files to strings (not %s)", me, nrrdFormatNRRD->name, nio->format->name); biffAdd(NRRD, err); airMopError(mop); return 1; } /* we do this in two passes; first see how much room is needed for the header, then allocate, then write the header */ nio->learningHeaderStrlen = AIR_TRUE; if (nio->format->write(NULL, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } *stringP = (char*)malloc(nio->headerStrlen + 1); if (!*stringP) { sprintf(err, "%s: couldn't allocate header string (%u len )", me, nio->headerStrlen); biffAdd(NRRD, err); airMopError(mop); return 1; } nio->learningHeaderStrlen = AIR_FALSE; nio->headerStringWrite = *stringP; if (nio->format->write(NULL, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } } else { /* call the writer appropriate for the format */ if (nio->format->write(file, nrrd, nio)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } } airMopOkay(mop); 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; }
/* ******** 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; }
int alanInit(alanContext *actx, const Nrrd *nlevInit, const Nrrd *nparmInit) { char me[]="alanInit", err[BIFF_STRLEN]; alan_t *levInit=NULL, *lev0, *parmInit=NULL, *parm; size_t I, N; if (_alanCheck(actx)) { sprintf(err, "%s: ", me); biffAdd(ALAN, err); return 1; } if (!( actx->_nlev[0] && actx->_nlev[0] && actx->nparm )) { sprintf(err, "%s: _nlev[0,1] not allocated: call alanUpdate", me); biffAdd(ALAN, err); return 1; } if (nlevInit) { if (nrrdCheck(nlevInit)) { sprintf(err, "%s: given nlevInit has problems", me); biffMove(ALAN, err, NRRD); return 1; } if (!( alan_nt == nlevInit->type && nlevInit->dim == 1 + actx->dim && actx->_nlev[0]->axis[0].size == nlevInit->axis[0].size && actx->size[0] == nlevInit->axis[1].size && actx->size[1] == nlevInit->axis[2].size && (2 == actx->dim || actx->size[2] == nlevInit->axis[3].size) )) { sprintf(err, "%s: type/size mismatch with given nlevInit", me); biffAdd(ALAN, err); return 1; } levInit = (alan_t*)(nlevInit->data); } if (nparmInit) { if (nrrdCheck(nparmInit)) { sprintf(err, "%s: given nparmInit has problems", me); biffMove(ALAN, err, NRRD); return 1; } if (!( alan_nt == nparmInit->type && nparmInit->dim == 1 + actx->dim && 3 == nparmInit->axis[0].size && actx->size[0] == nparmInit->axis[1].size && actx->size[1] == nparmInit->axis[2].size && (2 == actx->dim || actx->size[2] == nparmInit->axis[3].size) )) { sprintf(err, "%s: type/size mismatch with given nparmInit", me); biffAdd(ALAN, err); return 1; } parmInit = (alan_t*)(nparmInit->data); } #define RAND AIR_AFFINE(0, airDrandMT(), 1, -actx->randRange, actx->randRange) N = nrrdElementNumber(actx->_nlev[0])/actx->_nlev[0]->axis[0].size; lev0 = (alan_t*)(actx->_nlev[0]->data); parm = (alan_t*)(actx->nparm->data); for (I=0; I<N; I++) { if (levInit) { lev0[0 + 2*I] = levInit[0 + 2*I]; lev0[1 + 2*I] = levInit[1 + 2*I]; } else { /* NOTE: the random number stuff here is OUTSIDE the multi-threaded segment of the program- only the init thread does this */ lev0[0 + 2*I] = AIR_CAST(alan_t, actx->initA + RAND); lev0[1 + 2*I] = AIR_CAST(alan_t, actx->initB + RAND); } if (parmInit) { parm[0 + 3*I] = parmInit[0 + 3*I]; parm[1 + 3*I] = parmInit[1 + 3*I]; parm[2 + 3*I] = parmInit[2 + 3*I]; } else { parm[0 + 3*I] = actx->deltaT; parm[1 + 3*I] = actx->alpha; parm[2 + 3*I] = actx->beta; } } return 0; }
int _pushContextCheck(pushContext *pctx) { char me[]="_pushContextCheck", err[BIFF_STRLEN]; unsigned int sidx; int nul; if (!pctx) { sprintf(err, "%s: got NULL pointer", me); biffAdd(PUSH, err); return 1; } if (!( AIR_IN_CL(1, pctx->numStage, PUSH_STAGE_MAXNUM) )) { sprintf(err, "%s: pctx->numStage (%d) outside valid range [1,%d]", me, pctx->numStage, PUSH_STAGE_MAXNUM); biffAdd(PUSH, err); return 1; } nul = AIR_FALSE; for (sidx=0; sidx<pctx->numStage; sidx++) { nul |= !(pctx->process[sidx]); } if (nul) { sprintf(err, "%s: one or more of the process functions was NULL", me); biffAdd(PUSH, err); return 1; } if (!( pctx->numThing >= 1 )) { sprintf(err, "%s: pctx->numThing (%d) not >= 1\n", me, pctx->numThing); biffAdd(PUSH, err); return 1; } if (!( pctx->numThread >= 1 )) { sprintf(err, "%s: pctx->numThread (%d) not >= 1\n", me, pctx->numThread); biffAdd(PUSH, err); return 1; } if (!( AIR_IN_CL(1, pctx->numThread, PUSH_THREAD_MAXNUM) )) { sprintf(err, "%s: pctx->numThread (%d) outside valid range [1,%d]", me, pctx->numThread, PUSH_THREAD_MAXNUM); biffAdd(PUSH, err); return 1; } if (nrrdCheck(pctx->nin)) { sprintf(err, "%s: got a broken input nrrd", me); biffMove(PUSH, err, NRRD); return 1; } if (!( (3 == pctx->nin->dim && 4 == pctx->nin->axis[0].size) || (4 == pctx->nin->dim && 7 == pctx->nin->axis[0].size) )) { sprintf(err, "%s: input doesn't look like 2D or 3D masked tensors", me); biffAdd(PUSH, err); return 1; } if (pctx->npos) { if (nrrdCheck(pctx->npos)) { sprintf(err, "%s: got a broken position nrrd", me); biffMove(PUSH, err, NRRD); return 1; } if (!( 2 == pctx->npos->dim && 3 == pctx->npos->axis[0].size )) { sprintf(err, "%s: position nrrd not 2-D 3-by-N", me); biffAdd(PUSH, err); return 1; } } if (pctx->nstn) { if (!pctx->npos) { sprintf(err, "%s: can't have start/num nrrd w/out position nrrd", me); biffAdd(PUSH, err); return 1; } if (nrrdCheck(pctx->nstn)) { sprintf(err, "%s: got a broken start/num nrrd", me); biffMove(PUSH, err, NRRD); return 1; } if (!( 2 == pctx->nstn->dim && nrrdTypeInt == pctx->nstn->type && 3 == pctx->nstn->axis[0].size )) { sprintf(err, "%s: start/num nrrd not 2-D 3-by-N array of %ss", me, airEnumStr(nrrdType, nrrdTypeInt)); biffAdd(PUSH, err); return 1; } } return 0; }
int miteNtxfCheck(const Nrrd *ntxf) { static const char me[]="miteNtxfCheck"; char *rangeStr, *domStr; gageItemSpec isp; unsigned int rii, axi; int ilog2; if (nrrdCheck(ntxf)) { biffMovef(MITE, NRRD, "%s: basic nrrd validity check failed", me); return 1; } if (!( nrrdTypeFloat == ntxf->type || nrrdTypeDouble == ntxf->type || nrrdTypeUChar == ntxf->type )) { biffAddf(MITE, "%s: need a type %s, %s or %s nrrd (not %s)", me, airEnumStr(nrrdType, nrrdTypeFloat), airEnumStr(nrrdType, nrrdTypeDouble), airEnumStr(nrrdType, nrrdTypeUChar), airEnumStr(nrrdType, ntxf->type)); return 1; } if (!( 2 <= ntxf->dim )) { biffAddf(MITE, "%s: nrrd dim (%d) isn't at least 2 (for a 1-D txf)", me, ntxf->dim); return 1; } rangeStr = ntxf->axis[0].label; if (0 == airStrlen(rangeStr)) { biffAddf(MITE, "%s: axis[0]'s label doesn't specify txf range", me); return 1; } if (airStrlen(rangeStr) != ntxf->axis[0].size) { char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; biffAddf(MITE, "%s: axis[0]'s size %s, but label specifies %s values", me, airSprintSize_t(stmp1, ntxf->axis[0].size), airSprintSize_t(stmp2, airStrlen(rangeStr))); return 1; } for (rii=0; rii<airStrlen(rangeStr); rii++) { if (!strchr(miteRangeChar, rangeStr[rii])) { biffAddf(MITE, "%s: char %d of axis[0]'s label (\"%c\") isn't a valid " "transfer function range specifier (not in \"%s\")", me, rii, rangeStr[rii], miteRangeChar); return 1; } } for (axi=1; axi<ntxf->dim; axi++) { if (1 == ntxf->axis[axi].size) { biffAddf(MITE, "%s: # samples on axis %d must be > 1", me, axi); return 1; } domStr = ntxf->axis[axi].label; if (0 == airStrlen(domStr)) { biffAddf(MITE, "%s: axis[%d] of txf didn't specify a domain variable", me, axi); return 1; } if (miteVariableParse(&isp, domStr)) { biffAddf(MITE, "%s: couldn't parse txf domain \"%s\" for axis %d\n", me, domStr, axi); return 1; } if (!( 1 == isp.kind->table[isp.item].answerLength || 3 == isp.kind->table[isp.item].answerLength )) { biffAddf(MITE, "%s: %s (item %d) not a scalar or vector " "(answerLength = %d): " "can't be a txf domain variable", me, domStr, isp.item, isp.kind->table[isp.item].answerLength); return 1; } if (3 == isp.kind->table[isp.item].answerLength) { /* has to be right length for one of the quantization schemes */ ilog2 = airLog2(ntxf->axis[axi].size); if (-1 == ilog2) { char stmp[AIR_STRLEN_SMALL]; biffAddf(MITE, "%s: txf axis size for %s must be power of 2 (not %s)", me, domStr, airSprintSize_t(stmp, ntxf->axis[axi].size)); return 1; } else { if (!( AIR_IN_CL(8, ilog2, 16) )) { biffAddf(MITE, "%s: log_2 of txf axis size for %s should be in " "range [8,16] (not %d)", me, domStr, ilog2); return 1; } } } else { if (!( AIR_EXISTS(ntxf->axis[axi].min) && AIR_EXISTS(ntxf->axis[axi].max) )) { biffAddf(MITE, "%s: min and max of axis %d aren't both set", me, axi); return 1; } if (!( ntxf->axis[axi].min < ntxf->axis[axi].max )) { biffAddf(MITE, "%s: min (%g) not less than max (%g) on axis %d", me, ntxf->axis[axi].min, ntxf->axis[axi].max, axi); return 1; } } } return 0; }
/* ** _gageShapeSet ** ** we are serving two masters here. If ctx is non-NULL, we are being called ** from within gage, and we are to be lax or strict according to the settings ** of ctx->parm.requireAllSpacings and ctx->parm.requireEqualCenters. If ** ctx is NULL, gageShapeSet was called, in which case we go with lax ** behavior (nothing "required") ** ** This function has subsumed the contents of the old gageVolumeCheck, ** and hence has become this weird beast- part error checker and part ** (gageShape) initializer. Oh well... */ int _gageShapeSet(const gageContext *ctx, gageShape *shape, const Nrrd *nin, unsigned int baseDim) { static const char me[]="_gageShapeSet"; int ai, cx, cy, cz, statCalc[3], status, ofspc; unsigned int minsize; const NrrdAxisInfo *ax[3]; double vecA[4], vecB[3], vecC[3], vecD[4], matA[9], spcCalc[3], vecCalc[3][NRRD_SPACE_DIM_MAX], orig[NRRD_SPACE_DIM_MAX]; airArray *mop; /* fprintf(stderr, "!%s: ctx = %p (%s, %s)\n", me, ctx, (ctx ? (ctx->shape->fromOrientation ? "YES from orient" : "not from orient") : "???"), (ctx ? (ctx->parm.orientationFromSpacing ? "YES ofs" : "not ofs") : "???")); */ /* ------ basic error checking */ mop = airMopNew(); airMopAdd(mop, shape, _mopShapeReset, airMopOnError); if (!( shape && nin )) { biffAddf(GAGE, "%s: got NULL pointer", me); airMopError(mop); return 1; } if (nrrdCheck(nin)) { biffMovef(GAGE, NRRD, "%s: basic nrrd validity check failed", me); airMopError(mop); return 1; } if (nrrdTypeBlock == nin->type) { biffAddf(GAGE, "%s: need a non-block type nrrd", me); airMopError(mop); return 1; } if (!(nin->dim == 3 + baseDim)) { biffAddf(GAGE, "%s: nrrd should be %u-D, not %u-D", me, 3 + baseDim, nin->dim); airMopError(mop); return 1; } ax[0] = &(nin->axis[baseDim+0]); ax[1] = &(nin->axis[baseDim+1]); ax[2] = &(nin->axis[baseDim+2]); statCalc[0] = nrrdSpacingCalculate(nin, baseDim + 0, spcCalc + 0, vecCalc[0]); statCalc[1] = nrrdSpacingCalculate(nin, baseDim + 1, spcCalc + 1, vecCalc[1]); statCalc[2] = nrrdSpacingCalculate(nin, baseDim + 2, spcCalc + 2, vecCalc[2]); /* see if nrrdSpacingCalculate ever *failed* */ if (nrrdSpacingStatusUnknown == statCalc[0] || nrrdSpacingStatusUnknown == statCalc[1] || nrrdSpacingStatusUnknown == statCalc[2]) { biffAddf(GAGE, "%s: nrrdSpacingCalculate trouble on axis %d, %d, or %d", me, baseDim + 0, baseDim + 1, baseDim + 2); airMopError(mop); return 1; } if (!( statCalc[0] == statCalc[1] && statCalc[1] == statCalc[2] )) { biffAddf(GAGE, "%s: inconsistent spacing information on axes " "%u (%s), %u (%s), and %u (%s)", me, baseDim + 0, airEnumDesc(nrrdSpacingStatus, statCalc[0]), baseDim + 1, airEnumDesc(nrrdSpacingStatus, statCalc[1]), baseDim + 2, airEnumDesc(nrrdSpacingStatus, statCalc[2])); airMopError(mop); return 1; } /* this simplifies reasoning in the code that follows */ status = statCalc[0]; /* zero spacing would be problematic */ if (0 == spcCalc[0] && 0 == spcCalc[1] && 0 == spcCalc[2]) { biffAddf(GAGE, "%s: spacings (%g,%g,%g) for axes %d,%d,%d not all " "non-zero", me, spcCalc[1], spcCalc[1], spcCalc[2], baseDim+0, baseDim+1, baseDim+2); airMopError(mop); return 1; } /* error checking based on status */ if (nrrdSpacingStatusScalarWithSpace == status) { biffAddf(GAGE, "%s: sorry, can't handle per-axis spacing that isn't part " "of a surrounding world space (%s)", me, airEnumStr(nrrdSpacingStatus, status)); airMopError(mop); return 1; } /* we no longer allow a nrrd to come in with no spacing info at all */ if (nrrdSpacingStatusNone == status) { biffAddf(GAGE, "%s: sorry, need some spacing info for spatial axes " "%u, %u, %u", me, baseDim+0, baseDim+1, baseDim+2); airMopError(mop); return 1; } /* actually, there shouldn't be any other options for spacing status besides these too; this is just being careful */ if (!( nrrdSpacingStatusDirection == status || nrrdSpacingStatusScalarNoSpace == status )) { biffAddf(GAGE, "%s: sorry, can only handle spacing status %d (%s) " "or %d (%s), not %d (%s)", me, nrrdSpacingStatusDirection, airEnumStr(nrrdSpacingStatus, nrrdSpacingStatusDirection), nrrdSpacingStatusScalarNoSpace, airEnumStr(nrrdSpacingStatus, nrrdSpacingStatusScalarNoSpace), status, airEnumStr(nrrdSpacingStatus, status)); airMopError(mop); return 1; } if (nrrdSpacingStatusDirection == status) { shape->fromOrientation = AIR_TRUE; if (3 != nin->spaceDim) { biffAddf(GAGE, "%s: orientation space dimension %d != 3", me, nin->spaceDim); airMopError(mop); return 1; } } else { shape->fromOrientation = AIR_FALSE; } /* ------ find centering (set shape->center) */ /* NOTE: when the volume is being crammed in a bi-unit cube, the centering will actually affect the positions of the samples. Otherwise, (having full orientation, or using orientationFromSpacing), the centering will only affect the probe-able bounds of the volume, but the sample positions in space don't depend on centering */ cx = ax[0]->center; cy = ax[1]->center; cz = ax[2]->center; if (!( cx == cy && cy == cz )) { biffAddf(GAGE, "%s: axes %d,%d,%d centerings (%s,%s,%s) not all equal", me, baseDim+0, baseDim+1, baseDim+2, airEnumStr(nrrdCenter, cx), airEnumStr(nrrdCenter, cy), airEnumStr(nrrdCenter, cz)); airMopError(mop); return 1; } /* Hopefully, ctx->parm.defaultCenter == shape->defaultCenter; and this worry will be moot if ctx->parm.defaultCenter goes away */ shape->center = (nrrdCenterUnknown != cx ? cx /* cx == cy == cz, by above */ : (ctx ? ctx->parm.defaultCenter : shape->defaultCenter)); /* ------ find sizes (set shape->size[0,1,2]) */ shape->size[0] = ax[0]->size; shape->size[1] = ax[1]->size; shape->size[2] = ax[2]->size; minsize = (nrrdCenterCell == shape->center ? 1 : 2); /* this can't be relaxed in the face of having full orientation info, because even then, you can't have a non-zero probe-able volume if there's only one sample along a node-centered axis */ if (!(shape->size[0] >= minsize && shape->size[1] >= minsize && shape->size[2] >= minsize )) { biffAddf(GAGE, "%s: sizes (%u,%u,%u) must all be >= %u " "(min number of %s-centered samples)", me, shape->size[0], shape->size[1], shape->size[2], minsize, airEnumStr(nrrdCenter, shape->center)); airMopError(mop); return 1; } /* ------ find spacings[0,1,2] and ItoW matrix */ /* Hopefully, ctx->parm.orientationFromSpacing and shape->orientationFromSpacing don't represent competing interests; this worry will be moot if ctx->parm.orientationFromSpacing goes away */ ofspc = ((ctx && ctx->parm.orientationFromSpacing) || shape->orientationFromSpacing); if (shape->fromOrientation || ofspc) { if (ofspc) { /* need abs() in case an axis had negative spacing */ ELL_3V_ABS(shape->spacing, spcCalc); ELL_3V_SET(vecCalc[0], airSgn(spcCalc[0]), 0.0, 0.0); ELL_3V_SET(vecCalc[1], 0.0, airSgn(spcCalc[1]), 0.0); ELL_3V_SET(vecCalc[2], 0.0, 0.0, airSgn(spcCalc[2])); } else { ELL_3V_COPY(shape->spacing, spcCalc); /* vecCalc set by nrrdSpacingCalculate */ } if (shape->fromOrientation) { /* if the spaceOrigin isn't set, this will be all NaNs */ nrrdSpaceOriginGet(nin, orig); } else { /* sorry, if you want to specify an image origin that over-rides the behavior of centering the volume at (0,0,0), then it has to be done through the full orientation info. That is, we don't want to use nrrdOriginCalculate() because otherwise the logic gets too complicated */ ELL_3V_SET(orig, AIR_NAN, AIR_NAN, AIR_NAN); } if (!ELL_3V_EXISTS(orig)) { /* don't have origin, for whatever reason; center volume on (0,0,0) */ ELL_3V_SET(orig, 0.0, 0.0, 0.0); ELL_3V_SCALE_INCR(orig, -(shape->size[0] - 1.0)*shape->spacing[0]/2.0, vecCalc[0]); ELL_3V_SCALE_INCR(orig, -(shape->size[1] - 1.0)*shape->spacing[1]/2.0, vecCalc[1]); ELL_3V_SCALE_INCR(orig, -(shape->size[2] - 1.0)*shape->spacing[2]/2.0, vecCalc[2]); } vecD[3] = 0; ELL_3V_SCALE(vecD, spcCalc[0], vecCalc[0]); ELL_4MV_COL0_SET(shape->ItoW, vecD); ELL_3V_SCALE(vecD, spcCalc[1], vecCalc[1]); ELL_4MV_COL1_SET(shape->ItoW, vecD); ELL_3V_SCALE(vecD, spcCalc[2], vecCalc[2]); ELL_4MV_COL2_SET(shape->ItoW, vecD); vecD[3] = 1; ELL_3V_COPY(vecD, orig); ELL_4MV_COL3_SET(shape->ItoW, vecD); /* fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[0], vecCalc[0][0], vecCalc[0][1], vecCalc[0][2]); fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[1], vecCalc[1][0], vecCalc[1][1], vecCalc[1][2]); fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[2], vecCalc[2][0], vecCalc[2][1], vecCalc[2][2]); */ /* fprintf(stderr, "%s: ItoW = %g %g %g %g\n", me, shape->ItoW[ 0], shape->ItoW[ 1], shape->ItoW[ 2], shape->ItoW[ 3]); fprintf(stderr, "%s: %g %g %g %g\n", me, shape->ItoW[ 4], shape->ItoW[ 5], shape->ItoW[ 6], shape->ItoW[ 7]); fprintf(stderr, "%s: %g %g %g %g\n", me, shape->ItoW[ 8], shape->ItoW[ 9], shape->ItoW[10], shape->ItoW[11]); fprintf(stderr, "%s: %g %g %g %g\n", me, shape->ItoW[12], shape->ItoW[13], shape->ItoW[14], shape->ItoW[15]); */ } else { /* not (shape->fromOrientation || ofspc) */ double maxLen, volHalfLen[3]; size_t num[3]; /* ------ learn lengths for bounding nrrd in bi-unit cube */ ELL_3V_ABS(shape->spacing, spcCalc); maxLen = 0.0; for (ai=0; ai<=2; ai++) { num[ai] = (nrrdCenterNode == shape->center ? shape->size[ai]-1 : shape->size[ai]); volHalfLen[ai] = num[ai]*shape->spacing[ai]; maxLen = AIR_MAX(maxLen, volHalfLen[ai]); } /* Thu Dec 13 02:45:01 EST 2007 fixed long-standing bug in handling vols without full orientation info: spacing[ai] was never scaled to account for being crammed into the bi-unit cube!! */ for (ai=0; ai<=2; ai++) { volHalfLen[ai] /= maxLen; shape->spacing[ai] = 2*volHalfLen[ai]/num[ai]; } ELL_3V_SET(vecC, 0, 0, 0); shapeUnitItoW(shape, vecA, vecC, volHalfLen); ELL_3V_SET(vecC, 1, 0, 0); shapeUnitItoW(shape, vecB, vecC, volHalfLen); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL0_SET(shape->ItoW, vecD); ELL_3V_SET(vecC, 0, 1, 0); shapeUnitItoW(shape, vecB, vecC, volHalfLen); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL1_SET(shape->ItoW, vecD); ELL_3V_SET(vecC, 0, 0, 1); shapeUnitItoW(shape, vecB, vecC, volHalfLen); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL2_SET(shape->ItoW, vecD); vecA[3] = 1; ELL_4MV_COL3_SET(shape->ItoW, vecA); } /* ------ set the rest of the matrices */ ell_4m_inv_d(shape->WtoI, shape->ItoW); ELL_34M_EXTRACT(matA, shape->ItoW); ell_3m_inv_d(shape->ItoWSubInv, matA); ELL_3M_TRANSPOSE(shape->ItoWSubInvTransp, shape->ItoWSubInv); airMopOkay(mop); 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; }
/* ** _gageShapeSet ** ** we are serving two masters here. If ctx is non-NULL, we are being called ** from within gage, and we are to be lax or strict according to the settings ** of ctx->parm.requireAllSpacings and ctx->parm.requireEqualCenters. If ** ctx is NULL, gageShapeSet was called, in which case we go with lax ** behavior (nothing "required") ** ** This function has subsumed the old gageVolumeCheck, and hence has ** become this weird beast- part error checker and part (gageShape) ** initializer. Oh well... */ int _gageShapeSet(const gageContext *ctx, gageShape *shape, const Nrrd *nin, unsigned int baseDim) { char me[]="_gageShapeSet", err[BIFF_STRLEN]; int ai, cx, cy, cz, defCenter, statCalc[3]; unsigned int minsize, sx, sy, sz; const NrrdAxisInfo *ax[3]; double maxLen, defSpacing, vecA[4], vecB[3], vecC[3], vecD[4], matA[9], spcCalc[3], vecCalc[3][NRRD_SPACE_DIM_MAX], orig[NRRD_SPACE_DIM_MAX]; /* ------ basic error checking */ if (!( shape && nin )) { sprintf(err, "%s: got NULL pointer", me); biffAdd(GAGE, err); if (shape) { gageShapeReset(shape); } return 1; } if (nrrdCheck(nin)) { sprintf(err, "%s: basic nrrd validity check failed", me); biffMove(GAGE, err, NRRD); gageShapeReset(shape); return 1; } if (nrrdTypeBlock == nin->type) { sprintf(err, "%s: need a non-block type nrrd", me); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } if (!(nin->dim == 3 + baseDim)) { sprintf(err, "%s: nrrd should be %u-D, not %u-D", me, 3 + baseDim, nin->dim); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } ax[0] = &(nin->axis[baseDim+0]); ax[1] = &(nin->axis[baseDim+1]); ax[2] = &(nin->axis[baseDim+2]); /* if (1) { unsigned int ai; for (ai=0; ai<3; ai++) { fprintf(stderr, "!%s: ax[%u] spc = %g, sd = %g %g %g\n", me, ai, ax[ai]->spacing, ax[ai]->spaceDirection[0], ax[ai]->spaceDirection[1], ax[ai]->spaceDirection[2]); } } */ statCalc[0] = nrrdSpacingCalculate(nin, baseDim + 0, spcCalc + 0, vecCalc[0]); statCalc[1] = nrrdSpacingCalculate(nin, baseDim + 1, spcCalc + 1, vecCalc[1]); statCalc[2] = nrrdSpacingCalculate(nin, baseDim + 2, spcCalc + 2, vecCalc[2]); /* fprintf(stderr, "!%s: axis stat %d %d %d\n", me, statCalc[0], statCalc[1], statCalc[2]); */ /* see if nrrdSpacingCalculate ever *failed* */ if (nrrdSpacingStatusUnknown == statCalc[0] || nrrdSpacingStatusUnknown == statCalc[1] || nrrdSpacingStatusUnknown == statCalc[2]) { sprintf(err, "%s: nrrdSpacingCalculate trouble on axis %d, %d, or %d", me, baseDim + 0, baseDim + 1, baseDim + 2); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } /* see if nrrdSpacingCalculate encountered an axis with no space direction in a nrrd that nominally has a surrounding space */ if (nrrdSpacingStatusScalarWithSpace == statCalc[0] || nrrdSpacingStatusScalarWithSpace == statCalc[1] || nrrdSpacingStatusScalarWithSpace == statCalc[2]) { sprintf(err, "%s: nrrdSpacingCalculate weirdness on axis %d, %d, or %d", me, baseDim + 0, baseDim + 1, baseDim + 2); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } if (!( ( nrrdSpacingStatusDirection == statCalc[0] && nrrdSpacingStatusDirection == statCalc[1] && nrrdSpacingStatusDirection == statCalc[2]) || ( nrrdSpacingStatusDirection != statCalc[0] && nrrdSpacingStatusDirection != statCalc[1] && nrrdSpacingStatusDirection != statCalc[2]) )) { sprintf(err, "%s: inconsistent space directions use " "in axis %d, %d, and %d", me, baseDim + 0, baseDim + 1, baseDim + 2); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } if ( nrrdSpacingStatusDirection == statCalc[0] && nrrdSpacingStatusDirection == statCalc[1] && nrrdSpacingStatusDirection == statCalc[2]) { /* this will get reset to false in case of error */ shape->fromOrientation = AIR_TRUE; } else { shape->fromOrientation = AIR_FALSE; } /* oh yea, we should make sure the space dimension is right! */ if (shape->fromOrientation && 3 != nin->spaceDim) { sprintf(err, "%s: orientation space dimension %d != 3", me, nin->spaceDim); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } /* ------ find centering (set shape->center) */ /* HEY: when we have full orientation information (via spaceDirections and spaceOrigin) the centering information is moot for determining shape, but until all usage of gageShape stuff is properly overhauled to take orientation into account, we'll still set shape->center */ cx = ax[0]->center; cy = ax[1]->center; cz = ax[2]->center; if (ctx && ctx->parm.requireEqualCenters) { if (!( cx == cy && cx == cz )) { sprintf(err, "%s: axes %d,%d,%d centerings (%s,%s,%s) not equal", me, baseDim+0, baseDim+1, baseDim+2, airEnumStr(nrrdCenter, cx), airEnumStr(nrrdCenter, cy), airEnumStr(nrrdCenter, cz)); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } } else { if ( (nrrdCenterUnknown != cx && nrrdCenterUnknown != cy && cx != cy) || (nrrdCenterUnknown != cy && nrrdCenterUnknown != cz && cy != cz) || (nrrdCenterUnknown != cx && nrrdCenterUnknown != cz && cx != cz) ) { sprintf(err, "%s: two known centerings (of %s,%s,%s) are unequal", me, airEnumStr(nrrdCenter, cx), airEnumStr(nrrdCenter, cy), airEnumStr(nrrdCenter, cz)); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } } defCenter = ctx ? ctx->parm.defaultCenter : shape->defaultCenter; shape->center = (nrrdCenterUnknown != cx ? cx : (nrrdCenterUnknown != cy ? cy : (nrrdCenterUnknown != cz ? cz : defCenter))); /* ------ find sizes (set shape->size[0,1,2]) */ sx = ax[0]->size; sy = ax[1]->size; sz = ax[2]->size; minsize = (nrrdCenterCell == shape->center ? 1 : 2); /* HEY: perhaps this should be relaxed if we have full orientation info */ if (!(sx >= minsize && sy >= minsize && sz >= minsize )) { sprintf(err, "%s: sizes (%u,%u,%u) must all be >= %u " "(min number of %s-centered samples)", me, sx, sy, sz, minsize, airEnumStr(nrrdCenter, shape->center)); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } shape->size[0] = sx; shape->size[1] = sy; shape->size[2] = sz; /* ------ find spacings (set shape->spacing[0,1,2]) */ if (shape->fromOrientation) { shape->spacing[0] = AIR_ABS(spcCalc[0]); shape->spacing[1] = AIR_ABS(spcCalc[1]); shape->spacing[2] = AIR_ABS(spcCalc[2]); for (ai=0; ai<=2; ai++) { shape->volHalfLen[ai] = AIR_NAN; shape->voxLen[ai] = AIR_NAN; } } else { double xs, ys, zs; unsigned int num[3]; xs = ax[0]->spacing; ys = ax[1]->spacing; zs = ax[2]->spacing; if (ctx && ctx->parm.requireAllSpacings) { if (!( AIR_EXISTS(xs) && AIR_EXISTS(ys) && AIR_EXISTS(zs) )) { sprintf(err, "%s: spacings for axes %d,%d,%d don't all exist", me, baseDim+0, baseDim+1, baseDim+2); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } } /* there is no shape->defaultSpacing, we'll go out on a limb ... */ defSpacing = ctx ? ctx->parm.defaultSpacing : nrrdDefaultSpacing; xs = AIR_EXISTS(xs) ? xs : defSpacing; ys = AIR_EXISTS(ys) ? ys : defSpacing; zs = AIR_EXISTS(zs) ? zs : defSpacing; if (!( xs != 0 && ys != 0 && zs != 0 )) { sprintf(err, "%s: spacings (%g,%g,%g) for axes %d,%d,%d not all " "non-zero", me, xs, ys, zs, baseDim+0, baseDim+1, baseDim+2); biffAdd(GAGE, err); gageShapeReset(shape); return 1; } /* ------ learn lengths for bounding nrrd in bi-unit cube (set shape->volHalfLen[0,1,2] and shape->voxLen[0,1,2]) */ shape->spacing[0] = AIR_ABS(xs); shape->spacing[1] = AIR_ABS(ys); shape->spacing[2] = AIR_ABS(zs); maxLen = 0.0; for (ai=0; ai<=2; ai++) { num[ai] = (nrrdCenterNode == shape->center ? shape->size[ai]-1 : shape->size[ai]); shape->volHalfLen[ai] = num[ai]*shape->spacing[ai]; maxLen = AIR_MAX(maxLen, shape->volHalfLen[ai]); } /* Thu Dec 13 02:45:01 EST 2007 fixed long-standing bug in handling vols without full orientation info: spacing[ai] was never scaled to account for being crammed into the bi-unit cube!! */ for (ai=0; ai<=2; ai++) { shape->volHalfLen[ai] /= maxLen; shape->spacing[ai] = shape->voxLen[ai] = 2*shape->volHalfLen[ai]/num[ai]; } } /* ------ set transform matrices */ if (shape->fromOrientation) { /* find translation vector (we check above that spaceDim == 3) */ nrrdSpaceOriginGet(nin, orig); if (!( AIR_EXISTS(orig[0]) && AIR_EXISTS(orig[1]) && AIR_EXISTS(orig[2]) )) { /* don't have origin, so set it to come from the middle of volume */ ELL_3V_SET(orig, 0.0f, 0.0f, 0.0f); ELL_3V_SCALE_INCR(orig, -(shape->size[0] - 1.0f)*spcCalc[0]/2.0f, vecCalc[0]); ELL_3V_SCALE_INCR(orig, -(shape->size[1] - 1.0f)*spcCalc[1]/2.0f, vecCalc[1]); ELL_3V_SCALE_INCR(orig, -(shape->size[2] - 1.0f)*spcCalc[2]/2.0f, vecCalc[2]); } vecD[3] = 0; ELL_3V_SCALE(vecD, spcCalc[0], vecCalc[0]); ELL_4MV_COL0_SET(shape->ItoW, vecD); ELL_3V_SCALE(vecD, spcCalc[1], vecCalc[1]); ELL_4MV_COL1_SET(shape->ItoW, vecD); ELL_3V_SCALE(vecD, spcCalc[2], vecCalc[2]); ELL_4MV_COL2_SET(shape->ItoW, vecD); vecD[3] = 1; ELL_3V_COPY(vecD, orig); ELL_4MV_COL3_SET(shape->ItoW, vecD); /* fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[0], vecCalc[0][0], vecCalc[0][1], vecCalc[0][2]); fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[1], vecCalc[1][0], vecCalc[1][1], vecCalc[1][2]); fprintf(stderr, "%s: %g (%g,%g,%g)\n", me, spcCalc[2], vecCalc[2][0], vecCalc[2][1], vecCalc[2][2]); */ } else { ELL_3V_SET(vecC, 0, 0, 0); _gageShapeUnitItoW(shape, vecA, vecC); ELL_3V_SET(vecC, 1, 0, 0); _gageShapeUnitItoW(shape, vecB, vecC); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL0_SET(shape->ItoW, vecD); ELL_3V_SET(vecC, 0, 1, 0); _gageShapeUnitItoW(shape, vecB, vecC); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL1_SET(shape->ItoW, vecD); ELL_3V_SET(vecC, 0, 0, 1); _gageShapeUnitItoW(shape, vecB, vecC); ELL_3V_SUB(vecD, vecB, vecA); vecD[3] = 0; ELL_4MV_COL2_SET(shape->ItoW, vecD); vecA[3] = 1; ELL_4MV_COL3_SET(shape->ItoW, vecA); } ell_4m_inv_d(shape->WtoI, shape->ItoW); ELL_34M_EXTRACT(matA, shape->ItoW); ell_3m_inv_d(shape->ItoWSubInv, matA); ELL_3M_TRANSPOSE(shape->ItoWSubInvTransp, shape->ItoWSubInv); return 0; }