GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/ten/fiberMethods.c Lines: 0 423 0.0 %
Date: 2017-05-26 Branches: 0 250 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "ten.h"
25
#include "privateTen.h"
26
27
28
void
29
tenFiberSingleInit(tenFiberSingle *tfbs) {
30
  /* char me[]="tenFiberSingleInit"; */
31
  unsigned idx;
32
33
  ELL_3V_SET(tfbs->seedPos, AIR_NAN, AIR_NAN, AIR_NAN);
34
  tfbs->dirIdx = tfbs->dirNum = 0;
35
  tfbs->nvert = nrrdNew();
36
  tfbs->halfLen[0] = tfbs->halfLen[1] = AIR_NAN;
37
  tfbs->seedIdx = tfbs->stepNum[0] = tfbs->stepNum[1] = 0;
38
  tfbs->whyStop[0] = tfbs->whyStop[1] = tenFiberStopUnknown;
39
  tfbs->whyNowhere = tenFiberStopUnknown; /* actually, the semantics of this
40
                                             field is reversed, so this is not
41
                                             really the way it should be set */
42
  tfbs->nval = nrrdNew();
43
  for (idx=0; idx<=NRRD_MEASURE_MAX; idx++) {
44
    tfbs->measr[idx] = AIR_NAN;
45
  }
46
  return;
47
}
48
49
void
50
tenFiberSingleDone(tenFiberSingle *tfbs) {
51
52
  tfbs->nvert = nrrdNuke(tfbs->nvert);
53
  tfbs->nval = nrrdNuke(tfbs->nval);
54
}
55
56
tenFiberSingle *
57
tenFiberSingleNew() {
58
  tenFiberSingle *ret;
59
60
  ret = AIR_CALLOC(1, tenFiberSingle);
61
  if (ret) {
62
    tenFiberSingleInit(ret);
63
  }
64
  return ret;
65
}
66
67
tenFiberSingle *
68
tenFiberSingleNix(tenFiberSingle *tfbs) {
69
70
  if (tfbs) {
71
    tenFiberSingleDone(tfbs);
72
    airFree(tfbs);
73
  }
74
  return NULL;
75
}
76
77
static
78
tenFiberContext *
79
_tenFiberContextCommonNew(const Nrrd *vol, int useDwi,
80
                          double thresh, double soft, double valueMin,
81
                          int ten1method, int ten2method) {
82
  static const char me[]="_tenFiberContextCommonNew";
83
  tenFiberContext *tfx;
84
  gageKind *kind;
85
  airArray *mop;
86
87
  if (!( tfx = AIR_CALLOC(1, tenFiberContext) )) {
88
    biffAddf(TEN, "%s: couldn't allocate new context", me);
89
    return NULL;
90
  }
91
  mop = airMopNew();
92
  airMopAdd(mop, tfx, airFree, airMopOnError);
93
94
  if (useDwi) {
95
    Nrrd *ngrad=NULL, *nbmat=NULL;
96
    double bval=0;
97
    unsigned int *skip=NULL, skipNum;
98
99
    tfx->useDwi = AIR_TRUE;
100
    /* default fiber type */
101
    tfx->fiberType = tenDwiFiberTypeUnknown;
102
103
    if (tenDWMRIKeyValueParse(&ngrad, &nbmat, &bval, &skip, &skipNum, vol)) {
104
      biffAddf(TEN, "%s: trouble parsing DWI info", me );
105
      airMopError(mop); return NULL;
106
    }
107
    airMopAdd(mop, ngrad, (airMopper)nrrdNuke, airMopOnError);
108
    airMopAdd(mop, nbmat, (airMopper)nrrdNuke, airMopOnError);
109
    airMopAdd(mop, skip, airFree, airMopOnError);
110
    if (skipNum) {
111
      biffAddf(TEN, "%s: sorry, can't do DWI skipping here", me);
112
      airMopError(mop); return NULL;
113
    }
114
    kind = tenDwiGageKindNew();
115
    airMopAdd(mop, kind, (airMopper)tenDwiGageKindNix, airMopOnError);
116
    if (tenDwiGageKindSet(kind,
117
                          thresh, soft, bval, valueMin,
118
                          ngrad, NULL,
119
                          ten1method, ten2method, 42)) {
120
      biffAddf(TEN, "%s: trouble setting DWI kind", me);
121
      airMopError(mop); return NULL;
122
    }
123
  } else {
124
    /* it should be a tensor volume */
125
    tfx->useDwi = AIR_FALSE;
126
    /* default fiber type */
127
    tfx->fiberType = tenFiberTypeUnknown;
128
    if (tenTensorCheck(vol, nrrdTypeUnknown, AIR_TRUE, AIR_TRUE)) {
129
      biffAddf(TEN, "%s: didn't get a tensor volume", me);
130
      airMopError(mop); return NULL;
131
    }
132
    kind = tenGageKind;
133
  }
134
135
  tfx->gtx = gageContextNew();
136
  airMopAdd(mop, tfx->gtx, (airMopper)gageContextNix, airMopOnError);
137
  tfx->pvl = gagePerVolumeNew(tfx->gtx, vol, kind);
138
  airMopAdd(mop, tfx->pvl, (airMopper)gagePerVolumeNix, airMopOnError);
139
  if (!( tfx->gtx && tfx->pvl && !gagePerVolumeAttach(tfx->gtx, tfx->pvl) )) {
140
    biffMovef(TEN, GAGE, "%s: gage trouble", me);
141
    airMopError(mop); return NULL;
142
  }
143
144
  tfx->nin = vol;
145
  tfx->ksp = nrrdKernelSpecNew();
146
  airMopAdd(mop, tfx->ksp, (airMopper)nrrdKernelSpecNix, airMopOnError);
147
  if (nrrdKernelSpecParse(tfx->ksp, tenDefFiberKernel)) {
148
    biffMovef(TEN, NRRD, "%s: couldn't parse tenDefFiberKernel \"%s\"",
149
              me,  tenDefFiberKernel);
150
    airMopError(mop); return NULL;
151
  }
152
  if (tenFiberKernelSet(tfx, tfx->ksp->kernel, tfx->ksp->parm)) {
153
    biffAddf(TEN, "%s: couldn't set default kernel", me);
154
    airMopError(mop); return NULL;
155
  }
156
  tfx->fiberProbeItem = 0; /* unknown for any gageKind */
157
  /* looks to GK like GK says that we must set some stop criterion */
158
  tfx->intg = tenDefFiberIntg;
159
  tfx->anisoStopType = tenDefFiberAnisoStopType;
160
  tfx->anisoSpeedType = tenAnisoUnknown;
161
  tfx->stop = 0;
162
  tfx->anisoThresh = tenDefFiberAnisoThresh;
163
  /* so I'm not using the normal default mechanism, shoot me */
164
  tfx->anisoSpeedFunc[0] = 0;
165
  tfx->anisoSpeedFunc[1] = 0;
166
  tfx->anisoSpeedFunc[2] = 0;
167
  tfx->maxNumSteps = tenDefFiberMaxNumSteps;
168
  tfx->minNumSteps = 0;
169
  tfx->useIndexSpace = tenDefFiberUseIndexSpace;
170
  tfx->verbose = 0;
171
  tfx->stepSize = tenDefFiberStepSize;
172
  tfx->maxHalfLen = tenDefFiberMaxHalfLen;
173
  tfx->minWholeLen = 0.0;
174
  tfx->confThresh = 0.5; /* why do I even bother setting these- they'll
175
                            only get read if the right tenFiberStopSet has
176
                            been called, in which case they'll be set... */
177
  tfx->minRadius = 1;    /* above lament applies here as well */
178
  tfx->minFraction = 0.5; /* and here */
179
  tfx->wPunct = tenDefFiberWPunct;
180
181
  GAGE_QUERY_RESET(tfx->query);
182
  tfx->mframe[0] = vol->measurementFrame[0][0];
183
  tfx->mframe[1] = vol->measurementFrame[1][0];
184
  tfx->mframe[2] = vol->measurementFrame[2][0];
185
  tfx->mframe[3] = vol->measurementFrame[0][1];
186
  tfx->mframe[4] = vol->measurementFrame[1][1];
187
  tfx->mframe[5] = vol->measurementFrame[2][1];
188
  tfx->mframe[6] = vol->measurementFrame[0][2];
189
  tfx->mframe[7] = vol->measurementFrame[1][2];
190
  tfx->mframe[8] = vol->measurementFrame[2][2];
191
  if (ELL_3M_EXISTS(tfx->mframe)) {
192
    tfx->mframeUse = AIR_TRUE;
193
    ELL_3M_TRANSPOSE(tfx->mframeT, tfx->mframe);
194
  } else {
195
    tfx->mframeUse = AIR_FALSE;
196
  }
197
198
  tfx->gageAnisoStop = NULL;
199
  tfx->gageAnisoSpeed = NULL;
200
  tfx->ten2AnisoStop = AIR_NAN;
201
  /* ... don't really see the point of initializing the ten2 stuff here;
202
     its properly done in tenFiberTraceSet() ... */
203
  tfx->radius = AIR_NAN;
204
205
  airMopOkay(mop);
206
  return tfx;
207
}
208
209
tenFiberContext *
210
tenFiberContextDwiNew(const Nrrd *dwivol,
211
                      double thresh, double soft, double valueMin,
212
                      int ten1method, int ten2method) {
213
  static const char me[]="tenFiberContextDwiNew";
214
  tenFiberContext *tfx;
215
216
  if (!( tfx = _tenFiberContextCommonNew(dwivol, AIR_TRUE,
217
                                         thresh, soft, valueMin,
218
                                         ten1method, ten2method) )) {
219
    biffAddf(TEN, "%s: couldn't create new context", me);
220
    return NULL;
221
  }
222
  return tfx;
223
}
224
225
tenFiberContext *
226
tenFiberContextNew(const Nrrd *dtvol) {
227
  static const char me[]="tenFiberContextNew";
228
  tenFiberContext *tfx;
229
230
  if (!( tfx = _tenFiberContextCommonNew(dtvol, AIR_FALSE,
231
                                         AIR_NAN, AIR_NAN, AIR_NAN,
232
                                         tenEstimate1MethodUnknown,
233
                                         tenEstimate2MethodUnknown) )) {
234
    biffAddf(TEN, "%s: couldn't create new context", me);
235
    return NULL;
236
  }
237
238
  return tfx;
239
}
240
241
void
242
tenFiberVerboseSet(tenFiberContext *tfx, int verbose) {
243
244
  if (tfx) {
245
    tfx->verbose = verbose;
246
  }
247
  return;
248
}
249
250
int
251
tenFiberTypeSet(tenFiberContext *tfx, int ftype) {
252
  static const char me[]="tenFiberTypeSet";
253
254
  if (!tfx) {
255
    biffAddf(TEN, "%s: got NULL pointer", me);
256
    return 1;
257
  }
258
  if (tfx->useDwi) {
259
    fprintf(stderr, "!%s(%d)--- hello\n", me, ftype);
260
    switch (ftype) {
261
    case tenDwiFiberType1Evec0:
262
      GAGE_QUERY_ITEM_ON(tfx->query, tenDwiGageTensorLLS);
263
      tfx->gageTen = gageAnswerPointer(tfx->gtx, tfx->pvl,
264
                                       tenDwiGageTensorLLS);
265
      tfx->gageTen2 = NULL;
266
      break;
267
    case tenDwiFiberType2Evec0:
268
      GAGE_QUERY_ITEM_ON(tfx->query, tenDwiGage2TensorPeled);
269
      tfx->gageTen = NULL;
270
      tfx->gageTen2 = gageAnswerPointer(tfx->gtx, tfx->pvl,
271
                                        tenDwiGage2TensorPeled);
272
      break;
273
    case tenDwiFiberType12BlendEvec0:
274
      GAGE_QUERY_ITEM_ON(tfx->query, tenDwiGageTensorLLS);
275
      tfx->gageTen = gageAnswerPointer(tfx->gtx, tfx->pvl,
276
                                       tenDwiGageTensorLLS);
277
      GAGE_QUERY_ITEM_ON(tfx->query, tenDwiGage2TensorPeled);
278
      tfx->gageTen2 = gageAnswerPointer(tfx->gtx, tfx->pvl,
279
                                        tenDwiGage2TensorPeled);
280
      break;
281
    default:
282
      biffAddf(TEN, "%s: unimplemented %s %d", me,
283
              tenDwiFiberType->name, ftype);
284
      return 1;
285
      break;
286
    }
287
    tfx->gageEval = NULL;
288
    tfx->gageEvec = NULL;
289
  } else {
290
    /* working with tensor volume */
291
    switch(ftype) {
292
    case tenFiberTypeEvec0:
293
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec0);
294
      /* HEY: COPY AND PASTE */
295
      tfx->gageEvec
296
        = gageAnswerPointer(tfx->gtx, tfx->pvl,
297
                            (tenFiberTypeEvec0 == tfx->fiberType
298
                             ? tenGageEvec0
299
                             : (tenFiberTypeEvec1 == tfx->fiberType
300
                                ? tenGageEvec1
301
                                : tenGageEvec2)));
302
      break;
303
    case tenFiberTypeEvec1:
304
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec1);
305
      /* HEY: COPY AND PASTE */
306
      tfx->gageEvec
307
        = gageAnswerPointer(tfx->gtx, tfx->pvl,
308
                            (tenFiberTypeEvec0 == tfx->fiberType
309
                             ? tenGageEvec0
310
                             : (tenFiberTypeEvec1 == tfx->fiberType
311
                                ? tenGageEvec1
312
                                : tenGageEvec2)));
313
      break;
314
    case tenFiberTypeEvec2:
315
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec2);
316
      /* HEY: COPY AND PASTE */
