/* ******** ell_Nm_inv ** ** computes the inverse of given matrix in nmat, and puts the ** inverse in the (maybe allocated) ninv. Does not touch the ** values in nmat. */ int ell_Nm_inv(Nrrd *ninv, Nrrd *nmat) { static const char me[]="ell_Nm_inv"; double *mat, *inv; size_t NN; if (!( ninv && !ell_Nm_check(nmat, AIR_FALSE) )) { biffAddf(ELL, "%s: NULL or invalid args", me); return 1; } NN = nmat->axis[0].size; if (!( NN == nmat->axis[1].size )) { char stmp[2][AIR_STRLEN_SMALL]; biffAddf(ELL, "%s: need a square matrix, not %s-by-%s", me, airSprintSize_t(stmp[0], nmat->axis[1].size), airSprintSize_t(stmp[1], NN)); return 1; } if (nrrdMaybeAlloc_va(ninv, nrrdTypeDouble, 2, NN, NN)) { biffMovef(ELL, NRRD, "%s: trouble", me); return 1; } inv = (double*)(ninv->data); mat = (double*)(nmat->data); if (_ell_inv(inv, mat, NN)) { biffAddf(ELL, "%s: trouble", me); return 1; } return 0; }
/* ******** nrrdSameSize() ** ** returns 1 iff given two nrrds have same dimension and axes sizes. ** This does NOT look at the type of the elements. ** ** The intended user of this is someone who really wants the nrrds to be ** the same size, so that if they aren't, some descriptive (error) message ** can be generated according to useBiff */ int /*Teem: biff?2 if (!ret) */ nrrdSameSize(const Nrrd *n1, const Nrrd *n2, int useBiff) { static const char me[]="nrrdSameSize"; unsigned int ai; char stmp[2][AIR_STRLEN_SMALL]; if (!(n1 && n2)) { biffMaybeAddf(useBiff, NRRD, "%s: got NULL pointer", me); return 0; } if (n1->dim != n2->dim) { biffMaybeAddf(useBiff, NRRD, "%s: n1->dim (%u) != n2->dim (%u)", me, n1->dim, n2->dim); return 0; } for (ai=0; ai<n1->dim; ai++) { if (n1->axis[ai].size != n2->axis[ai].size) { biffMaybeAddf(useBiff, NRRD, "%s: n1->axis[%d].size (%s) " "!= n2->axis[%d].size (%s)", me, ai, airSprintSize_t(stmp[0], n1->axis[ai].size), ai, airSprintSize_t(stmp[1], n2->axis[ai].size)); return 0; } } return 1; }
int main(int argc, char *argv[]) { int aret; char *me; AIR_UNUSED(argc); me = argv[0]; aret = airSanity(); if (airInsane_not == aret) { char stmp[AIR_STRLEN_SMALL]; fprintf(stderr, "%s: air sanity check passed.\n", me); fprintf(stderr, "\n"); fprintf(stderr, "airMyEndian() == %d\n", airMyEndian()); fprintf(stderr, "AIR_QNANHIBIT == %d\n", AIR_QNANHIBIT); fprintf(stderr, "AIR_DIO == %d\n", AIR_DIO); fprintf(stderr, "sizeof(size_t) = %s\n", airSprintSize_t(stmp, sizeof(size_t))); fprintf(stderr, "sizeof(void*) = %s\n", airSprintSize_t(stmp, sizeof(void*))); return 0; } /* else */ fprintf(stderr, "%s: air sanity check FAILED:\n%s\n", me, airInsaneErr(aret)); return 1; }
static int _nrrdEncodingRaw_read(FILE *file, void *data, size_t elementNum, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingRaw_read"; size_t ret, bsize; int fd, dio, car; long savePos; char *data_c; size_t elementSize, maxChunkSize, remainderValue, chunkSize; size_t retTmp; char stmp[3][AIR_STRLEN_SMALL]; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioRead(fd, data, bsize); if (ret != bsize) { biffAddf(NRRD, "%s: airDioRead got read only %s of %sbytes " "(%g%% of expected)", me, airSprintSize_t(stmp[0], ret), airSprintSize_t(stmp[1], bsize), 100.0*AIR_CAST(double, ret)/AIR_CAST(double, bsize)); return 1; } } else {
int tenGradientCheck(const Nrrd *ngrad, int type, unsigned int minnum) { static const char me[]="tenGradientCheck"; if (nrrdCheck(ngrad)) { biffMovef(TEN, NRRD, "%s: basic validity check failed", me); return 1; } if (!( 3 == ngrad->axis[0].size && 2 == ngrad->dim )) { char stmp[AIR_STRLEN_SMALL]; biffAddf(TEN, "%s: need a 3xN 2-D array (not a %sx? %u-D array)", me, airSprintSize_t(stmp, ngrad->axis[0].size), ngrad->dim); return 1; } if (nrrdTypeDefault != type && type != ngrad->type) { biffAddf(TEN, "%s: requested type %s but got type %s", me, airEnumStr(nrrdType, type), airEnumStr(nrrdType, ngrad->type)); return 1; } if (nrrdTypeBlock == ngrad->type) { biffAddf(TEN, "%s: sorry, can't use %s type", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (!( minnum <= ngrad->axis[1].size )) { char stmp[AIR_STRLEN_SMALL]; biffAddf(TEN, "%s: have only %s gradients, need at least %d", me, airSprintSize_t(stmp, ngrad->axis[1].size), minnum); return 1; } 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 (kind->baseDim) { char stmp[AIR_STRLEN_SMALL]; if (1 == kind->baseDim) { if (kind->valLen != nrrd->axis[0].size) { biffAddf(GAGE, "%s: %s kind needs %u axis 0 values, not %s", me, kind->name, kind->valLen, airSprintSize_t(stmp, nrrd->axis[0].size)); return 1; } } else { /* actually there is yet to be a kind in Teem for which kind->baseDim > 1, but this code would work in that case */ unsigned int axi; size_t numsub; /* number of samples sub base dim */ numsub = 1; for (axi=0; axi<kind->baseDim; axi++) { numsub *= nrrd->axis[axi].size; } if (kind->valLen != numsub) { biffAddf(GAGE, "%s: %s kind needs %u values below baseDim axis %u, " "not %s", me, kind->name,kind->valLen, kind->baseDim, airSprintSize_t(stmp, numsub)); 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; }
/* ******** nrrdDescribe ** ** writes verbose description of nrrd to given file */ void nrrdDescribe(FILE *file, const Nrrd *nrrd) { unsigned int ai; char stmp[AIR_STRLEN_SMALL]; if (file && nrrd) { fprintf(file, "Nrrd at 0x%p:\n", AIR_CVOIDP(nrrd)); fprintf(file, "Data at 0x%p is %s elements of type %s.\n", nrrd->data, airSprintSize_t(stmp, nrrdElementNumber(nrrd)), airEnumStr(nrrdType, nrrd->type)); if (nrrdTypeBlock == nrrd->type) { fprintf(file, "The blocks have size %s\n", airSprintSize_t(stmp, nrrd->blockSize)); } if (airStrlen(nrrd->content)) { fprintf(file, "Content = \"%s\"\n", nrrd->content); } fprintf(file, "%d-dimensional array, with axes:\n", nrrd->dim); for (ai=0; ai<nrrd->dim; ai++) { if (airStrlen(nrrd->axis[ai].label)) { fprintf(file, "%d: (\"%s\") ", ai, nrrd->axis[ai].label); } else { fprintf(file, "%d: ", ai); } fprintf(file, "%s-centered, size=%s, ", airEnumStr(nrrdCenter, nrrd->axis[ai].center), airSprintSize_t(stmp, nrrd->axis[ai].size)); airSinglePrintf(file, NULL, "spacing=%lg, \n", nrrd->axis[ai].spacing); airSinglePrintf(file, NULL, "thickness=%lg, \n", nrrd->axis[ai].thickness); airSinglePrintf(file, NULL, " axis(Min,Max) = (%lg,", nrrd->axis[ai].min); airSinglePrintf(file, NULL, "%lg)\n", nrrd->axis[ai].max); if (airStrlen(nrrd->axis[ai].units)) { fprintf(file, "units=%s, \n", nrrd->axis[ai].units); } } /* airSinglePrintf(file, NULL, "The min, max values are %lg", nrrd->min); airSinglePrintf(file, NULL, ", %lg\n", nrrd->max); */ airSinglePrintf(file, NULL, "The old min, old max values are %lg", nrrd->oldMin); airSinglePrintf(file, NULL, ", %lg\n", nrrd->oldMax); /* fprintf(file, "hasNonExist = %d\n", nrrd->hasNonExist); */ if (nrrd->cmtArr->len) { fprintf(file, "Comments:\n"); for (ai=0; ai<nrrd->cmtArr->len; ai++) { fprintf(file, "%s\n", nrrd->cmt[ai]); } } fprintf(file, "\n"); } }
static int _nrrdEncodingHex_read(FILE *file, void *_data, size_t elNum, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingHex_read"; size_t nibIdx, nibNum; unsigned char *data; int car=0, nib; AIR_UNUSED(nio); data = AIR_CAST(unsigned char *, _data); nibIdx = 0; nibNum = 2*elNum*nrrdElementSize(nrrd); if (nibNum/elNum != 2*nrrdElementSize(nrrd)) { biffAddf(NRRD, "%s: size_t can't hold 2*(#bytes in array)\n", me); return 1; } while (nibIdx < nibNum) { unsigned char nibshift; car = fgetc(file); if (EOF == car) break; nib = _nrrdReadHexTable[car & 127]; if (-2 == nib) { /* not a valid hex character */ break; } if (-1 == nib) { /* its white space */ continue; } /* else it is a valid character, representing a value from 0 to 15 */ nibshift = AIR_CAST(unsigned char, nib << (4*(1-(nibIdx & 1)))); /* HEY not sure why the cast is needed with gcc v4.8 -Wconversion */ *data = AIR_CAST(unsigned char, *data + nibshift); data += nibIdx & 1; nibIdx++; } if (nibIdx != nibNum) { char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; if (EOF == car) { biffAddf(NRRD, "%s: hit EOF getting byte %s of %s", me, airSprintSize_t(stmp1, nibIdx/2), airSprintSize_t(stmp2, nibNum/2)); } else { biffAddf(NRRD, "%s: hit invalid character ('%c') getting " "byte %s of %s", me, car, airSprintSize_t(stmp1, nibIdx/2), airSprintSize_t(stmp2, nibNum/2)); } return 1; } return 0; }
static int _nrrdFieldCheck_kinds(const Nrrd *nrrd, int useBiff) { static const char me[]="_nrrdFieldCheck_kinds"; int val[NRRD_DIM_MAX]; unsigned int wantLen, ai; nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoKind, val); for (ai=0; ai<nrrd->dim; ai++) { if (!( nrrdKindUnknown == val[ai] || !airEnumValCheck(nrrdKind, val[ai]) )) { biffMaybeAddf(useBiff, NRRD, "%s: axis %d kind %d invalid", me, ai, val[ai]); return 1; } wantLen = nrrdKindSize(val[ai]); if (wantLen && wantLen != nrrd->axis[ai].size) { char stmp[AIR_STRLEN_SMALL]; biffMaybeAddf(useBiff, NRRD, "%s: axis %d kind %s requires size %u, but have %s", me, ai, airEnumStr(nrrdKind, val[ai]), wantLen, airSprintSize_t(stmp, nrrd->axis[ai].size)); return 1; } } return 0; }
int unrrdu_cksumDoit(const char *me, char *inS, int endian, int printendian, FILE *fout) { Nrrd *nrrd; airArray *mop; unsigned int crc; char stmp[AIR_STRLEN_SMALL], ends[AIR_STRLEN_SMALL]; size_t nn; mop = airMopNew(); airMopAdd(mop, nrrd=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); if (nrrdLoad(nrrd, inS, NULL)) { biffMovef(me, NRRD, "%s: trouble loading \"%s\"", me, inS); airMopError(mop); return 1; } crc = nrrdCRC32(nrrd, endian); nn = nrrdElementNumber(nrrd)*nrrdElementSize(nrrd); sprintf(ends, "(%s)", airEnumStr(airEndian, endian)); fprintf(fout, "%u%s %s%s%s\n", crc, printendian ? ends : "", airSprintSize_t(stmp, nn), strcmp("-", inS) ? " " : "", strcmp("-", inS) ? inS : ""); airMopOkay(mop); return 0; }
int main(int argc, const char *argv[]) { const char *me; size_t sz; ptrdiff_t pd; char stmp[AIR_STRLEN_SMALL]; AIR_UNUSED(argc); me = argv[0]; sz = 123456789; airSprintSize_t(stmp, sz); if (strcmp("123456789", stmp)) { fprintf(stderr, "%s: airSprintSize_t: |%s|\n", me, stmp); exit(1); } pd = -123456789; airSprintPtrdiff_t(stmp, pd); if (strcmp("-123456789", stmp)) { fprintf(stderr, "%s: airSprintPtrdiff_t: |%s|\n", me, stmp); exit(1); } exit(0); }
/* ******** ell_Nm_mul ** ** Currently, only useful for matrix-matrix multiplication ** ** matrix-matrix: M N ** L [A] . M [B] */ int ell_Nm_mul(Nrrd *nAB, Nrrd *nA, Nrrd *nB) { static const char me[]="ell_Nm_mul"; double *A, *B, *AB, tmp; size_t LL, MM, NN, ll, mm, nn; char stmp[4][AIR_STRLEN_SMALL]; if (!( nAB && !ell_Nm_check(nA, AIR_FALSE) && !ell_Nm_check(nB, AIR_FALSE) )) { biffAddf(ELL, "%s: NULL or invalid args", me); return 1; } if (nAB == nA || nAB == nB) { biffAddf(ELL, "%s: can't do in-place multiplication", me); return 1; } LL = nA->axis[1].size; MM = nA->axis[0].size; NN = nB->axis[0].size; if (MM != nB->axis[1].size) { biffAddf(ELL, "%s: size mismatch: %s-by-%s times %s-by-%s", me, airSprintSize_t(stmp[0], LL), airSprintSize_t(stmp[1], MM), airSprintSize_t(stmp[2], nB->axis[1].size), airSprintSize_t(stmp[3], NN)); return 1; } if (nrrdMaybeAlloc_va(nAB, nrrdTypeDouble, 2, NN, LL)) { biffMovef(ELL, NRRD, "%s: trouble", me); return 1; } A = (double*)(nA->data); B = (double*)(nB->data); AB = (double*)(nAB->data); for (ll=0; ll<LL; ll++) { for (nn=0; nn<NN; nn++) { tmp = 0; for (mm=0; mm<MM; mm++) { tmp += A[mm + MM*ll]*B[nn + NN*mm]; } AB[ll*NN + nn] = tmp; } } return 0; }
int unrrdu_shuffleMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nout; unsigned int di, axis, permLen, *perm, *iperm, *whichperm; size_t *realperm; int inverse, pret; airArray *mop; /* so that long permutations can be read from file */ hparm->respFileEnable = AIR_TRUE; hestOptAdd(&opt, "p,permute", "slc0 slc1", airTypeUInt, 1, -1, &perm, NULL, "new slice ordering", &permLen); hestOptAdd(&opt, "inv,inverse", NULL, airTypeInt, 0, 0, &inverse, NULL, "use inverse of given permutation"); OPT_ADD_AXIS(axis, "axis to shuffle along"); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_shuffleInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); /* we have to do error checking on axis in order to do error checking on length of permutation */ if (!( axis < nin->dim )) { fprintf(stderr, "%s: axis %d not in valid range [0,%d]\n", me, axis, nin->dim-1); airMopError(mop); return 1; } if (!( permLen == nin->axis[axis].size )) { char stmp[AIR_STRLEN_SMALL]; fprintf(stderr, "%s: permutation length (%u) != axis %d's size (%s)\n", me, permLen, axis, airSprintSize_t(stmp, nin->axis[axis].size)); airMopError(mop); return 1; } if (inverse) { iperm = AIR_CALLOC(permLen, unsigned int); airMopAdd(mop, iperm, airFree, airMopAlways); if (nrrdInvertPerm(iperm, perm, permLen)) { fprintf(stderr, "%s: couldn't compute inverse of given permutation\n", me); airMopError(mop); return 1; } whichperm = iperm; } else {
static int _nrrdFieldCheck_block_size(const Nrrd *nrrd, int useBiff) { static const char me[]="_nrrdFieldCheck_block_size"; char stmp[AIR_STRLEN_SMALL]; if (nrrdTypeBlock == nrrd->type && (!(0 < nrrd->blockSize)) ) { biffMaybeAddf(useBiff, NRRD, "%s: type is %s but nrrd->blockSize (%s) invalid", me, airEnumStr(nrrdType, nrrdTypeBlock), airSprintSize_t(stmp, nrrd->blockSize)); return 1; } if (nrrdTypeBlock != nrrd->type && (0 < nrrd->blockSize)) { biffMaybeAddf(useBiff, NRRD, "%s: type is %s (not block) but blockSize is %s", me, airEnumStr(nrrdType, nrrd->type), airSprintSize_t(stmp, nrrd->blockSize)); return 1; } return 0; }
int tenTripleConvert(Nrrd *nout, int dstType, const Nrrd *nin, int srcType) { static const char me[]="tenTripleConvert"; size_t II, NN; double (*ins)(void *, size_t, double), (*lup)(const void *, size_t); if (!( nout && nin )) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } if ( airEnumValCheck(tenTripleType, dstType) || airEnumValCheck(tenTripleType, srcType) ) { biffAddf(TEN, "%s: got invalid %s dst (%d) or src (%d)", me, tenTripleType->name, dstType, srcType); return 1; } if (3 != nin->axis[0].size) { char stmp[AIR_STRLEN_SMALL]; biffAddf(TEN, "%s: need axis[0].size 3, not %s", me, airSprintSize_t(stmp, nin->axis[0].size)); return 1; } if (nrrdTypeBlock == nin->type) { biffAddf(TEN, "%s: input has non-scalar %s type", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (nrrdCopy(nout, nin)) { biffMovef(TEN, NRRD, "%s: couldn't initialize output", me); return 1; } lup = nrrdDLookup[nin->type]; ins = nrrdDInsert[nout->type]; NN = nrrdElementNumber(nin)/3; for (II=0; II<NN; II++) { double src[3], dst[3]; src[0] = lup(nin->data, 0 + 3*II); src[1] = lup(nin->data, 1 + 3*II); src[2] = lup(nin->data, 2 + 3*II); tenTripleConvertSingle_d(dst, dstType, src, srcType); ins(nout->data, 0 + 3*II, dst[0]); ins(nout->data, 1 + 3*II, dst[1]); ins(nout->data, 2 + 3*II, dst[2]); } return 0; }
float * _baneTRexRead(char *fname) { char me[]="_baneTRexRead"; if (nrrdLoad(baneNpos=nrrdNew(), fname, NULL)) { fprintf(stderr, "%s: !!! trouble reading \"%s\":\n%s\n", me, fname, biffGet(NRRD)); return NULL; } if (banePosCheck(baneNpos, 1)) { fprintf(stderr, "%s: !!! didn't get a valid p(x) file:\n%s\n", me, biffGet(BANE)); return NULL; } if (TREX_LUTLEN != baneNpos->axis[0].size) { char stmp[AIR_STRLEN_SMALL]; fprintf(stderr, "%s: !!! need a length %d p(x) (not %s)\n", me, TREX_LUTLEN, airSprintSize_t(stmp, baneNpos->axis[0].size)); return NULL; } return (float *)baneNpos->data; }
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; }
/* ******** 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) { static const char me[]="nrrdInset", func[] = "inset"; char 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, stmp[3][AIR_STRLEN_SMALL]; /* errors */ if (!(nout && nin && nsub && min)) { biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nout == nsub) { biffAddf(NRRD, "%s: nout==nsub disallowed", me); return 1; } if (nrrdCheck(nin)) { biffAddf(NRRD, "%s: input not valid nrrd", me); return 1; } if (nrrdCheck(nsub)) { biffAddf(NRRD, "%s: subvolume not valid nrrd", me); return 1; } if (!( nin->dim == nsub->dim )) { biffAddf(NRRD, "%s: input's dim (%d) != subvolume's dim (%d)", me, nin->dim, nsub->dim); return 1; } if (!( nin->type == nsub->type )) { biffAddf(NRRD, "%s: input's type (%s) != subvolume's type (%s)", me, airEnumStr(nrrdType, nin->type), airEnumStr(nrrdType, nsub->type)); return 1; } if (nrrdTypeBlock == nin->type) { if (!( nin->blockSize == nsub->blockSize )) { biffAddf(NRRD, "%s: input's blockSize (%s) != subvolume's (%s)", me, airSprintSize_t(stmp[0], nin->blockSize), airSprintSize_t(stmp[1], nsub->blockSize)); return 1; } } for (ai=0; ai<nin->dim; ai++) { if (!( min[ai] + nsub->axis[ai].size - 1 <= nin->axis[ai].size - 1)) { biffAddf(NRRD, "%s: axis %d range of inset indices [%s,%s] not within " "input indices [0,%s]", me, ai, airSprintSize_t(stmp[0], min[ai]), airSprintSize_t(stmp[1], min[ai] + nsub->axis[ai].size - 1), airSprintSize_t(stmp[2], nin->axis[ai].size - 1)); return 1; } } if (nout != nin) { if (nrrdCopy(nout, nin)) { biffAddf(NRRD, "%s:", me); 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%s", (ai ? "," : ""), airSprintSize_t(stmp[0], min[ai])); strcat(buff1, buff2); } strcat(buff1, "]"); subCont = _nrrdContentGet(nsub); if (nrrdContentSet_va(nout, func, nin, "%s,%s", subCont, buff1)) { biffAddf(NRRD, "%s:", me); free(subCont); return 1; } free(subCont); /* basic info copied by nrrdCopy above */ 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) { static const char me[]="nrrdSplice", func[]="splice"; 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; char stmp[2][AIR_STRLEN_SMALL]; if (!(nin && nout && nslice)) { biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nout == nslice) { biffAddf(NRRD, "%s: nout==nslice disallowed", me); return 1; } /* check that desired slice location is legit */ if (!( axis < nin->dim )) { biffAddf(NRRD, "%s: slice axis %d out of bounds (0 to %d)", me, axis, nin->dim-1); return 1; } if (!( pos < nin->axis[axis].size )) { biffAddf(NRRD, "%s: position %s out of bounds (0 to %s)", me, airSprintSize_t(stmp[0], pos), airSprintSize_t(stmp[1], nin->axis[axis].size-1)); return 1; } /* check that slice will fit in nin */ if (nrrdCheck(nslice) || nrrdCheck(nin)) { biffAddf(NRRD, "%s: input or slice not valid nrrd", me); return 1; } if (!( nin->dim-1 == nslice->dim )) { biffAddf(NRRD, "%s: dim of slice (%d) not one less than " "dim of input (%d)", me, nslice->dim, nin->dim); return 1; } if (!( nin->type == nslice->type )) { biffAddf(NRRD, "%s: type of slice (%s) != type of input (%s)", me, airEnumStr(nrrdType, nslice->type), airEnumStr(nrrdType, nin->type)); return 1; } if (nrrdTypeBlock == nin->type) { if (!( nin->blockSize == nslice->blockSize )) { biffAddf(NRRD, "%s: input's blockSize (%s) != subvolume's (%s)", me, airSprintSize_t(stmp[0], nin->blockSize), airSprintSize_t(stmp[1], nslice->blockSize)); return 1; } } for (ai=0; ai<nslice->dim; ai++) { if (!( nin->axis[ai + (ai >= axis)].size == nslice->axis[ai].size )) { biffAddf(NRRD, "%s: input ax %d size (%s) != slices ax %d size (%s)", me, ai + (ai >= axis), airSprintSize_t(stmp[0], nin->axis[ai + (ai >= axis)].size), ai, airSprintSize_t(stmp[1], nslice->axis[ai].size)); return 1; } } if (nout != nin) { if (nrrdCopy(nout, nin)) { biffAddf(NRRD, "%s:", me); 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,%s", sliceCont, axis, airSprintSize_t(stmp[0], pos))) { biffAddf(NRRD, "%s:", me); free(sliceCont); return 1; } free(sliceCont); /* basic info copied by nrrdCopy above */ return 0; }
int unrrdu_diceMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; char *base, *err, fnout[AIR_STRLEN_MED], /* file name out */ fffname[AIR_STRLEN_MED], /* format for filename */ *ftmpl; /* format template */ Nrrd *nin, *nout; int pret, fit; unsigned int axis, start, pos, top, size, sanity; airArray *mop; OPT_ADD_AXIS(axis, "axis to slice along"); OPT_ADD_NIN(nin, "input nrrd"); hestOptAdd(&opt, "s,start", "start", airTypeUInt, 1, 1, &start, "0", "integer value to start numbering with"); hestOptAdd(&opt, "ff,format", "form", airTypeString, 1, 1, &ftmpl, "", "a printf-style format to use for generating all " "filenames. Use this to override the number of characters " "used to represent the slice position, or the file format " "of the output, e.g. \"-ff %03d.ppm\" for 000.ppm, " "001.ppm, etc. By default (not using this option), slices " "are saved in NRRD format (or PNM or PNG where possible) " "with shortest possible filenames."); /* the fact that we're using unsigned int instead of size_t is its own kind of sanity check */ hestOptAdd(&opt, "l,limit", "max#", airTypeUInt, 1, 1, &sanity, "9999", "a sanity check on how many slice files should be saved " "out, to prevent accidentally dicing the wrong axis " "or the wrong array. Can raise this value if needed."); hestOptAdd(&opt, "o,output", "prefix", airTypeString, 1, 1, &base, NULL, "output filename prefix (excluding info set via \"-ff\"), " "basically to set path of output files (so be sure to end " "with \"/\"."); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_diceInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); if (!( axis < nin->dim )) { fprintf(stderr, "%s: given axis (%u) outside range [0,%u]\n", me, axis, nin->dim-1); airMopError(mop); return 1; } if (nin->axis[axis].size > sanity) { char stmp[AIR_STRLEN_SMALL]; fprintf(stderr, "%s: axis %u size %s > sanity limit %u; " "increase via \"-l\"\n", me, axis, airSprintSize_t(stmp, nin->axis[axis].size), sanity); airMopError(mop); return 1; } size = AIR_UINT(nin->axis[axis].size); /* HEY: this should use nrrdSaveMulti(), and if there's additional smarts here, they should be moved into nrrdSaveMulti() */ if (airStrlen(ftmpl)) { if (!( _nrrdContainsPercentThisAndMore(ftmpl, 'd') || _nrrdContainsPercentThisAndMore(ftmpl, 'u') )) { fprintf(stderr, "%s: given filename format \"%s\" doesn't seem to " "have the converstion specification to print an integer\n", me, ftmpl); airMopError(mop); return 1; } sprintf(fffname, "%%s%s", ftmpl); } else { unsigned int dignum=0, tmps; tmps = top = start + size - 1; do { dignum++; tmps /= 10; } while (tmps); /* sprintf the number of digits into the string that will be used to sprintf the slice number into the filename */ sprintf(fffname, "%%s%%0%uu.nrrd", dignum); } nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); for (pos=0; pos<size; pos++) { if (nrrdSlice(nout, nin, axis, pos)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error slicing nrrd:%s\n", me, err); airMopError(mop); return 1; } if (0 == pos && !airStrlen(ftmpl)) { /* See if these slices would be better saved as PNG or PNM images. Altering the file name will tell nrrdSave() to use a different file format. We wait till now to check this so that we can work from the actual slice */ if (nrrdFormatPNG->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE)) { strcpy(fffname + strlen(fffname) - 4, "png"); } else { fit = nrrdFormatPNM->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE); if (2 == fit) { strcpy(fffname + strlen(fffname) - 4, "pgm"); } else if (3 == fit) { strcpy(fffname + strlen(fffname) - 4, "ppm"); } } } sprintf(fnout, fffname, base, pos+start); fprintf(stderr, "%s: %s ...\n", me, fnout); if (nrrdSave(fnout, nout, NULL)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error writing nrrd to \"%s\":%s\n", me, fnout, err); airMopError(mop); return 1; } } airMopOkay(mop); return 0; }
int tenGlyphParmCheck(tenGlyphParm *parm, const Nrrd *nten, const Nrrd *npos, const Nrrd *nslc) { static const char me[]="tenGlyphParmCheck"; int duh; size_t tenSize[3]; char stmp[5][AIR_STRLEN_SMALL]; if (!(parm && nten)) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } if (airEnumValCheck(tenAniso, parm->anisoType)) { biffAddf(TEN, "%s: unset (or invalid) anisoType (%d)", me, parm->anisoType); return 1; } if (airEnumValCheck(tenAniso, parm->colAnisoType)) { biffAddf(TEN, "%s: unset (or invalid) colAnisoType (%d)", me, parm->colAnisoType); return 1; } if (!( parm->facetRes >= 3 )) { biffAddf(TEN, "%s: facet resolution %d not >= 3", me, parm->facetRes); return 1; } if (!( AIR_IN_OP(tenGlyphTypeUnknown, parm->glyphType, tenGlyphTypeLast) )) { biffAddf(TEN, "%s: unset (or invalid) glyphType (%d)", me, parm->glyphType); return 1; } if (!( parm->glyphScale > 0)) { biffAddf(TEN, "%s: glyphScale must be > 0 (not %g)", me, parm->glyphScale); return 1; } if (parm->nmask) { if (npos) { biffAddf(TEN, "%s: can't do masking with explicit coordinate list", me); return 1; } if (!( 3 == parm->nmask->dim && parm->nmask->axis[0].size == nten->axis[1].size && parm->nmask->axis[1].size == nten->axis[2].size && parm->nmask->axis[2].size == nten->axis[3].size )) { biffAddf(TEN, "%s: mask isn't 3-D or doesn't have sizes (%s,%s,%s)", me, airSprintSize_t(stmp[0], nten->axis[1].size), airSprintSize_t(stmp[1], nten->axis[2].size), airSprintSize_t(stmp[2], nten->axis[3].size)); return 1; } if (!(AIR_EXISTS(parm->maskThresh))) { biffAddf(TEN, "%s: maskThresh hasn't been set", me); return 1; } } if (!( AIR_EXISTS(parm->anisoThresh) && AIR_EXISTS(parm->confThresh) )) { biffAddf(TEN, "%s: anisoThresh and confThresh haven't both been set", me); return 1; } if (parm->doSlice) { if (npos) { biffAddf(TEN, "%s: can't do slice with explicit coordinate list", me); return 1; } if (!( parm->sliceAxis <=2 )) { biffAddf(TEN, "%s: slice axis %d invalid", me, parm->sliceAxis); return 1; } if (!( parm->slicePos < nten->axis[1+parm->sliceAxis].size )) { biffAddf(TEN, "%s: slice pos %s not in valid range [0..%s]", me, airSprintSize_t(stmp[0], parm->slicePos), airSprintSize_t(stmp[1], nten->axis[1+parm->sliceAxis].size-1)); return 1; } if (nslc) { if (2 != nslc->dim) { biffAddf(TEN, "%s: explicit slice must be 2-D (not %d)", me, nslc->dim); return 1; } tenSize[0] = nten->axis[1].size; tenSize[1] = nten->axis[2].size; tenSize[2] = nten->axis[3].size; for (duh=parm->sliceAxis; duh<2; duh++) { tenSize[duh] = tenSize[duh+1]; } if (!( tenSize[0] == nslc->axis[0].size && tenSize[1] == nslc->axis[1].size )) { biffAddf(TEN, "%s: axis %u slice of %sx%sx%s volume != %sx%s", me, parm->sliceAxis, airSprintSize_t(stmp[0], nten->axis[1].size), airSprintSize_t(stmp[1], nten->axis[2].size), airSprintSize_t(stmp[2], nten->axis[3].size), airSprintSize_t(stmp[3], nslc->axis[0].size), airSprintSize_t(stmp[4], nslc->axis[1].size)); return 1; } } else { if (airEnumValCheck(tenAniso, parm->sliceAnisoType)) { biffAddf(TEN, "%s: unset (or invalid) sliceAnisoType (%d)", me, parm->sliceAnisoType); return 1; } } } return 0; }
int tenGlyphGen(limnObject *glyphsLimn, echoScene *glyphsEcho, tenGlyphParm *parm, const Nrrd *nten, const Nrrd *npos, const Nrrd *nslc) { static const char me[]="tenGlyphGen"; gageShape *shape; airArray *mop; float *tdata, eval[3], evec[9], *cvec, rotEvec[9], mA_f[16], absEval[3], glyphScl[3]; double pI[3], pW[3], cl, cp, sRot[16], mA[16], mB[16], msFr[9], tmpvec[3], R, G, B, qA, qB, qC, glyphAniso, sliceGray; unsigned int duh; int slcCoord[3], idx, glyphIdx, axis, numGlyphs, svRGBAfl=AIR_FALSE; limnLook *look; int lookIdx; echoObject *eglyph, *inst, *list=NULL, *split, *esquare; echoPos_t eM[16], originOffset[3], edge0[3], edge1[3]; char stmp[AIR_STRLEN_SMALL]; /* int eret; double tmp1[3], tmp2[3]; */ if (!( (glyphsLimn || glyphsEcho) && nten && parm)) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } mop = airMopNew(); shape = gageShapeNew(); shape->defaultCenter = nrrdCenterCell; airMopAdd(mop, shape, (airMopper)gageShapeNix, airMopAlways); if (npos) { if (!( 2 == nten->dim && 7 == nten->axis[0].size )) { biffAddf(TEN, "%s: nten isn't 2-D 7-by-N array", me); airMopError(mop); return 1; } if (!( 2 == npos->dim && 3 == npos->axis[0].size && nten->axis[1].size == npos->axis[1].size )) { biffAddf(TEN, "%s: npos isn't 2-D 3-by-%s array", me, airSprintSize_t(stmp, nten->axis[1].size)); airMopError(mop); return 1; } if (!( nrrdTypeFloat == nten->type && nrrdTypeFloat == npos->type )) { biffAddf(TEN, "%s: nten and npos must be %s, not %s and %s", me, airEnumStr(nrrdType, nrrdTypeFloat), airEnumStr(nrrdType, nten->type), airEnumStr(nrrdType, npos->type)); airMopError(mop); return 1; } } else { if (tenTensorCheck(nten, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) { biffAddf(TEN, "%s: didn't get a valid DT volume", me); airMopError(mop); return 1; } } if (tenGlyphParmCheck(parm, nten, npos, nslc)) { biffAddf(TEN, "%s: trouble", me); airMopError(mop); return 1; } if (!npos) { if (gageShapeSet(shape, nten, tenGageKind->baseDim)) { biffMovef(TEN, GAGE, "%s: trouble", me); airMopError(mop); return 1; } } if (parm->doSlice) { ELL_3V_COPY(edge0, shape->spacing); ELL_3V_COPY(edge1, shape->spacing); edge0[parm->sliceAxis] = edge1[parm->sliceAxis] = 0.0; switch(parm->sliceAxis) { case 0: edge0[1] = edge1[2] = 0; ELL_4M_ROTATE_Y_SET(sRot, AIR_PI/2); break; case 1: edge0[0] = edge1[2] = 0; ELL_4M_ROTATE_X_SET(sRot, AIR_PI/2); break; case 2: default: edge0[0] = edge1[1] = 0; ELL_4M_IDENTITY_SET(sRot); break; } ELL_3V_COPY(originOffset, shape->spacing); ELL_3V_SCALE(originOffset, -0.5, originOffset); originOffset[parm->sliceAxis] *= -2*parm->sliceOffset; } if (glyphsLimn) { /* create limnLooks for diffuse and ambient-only shading */ /* ??? */ /* hack: save old value of setVertexRGBAFromLook, and set to true */ svRGBAfl = glyphsLimn->setVertexRGBAFromLook; glyphsLimn->setVertexRGBAFromLook = AIR_TRUE; } if (glyphsEcho) { list = echoObjectNew(glyphsEcho, echoTypeList); } if (npos) { numGlyphs = AIR_UINT(nten->axis[1].size); } else { numGlyphs = shape->size[0] * shape->size[1] * shape->size[2]; } /* find measurement frame transform */ if (3 == nten->spaceDim && AIR_EXISTS(nten->measurementFrame[0][0])) { /* msFr nten->measurementFrame ** 0 1 2 [0][0] [1][0] [2][0] ** 3 4 5 [0][1] [1][1] [2][1] ** 6 7 8 [0][2] [1][2] [2][2] */ msFr[0] = nten->measurementFrame[0][0]; msFr[3] = nten->measurementFrame[0][1]; msFr[6] = nten->measurementFrame[0][2]; msFr[1] = nten->measurementFrame[1][0]; msFr[4] = nten->measurementFrame[1][1]; msFr[7] = nten->measurementFrame[1][2]; msFr[2] = nten->measurementFrame[2][0]; msFr[5] = nten->measurementFrame[2][1]; msFr[8] = nten->measurementFrame[2][2]; } else { ELL_3M_IDENTITY_SET(msFr); } for (idx=0; idx<numGlyphs; idx++) { tdata = (float*)(nten->data) + 7*idx; if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: hello %g %g %g %g %g %g %g\n", me, idx, numGlyphs, tdata[0], tdata[1], tdata[2], tdata[3], tdata[4], tdata[5], tdata[6]); } if (!( TEN_T_EXISTS(tdata) )) { /* there's nothing we can do here */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: non-existent data\n", me, idx, numGlyphs); } continue; } if (npos) { ELL_3V_COPY(pW, (float*)(npos->data) + 3*idx); if (!( AIR_EXISTS(pW[0]) && AIR_EXISTS(pW[1]) && AIR_EXISTS(pW[2]) )) { /* position doesn't exist- perhaps because its from the push library, which might kill points by setting coords to nan */ continue; } } else { NRRD_COORD_GEN(pI, shape->size, 3, idx); /* this does take into account full orientation */ gageShapeItoW(shape, pW, pI); if (parm->nmask) { if (!( nrrdFLookup[parm->nmask->type](parm->nmask->data, idx) >= parm->maskThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: doesn't meet mask thresh\n", me, idx, numGlyphs); } continue; } } } tenEigensolve_f(eval, evec, tdata); /* transform eigenvectors by measurement frame */ ELL_3MV_MUL(tmpvec, msFr, evec + 0); ELL_3V_COPY_TT(evec + 0, float, tmpvec); ELL_3MV_MUL(tmpvec, msFr, evec + 3); ELL_3V_COPY_TT(evec + 3, float, tmpvec); ELL_3MV_MUL(tmpvec, msFr, evec + 6); ELL_3V_COPY_TT(evec + 6, float, tmpvec); ELL_3V_CROSS(tmpvec, evec + 0, evec + 3); if (0 > ELL_3V_DOT(tmpvec, evec + 6)) { ELL_3V_SCALE(evec + 6, -1, evec + 6); } ELL_3M_TRANSPOSE(rotEvec, evec); if (parm->doSlice && pI[parm->sliceAxis] == parm->slicePos) { /* set sliceGray */ if (nslc) { /* we aren't masked by confidence, as anisotropy slice is */ for (duh=0; duh<parm->sliceAxis; duh++) { slcCoord[duh] = (int)(pI[duh]); } for (duh=duh<parm->sliceAxis; duh<2; duh++) { slcCoord[duh] = (int)(pI[duh+1]); } /* HEY: GLK has no idea what's going here */ slcCoord[0] = (int)(pI[0]); slcCoord[1] = (int)(pI[1]); slcCoord[2] = (int)(pI[2]); sliceGray = nrrdFLookup[nslc->type](nslc->data, slcCoord[0] + nslc->axis[0].size*slcCoord[1]); } else { if (!( tdata[0] >= parm->confThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d (slice): conf %g < thresh %g\n", me, idx, numGlyphs, tdata[0], parm->confThresh); } continue; } sliceGray = tenAnisoEval_f(eval, parm->sliceAnisoType); } if (parm->sliceGamma > 0) { sliceGray = AIR_AFFINE(0, sliceGray, 1, parm->sliceBias, 1); sliceGray = pow(sliceGray, 1.0/parm->sliceGamma); } else { sliceGray = AIR_AFFINE(0, sliceGray, 1, 0, 1-parm->sliceBias); sliceGray = 1.0 - pow(sliceGray, -1.0/parm->sliceGamma); } /* make slice contribution */ /* HEY: this is *NOT* aware of shape->fromOrientation */ if (glyphsLimn) { lookIdx = limnObjectLookAdd(glyphsLimn); look = glyphsLimn->look + lookIdx; ELL_4V_SET_TT(look->rgba, float, sliceGray, sliceGray, sliceGray, 1); ELL_3V_SET(look->kads, 1, 0, 0); look->spow = 0; glyphIdx = limnObjectSquareAdd(glyphsLimn, lookIdx); ELL_4M_IDENTITY_SET(mA); ell_4m_post_mul_d(mA, sRot); if (!npos) { ELL_4M_SCALE_SET(mB, shape->spacing[0], shape->spacing[1], shape->spacing[2]); } ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]); ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, originOffset[0], originOffset[1], originOffset[2]); ell_4m_post_mul_d(mA, mB); ELL_4M_COPY_TT(mA_f, float, mA); limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f); } if (glyphsEcho) { esquare = echoObjectNew(glyphsEcho,echoTypeRectangle); ELL_3V_ADD2(((echoRectangle*)esquare)->origin, pW, originOffset); ELL_3V_COPY(((echoRectangle*)esquare)->edge0, edge0); ELL_3V_COPY(((echoRectangle*)esquare)->edge1, edge1); echoColorSet(esquare, AIR_CAST(echoCol_t, sliceGray), AIR_CAST(echoCol_t, sliceGray), AIR_CAST(echoCol_t, sliceGray), 1); /* this is pretty arbitrary- but I want shadows to have some effect. Previously, the material was all ambient: (A,D,S) = (1,0,0), which avoided all shadow effects. */ echoMatterPhongSet(glyphsEcho, esquare, 0.4f, 0.6f, 0, 40); echoListAdd(list, esquare); } } if (parm->onlyPositive) { if (eval[2] < 0) { /* didn't have all positive eigenvalues, its outta here */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: not all evals %g %g %g > 0\n", me, idx, numGlyphs, eval[0], eval[1], eval[2]); } continue; } } if (!( tdata[0] >= parm->confThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: conf %g < thresh %g\n", me, idx, numGlyphs, tdata[0], parm->confThresh); } continue; } if (!( tenAnisoEval_f(eval, parm->anisoType) >= parm->anisoThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: aniso[%d] %g < thresh %g\n", me, idx, numGlyphs, parm->anisoType, tenAnisoEval_f(eval, parm->anisoType), parm->anisoThresh); } continue; } glyphAniso = tenAnisoEval_f(eval, parm->colAnisoType); /* fprintf(stderr, "%s: eret = %d; evals = %g %g %g\n", me, eret, eval[0], eval[1], eval[2]); ELL_3V_CROSS(tmp1, evec+0, evec+3); tmp2[0] = ELL_3V_LEN(tmp1); ELL_3V_CROSS(tmp1, evec+0, evec+6); tmp2[1] = ELL_3V_LEN(tmp1); ELL_3V_CROSS(tmp1, evec+3, evec+6); tmp2[2] = ELL_3V_LEN(tmp1); fprintf(stderr, "%s: crosses = %g %g %g\n", me, tmp2[0], tmp2[1], tmp2[2]); */ /* set transform (in mA) */ ELL_3V_ABS(absEval, eval); ELL_4M_IDENTITY_SET(mA); /* reset */ ELL_3V_SCALE(glyphScl, parm->glyphScale, absEval); /* scale by evals */ ELL_4M_SCALE_SET(mB, glyphScl[0], glyphScl[1], glyphScl[2]); ell_4m_post_mul_d(mA, mB); ELL_43M_INSET(mB, rotEvec); /* rotate by evecs */ ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]); /* translate */ ell_4m_post_mul_d(mA, mB); /* set color (in R,G,B) */ cvec = evec + 3*(AIR_CLAMP(0, parm->colEvec, 2)); R = AIR_ABS(cvec[0]); /* standard mapping */ G = AIR_ABS(cvec[1]); B = AIR_ABS(cvec[2]); /* desaturate by colMaxSat */ R = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, R); G = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, G); B = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, B); /* desaturate some by anisotropy */ R = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, R, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, R)); G = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, G, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, G)); B = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, B, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, B)); /* clamp and do gamma */ R = AIR_CLAMP(0.0, R, 1.0); G = AIR_CLAMP(0.0, G, 1.0); B = AIR_CLAMP(0.0, B, 1.0); R = pow(R, parm->colGamma); G = pow(G, parm->colGamma); B = pow(B, parm->colGamma); /* find axis, and superquad exponents qA and qB */ if (eval[2] > 0) { /* all evals positive */ cl = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cl1)); cp = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cp1)); if (cl > cp) { axis = 0; qA = pow(1-cp, parm->sqdSharp); qB = pow(1-cl, parm->sqdSharp); } else { axis = 2; qA = pow(1-cl, parm->sqdSharp); qB = pow(1-cp, parm->sqdSharp); } qC = qB; } else if (eval[0] < 0) { /* all evals negative */ float aef[3]; aef[0] = absEval[2]; aef[1] = absEval[1]; aef[2] = absEval[0]; cl = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cl1)); cp = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cp1)); if (cl > cp) { axis = 2; qA = pow(1-cp, parm->sqdSharp); qB = pow(1-cl, parm->sqdSharp); } else { axis = 0; qA = pow(1-cl, parm->sqdSharp); qB = pow(1-cp, parm->sqdSharp); } qC = qB; } else { #define OOSQRT2 0.70710678118654752440 #define OOSQRT3 0.57735026918962576451 /* double poleA[3]={OOSQRT3, OOSQRT3, OOSQRT3}; */ double poleB[3]={1, 0, 0}; double poleC[3]={OOSQRT2, OOSQRT2, 0}; double poleD[3]={OOSQRT3, -OOSQRT3, -OOSQRT3}; double poleE[3]={OOSQRT2, 0, -OOSQRT2}; double poleF[3]={OOSQRT3, OOSQRT3, -OOSQRT3}; double poleG[3]={0, -OOSQRT2, -OOSQRT2}; double poleH[3]={0, 0, -1}; /* double poleI[3]={-OOSQRT3, -OOSQRT3, -OOSQRT3}; */ double funk[3]={0,4,2}, thrn[3]={1,4,4}; double octa[3]={0,2,2}, cone[3]={1,2,2}; double evalN[3], tmp, bary[3]; double qq[3]; ELL_3V_NORM(evalN, eval, tmp); if (eval[1] >= -eval[2]) { /* inside B-F-C */ ell_3v_barycentric_spherical_d(bary, poleB, poleF, poleC, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], thrn, bary[2], cone); axis = 2; } else if (eval[0] >= -eval[2]) { /* inside B-D-F */ if (eval[1] >= 0) { /* inside B-E-F */ ell_3v_barycentric_spherical_d(bary, poleB, poleE, poleF, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], funk, bary[2], thrn); axis = 2; } else { /* inside B-D-E */ ell_3v_barycentric_spherical_d(bary, poleB, poleD, poleE, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], cone, bary[1], thrn, bary[2], funk); axis = 0; } } else if (eval[0] < -eval[1]) { /* inside D-G-H */ ell_3v_barycentric_spherical_d(bary, poleD, poleG, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], cone, bary[2], octa); axis = 0; } else if (eval[1] < 0) { /* inside E-D-H */ ell_3v_barycentric_spherical_d(bary, poleE, poleD, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], funk, bary[1], thrn, bary[2], octa); axis = 0; } else { /* inside F-E-H */ ell_3v_barycentric_spherical_d(bary, poleF, poleE, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], funk, bary[2], cone); axis = 2; } qA = qq[0]; qB = qq[1]; qC = qq[2]; #undef OOSQRT2 #undef OOSQRT3 } /* add the glyph */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: the glyph stays!\n", me, idx, numGlyphs); } if (glyphsLimn) { lookIdx = limnObjectLookAdd(glyphsLimn); look = glyphsLimn->look + lookIdx; ELL_4V_SET_TT(look->rgba, float, R, G, B, 1); ELL_3V_SET(look->kads, parm->ADSP[0], parm->ADSP[1], parm->ADSP[2]); look->spow = 0; switch(parm->glyphType) { case tenGlyphTypeBox: glyphIdx = limnObjectCubeAdd(glyphsLimn, lookIdx); break; case tenGlyphTypeSphere: glyphIdx = limnObjectPolarSphereAdd(glyphsLimn, lookIdx, axis, 2*parm->facetRes, parm->facetRes); break; case tenGlyphTypeCylinder: glyphIdx = limnObjectCylinderAdd(glyphsLimn, lookIdx, axis, parm->facetRes); break; case tenGlyphTypeSuperquad: default: glyphIdx = limnObjectPolarSuperquadFancyAdd(glyphsLimn, lookIdx, axis, AIR_CAST(float, qA), AIR_CAST(float, qB), AIR_CAST(float, qC), 0, 2*parm->facetRes, parm->facetRes); break; } ELL_4M_COPY_TT(mA_f, float, mA); limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f); } if (glyphsEcho) { switch(parm->glyphType) { case tenGlyphTypeBox: eglyph = echoObjectNew(glyphsEcho, echoTypeCube); /* nothing else to set */ break; case tenGlyphTypeSphere: eglyph = echoObjectNew(glyphsEcho, echoTypeSphere); echoSphereSet(eglyph, 0, 0, 0, 1); break; case tenGlyphTypeCylinder: eglyph = echoObjectNew(glyphsEcho, echoTypeCylinder); echoCylinderSet(eglyph, axis); break; case tenGlyphTypeSuperquad: default: eglyph = echoObjectNew(glyphsEcho, echoTypeSuperquad); echoSuperquadSet(eglyph, axis, qA, qB); break; } echoColorSet(eglyph, AIR_CAST(echoCol_t, R), AIR_CAST(echoCol_t, G), AIR_CAST(echoCol_t, B), 1); echoMatterPhongSet(glyphsEcho, eglyph, parm->ADSP[0], parm->ADSP[1], parm->ADSP[2], parm->ADSP[3]); inst = echoObjectNew(glyphsEcho, echoTypeInstance); ELL_4M_COPY(eM, mA); echoInstanceSet(inst, eM, eglyph); echoListAdd(list, inst); } } if (glyphsLimn) { glyphsLimn->setVertexRGBAFromLook = svRGBAfl; } if (glyphsEcho) { split = echoListSplit3(glyphsEcho, list, 10); echoObjectAdd(glyphsEcho, split); } airMopOkay(mop); return 0; }
/* ******** nrrdSlice() ** ** slices a nrrd along a given axis, at a given position. ** ** This is a newer version of the procedure, which is simpler, faster, ** and requires less memory overhead than the first one. It is based ** on the observation that any slice is a periodic square-wave pattern ** in the original data (viewed as a one- dimensional array). The ** characteristics of that periodic pattern are how far from the ** beginning it starts (offset), the length of the "on" part (length), ** the period (period), and the number of periods (numper). */ int nrrdSlice(Nrrd *nout, const Nrrd *cnin, unsigned int saxi, size_t pos) { static const char me[]="nrrdSlice", func[]="slice"; size_t I, rowLen, /* length of segment */ colStep, /* distance between start of each segment */ colLen, /* number of periods */ szOut[NRRD_DIM_MAX]; unsigned int ai, outdim; int map[NRRD_DIM_MAX]; const char *src; char *dest, stmp[2][AIR_STRLEN_SMALL]; airArray *mop; Nrrd *nin; if (!(cnin && nout)) { biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nout == cnin) { biffAddf(NRRD, "%s: nout==nin disallowed", me); return 1; } if (1 == cnin->dim) { if (0 != saxi) { biffAddf(NRRD, "%s: slice axis must be 0, not %u, for 1-D array", me, saxi); return 1; } } else { if (!( saxi < cnin->dim )) { biffAddf(NRRD, "%s: slice axis %d out of bounds (0 to %d)", me, saxi, cnin->dim-1); return 1; } } if (!( pos < cnin->axis[saxi].size )) { biffAddf(NRRD, "%s: position %s out of bounds (0 to %s)", me, airSprintSize_t(stmp[0], pos), airSprintSize_t(stmp[1], cnin->axis[saxi].size-1)); return 1; } /* this shouldn't actually be necessary .. */ if (!nrrdElementSize(cnin)) { biffAddf(NRRD, "%s: nrrd reports zero element size!", me); return 1; } /* HEY: copy and paste from measure.c/nrrdProject */ mop = airMopNew(); if (1 == cnin->dim) { /* There are more efficient ways of dealing with this case; this way is easy to implement because it leaves most of the established code below only superficially changed; uniformly replacing nin with (nin ? nin : cnin), even if pointlessly so; this expression that can't be assigned to a new variable because of the difference in const. */ nin = nrrdNew(); airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); if (nrrdAxesInsert(nin, cnin, 1)) { biffAddf(NRRD, "%s: trouble inserting axis on 1-D array", me); airMopError(mop); return 1; } } else { nin = NULL; } /* set up control variables */ rowLen = colLen = 1; for (ai=0; ai<(nin ? nin : cnin)->dim; ai++) { if (ai < saxi) { rowLen *= (nin ? nin : cnin)->axis[ai].size; } else if (ai > saxi) { colLen *= (nin ? nin : cnin)->axis[ai].size; } } rowLen *= nrrdElementSize(nin ? nin : cnin); colStep = rowLen*(nin ? nin : cnin)->axis[saxi].size; outdim = (nin ? nin : cnin)->dim-1; for (ai=0; ai<outdim; ai++) { map[ai] = AIR_INT(ai) + (ai >= saxi); szOut[ai] = (nin ? nin : cnin)->axis[map[ai]].size; } nout->blockSize = (nin ? nin : cnin)->blockSize; if (nrrdMaybeAlloc_nva(nout, (nin ? nin : cnin)->type, outdim, szOut)) { biffAddf(NRRD, "%s: failed to create slice", me); airMopError(mop); return 1; } /* the skinny */ src = AIR_CAST(const char *, (nin ? nin : cnin)->data); dest = AIR_CAST(char *, nout->data); src += rowLen*pos; for (I=0; I<colLen; I++) { /* HEY: replace with AIR_MEMCPY() or similar, when applicable */ memcpy(dest, src, rowLen); src += colStep; dest += rowLen; } /* copy the peripheral information */ if (nrrdAxisInfoCopy(nout, (nin ? nin : cnin), map, NRRD_AXIS_INFO_NONE)) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } if (nrrdContentSet_va(nout, func, cnin /* hide possible axinsert*/, "%d,%d", saxi, pos)) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } if (nrrdBasicInfoCopy(nout, (nin ? nin : cnin), NRRD_BASIC_INFO_DATA_BIT | NRRD_BASIC_INFO_TYPE_BIT | NRRD_BASIC_INFO_BLOCKSIZE_BIT | NRRD_BASIC_INFO_DIMENSION_BIT | NRRD_BASIC_INFO_SPACEORIGIN_BIT | NRRD_BASIC_INFO_CONTENT_BIT | NRRD_BASIC_INFO_COMMENTS_BIT | (nrrdStateKeyValuePairsPropagate ? 0 : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } /* translate origin if this was a spatial axis, otherwise copy */ /* note that if there is no spatial info at all, this is all harmless */ if (AIR_EXISTS((nin ? nin : cnin)->axis[saxi].spaceDirection[0])) { nrrdSpaceVecScaleAdd2(nout->spaceOrigin, 1.0, (nin ? nin : cnin)->spaceOrigin, AIR_CAST(double, pos), (nin ? nin : cnin)->axis[saxi].spaceDirection); } else {
/* ******** nrrdShuffle ** ** rearranges hyperslices of a nrrd along a given axis according to ** given permutation. This could be used to on a 4D array, ** representing a 3D volume of vectors, to re-order the vector ** components. ** ** the given permutation array must allocated for at least as long as ** the input nrrd along the chosen axis. perm[j] = i means that the ** value at position j in the _new_ array should come from position i ** in the _old_array. The standpoint is from the new, looking at ** where to find the values amid the old array (perm answers "what do ** I put here", not "where do I put this"). This allows multiple ** positions in the new array to copy from the same old position, and ** insures that there is an source for all positions along the new ** array. */ int nrrdShuffle(Nrrd *nout, const Nrrd *nin, unsigned int axis, const size_t *perm) { static const char me[]="nrrdShuffle", func[]="shuffle"; char buff2[AIR_STRLEN_SMALL]; /* Sun Feb 8 13:13:58 CST 2009: There was a memory bug here caused by using the same buff1[NRRD_DIM_MAX*30] declaration that had worked fine for nrrdAxesPermute and nrrdReshape, but does NOT work here because now samples along an axes are re-ordered, not axes, so its often not allocated for long enough to hold the string that's printed to it. Ideally there'd be another argument that says whether to document the shuffle in the content string, which would mean an API change. Or, we can use a secret heuristic (or maybe later a nrrdState variable) for determining when an axis is short enough to make documenting the shuffle interesting. This is useful since functions like nrrdFlip() probably do *not* need the shuffle (the sample reversal) to be documented for long axes */ #define LONGEST_INTERESTING_AXIS 42 char buff1[LONGEST_INTERESTING_AXIS*30]; unsigned int ai, ldim, len; size_t idxInB=0, idxOut, lineSize, numLines, size[NRRD_DIM_MAX], *lsize, cIn[NRRD_DIM_MAX+1], cOut[NRRD_DIM_MAX+1]; char *dataIn, *dataOut; if (!(nin && nout && perm)) { biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nout == nin) { biffAddf(NRRD, "%s: nout==nin disallowed", me); return 1; } if (!( axis < nin->dim )) { biffAddf(NRRD, "%s: axis %d outside valid range [0,%d]", me, axis, nin->dim-1); return 1; } len = AIR_CAST(unsigned int, nin->axis[axis].size); for (ai=0; ai<len; ai++) { if (!( perm[ai] < len )) { char stmp[AIR_STRLEN_SMALL]; biffAddf(NRRD, "%s: perm[%d] (%s) outside valid range [0,%d]", me, ai, airSprintSize_t(stmp, perm[ai]), len-1); return 1; } } /* this shouldn't actually be necessary .. */ if (!nrrdElementSize(nin)) { biffAddf(NRRD, "%s: nrrd reports zero element size!", me); return 1; } /* set information in new volume */ nout->blockSize = nin->blockSize; nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size); if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, size)) { biffAddf(NRRD, "%s: failed to allocate output", me); return 1; } if (nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE)) { biffAddf(NRRD, "%s:", me); return 1; } /* the min and max along the shuffled axis are now meaningless */ nout->axis[axis].min = nout->axis[axis].max = AIR_NAN; /* do the safe thing first */ nout->axis[axis].kind = _nrrdKindAltered(nin->axis[axis].kind, AIR_FALSE); /* try cleverness */ if (!nrrdStateKindNoop) { if (0 == nrrdKindSize(nin->axis[axis].kind) || nrrdKindStub == nin->axis[axis].kind || nrrdKindScalar == nin->axis[axis].kind || nrrdKind2Vector == nin->axis[axis].kind || nrrdKind3Color == nin->axis[axis].kind || nrrdKind4Color == nin->axis[axis].kind || nrrdKind3Vector == nin->axis[axis].kind || nrrdKind3Gradient == nin->axis[axis].kind || nrrdKind3Normal == nin->axis[axis].kind || nrrdKind4Vector == nin->axis[axis].kind) { /* these kinds have no intrinsic ordering */ nout->axis[axis].kind = nin->axis[axis].kind; } } /* the skinny */ lineSize = 1; for (ai=0; ai<axis; ai++) { lineSize *= nin->axis[ai].size; } numLines = nrrdElementNumber(nin)/lineSize; lineSize *= nrrdElementSize(nin); lsize = size + axis; ldim = nin->dim - axis; dataIn = AIR_CAST(char *, nin->data); dataOut = AIR_CAST(char *, nout->data); memset(cIn, 0, sizeof(cIn)); memset(cOut, 0, sizeof(cOut)); for (idxOut=0; idxOut<numLines; idxOut++) { memcpy(cIn, cOut, sizeof(cIn)); cIn[0] = perm[cOut[0]]; NRRD_INDEX_GEN(idxInB, cIn, lsize, ldim); NRRD_INDEX_GEN(idxOut, cOut, lsize, ldim); memcpy(dataOut + idxOut*lineSize, dataIn + idxInB*lineSize, lineSize); NRRD_COORD_INCR(cOut, lsize, ldim, 0); } /* Set content. The LONGEST_INTERESTING_AXIS hack avoids the previous array out-of-bounds bug */ if (len <= LONGEST_INTERESTING_AXIS) { strcpy(buff1, ""); for (ai=0; ai<len; ai++) { char stmp[AIR_STRLEN_SMALL]; sprintf(buff2, "%s%s", (ai ? "," : ""), airSprintSize_t(stmp, perm[ai])); strcat(buff1, buff2); } if (nrrdContentSet_va(nout, func, nin, "%s", buff1)) { biffAddf(NRRD, "%s:", me); return 1; } } else { if (nrrdContentSet_va(nout, func, nin, "")) { biffAddf(NRRD, "%s:", me); return 1; } } 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 | NRRD_BASIC_INFO_COMMENTS_BIT | (nrrdStateKeyValuePairsPropagate ? 0 : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) { biffAddf(NRRD, "%s:", me); return 1; } return 0; #undef LONGEST_INTERESTING_AXIS }
/* ** nio->byteSkip < 0 functionality contributed by Katharina Quintus */ static int _nrrdEncodingGzip_read(FILE *file, void *_data, size_t elNum, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingGzip_read"; #if TEEM_ZLIB size_t sizeData, sizeRed; int error; long int bi; unsigned int didread, sizeChunk, maxChunk; char *data; gzFile gzfin; airPtrPtrUnion appu; sizeData = nrrdElementSize(nrrd)*elNum; /* Create the gzFile for reading in the gzipped data. */ if ((gzfin = _nrrdGzOpen(file, "rb")) == Z_NULL) { /* there was a problem */ biffAddf(NRRD, "%s: error opening gzFile", me); return 1; } /* keeps track of how many bytes have been successfully read in */ sizeRed = 0; /* zlib can only handle data sizes up to UINT_MAX ==> if there's more than UINT_MAX bytes to read in, we read in in chunks. However, we wrap a value _nrrdZlibMaxChunk around UINT_MAX for testing purposes. Given how sizeChunk is used below, we also cap chunk size at _nrrdZlibMaxChunk/2 to prevent overflow. */ maxChunk = _nrrdZlibMaxChunk/2; sizeChunk = AIR_CAST(unsigned int, AIR_MIN(sizeData, maxChunk)); if (nio->byteSkip < 0) { /* We don't know the size of the size to skip before the data, so decompress the data first into a temporary memory buffer. Then the byteskipping is then just memcpy-ing the appropriate region of memory from "buff" into the given "_data" pointer */ char *buff; airArray *buffArr; long backwards; /* setting the airArray increment to twice the chunk size means that for headers that are small compared to the data, the airArray never actually has to reallocate. The unit is 1 because we are managing the reading in terms of bytes (sizeof(char)==1 by definition) */ buff = NULL; appu.c = &buff; buffArr = airArrayNew(appu.v, NULL, 1, 2*sizeChunk); airArrayLenSet(buffArr, sizeChunk); if (!( buffArr && buffArr->data )) { biffAddf(NRRD, "%s: couldn't initialize airArray\n", me); return 1; } /* we keep reading in chunks as long as there hasn't been an error, and we haven't hit EOF (EOF signified by read == 0). Unlike the code below (for positive byteskip), we are obligated to read until the bitter end, and can't update sizeChunk to encompass only the required data. */ while (!(error = _nrrdGzRead(gzfin, buff + sizeRed, sizeChunk, &didread)) && didread > 0) { sizeRed += didread; if (didread >= sizeChunk) { /* we were able to read as much data as we requested, maybe there is more, so we need to make our temp buffer bigger */ unsigned int newlen = buffArr->len + sizeChunk; if (newlen < buffArr->len) { biffAddf(NRRD, "%s: array size will exceed uint capacity", me); return 1; } airArrayLenSet(buffArr, newlen); if (!buffArr->data) { biffAddf(NRRD, "%s: couldn't re-allocate data buffer", me); return 1; } } } if (error) { biffAddf(NRRD, "%s: error reading from gzFile", me); return 1; } /* backwards is (positive) number of bytes AFTER data that we ignore */ backwards = -nio->byteSkip - 1; if (sizeRed < sizeData + AIR_CAST(size_t, backwards)) { char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; biffAddf(NRRD, "%s: expected %s bytes but received only %s", me, airSprintSize_t(stmp1, sizeData + AIR_CAST(size_t, backwards)), airSprintSize_t(stmp2, sizeRed)); return 1; } /* also handles nio->byteSkip == -N-1 signifying extra N bytes at end */ memcpy(_data, buff + sizeRed - sizeData - backwards, sizeData); airArrayNuke(buffArr); } else { /* no negative byteskip: after byteskipping, we can read directly into given data buffer */ if (nio->byteSkip > 0) { for (bi=0; bi<nio->byteSkip; bi++) { unsigned char b; /* Check to see if a single byte was able to be read. */ if (_nrrdGzRead(gzfin, &b, 1, &didread) != 0 || didread != 1) { biffAddf(NRRD, "%s: hit an error skipping byte %ld of %ld", me, bi, nio->byteSkip); return 1; } } } /* Pointer to chunks as we read them. */ data = AIR_CAST(char *, _data); while (!(error = _nrrdGzRead(gzfin, data, sizeChunk, &didread)) && didread > 0) { /* Increment the data pointer to the next available chunk. */ data += didread; sizeRed += didread; /* We only want to read as much data as we need, so we need to check to make sure that we don't request data that might be there but that we don't want. This will reduce sizeChunk when we get to the last block (which may be smaller than the original sizeChunk). */ if (sizeData >= sizeRed && sizeData - sizeRed < sizeChunk) { sizeChunk = AIR_CAST(unsigned int, sizeData - sizeRed); } } if (error) { biffAddf(NRRD, "%s: error reading from gzFile", me); return 1; } /* Check to see if we got out as much as we thought we should. */ if (sizeRed != sizeData) { char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; biffAddf(NRRD, "%s: expected %s bytes but received %s", me, airSprintSize_t(stmp1, sizeData), airSprintSize_t(stmp2, sizeRed)); return 1; } }
/* ** _ell_LU_decomp() ** ** in-place LU decomposition */ int _ell_LU_decomp(double *aa, size_t *indx, size_t NN) { static const char me[]="_ell_LU_decomp"; int ret=0; size_t ii, imax=0, jj, kk; double big, sum, tmp; double *vv; if (!( vv = (double*)calloc(NN, sizeof(double)) )) { biffAddf(ELL, "%s: couldn't allocate vv[]!", me); ret = 1; goto seeya; } /* find vv[i]: max of abs of everything in column i */ for (ii=0; ii<NN; ii++) { big = 0.0; for (jj=0; jj<NN; jj++) { if ((tmp=AIR_ABS(aa[ii*NN + jj])) > big) { big = tmp; } } if (!big) { char stmp[AIR_STRLEN_SMALL]; biffAddf(ELL, "%s: singular matrix since column %s all zero", me, airSprintSize_t(stmp, ii)); ret = 1; goto seeya; } vv[ii] = big; } for (jj=0; jj<NN; jj++) { /* for aa[ii][jj] in lower triangle (below diagonal), subtract from aa[ii][jj] the dot product of all elements to its left with elements above it (starting at the top) */ for (ii=0; ii<jj; ii++) { sum = aa[ii*NN + jj]; for (kk=0; kk<ii; kk++) { sum -= aa[ii*NN + kk]*aa[kk*NN + jj]; } aa[ii*NN + jj] = sum; } /* for aa[ii][jj] in upper triangle (including diagonal), subtract from aa[ii][jj] the dot product of all elements above it with elements to its left (starting from the left) */ big = 0.0; for (ii=jj; ii<NN; ii++) { sum = aa[ii*NN + jj]; for (kk=0; kk<jj; kk++) { sum -= aa[ii*NN + kk]*aa[kk*NN + jj]; } aa[ii*NN + jj] = sum; /* imax column is one in which abs(aa[i][j])/vv[i] */ if ((tmp = AIR_ABS(sum)/vv[ii]) >= big) { big = tmp; imax = ii; } } /* unless we're on the imax column, swap this column the with imax column, and permute vv[] accordingly */ if (jj != imax) { /* could record parity # of permutes here */ for (kk=0; kk<NN; kk++) { tmp = aa[imax*NN + kk]; aa[imax*NN + kk] = aa[jj*NN + kk]; aa[jj*NN + kk] = tmp; } tmp = vv[imax]; vv[imax] = vv[jj]; vv[jj] = tmp; } indx[jj] = imax; if (aa[jj*NN + jj] == 0.0) { aa[jj*NN + jj] = ELL_EPS; } /* divide everything right of a[jj][jj] by a[jj][jj] */ if (jj != NN) { tmp = 1.0/aa[jj*NN + jj]; for (ii=jj+1; ii<NN; ii++) { aa[ii*NN + jj] *= tmp; } } } seeya: airFree(vv); return ret; }
/* ** _nrrdSprintFieldInfo ** ** this prints "<prefix><field>: <info>" into *strP (after allocating it for ** big enough, usually with a stupidly big margin of error), in a form ** suitable to be written to NRRD or other image headers. This will always ** print something (for valid inputs), even stupid <info>s like ** "(unknown endian)". It is up to the caller to decide which fields ** are worth writing, via _nrrdFieldInteresting(). ** ** NOTE: some of these fields make sense in non-NRRD files (e.g. all ** the per-axis information), but many only make sense in NRRD files. ** This is just one example of NRRD-format-specific stuff that is not ** in formatNRRD.c */ void _nrrdSprintFieldInfo(char **strP, const char *prefix, const Nrrd *nrrd, NrrdIoState *nio, int field) { static const char me[]="_nrrdSprintFieldInfo"; char buff[AIR_STRLEN_MED], *fnb, stmp[AIR_STRLEN_SMALL], *strtmp=NULL; double colvec[NRRD_SPACE_DIM_MAX]; const char *fs; unsigned int ii, dd, uintStrlen = 11, size_tStrlen = 33, doubleStrlen = 513; size_t fslen, fdlen, maxl; int endi; if (!( strP && prefix && nrrd && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) && AIR_IN_OP(nrrdField_unknown, field, nrrdField_last) )) { return; } /* As of Sun Dec 2 01:57:48 CST 2012 (revision 5832) the only places where this function is called is when it has been guarded by "if (_nrrdFieldInteresting())" (except for in formatText.c when its called on the dimension field, which is always interesting). So, the following: if (!_nrrdFieldInteresting(nrrd, nio, field)) { *strP = airStrdup(""); } was redundant and confusingly created the appearance of a memory leak waiting to happen. We now let the default switch statement set *strP to NULL (all the other cases set it), to smoke out errors in how this function is called */ fs = airEnumStr(nrrdField, field); fslen = strlen(prefix) + strlen(fs) + strlen(": ") + 1; switch (field) { case nrrdField_comment: case nrrdField_keyvalue: fprintf(stderr, "%s: CONFUSION: why are you calling me on \"%s\"?\n", me, airEnumStr(nrrdField, nrrdField_comment)); *strP = airStrdup(""); break; case nrrdField_content: strtmp = airOneLinify(airStrdup(nrrd->content)); *strP = AIR_CALLOC(fslen + strlen(strtmp), char); sprintf(*strP, "%s%s: %s", prefix, fs, strtmp); airFree(strtmp); strtmp = NULL; break; case nrrdField_number: *strP = AIR_CALLOC(fslen + size_tStrlen, char); sprintf(*strP, "%s%s: %s", prefix, fs, airSprintSize_t(stmp, nrrdElementNumber(nrrd))); break; case nrrdField_type: *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdType, nrrd->type)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdType, nrrd->type)); break; case nrrdField_block_size: *strP = AIR_CALLOC(fslen + size_tStrlen, char); sprintf(*strP, "%s%s: %s", prefix, fs, airSprintSize_t(stmp, nrrd->blockSize)); break; case nrrdField_dimension: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->dim); break; case nrrdField_space: *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdSpace, nrrd->space)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdSpace, nrrd->space)); break; case nrrdField_space_dimension: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->spaceDim); break; /* ---- begin per-axis fields ---- */ case nrrdField_sizes: *strP = AIR_CALLOC(fslen + nrrd->dim*(size_tStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", airSprintSize_t(stmp, nrrd->axis[ii].size)); strcat(*strP, buff); } break; case nrrdField_spacings: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].spacing); strcat(*strP, buff); } break; case nrrdField_thicknesses: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].thickness); strcat(*strP, buff); } break; case nrrdField_axis_mins: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].min); strcat(*strP, buff); } break; case nrrdField_axis_maxs: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].max); strcat(*strP, buff); } break; case nrrdField_space_directions: *strP = AIR_CALLOC(fslen + nrrd->dim*nrrd->spaceDim*(doubleStrlen + strlen("(,) ")), char); sprintf(*strP, "%s%s: ", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->axis[ii].spaceDirection); if (ii < nrrd->dim-1) { strcat(*strP, " "); } } break; case nrrdField_centers: fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { fdlen += 1 + airStrlen(nrrd->axis[ii].center ? airEnumStr(nrrdCenter, nrrd->axis[ii].center) : NRRD_UNKNOWN); } *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", (nrrd->axis[ii].center ? airEnumStr(nrrdCenter, nrrd->axis[ii].center) : NRRD_UNKNOWN)); strcat(*strP, buff); } break; case nrrdField_kinds: fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { fdlen += 1 + airStrlen(nrrd->axis[ii].kind ? airEnumStr(nrrdKind, nrrd->axis[ii].kind) : NRRD_UNKNOWN); } *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", (nrrd->axis[ii].kind ? airEnumStr(nrrdKind, nrrd->axis[ii].kind) : NRRD_UNKNOWN)); strcat(*strP, buff); } break; case nrrdField_labels: case nrrdField_units: #define LABEL_OR_UNITS (nrrdField_labels == field \ ? nrrd->axis[ii].label \ : nrrd->axis[ii].units) fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { /* The "2*" is because at worst every character needs escaping. The "+ 3" for the |" "| between each part */ fdlen += 2*airStrlen(LABEL_OR_UNITS) + 3; } fdlen += 1; /* for '\0' */ *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { strcat(*strP, " \""); if (airStrlen(nrrd->axis[ii].label)) { _nrrdWriteEscaped(NULL, *strP, LABEL_OR_UNITS, "\"", _NRRD_WHITESPACE_NOTAB); } strcat(*strP, "\""); } #undef LABEL_OR_UNITS break; /* ---- end per-axis fields ---- */ case nrrdField_min: case nrrdField_max: /* we're basically a no-op, now that these fields became meaningless */ *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: 0.0", prefix, fs); strcat(*strP, buff); break; case nrrdField_old_min: *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: ", prefix, fs); airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMin); strcat(*strP, buff); break; case nrrdField_old_max: *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: ", prefix, fs); airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMax); strcat(*strP, buff); break; case nrrdField_endian: if (airEndianUnknown != nio->endian) { /* we know a specific endianness because either it was recorded as part of "unu make -h", or it was set (and data was possibly altered) as part of "unu save" */ endi = nio->endian; } else { /* we record our current architecture's endian because we're going to writing out data */ endi = airMyEndian(); } *strP = AIR_CALLOC(fslen + strlen(airEnumStr(airEndian, endi)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(airEndian, endi)); break; case nrrdField_encoding: *strP = AIR_CALLOC(fslen + strlen(nio->encoding->name), char); sprintf(*strP, "%s%s: %s", prefix, fs, nio->encoding->name); break; case nrrdField_line_skip: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nio->lineSkip); break; case nrrdField_byte_skip: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %ld", prefix, fs, nio->byteSkip); break; case nrrdField_sample_units: strtmp = airOneLinify(airStrdup(nrrd->sampleUnits)); *strP = AIR_CALLOC(fslen + strlen(strtmp), char); sprintf(*strP, "%s%s: \"%s\"", prefix, fs, strtmp); airFree(strtmp); strtmp = NULL; break; case nrrdField_space_units: fdlen = 0; for (ii=0; ii<nrrd->spaceDim; ii++) { /* The "2*" is because at worst every character needs escaping. See note in formatNRRD.c about how even though its not part of the format, we have worst-case scenario of having to escape a space units which is nothing but ". The "+ 3" for the |" "| between each part */ fdlen += 2*airStrlen(nrrd->spaceUnits[ii]) + 3; } fdlen += 1; /* for '\0' */ *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->spaceDim; ii++) { strcat(*strP, " \""); if (airStrlen(nrrd->spaceUnits[ii])) { _nrrdWriteEscaped(NULL, *strP, nrrd->spaceUnits[ii], "\"", _NRRD_WHITESPACE_NOTAB); } strcat(*strP, "\""); } break; case nrrdField_space_origin: *strP = AIR_CALLOC(fslen + nrrd->spaceDim*(doubleStrlen + strlen("(,) ")), char); sprintf(*strP, "%s%s: ", prefix, fs); _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->spaceOrigin); break; case nrrdField_measurement_frame: *strP = AIR_CALLOC(fslen + (nrrd->spaceDim* nrrd->spaceDim*(doubleStrlen + strlen("(,) "))), char); sprintf(*strP, "%s%s: ", prefix, fs); for (dd=0; dd<nrrd->spaceDim; dd++) { for (ii=0; ii<nrrd->spaceDim; ii++) { colvec[ii] = nrrd->measurementFrame[dd][ii]; } _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, colvec); if (dd < nrrd->spaceDim-1) { strcat(*strP, " "); } } break; case nrrdField_data_file: /* NOTE: this comes last (nrrdField_data_file is the highest-valued member of the nrrdField* enum) because the "LIST" form of the data file specification requires that the following lines be the filenames */ /* error checking elsewhere: assumes there is data file info */ if (nio->dataFNFormat) { *strP = AIR_CALLOC(fslen + strlen(nio->dataFNFormat) + 4*uintStrlen, char); if (nio->dataFileDim == nrrd->dim-1) { sprintf(*strP, "%s%s: %s %d %d %d", prefix, fs, nio->dataFNFormat, nio->dataFNMin, nio->dataFNMax, nio->dataFNStep); } else { sprintf(*strP, "%s%s: %s %d %d %d %u", prefix, fs, nio->dataFNFormat, nio->dataFNMin, nio->dataFNMax, nio->dataFNStep, nio->dataFileDim); } } else if (nio->dataFNArr->len > 1) {
/* ** _miteStageSet ** ** ALLOCATES and initializes stage array in a miteThread */ int _miteStageSet(miteThread *mtt, miteRender *mrr) { static const char me[]="_miteStageSet"; char *value; int ni, di, stageIdx, rii, stageNum, ilog2; Nrrd *ntxf; miteStage *stage; gageItemSpec isp; char rc; stageNum = _miteStageNum(mrr); /* fprintf(stderr, "!%s: stageNum = %d\n", me, stageNum); */ mtt->stage = AIR_CALLOC(stageNum, miteStage); if (!mtt->stage) { biffAddf(MITE, "%s: couldn't alloc array of %d stages", me, stageNum); return 1; } airMopAdd(mtt->rmop, mtt->stage, airFree, airMopAlways); mtt->stageNum = stageNum; stageIdx = 0; for (ni=0; ni<mrr->ntxfNum; ni++) { ntxf = mrr->ntxf[ni]; for (di=ntxf->dim-1; di>=1; di--) { stage = mtt->stage + stageIdx; _miteStageInit(stage); miteVariableParse(&isp, ntxf->axis[di].label); stage->val = _miteAnswerPointer(mtt, &isp); stage->label = ntxf->axis[di].label; /* fprintf(stderr, "!%s: ans=%p + offset[%d]=%d == %p\n", me, mtt->ans, dom, kind->ansOffset[dom], stage->val); */ stage->size = ntxf->axis[di].size; stage->min = ntxf->axis[di].min; stage->max = ntxf->axis[di].max; if (di > 1) { stage->data = NULL; } else { stage->data = (mite_t *)ntxf->data; value = nrrdKeyValueGet(ntxf, "miteStageOp"); if (value) { stage->op = airEnumVal(miteStageOp, value); if (miteStageOpUnknown == stage->op) { stage->op = miteStageOpMultiply; } } else { stage->op = miteStageOpMultiply; } if (1 == isp.kind->table[isp.item].answerLength) { stage->qn = NULL; } else if (3 == isp.kind->table[isp.item].answerLength) { char stmp[AIR_STRLEN_SMALL]; ilog2 = airLog2(ntxf->axis[di].size); switch(ilog2) { case 8: stage->qn = limnVtoQN_d[ limnQN8octa]; break; case 9: stage->qn = limnVtoQN_d[ limnQN9octa]; break; case 10: stage->qn = limnVtoQN_d[limnQN10octa]; break; case 11: stage->qn = limnVtoQN_d[limnQN11octa]; break; case 12: stage->qn = limnVtoQN_d[limnQN12octa]; break; case 13: stage->qn = limnVtoQN_d[limnQN13octa]; break; case 14: stage->qn = limnVtoQN_d[limnQN14octa]; break; case 15: stage->qn = limnVtoQN_d[limnQN15octa]; break; case 16: stage->qn = limnVtoQN_d[limnQN16octa]; break; default: biffAddf(MITE, "%s: txf axis %d size %s not usable for " "vector txf domain variable %s", me, di, airSprintSize_t(stmp, ntxf->axis[di].size), ntxf->axis[di].label); return 1; break; } } else { biffAddf(MITE, "%s: %s not scalar or vector (len = %d): can't be " "a txf domain variable", me, ntxf->axis[di].label, isp.kind->table[isp.item].answerLength); return 1; } stage->rangeNum = ntxf->axis[0].size; for (rii=0; rii<stage->rangeNum; rii++) { rc = ntxf->axis[0].label[rii]; stage->rangeIdx[rii] = strchr(miteRangeChar, rc) - miteRangeChar; /* fprintf(stderr, "!%s: range: %c -> %d\n", "_miteStageSet", ntxf->axis[0].label[rii], stage->rangeIdx[rii]); */ } } stageIdx++; } } return 0; }
/* ** nrrdArrayCompare ** ** something like strcmp() for arrays of numeric values, except ** that the arrays have to be equal length, and it has to do ** error checking. ** ** See comment about logic of return value above nrrdCompare() ** ** This is a very rare kind of nrrd function that operates on ** a bare array and not a Nrrd itself */ int nrrdArrayCompare(int type, const void *_valA, const void *_valB, size_t valNum, double epsilon, int *differ, char explain[AIR_STRLEN_LARGE]) { static const char me[]="nrrdArrayCompare"; const unsigned char *valA, *valB; int (*compare)(const void *, const void *); size_t ii, sze; char stmp[AIR_STRLEN_SMALL]; if (!(_valA && _valB && differ)) { biffAddf(NRRD, "%s: got NULL pointer (%p, %p, or %p)", me, _valA, _valB, AIR_VOIDP(differ)); return 1; } if (!valNum) { biffAddf(NRRD, "%s: can't work with 0-length arrays", me); return 1; } if (!AIR_EXISTS(epsilon)) { biffAddf(NRRD, "%s: non-existent epsilon %g", me, epsilon); return 1; } if (airEnumValCheck(nrrdType, type)) { biffAddf(NRRD, "%s: invalid nrrd type %d", me, type); return 1; } if (nrrdTypeBlock == type) { biffAddf(NRRD, "%s: can't use type %s", me, airEnumStr(nrrdType, type)); return 1; } if (explain) { strcpy(explain, ""); } if (type == nrrdTypeLLong || type == nrrdTypeULLong) { fprintf(stderr, "%s: WARNING: possible erroneous comparison of " "%s values with %s-based comparison\n", me, airEnumStr(nrrdType, type), airEnumStr(nrrdType, nrrdTypeDouble)); } sze = nrrdTypeSize[type]; compare = nrrdValCompare[type]; valA = AIR_CAST(const unsigned char *, _valA); valB = AIR_CAST(const unsigned char *, _valB); for (ii=0; ii<valNum; ii++) { *differ = compare(valA + ii*sze, valB + ii*sze); if (*differ) { double aa, bb; /* same loss of precision as warned about above */ aa = nrrdDLookup[type](valA, ii); bb = nrrdDLookup[type](valB, ii); if (0 == epsilon || fabs(aa - bb) > epsilon) { if (explain) { airSprintSize_t(stmp, ii); if (0 == epsilon) { sprintf(explain, "valA[%s]=%.17g %s valB[%s]=%.17g " "by %g", stmp, aa, *differ < 0 ? "<" : ">", stmp, bb, fabs(aa - bb)); } else { sprintf(explain, "valA[%s]=%.17g %s valB[%s]=%.17g " "by %g, more than eps %g", stmp, aa, *differ < 0 ? "<" : ">", stmp, bb, fabs(aa - bb), epsilon); } } break; } else { /* we did detect a difference, but it was not in excess of epsilon, so we reset *differ to 0 */ *differ = 0; } } } return 0; }
int main(int argc, const char **argv) { /* stock variables */ char me[] = BKEY; hestOpt *hopt=NULL; hestParm *hparm; airArray *mop; /* variables specific to this program */ int negskip, progress; Nrrd *nref, *nin; size_t *size, ii, nn, tick, pad[2]; unsigned int axi, refCRC, gotCRC, sizeNum; char *berr, *outS[2], stmp[AIR_STRLEN_SMALL], doneStr[AIR_STRLEN_SMALL]; airRandMTState *rng; unsigned int seed, *rdata, printbytes; unsigned char *dataUC; double time0, time1; FILE *fout; /* start-up */ mop = airMopNew(); hparm = hestParmNew(); airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); /* learn things from hest */ hestOptAdd(&hopt, "seed", "N", airTypeUInt, 1, 1, &seed, "42", "seed for RNG"); hestOptAdd(&hopt, "s", "sz0", airTypeSize_t, 1, -1, &size, NULL, "sizes of desired output", &sizeNum); hestOptAdd(&hopt, "p", "pb pa", airTypeSize_t, 2, 2, pad, "0 0", "bytes of padding before, and after, the data segment " "in the written data"); hestOptAdd(&hopt, "ns", "bool", airTypeInt, 0, 0, &negskip, NULL, "skipping should be relative to end of file"); hestOptAdd(&hopt, "pb", "print", airTypeUInt, 1, 1, &printbytes, "0", "bytes to print at beginning and end of data, to help " "debug problems"); hestOptAdd(&hopt, "o", "out.data out.nhdr", airTypeString, 2, 2, outS, NULL, "output filenames of data and header"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, tskipInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); /* generate reference nrrd data */ nref = nrrdNew(); airMopAdd(mop, nref, (airMopper)nrrdNuke, airMopAlways); if (nrrdMaybeAlloc_nva(nref, nrrdTypeUInt, sizeNum, size)) { airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error allocating data: %s\n", me, berr); airMopError(mop); return 1; } rng = airRandMTStateNew(seed); airMopAdd(mop, rng, (airMopper)airRandMTStateNix, airMopAlways); nn = nrrdElementNumber(nref); rdata = AIR_CAST(unsigned int *, nref->data); fprintf(stderr, "generating data: . . . "); fflush(stderr); time0 = airTime(); progress = AIR_FALSE; tick = nn/100; for (ii=0; ii<nn; ii++) { rdata[ii] = airUIrandMT_r(rng); if (ii && tick && !(ii % tick)) { time1 = airTime(); if (time1 - time0 > 1.0) { /* if it took more than a second to do 1% of the thing, would be good to generate some progress indication */ progress = AIR_TRUE; } if (progress) { fprintf(stderr, "%s", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); } } } if (progress) { fprintf(stderr, "%s\n", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); } else { fprintf(stderr, "\n"); } fprintf(stderr, "finding reference (big-endian) CRC: "); fflush(stderr); refCRC = nrrdCRC32(nref, airEndianBig); fprintf(stderr, "%u\n", refCRC); /* write data, with padding */ fprintf(stderr, "saving data . . . "); fflush(stderr); if (!(fout = fopen(outS[0], "wb" COMMIT))) { fprintf(stderr, "\n%s: couldn't open %s for writing: %s\n", me, outS[0], strerror(errno)); airMopError(mop); return 1; } airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); for (ii=0; ii<pad[0]; ii++) { if (EOF == fputc(1, fout)) { fprintf(stderr, "\n%s: error doing pre-padding\n", me); airMopError(mop); return 1; } } if (nn != fwrite(nref->data, nrrdElementSize(nref), nn, fout)) { fprintf(stderr, "\n%s: error writing data\n", me); airMopError(mop); return 1; } for (ii=0; ii<pad[1]; ii++) { if (EOF == fputc(2, fout)) { fprintf(stderr, "\n%s: error doing post-padding\n", me); airMopError(mop); return 1; } } if (EOF == fflush(fout)) { fprintf(stderr, "\n%s: error fflushing data: %s\n", me, strerror(errno)); } fprintf(stderr, "\n"); if (printbytes) { size_t bi, rpb, nn; char stmp[AIR_STRLEN_SMALL]; nn = nrrdElementSize(nref)*nrrdElementNumber(nref); rpb = AIR_MIN(printbytes, nn); dataUC = AIR_CAST(unsigned char *, nref->data); fprintf(stderr, "CORRECT %s bytes at beginning:\n", airSprintSize_t(stmp, rpb)); for (bi=0; bi<rpb; bi++) { fprintf(stderr, "%x ", dataUC[bi]); } fprintf(stderr, "...\n"); fprintf(stderr, "CORRECT %s bytes at end:\n", airSprintSize_t(stmp, rpb)); fprintf(stderr, "..."); for (bi=nn - rpb; bi<nn; bi++) { fprintf(stderr, " %x", dataUC[bi]); } fprintf(stderr, "\n"); } airMopSingleOkay(mop, fout); airMopSingleOkay(mop, nref); nref = NULL; /* write header; for now just writing the header directly */ fprintf(stderr, "writing header . . . \n"); if (!(fout = fopen(outS[1], "w"))) { fprintf(stderr, "%s: couldn't open %s for writing: %s\n", me, outS[1], strerror(errno)); airMopError(mop); return 1; } airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); fprintf(fout, "NRRD0005\n"); fprintf(fout, "type: unsigned int\n"); fprintf(fout, "dimension: %u\n", sizeNum); fprintf(fout, "sizes:"); for (axi=0; axi<sizeNum; axi++) { fprintf(fout, " %s", airSprintSize_t(stmp, size[axi])); } fprintf(fout, "\n"); fprintf(fout, "endian: %s\n", airEnumStr(airEndian, airMyEndian())); fprintf(fout, "encoding: %s\n", airEnumStr(nrrdEncodingType, nrrdEncodingTypeRaw)); if (!negskip) { if (pad[0]) { fprintf(fout, "byte skip: %s\n", airSprintSize_t(stmp, pad[0])); } } else { fprintf(fout, "byte skip: -%s\n", airSprintSize_t(stmp, pad[1]+1)); } fprintf(fout, "data file: %s\n", outS[0]); airMopSingleOkay(mop, fout); /* read it in, make sure it checks out */ fprintf(stderr, "reading data . . . \n"); nin = nrrdNew(); airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); if (nrrdLoad(nin, outS[1], NULL)) { airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error reading back in: %s\n", me, berr); airMopError(mop); return 1; } if (printbytes) { size_t bi, rpb, nn; char stmp[AIR_STRLEN_SMALL]; nn = nrrdElementSize(nin)*nrrdElementNumber(nin); rpb = AIR_MIN(printbytes, nn); dataUC = AIR_CAST(unsigned char *, nin->data); fprintf(stderr, "FOUND %s bytes at beginning:\n", airSprintSize_t(stmp, rpb)); for (bi=0; bi<rpb; bi++) { fprintf(stderr, "%x ", dataUC[bi]); } fprintf(stderr, "...\n"); fprintf(stderr, "FOUND %s bytes at end:\n", airSprintSize_t(stmp, rpb)); fprintf(stderr, "..."); for (bi=nn - rpb; bi<nn; bi++) { fprintf(stderr, " %x", dataUC[bi]); } fprintf(stderr, "\n"); } fprintf(stderr, "finding new CRC . . . \n"); gotCRC = nrrdCRC32(nin, airEndianBig); if (refCRC != gotCRC) { fprintf(stderr, "%s: got CRC %u but wanted %u\n", me, gotCRC, refCRC); airMopError(mop); return 1; } fprintf(stderr, "(all ok)\n"); /* HEY: to test gzip reading, we really want to do a system call to gzip compress the data, and write a new header to point to the compressed data, and make sure we can read in that just the same */ airMopOkay(mop); return 0; }