/* ******** nrrdNuke() ** ** blows away the nrrd and everything inside ** ** always returns NULL */ Nrrd * nrrdNuke(Nrrd *nrrd) { if (nrrd) { nrrdEmpty(nrrd); nrrdNix(nrrd); } return NULL; }
/* ******** tenFiberTraceSet ** ** slightly more flexible API for fiber tracking than tenFiberTrace ** ** EITHER: pass a non-NULL nfiber, and NULL, 0, NULL, NULL for ** the following arguments, and things are the same as with tenFiberTrace: ** data inside the nfiber is allocated, and the tract vertices are copied ** into it, having been stored in dynamically allocated airArrays ** ** OR: pass a NULL nfiber, and a buff allocated for 3*(2*halfBuffLen + 1) ** (note the "+ 1" !!!) doubles. The fiber tracking on each half will stop ** at halfBuffLen points. The given seedpoint will be stored in ** buff[0,1,2 + 3*halfBuffLen]. The indices for the end of the first ** tract half, and the end of the second tract half, will be set in ** *startIdxP and *endIdxP respectively. */ int tenFiberTraceSet(tenFiberContext *tfx, Nrrd *nfiber, double *buff, unsigned int halfBuffLen, unsigned int *startIdxP, unsigned int *endIdxP, double seed[3]) { char me[]="tenFiberTraceSet", err[BIFF_STRLEN]; airArray *fptsArr[2]; /* airArrays of backward (0) and forward (1) fiber points */ double *fpts[2]; /* arrays storing forward and backward fiber points */ double tmp[3], iPos[3], currPoint[3], forwDir[3], *fiber; /* array of both forward and backward points, when finished */ int ret, whyStop, buffIdx, fptsIdx, outIdx, oldStop; unsigned int i; airArray *mop; if (!(tfx)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(TEN, err); return 1; } /* HEY: a hack to preserve the state inside tenFiberContext so that we have fewer side effects (tfx->maxNumSteps may still be set) */ oldStop = tfx->stop; if (!nfiber) { if (!( buff && halfBuffLen > 0 && startIdxP && startIdxP )) { sprintf(err, "%s: need either non-NULL nfiber or fpts buffer info", me); biffAdd(TEN, err); return 1; } if (tenFiberStopSet(tfx, tenFiberStopNumSteps, halfBuffLen)) { sprintf(err, "%s: error setting new fiber stop", me); biffAdd(TEN, err); return 1; } } /* initialize the quantities which describe the fiber halves */ tfx->halfLen[0] = tfx->halfLen[1] = 0.0; tfx->numSteps[0] = tfx->numSteps[1] = 0; tfx->whyStop[0] = tfx->whyStop[1] = tenFiberStopUnknown; /* try probing once */ if (tfx->useIndexSpace) { ret = gageProbe(tfx->gtx, AIR_CAST(gage_t, seed[0]), AIR_CAST(gage_t, seed[1]), AIR_CAST(gage_t, seed[2])); } else { gageShapeWtoI(tfx->gtx->shape, tmp, seed); ret = gageProbe(tfx->gtx, AIR_CAST(gage_t, tmp[0]), AIR_CAST(gage_t, tmp[1]), AIR_CAST(gage_t, tmp[2])); } if (ret) { sprintf(err, "%s: first gageProbe failed: %s (%d)", me, tfx->gtx->errStr, tfx->gtx->errNum); biffAdd(TEN, err); return 1; } /* see if we're doomed */ if ((whyStop = _tenFiberStopCheck(tfx))) { /* stopped immediately at seed point, but that's not an error */ tfx->whyNowhere = whyStop; if (nfiber) { nrrdEmpty(nfiber); } else { *startIdxP = *endIdxP = 0; } return 0; } else { /* did not immediately halt */ tfx->whyNowhere = tenFiberStopUnknown; } /* record the principal eigenvector at the seed point, which is needed to align the 4 intermediate steps of RK4 for the FIRST step of each half of the tract */ ELL_3V_COPY(tfx->firstEvec, tfx->evec + 3*0); /* airMop{Error,Okay}() can safely be called on NULL */ mop = nfiber ? airMopNew() : NULL; for (tfx->dir=0; tfx->dir<=1; tfx->dir++) { if (nfiber) { fptsArr[tfx->dir] = airArrayNew((void**)&(fpts[tfx->dir]), NULL, 3*sizeof(double), TEN_FIBER_INCR); airMopAdd(mop, fptsArr[tfx->dir], (airMopper)airArrayNuke, airMopAlways); buffIdx = -1; } else { fptsArr[tfx->dir] = NULL; fpts[tfx->dir] = NULL; buffIdx = halfBuffLen; fptsIdx = -1; } tfx->halfLen[tfx->dir] = 0; if (tfx->useIndexSpace) { ELL_3V_COPY(iPos, seed); gageShapeItoW(tfx->gtx->shape, tfx->wPos, iPos); } else { gageShapeWtoI(tfx->gtx->shape, iPos, seed); ELL_3V_COPY(tfx->wPos, seed); } ELL_3V_SET(tfx->lastDir, 0, 0, 0); tfx->lastDirSet = AIR_FALSE; for (tfx->numSteps[tfx->dir] = 0; AIR_TRUE; tfx->numSteps[tfx->dir]++) { if (_tenFiberProbe(tfx, tfx->wPos)) { /* even if gageProbe had an error OTHER than going out of bounds, we're not going to report it any differently here, alas */ tfx->whyStop[tfx->dir] = tenFiberStopBounds; break; } if ((whyStop = _tenFiberStopCheck(tfx))) { if (tenFiberStopNumSteps == whyStop) { /* we stopped along this direction because tfx->numSteps[tfx->dir] exceeded tfx->maxNumSteps. Okay. But tfx->numSteps[tfx->dir] is supposed to be a record of how steps were (successfully) taken. So we need to decrementing before moving on ... */ tfx->numSteps[tfx->dir]--; } tfx->whyStop[tfx->dir] = whyStop; break; } if (tfx->useIndexSpace) { gageShapeWtoI(tfx->gtx->shape, iPos, tfx->wPos); ELL_3V_COPY(currPoint, iPos); } else { ELL_3V_COPY(currPoint, tfx->wPos); } if (nfiber) { fptsIdx = airArrayLenIncr(fptsArr[tfx->dir], 1); ELL_3V_COPY(fpts[tfx->dir] + 3*fptsIdx, currPoint); } else { ELL_3V_COPY(buff + 3*buffIdx, currPoint); /* fprintf(stderr, "!%s: (dir %d) saving to %d pnt %g %g %g\n", me, tfx->dir, buffIdx, currPoint[0], currPoint[1], currPoint[2]); */ buffIdx += !tfx->dir ? -1 : 1; } /* forwDir is set by this to point to the next fiber point */ if (_tenFiberIntegrate[tfx->intg](tfx, forwDir)) { tfx->whyStop[tfx->dir] = tenFiberStopBounds; break; } ELL_3V_COPY(tfx->lastDir, forwDir); tfx->lastDirSet = AIR_TRUE; ELL_3V_ADD2(tfx->wPos, tfx->wPos, forwDir); tfx->halfLen[tfx->dir] += ELL_3V_LEN(forwDir); } } if (nfiber) { if (nrrdMaybeAlloc_va(nfiber, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, (fptsArr[0]->len + fptsArr[1]->len - 1)))) { sprintf(err, "%s: couldn't allocate fiber nrrd", me); biffMove(TEN, err, NRRD); airMopError(mop); return 1; } fiber = (double*)(nfiber->data); outIdx = 0; for (i=fptsArr[0]->len-1; i>=1; i--) { ELL_3V_COPY(fiber + 3*outIdx, fpts[0] + 3*i); outIdx++; } for (i=0; i<=fptsArr[1]->len-1; i++) { ELL_3V_COPY(fiber + 3*outIdx, fpts[1] + 3*i); outIdx++; } } else { *startIdxP = halfBuffLen - tfx->numSteps[0]; *endIdxP = halfBuffLen + tfx->numSteps[1]; } tfx->stop = oldStop; airMopOkay(mop); return 0; }