317
      tfx->gageEvec
318
        = gageAnswerPointer(tfx->gtx, tfx->pvl,
319
                            (tenFiberTypeEvec0 == ftype
320
                             ? tenGageEvec0
321
                             : (tenFiberTypeEvec1 == ftype
322
                                ? tenGageEvec1
323
                                : tenGageEvec2)));
324
      break;
325
    case tenFiberTypeTensorLine:
326
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageTensor);
327
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEval0);
328
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEval1);
329
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEval2);
330
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec0);
331
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec1);
332
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageEvec2);
333
      tfx->gageEvec = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageEvec0);
334
      tfx->gageTen = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageTensor);
335
      tfx->gageEval = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageEval);
336
      break;
337
    case tenFiberTypePureLine:
338
      GAGE_QUERY_ITEM_ON(tfx->query, tenGageTensor);
339
      break;
340
    case tenFiberTypeZhukov:
341
      biffAddf(TEN, "%s: sorry, Zhukov oriented tensors not implemented", me);
342
      return 1;
343
      break;
344
    default:
345
      biffAddf(TEN, "%s: fiber type %d not recognized", me, ftype);
346
      return 1;
347
      break;
348
    }  /* switch */
349
    if (tenFiberTypeEvec0 == ftype
350
        || tenFiberTypeEvec1 == ftype
351
        || tenFiberTypeEvec2 == ftype
352
        || tenFiberTypeTensorLine == ftype) {
353
      tfx->gageTen = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageTensor);
354
      tfx->gageEval = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageEval0);
355
      tfx->gageEvec
356
        = gageAnswerPointer(tfx->gtx, tfx->pvl,
357
                            (tenFiberTypeEvec0 == ftype
358
                             ? tenGageEvec0
359
                             : (tenFiberTypeEvec1 == ftype
360
                                ? tenGageEvec1
361
                                : (tenFiberTypeEvec2 == ftype
362
                                   ? tenGageEvec2
363
                                   : tenGageEvec))));
364
      tfx->gageTen2 = NULL;
365
    }
366
    tfx->ten2Which = 0;
367
  }
368
  tfx->fiberType = ftype;
369
370
  return 0;
371
}
372
373
/*
374
******** tenFiberStopSet
375
**
376
** how to set stop criteria and their parameters.  a little tricky because
377
** of the use of varargs
378
**
379
** valid calls:
380
** tenFiberStopSet(tfx, tenFiberStopLength, double max)
381
** tenFiberStopSet(tfx, tenFiberStopMinLength, double min)
382
** tenFiberStopSet(tfx, tenFiberStopAniso, int anisoType, double anisoThresh)
383
** tenFiberStopSet(tfx, tenFiberStopNumSteps, unsigned int num)
384
** tenFiberStopSet(tfx, tenFiberStopMinNumSteps, unsigned int num)
385
** tenFiberStopSet(tfx, tenFiberStopConfidence, double conf)
386
** tenFiberStopSet(tfx, tenFiberStopRadius, double radius)
387
** tenFiberStopSet(tfx, tenFiberStopBounds)
388
** tenFiberStopSet(tfx, tenFiberStopFraction, double fraction)
389
** tenFiberStopSet(tfx, tenFiberStopStub)
390
*/
391
int
392
tenFiberStopSet(tenFiberContext *tfx, int stop, ...) {
393
  static const char me[]="tenFiberStopSet";
394
  va_list ap;
395
  int ret=0;
396
  int anisoGage;
397
398
  if (!tfx) {
399
    biffAddf(TEN, "%s: got NULL pointer", me);
400
    return 1;
401
  }
402
  va_start(ap, stop);
403
  switch(stop) {
404
  case tenFiberStopAniso:
405
    tfx->anisoStopType = va_arg(ap, int);
406
    tfx->anisoThresh = va_arg(ap, double);
407
    if (!(AIR_IN_OP(tenAnisoUnknown, tfx->anisoStopType, tenAnisoLast))) {
408
      biffAddf(TEN, "%s: given aniso stop type %d not valid", me,
409
              tfx->anisoStopType);
410
      ret = 1; goto end;
411
    }
412
    if (!(AIR_EXISTS(tfx->anisoThresh))) {
413
      biffAddf(TEN, "%s: given aniso threshold doesn't exist", me);
414
      ret = 1; goto end;
415
    }
416
    if (tfx->useDwi) {
417
      /* the tensor of which we measure anisotropy can come from lots of
418
         places, not just a 1-tensor gage item, so there's no specific
419
         item to turn on here... */
420
      tfx->gageAnisoStop = NULL;
421
    } else { /* using tensors */
422
      switch(tfx->anisoStopType) {
423
      case tenAniso_FA:
424
        anisoGage = tenGageFA;
425
        break;
426
      case tenAniso_Cl1:
427
        anisoGage = tenGageCl1;
428
        break;
429
      case tenAniso_Cp1:
430
        anisoGage = tenGageCp1;
431
        break;
432
      case tenAniso_Ca1:
433
        anisoGage = tenGageCa1;
434
        break;
435
      case tenAniso_Clpmin1:
436
        anisoGage = tenGageClpmin1;
437
        break;
438
      case tenAniso_Cl2:
439
        anisoGage = tenGageCl2;
440
        break;
441
      case tenAniso_Cp2:
442
        anisoGage = tenGageCp2;
443
        break;
444
      case tenAniso_Ca2:
445
        anisoGage = tenGageCa2;
446
        break;
447
      case tenAniso_Clpmin2:
448
        anisoGage = tenGageClpmin2;
449
        break;
450
      default:
451
        biffAddf(TEN, "%s: sorry, currently don't have fast %s computation "
452
                "via gage", me, airEnumStr(tenAniso, tfx->anisoStopType));
453
        ret = 1; goto end;
454
        break;
455
      }
456
      /* NOTE: we are no longer computing ALL anisotropy measures ...
457
         GAGE_QUERY_ITEM_ON(tfx->query, tenGageAniso);
458
      */
459
      GAGE_QUERY_ITEM_ON(tfx->query, anisoGage);
460
      tfx->gageAnisoStop = gageAnswerPointer(tfx->gtx, tfx->pvl, anisoGage);
461
      /*
462
      fprintf(stderr, "!%s: stopping on aniso %s < %g\n", me,
463
              airEnumStr(tenAniso, tfx->anisoStopType), tfx->anisoThresh);
464
      */
465
    }
466
    break;
467
  case tenFiberStopLength:
468
    tfx->maxHalfLen = va_arg(ap, double);
469
    if (!( AIR_EXISTS(tfx->maxHalfLen) && tfx->maxHalfLen > 0.0 )) {
470
      biffAddf(TEN, "%s: given maxHalfLen %g doesn't exist or isn't > 0.0",
471
              me, tfx->maxHalfLen);
472
      ret = 1; goto end;
473
    }
474
    /* no query modifications needed */
475
    break;
476
  case tenFiberStopMinLength:
477
    tfx->minWholeLen = va_arg(ap, double);
478
    if (!( AIR_EXISTS(tfx->minWholeLen) && tfx->minWholeLen >= 0.0 )) {
479
      biffAddf(TEN, "%s: given minWholeLen %g doesn't exist or isn't >= 0.0",
480
              me, tfx->minWholeLen);
481
      ret = 1; goto end;
482
    }
483
    /* no query modifications needed */
484
    break;
485
  case tenFiberStopNumSteps:
486
    tfx->maxNumSteps = va_arg(ap, unsigned int);
487
    if (!( tfx->maxNumSteps > 0 )) {
488
      biffAddf(TEN, "%s: given maxNumSteps isn't > 0.0", me);
489
      ret = 1; goto end;
490
    }
491
    /* no query modifications needed */
492
    break;
493
  case tenFiberStopMinNumSteps:
494
    tfx->minNumSteps = va_arg(ap, unsigned int);
495
    /* no query modifications needed */
496
    break;
497
  case tenFiberStopConfidence:
498
    tfx->confThresh = va_arg(ap, double);
499
    if (!( AIR_EXISTS(tfx->confThresh) )) {
500
      biffAddf(TEN, "%s: given confThresh doesn't exist", me);
501
      ret = 1; goto end;
502
    }
503
    GAGE_QUERY_ITEM_ON(tfx->query, tenGageTensor);
504
    break;
505
  case tenFiberStopRadius:
506
    tfx->minRadius = va_arg(ap, double);
507
    if (!( AIR_EXISTS(tfx->minRadius) )) {
508
      biffAddf(TEN, "%s: given minimum radius doesn't exist", me);
509
      ret = 1; goto end;
510
    }
511
    /* no query modifications needed */
512
    break;
513
  case tenFiberStopBounds:
514
    /* nothing to set; always used as a stop criterion */
515
    break;
516
  case tenFiberStopFraction:
517
    if (!tfx->useDwi) {
518
      biffAddf(TEN, "%s: can only use %s-based termination in DWI tractography",
519
              me, airEnumStr(tenFiberStop, tenFiberStopFraction));
520
      ret = 1; goto end;
521
    }
522
    tfx->minFraction = va_arg(ap, double);
523
    if (!( AIR_EXISTS(tfx->minFraction) )) {
524
      biffAddf(TEN, "%s: given minimum fraction doesn't exist", me);
525
      ret = 1; goto end;
526
    }
527
    /* no query modifications needed */
528
    break;
529
  case tenFiberStopStub:
530
    /* no var-args to grab */
531
    /* no query modifications needed */
532
    break;
533
  default:
534
    biffAddf(TEN, "%s: stop criterion %d not recognized", me, stop);
535
    ret = 1; goto end;
536
  }
537
  tfx->stop = tfx->stop | (1 << stop);
538
 end:
539
  va_end(ap);
540
  return ret;
541
}
542
543
/* to avoid var-args */
544
int
545
tenFiberStopAnisoSet(tenFiberContext *tfx, int anisoType, double anisoThresh) {
546
  static const char me[]="tenFiberStopAnisoSet";
547
548
  if (tenFiberStopSet(tfx, tenFiberStopAniso, anisoType, anisoThresh)) {
549
    biffAddf(TEN, "%s: trouble", me);
550
    return 1;
551
  }
552
  return 0;
553
}
554
555
/* to avoid var-args */
556
int
557
tenFiberStopDoubleSet(tenFiberContext *tfx, int stop, double val) {
558
  static const char me[]="tenFiberStopDoubleSet";
559
560
  switch (stop) {
561
  case tenFiberStopLength:
562
  case tenFiberStopMinLength:
563
  case tenFiberStopConfidence:
564
  case tenFiberStopRadius:
565
  case tenFiberStopFraction:
566
    if (tenFiberStopSet(tfx, stop, val)) {
567
      biffAddf(TEN, "%s: trouble", me);
568
      return 1;
569
    }
570
    break;
571
  default:
572
    biffAddf(TEN, "%s: given stop criterion %d (%s) isn't a double", me,
573
            stop, airEnumStr(tenFiberStop, stop));
574
    return 1;
575
  }
576
  return 0;
577
}
578
579
/* to avoid var-args */
580
int
581
tenFiberStopUIntSet(tenFiberContext *tfx, int stop, unsigned int val) {
582
  static const char me[]="tenFiberStopUIntSet";
583
584
  switch (stop) {
585
  case tenFiberStopNumSteps:
586
  case tenFiberStopMinNumSteps:
587
    if (tenFiberStopSet(tfx, stop, val)) {
588
      biffAddf(TEN, "%s: trouble", me);
589
      return 1;
590
    }
591
    break;
592
  default:
593
    biffAddf(TEN, "%s: given stop criterion %d (%s) isn't an unsigned int", me,
594
            stop, airEnumStr(tenFiberStop, stop));
595
    return 1;
596
  }
597
  return 0;
598
}
599
600
void
601
tenFiberStopOn(tenFiberContext *tfx, int stop) {
602
603
  if (tfx && !airEnumValCheck(tenFiberStop, stop)) {
604
    tfx->stop = tfx->stop | (1 << stop);
605
  }
606
  return;
607
}
608
609
void
610
tenFiberStopOff(tenFiberContext *tfx, int stop) {
611
612
  if (tfx && !airEnumValCheck(tenFiberStop, stop)) {
613
    tfx->stop = tfx->stop & ~(1 << stop);
614
  }
615
  return;
616
}
617
618
void
619
tenFiberStopReset(tenFiberContext *tfx) {
620
621
  if (tfx) {
622
    tfx->stop = 0;
623
  }
624
  return;
625
}
626
627
int
628
tenFiberAnisoSpeedSet(tenFiberContext *tfx, int aniso,
629
                      double lerp, double thresh, double soft) {
630
  static const char me[]="tenFiberAnisoSpeedSet";
631
  int anisoGage;
632
633
  if (!tfx) {
634
    biffAddf(TEN, "%s: got NULL pointer", me);
635
    return 1;
636
  }
637
638
  if (tfx->useDwi) {
639
    fprintf(stderr, "!%s: sorry, can't yet work on DWIs; bye.\n", me);
640
    exit(1);
641
  }
642
643
  if (airEnumValCheck(tenAniso, aniso)) {
644
    biffAddf(TEN, "%s: aniso %d not valid", me, aniso);
645
    return 1;
646
  }
647
  switch(aniso) {
648
  case tenAniso_FA:
649
    anisoGage = tenGageFA;
650
    break;
651
  case tenAniso_Cl1:
652
    anisoGage = tenGageCl1;
653
    break;
654
  case tenAniso_Cp1:
655
    anisoGage = tenGageCp1;
656
    break;
657
  case tenAniso_Ca1:
658
    anisoGage = tenGageCa1;
659
    break;
660
  case tenAniso_Cl2:
661
    anisoGage = tenGageCl2;
662
    break;
663
  case tenAniso_Cp2:
664
    anisoGage = tenGageCp2;
665
    break;
666
  case tenAniso_Ca2:
667
    anisoGage = tenGageCa2;
668
    break;
669
  default:
670
    biffAddf(TEN, "%s: sorry, currently don't have fast %s computation "
671
            "via gage", me, airEnumStr(tenAniso, tfx->anisoStopType));
672
    return 1;
673
    break;
674
  }
675
  tfx->anisoSpeedType = aniso;
676
  if (tfx->useDwi) {
677
    /* actually, finding anisotropy in the context of 2-tensor
678
       tracking is not currently done by gage */
679
  } else {
680
    GAGE_QUERY_ITEM_ON(tfx->query, anisoGage);
681
    tfx->gageAnisoSpeed = gageAnswerPointer(tfx->gtx, tfx->pvl, anisoGage);
682
  }
683
  tfx->anisoSpeedFunc[0] = lerp;
684
  tfx->anisoSpeedFunc[1] = thresh;
685
  tfx->anisoSpeedFunc[2] = soft;
686
687
  return 0;
688
}
689
690
int
691
tenFiberAnisoSpeedReset(tenFiberContext *tfx) {
692
  static const char me[]="tenFiberAnisoSpeedReset";
693
694
  if (!tfx) {
695
    biffAddf(TEN, "%s: got NULL pointer", me);
696
    return 1;
697
  }
698
  tfx->anisoSpeedType = tenAnisoUnknown;
699
  /* HEY: GAGE_QUERY_ITEM_OFF something? */
700
  /* HEY: for both tensor and DWI */
701
  tfx->gageAnisoSpeed = NULL;
702
  return 0;
703
}
704
705
int
706
tenFiberKernelSet(tenFiberContext *tfx,
707
                  const NrrdKernel *kern,
708
                  const double parm[NRRD_KERNEL_PARMS_NUM]) {
709
  static const char me[]="tenFiberKernelSet";
710
711
  if (!(tfx && kern)) {
712
    biffAddf(TEN, "%s: got NULL pointer", me);
713
    return 1;
714
  }
715
  nrrdKernelSpecSet(tfx->ksp, kern, parm);
716
  if (gageKernelSet(tfx->gtx, gageKernel00,
717
                    tfx->ksp->kernel, tfx->ksp->parm)) {
718
    biffMovef(TEN, GAGE, "%s: problem setting kernel", me);
719
    return 1;
720
  }
721
722
  return 0;
723
}
724
725
int
726
tenFiberProbeItemSet(tenFiberContext *tfx, int item) {
727
  static const char me[]="tenFiberProbeItemSet";
728
729
  if (!tfx) {
730
    biffAddf(TEN, "%s: got NULL pointer", me);
731
    return 1;
732
  }
733
  tfx->fiberProbeItem = item;
734
  return 0;
735
}
736
737
int
738
tenFiberIntgSet(tenFiberContext *tfx, int intg) {
739
  static const char me[]="tenFiberIntTypeSet";
740
741
  if (!(tfx)) {
742
    biffAddf(TEN, "%s: got NULL pointer", me);
743
    return 1;
744
  }
745
  if (!( AIR_IN_OP(tenFiberIntgUnknown, intg, tenFiberIntgLast) )) {
746
    biffAddf(TEN, "%s: got invalid integration type %d", me, intg);
747
    return 1;
748
  }
749
  tfx->intg = intg;
750
751
  return 0;
752
}
753
754
int
755
tenFiberParmSet(tenFiberContext *tfx, int parm, double val) {
756
  static const char me[]="tenFiberParmSet";
757
758
  if (tfx) {
759
    switch(parm) {
760
    case tenFiberParmStepSize:
761
      tfx->stepSize = val;
762
      break;
763
    case tenFiberParmUseIndexSpace:
764
      tfx->useIndexSpace = !!val;
765
      break;
766
    case tenFiberParmWPunct:
767
      tfx->wPunct = val;
768
      break;
769
    case tenFiberParmVerbose:
770
      tfx->verbose = AIR_CAST(int, val);
771
      break;
772
    default:
773
      fprintf(stderr, "%s: WARNING!!! tenFiberParm %d not handled\n",
774
              me, parm);
775
      break;
776
    }
777
  }
778
  return 0;
779
}
780
781
int
782
tenFiberUpdate(tenFiberContext *tfx) {
783
  static const char me[]="tenFiberUpdate";
784
785
  if (!tfx) {
786
    biffAddf(TEN, "%s: got NULL pointer", me);
787
    return 1;
788
  }
789
  if (tenFiberTypeUnknown == tfx->fiberType) {
790
    biffAddf(TEN, "%s: fiber type not set", me);
791
    return 1;
792
  }
793
  if (!( AIR_IN_OP(tenFiberTypeUnknown, tfx->fiberType, tenFiberTypeLast) )) {
794
    biffAddf(TEN, "%s: tfx->fiberType set to bogus value (%d)", me,
795
            tfx->fiberType);
796
    return 1;
797
  }
798
  if (tenFiberIntgUnknown == tfx->intg) {
799
    biffAddf(TEN, "%s: integration type not set", me);
800
    return 1;
801
  }
802
  if (!( AIR_IN_OP(tenFiberIntgUnknown, tfx->intg, tenFiberIntgLast) )) {
803
    biffAddf(TEN, "%s: tfx->intg set to bogus value (%d)", me, tfx->intg);
804
    return 1;
805
  }
806
  if (0 == tfx->stop) {
807
    biffAddf(TEN, "%s: no fiber stopping criteria set", me);
808
    return 1;
809
  }
810
  /* HEY there should be a better place for setting this */
811
  if (tfx->fiberProbeItem) {
812
    GAGE_QUERY_ITEM_ON(tfx->query, tfx->fiberProbeItem);
813
  }
814
  if (gageQuerySet(tfx->gtx, tfx->pvl, tfx->query)
815
      || gageUpdate(tfx->gtx)) {
816
    biffMovef(TEN, GAGE, "%s: trouble with gage", me);
817
    return 1;
818
  }
819
  if (tfx->useDwi) {
820
    if (!(0 == tfx->ten2Which || 1 == tfx->ten2Which)) {
821
      biffAddf(TEN, "%s: ten2Which must be 0 or 1 (not %u)",
822
               me, tfx->ten2Which);
823
      return 1;
824
    }
825
  }
826
  return 0;
827
}
828
829
/*
830
** exact same precautions about utility of this as with gageContextCopy!!!
831
** So: only after tenFiberUpdate, and don't touch anything, and don't
832
** call anything except tenFiberTrace and tenFiberContextNix
833
*/
834
tenFiberContext *
835
tenFiberContextCopy(tenFiberContext *oldTfx) {
836
  static const char me[]="tenFiberContextCopy";
837
  tenFiberContext *tfx;
838
839
  if (oldTfx->useDwi) {
840
    fprintf(stderr, "!%s: sorry, can't copy DWI contexts; bye.\n", me);
841
    exit(1);
842
  }
843
  tfx = AIR_CALLOC(1, tenFiberContext);
844
  memcpy(tfx, oldTfx, sizeof(tenFiberContext));
845
  tfx->ksp = nrrdKernelSpecCopy(oldTfx->ksp);
846
  tfx->gtx = gageContextCopy(oldTfx->gtx);
847
  tfx->pvl = tfx->gtx->pvl[0];  /* HEY! gage API sucks */
848
  tfx->gageTen = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageTensor);
849
  tfx->gageEval = gageAnswerPointer(tfx->gtx, tfx->pvl, tenGageEval0);
850
  /* HEY: COPY AND PASTE */
851
  tfx->gageEvec
852
    = gageAnswerPointer(tfx->gtx, tfx->pvl,
853
                        (tenFiberTypeEvec0 == tfx->fiberType
854
                         ? tenGageEvec0
855
                         : (tenFiberTypeEvec1 == tfx->fiberType
856
                            ? tenGageEvec1
857
                            : tenGageEvec2)));
858
  tfx->gageAnisoStop = gageAnswerPointer(tfx->gtx, tfx->pvl,
859
                                         tfx->anisoStopType);
860
  tfx->gageAnisoSpeed = (tfx->anisoSpeedType
861
                         ? gageAnswerPointer(tfx->gtx, tfx->pvl,
862
                                             tfx->anisoSpeedType)
863
                         : NULL);
864
  return tfx;
865
}
866
867
tenFiberContext *
868
tenFiberContextNix(tenFiberContext *tfx) {
869
870
  if (tfx) {
871
    tfx->ksp = nrrdKernelSpecNix(tfx->ksp);
872
    tfx->gtx = gageContextNix(tfx->gtx);
873
    free(tfx);
874
  }
875
  return NULL;
876
}