GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/ten/aniso.c Lines: 43 526 8.2 %
Date: 2017-05-26 Branches: 14 252 5.6 %

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
** learned: don't take sqrt(FLT_EPSILON) and expect it to still be
29
** negligible
30
*/
31
32
/*
33
******** !!!! NOTE NOTE NOTE NOTE NOTE !!!!
34
********
35
******** THIS CODE IS NOT REALLY MEANT TO BE EDITED BY HUMANS
36
******** (only GLK :)
37
********
38
******** It is the worst possible example of the dangers of cut-and-paste
39
********
40
******** !!!! NOTE NOTE NOTE NOTE NOTE !!!!
41
*/
42
float  _tenAnisoEval_Conf_f(const float  eval[3]) {
43
  AIR_UNUSED(eval);
44
  return 1.0;
45
}
46
double _tenAnisoEval_Conf_d(const double eval[3]) {
47
  AIR_UNUSED(eval);
48
  return 1.0;  return 1.0;
49
}
50
float  _tenAnisoTen_Conf_f(const float  ten[7]) {
51
  return ten[0];
52
}
53
double _tenAnisoTen_Conf_d(const double ten[7]) {
54
  return ten[0];
55
}
56
57
58
float  _tenAnisoEval_Cl1_f(const float  eval[3]) {
59
  float sum = eval[0] + eval[1] + eval[2];
60
  sum = AIR_MAX(0, sum);
61
  return sum ? (eval[0] - eval[1])/sum : 0.0f;
62
}
63
double _tenAnisoEval_Cl1_d(const double eval[3]) {
64
  double sum = eval[0] + eval[1] + eval[2];
65
  sum = AIR_MAX(0, sum);
66
  return sum ? (eval[0] - eval[1])/sum : 0.0;
67
}
68
float  _tenAnisoTen_Cl1_f(const float  ten[7]) {
69
  float eval[3];
70
  tenEigensolve_f(eval, NULL, ten);
71
  return _tenAnisoEval_Cl1_f(eval);
72
}
73
double _tenAnisoTen_Cl1_d(const double ten[7]) {
74
  double eval[3];
75
  tenEigensolve_d(eval, NULL, ten);
76
  return _tenAnisoEval_Cl1_d(eval);
77
}
78
79
80
float  _tenAnisoEval_Cp1_f(const float  eval[3]) {
81
  float sum = eval[0] + eval[1] + eval[2];
82
  sum = AIR_MAX(0, sum);
83
  return sum ? 2*(eval[1] - eval[2])/sum : 0.0f;
84
}
85
double _tenAnisoEval_Cp1_d(const double eval[3]) {
86
  double sum = eval[0] + eval[1] + eval[2];
87
  sum = AIR_MAX(0, sum);
88
  return sum ? 2*(eval[1] - eval[2])/sum : 0.0;
89
}
90
float  _tenAnisoTen_Cp1_f(const float  ten[7]) {
91
  float eval[3];
92
  tenEigensolve_f(eval, NULL, ten);
93
  return _tenAnisoEval_Cp1_f(eval);
94
}
95
double _tenAnisoTen_Cp1_d(const double ten[7]) {
96
  double eval[3];
97
  tenEigensolve_d(eval, NULL, ten);
98
  return _tenAnisoEval_Cp1_d(eval);
99
}
100
101
102
float  _tenAnisoEval_Ca1_f(const float  eval[3]) {
103
  float sum = eval[0] + eval[1] + eval[2];
104
  sum = AIR_MAX(0, sum);
105
  return sum ? (eval[0] + eval[1] - 2*eval[2])/sum : 0.0f;
106
}
107
double _tenAnisoEval_Ca1_d(const double eval[3]) {
108
  double sum = eval[0] + eval[1] + eval[2];
109
  sum = AIR_MAX(0, sum);
110
  return sum ? (eval[0] + eval[1] - 2*eval[2])/sum : 0.0;
111
}
112
float  _tenAnisoTen_Ca1_f(const float  ten[7]) {
113
  float eval[3];
114
  tenEigensolve_f(eval, NULL, ten);
115
  return _tenAnisoEval_Ca1_f(eval);
116
}
117
double _tenAnisoTen_Ca1_d(const double ten[7]) {
118
  double eval[3];
119
  tenEigensolve_d(eval, NULL, ten);
120
  return _tenAnisoEval_Ca1_d(eval);
121
}
122
123
124
float  _tenAnisoEval_Clpmin1_f(const float  eval[3]) {
125
  float cl, cp, sum = eval[0] + eval[1] + eval[2];
126
  sum = AIR_MAX(0, sum);
127
  cl = sum ? (eval[0] - eval[1])/sum : 0.0f;
128
  cp = sum ? 2*(eval[1] - eval[2])/sum : 0.0f;
129
  return AIR_MIN(cl, cp);
130
}
131
double _tenAnisoEval_Clpmin1_d(const double eval[3]) {
132
  double cl, cp, sum = eval[0] + eval[1] + eval[2];
133
  sum = AIR_MAX(0, sum);
134
  cl = sum ? (eval[0] - eval[1])/sum : 0.0;
135
  cp = sum ? 2*(eval[1] - eval[2])/sum : 0.0;
136
  return AIR_MIN(cl, cp);
137
}
138
float  _tenAnisoTen_Clpmin1_f(const float  ten[7]) {
139
  float eval[3];
140
  tenEigensolve_f(eval, NULL, ten);
141
  return _tenAnisoEval_Clpmin1_f(eval);
142
}
143
double _tenAnisoTen_Clpmin1_d(const double ten[7]) {
144
  double eval[3];
145
  tenEigensolve_d(eval, NULL, ten);
146
  return _tenAnisoEval_Clpmin1_d(eval);
147
}
148
149
150
float  _tenAnisoEval_Cs1_f(const float  eval[3]) {
151
  float sum = eval[0] + eval[1] + eval[2];
152
  sum = AIR_MAX(0, sum);
153
  return sum ? 3*eval[2]/sum : 0.0f;
154
}
155
double _tenAnisoEval_Cs1_d(const double eval[3]) {
156
  double sum = eval[0] + eval[1] + eval[2];
157
  sum = AIR_MAX(0, sum);
158
  return sum ? 3*eval[2]/sum : 0.0;
159
}
160
float  _tenAnisoTen_Cs1_f(const float  ten[7]) {
161
  float eval[3];
162
  tenEigensolve_f(eval, NULL, ten);
163
  return _tenAnisoEval_Cs1_f(eval);
164
}
165
double _tenAnisoTen_Cs1_d(const double ten[7]) {
166
  double eval[3];
167
  tenEigensolve_d(eval, NULL, ten);
168
  return _tenAnisoEval_Cs1_d(eval);
169
}
170
171
172
float  _tenAnisoEval_Ct1_f(const float  _eval[3]) {
173
  float dem, mn, eval[3];
174
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
175
  ELL_3V_SET(eval, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
176
  dem = eval[0] + eval[1] - 2*eval[2];
177
  return dem ? 2*(eval[1] - eval[2])/dem : 0.0f;
178
}
179
double _tenAnisoEval_Ct1_d(const double _eval[3]) {
180
  double dem, mn, eval[3];
181
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
182
  ELL_3V_SET(eval, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
183
  dem = eval[0] + eval[1] - 2*eval[2];
184
  return dem ? 2*(eval[1] - eval[2])/dem : 0.0;
185
}
186
float  _tenAnisoTen_Ct1_f(const float  ten[7]) {
187
  float eval[3];
188
  tenEigensolve_f(eval, NULL, ten);
189
  return _tenAnisoEval_Ct1_f(eval);
190
}
191
double _tenAnisoTen_Ct1_d(const double ten[7]) {
192
  double eval[3];
193
  tenEigensolve_d(eval, NULL, ten);
194
  return _tenAnisoEval_Ct1_d(eval);
195
}
196
197
198
float  _tenAnisoEval_Cl2_f(const float  eval[3]) {
199
  float eval0 = AIR_MAX(0, eval[0]);
200
  return eval0 ? (eval[0] - eval[1])/eval0 : 0.0f;
201
}
202
double _tenAnisoEval_Cl2_d(const double eval[3]) {
203
  double eval0 = AIR_MAX(0, eval[0]);
204
  return eval0 ? (eval[0] - eval[1])/eval0 : 0.0;
205
}
206
float  _tenAnisoTen_Cl2_f(const float  ten[7]) {
207
  float eval[3];
208
  tenEigensolve_f(eval, NULL, ten);
209
  return _tenAnisoEval_Cl2_f(eval);
210
}
211
double _tenAnisoTen_Cl2_d(const double ten[7]) {
212
  double eval[3];
213
  tenEigensolve_d(eval, NULL, ten);
214
  return _tenAnisoEval_Cl2_d(eval);
215
}
216
217
218
float  _tenAnisoEval_Cp2_f(const float  eval[3]) {
219
  float eval0 = AIR_MAX(0, eval[0]);
220
  return eval0 ? (eval[1] - eval[2])/eval0 : 0.0f;
221
}
222
double _tenAnisoEval_Cp2_d(const double eval[3]) {
223
  double eval0 = AIR_MAX(0, eval[0]);
224
  return eval0 ? (eval[1] - eval[2])/eval0 : 0.0;
225
}
226
float  _tenAnisoTen_Cp2_f(const float  ten[7]) {
227
  float eval[3];
228
  tenEigensolve_f(eval, NULL, ten);
229
  return _tenAnisoEval_Cp2_f(eval);
230
}
231
double _tenAnisoTen_Cp2_d(const double ten[7]) {
232
  double eval[3];
233
  tenEigensolve_d(eval, NULL, ten);
234
  return _tenAnisoEval_Cp2_d(eval);
235
}
236
237
238
float  _tenAnisoEval_Ca2_f(const float  eval[3]) {
239
  float eval0 = AIR_MAX(0, eval[0]);
240
  return eval0 ? (eval[0] - eval[2])/eval0 : 0.0f;
241
}
242
double _tenAnisoEval_Ca2_d(const double eval[3]) {
243
  double eval0 = AIR_MAX(0, eval[0]);
244
  return eval0 ? (eval[0] - eval[2])/eval0 : 0.0;
245
}
246
float  _tenAnisoTen_Ca2_f(const float  ten[7]) {
247
  float eval[3];
248
  tenEigensolve_f(eval, NULL, ten);
249
  return _tenAnisoEval_Ca2_f(eval);
250
}
251
double _tenAnisoTen_Ca2_d(const double ten[7]) {
252
  double eval[3];
253
  tenEigensolve_d(eval, NULL, ten);
254
  return _tenAnisoEval_Ca2_d(eval);
255
}
256
257
258
float  _tenAnisoEval_Clpmin2_f(const float  eval[3]) {
259
  float cl, cp, eval0 = AIR_MAX(0, eval[0]);
260
  cl = eval0 ? (eval[0] - eval[1])/eval0 : 0.0f;
261
  cp = eval0 ? (eval[1] - eval[2])/eval0 : 0.0f;
262
  return AIR_MIN(cl, cp);
263
}
264
double _tenAnisoEval_Clpmin2_d(const double eval[3]) {
265
  double cl, cp, eval0 = AIR_MAX(0, eval[0]);
266
  cl = eval0 ? (eval[0] - eval[1])/eval0 : 0.0;
267
  cp = eval0 ? (eval[1] - eval[2])/eval0 : 0.0;
268
  return AIR_MIN(cl, cp);
269
}
270
float  _tenAnisoTen_Clpmin2_f(const float  ten[7]) {
271
  float eval[3];
272
  tenEigensolve_f(eval, NULL, ten);
273
  return _tenAnisoEval_Clpmin2_f(eval);
274
}
275
double _tenAnisoTen_Clpmin2_d(const double ten[7]) {
276
  double eval[3];
277
  tenEigensolve_d(eval, NULL, ten);
278
  return _tenAnisoEval_Clpmin2_d(eval);
279
}
280
281
282
float  _tenAnisoEval_Cs2_f(const float  eval[3]) {
283
  float eval0 = AIR_MAX(0, eval[0]);
284
  return eval0 ? eval[2]/eval0 : 0.0f;
285
}
286
double _tenAnisoEval_Cs2_d(const double eval[3]) {
287
  double eval0 = AIR_MAX(0, eval[0]);
288
  return eval0 ? eval[2]/eval0 : 0.0;
289
}
290
float  _tenAnisoTen_Cs2_f(const float  ten[7]) {
291
  float eval[3];
292
  tenEigensolve_f(eval, NULL, ten);
293
  return _tenAnisoEval_Cs2_f(eval);
294
}
295
double _tenAnisoTen_Cs2_d(const double ten[7]) {
296
  double eval[3];
297
  tenEigensolve_d(eval, NULL, ten);
298
  return _tenAnisoEval_Cs2_d(eval);
299
}
300
301
302
float  _tenAnisoEval_Ct2_f(const float  eval[3]) {
303
  float denom;
304
  denom = eval[0] - eval[2];
305
  return denom ? (eval[1] - eval[2])/denom : 0.0f;
306
}
307
double _tenAnisoEval_Ct2_d(const double eval[3]) {
308
  double denom;
309
  denom = eval[0] - eval[2];
310
  return denom ? (eval[1] - eval[2])/denom : 0.0;
311
}
312
float  _tenAnisoTen_Ct2_f(const float  ten[7]) {
313
  float eval[3];
314
  tenEigensolve_f(eval, NULL, ten);
315
  return _tenAnisoEval_Ct2_f(eval);
316
}
317
double _tenAnisoTen_Ct2_d(const double ten[7]) {
318
  double eval[3];
319
  tenEigensolve_d(eval, NULL, ten);
320
  return _tenAnisoEval_Ct2_d(eval);
321
}
322
323
324
#define SQRT6 2.44948974278317809819
325
float  _tenAnisoEval_RA_f(const float  eval[3]) {
326
  float mean, stdv;
327
  mean = (eval[0] + eval[1] + eval[2])/3;
328
  stdv = AIR_CAST(float,
329
                  sqrt((mean-eval[0])*(mean-eval[0])   /* not exactly stdv */
330
                       + (mean-eval[1])*(mean-eval[1])
331
                       + (mean-eval[2])*(mean-eval[2])));
332
  return mean ? AIR_CAST(float, stdv/(mean*SQRT6)) : 0.0f;
333
}
334
double _tenAnisoEval_RA_d(const double eval[3]) {
335
  double mean, stdv;
336
  mean = (eval[0] + eval[1] + eval[2])/3;
337
  stdv = sqrt((mean-eval[0])*(mean-eval[0])   /* not exactly standard dev */
338
              + (mean-eval[1])*(mean-eval[1])
339
              + (mean-eval[2])*(mean-eval[2]));
340
  return mean ? stdv/(mean*SQRT6) : 0.0;
341
}
342
float  _tenAnisoTen_RA_f(const float  tt[7]) {
343
  float mn, stdv, dev[7];
344
  mn = TEN_T_TRACE(tt)/3;
345
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
346
  stdv = AIR_CAST(float, sqrt(TEN_T_DOT(dev, dev)));
347
  return mn ? AIR_CAST(float, stdv/(mn*SQRT6)) : 0.0f;
348
}
349
double _tenAnisoTen_RA_d(const double tt[7]) {
350
  double mn, stdv, dev[7];
351
  mn = TEN_T_TRACE(tt)/3;
352
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
353
  stdv = sqrt(TEN_T_DOT(dev, dev));
354
  return mn ? stdv/(mn*SQRT6) : 0.0;
355
}
356
357
358
float  _tenAnisoEval_FA_f(const float  eval[3]) {
359
  float denom, mean, stdv;
360
  denom = 2.0f*(eval[0]*eval[0] + eval[1]*eval[1] + eval[2]*eval[2]);
361
  mean = (eval[0] + eval[1] + eval[2])/3;
362
  stdv = AIR_CAST(float,
363
                  (mean-eval[0])*(mean-eval[0]) /* not exactly stdv */
364
                  + (mean-eval[1])*(mean-eval[1])
365
                  + (mean-eval[2])*(mean-eval[2]));
366
  return denom ? AIR_CAST(float, sqrt(3.0*stdv/denom)) : 0.0f;
367
}
368
double _tenAnisoEval_FA_d(const double eval[3]) {
369
  double denom, mean, stdv;
370
  denom = 2.0*(eval[0]*eval[0] + eval[1]*eval[1] + eval[2]*eval[2]);
371
  mean = (eval[0] + eval[1] + eval[2])/3;
372
  stdv = ((mean-eval[0])*(mean-eval[0])   /* not exactly standard dev */
373
          + (mean-eval[1])*(mean-eval[1])
374
          + (mean-eval[2])*(mean-eval[2]));
375
  return denom ? sqrt(3.0*stdv/denom) : 0.0;
376
}
377
float  _tenAnisoTen_FA_f(const float  tt[7]) {
378
  float denom, mn, stdv, dev[7];
379
  denom = AIR_CAST(float, 2.0*TEN_T_DOT(tt, tt));
380
  mn = TEN_T_TRACE(tt)/3;
381
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
382
  stdv = TEN_T_DOT(dev, dev);
383
  return denom ? AIR_CAST(float, sqrt(3.0*stdv/denom)) : 0.0f;
384
}
385
double _tenAnisoTen_FA_d(const double tt[7]) {
386
  double denom, mn, stdv, dev[7];
387
  denom = 2.0*TEN_T_DOT(tt, tt);
388
  mn = TEN_T_TRACE(tt)/3;
389
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
390
  stdv = TEN_T_DOT(dev, dev);
391
  return denom ? AIR_CAST(float, sqrt(3.0*stdv/denom)) : 0.0;
392
}
393
394
395
float  _tenAnisoEval_VF_f(const float  eval[3]) {
396
  float mean;
397
  mean = (eval[0] + eval[1] + eval[2])/3.0f;
398
  mean = mean*mean*mean;
399
  return 1.0f - (mean ? eval[0]*eval[1]*eval[2]/mean : 0.0f);
400
}
401
double _tenAnisoEval_VF_d(const double eval[3]) {
402
  double mean;
403
  mean = (eval[0] + eval[1] + eval[2])/3;
404
  mean = mean*mean*mean;
405
  return 1.0 - (mean ? eval[0]*eval[1]*eval[2]/mean : 0.0);
406
}
407
float  _tenAnisoTen_VF_f(const float  ten[7]) {
408
  float mean;
409
  mean = TEN_T_TRACE(ten)/3.0f;
410
  mean = mean*mean*mean;
411
  return 1.0f - (mean ? TEN_T_DET(ten)/mean : 0.0f);
412
}
413
double _tenAnisoTen_VF_d(const double ten[7]) {
414
  double mean;
415
  mean = TEN_T_TRACE(ten)/3.0;
416
  mean = mean*mean*mean;
417
  return 1.0 - (mean ? TEN_T_DET(ten)/mean : 0.0);
418
}
419
420
421
float  _tenAnisoEval_B_f(const float  eval[3]) {
422
  return eval[0]*eval[1] + eval[0]*eval[2] + eval[1]*eval[2];
423
}
424
double _tenAnisoEval_B_d(const double eval[3]) {
425
  return eval[0]*eval[1] + eval[0]*eval[2] + eval[1]*eval[2];
426
}
427
float  _tenAnisoTen_B_f(const float  ten[7]) {
428
  return (ten[1]*ten[4] + ten[1]*ten[6] + ten[4]*ten[6]
429
          - ten[2]*ten[2] - ten[3]*ten[3] - ten[5]*ten[5]);
430
}
431
double _tenAnisoTen_B_d(const double ten[7]) {
432
  return (ten[1]*ten[4] + ten[1]*ten[6] + ten[4]*ten[6]
433
          - ten[2]*ten[2] - ten[3]*ten[3] - ten[5]*ten[5]);
434
}
435
436
437
float  _tenAnisoEval_Q_f(const float  eval[3]) {
438
  float A, B;
439
  A = -(eval[0] + eval[1] + eval[2]);
440
  B = _tenAnisoEval_B_f(eval);
441
  A = (A*A - 3.0f*B)/9.0f;
442
  return AIR_MAX(0, A);
443
}
444
double _tenAnisoEval_Q_d(const double eval[3]) {
445
  double A, B;
446
  A = -(eval[0] + eval[1] + eval[2]);
447
  B = _tenAnisoEval_B_d(eval);
448
  A = (A*A - 3.0*B)/9.0;
449
  return AIR_MAX(0, A);
450
}
451
float  _tenAnisoTen_Q_f(const float  ten[7]) {
452
  float A, B;
453
  A = -TEN_T_TRACE(ten);
454
  B = _tenAnisoTen_B_f(ten);
455
  A = (A*A - 3.0f*B)/9.0f;
456
  return AIR_MAX(0, A);
457
}
458
double _tenAnisoTen_Q_d(const double ten[7]) {
459
  double A, B;
460
  A = -TEN_T_TRACE(ten);
461
  B = _tenAnisoTen_B_d(ten);
462
  A = (A*A - 3.0*B)/9.0;
463
  return AIR_MAX(0, A);
464
}
465
466
467
float  _tenAnisoEval_R_f(const float  eval[3]) {
468
  float A, B, C;
469
  A = -(eval[0] + eval[1] + eval[2]);
470
  B = _tenAnisoEval_B_f(eval);
471
  C = -eval[0]*eval[1]*eval[2];
472
  return (-2*A*A*A + 9*A*B - 27*C)/54;
473
}
474
double _tenAnisoEval_R_d(const double eval[3]) {
475
  double A, B, C;
476
  A = -(eval[0] + eval[1] + eval[2]);
477
  B = _tenAnisoEval_B_d(eval);
478
  C = -eval[0]*eval[1]*eval[2];
479
  return (-2*A*A*A + 9*A*B - 27*C)/54;
480
}
481
float  _tenAnisoTen_R_f(const float  ten[7]) {
482
  float A, B, C;
483
  A = -TEN_T_TRACE(ten);
484
  B = _tenAnisoTen_B_f(ten);
485
  C = -TEN_T_DET(ten);
486
  return (-2*A*A*A + 9*A*B - 27*C)/54;
487
}
488
double _tenAnisoTen_R_d(const double ten[7]) {
489
  double A, B, C;
490
  A = -TEN_T_TRACE(ten);
491
  B = _tenAnisoTen_B_d(ten);
492
  C = -TEN_T_DET(ten);
493
  return (-2*A*A*A + 9*A*B - 27*C)/54;
494
}
495
496
497
float  _tenAnisoEval_S_f(const float  eval[3]) {
498
  return eval[0]*eval[0] + eval[1]*eval[1] + eval[2]*eval[2];
499
}
500
double _tenAnisoEval_S_d(const double eval[3]) {
501
  return eval[0]*eval[0] + eval[1]*eval[1] + eval[2]*eval[2];
502
}
503
float  _tenAnisoTen_S_f(const float  ten[7]) {
504
1556640
  return TEN_T_DOT(ten, ten);
505
}
506
double _tenAnisoTen_S_d(const double ten[7]) {
507
  return TEN_T_DOT(ten, ten);
508
}
509
510
#define OOSQRT2 0.70710678118654752440
511
float  _tenAnisoEval_Skew_f(const float  _eval[3]) {
512
  float Q, num, dnm, ret, mn, eval[3];
513
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
514
  ELL_3V_SET(eval, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
515
  Q = _tenAnisoEval_Q_f(eval);
516
  num = _tenAnisoEval_R_f(eval);
517
  dnm = AIR_CAST(float, Q*sqrt(2*Q));
518
  ret = dnm ? AIR_CAST(float, num/dnm) : 0.0f;
519
  return AIR_CAST(float, AIR_CLAMP(-OOSQRT2, ret, OOSQRT2));
520
}
521
double _tenAnisoEval_Skew_d(const double _eval[3]) {
522
  double Q, num, dnm, ret, mn, eval[3];
523
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
524
  ELL_3V_SET(eval, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
525
  Q = _tenAnisoEval_Q_d(eval);
526
  num = _tenAnisoEval_R_d(eval);
527
  dnm = Q*sqrt(2*Q);
528
  ret = dnm ? num/dnm : 0.0;
529
  return AIR_CLAMP(-OOSQRT2, ret, OOSQRT2);
530
}
531
float  _tenAnisoTen_Skew_f(const float  _t[7]) {
532
  float Q, num, dnm, ret, mn, ten[7];
533
  mn = TEN_T_TRACE(_t)/3;
534
  TEN_T_SET(ten, _t[0], _t[1]-mn, _t[2], _t[3], _t[4]-mn, _t[5], _t[6]-mn);
535
  Q = _tenAnisoTen_Q_f(ten);
536
  num = _tenAnisoTen_R_f(ten);
537
  dnm = AIR_CAST(float, Q*sqrt(2*Q));
538
  ret = dnm ? AIR_CAST(float, num/dnm) : 0.0f;
539
  return AIR_CAST(float, AIR_CLAMP(-OOSQRT2, ret, OOSQRT2));
540
}
541
double _tenAnisoTen_Skew_d(const double _t[7]) {
542
  double Q, num, dnm, ret, mn, ten[7];
543
  mn = TEN_T_TRACE(_t)/3;
544
  TEN_T_SET(ten, _t[0], _t[1]-mn, _t[2], _t[3], _t[4]-mn, _t[5], _t[6]-mn);
545
  Q = _tenAnisoTen_Q_d(ten);
546
  num = _tenAnisoTen_R_d(ten);
547
  dnm = Q*sqrt(2*Q);
548
  ret = dnm ? num/dnm : 0.0;
549
  return AIR_CLAMP(-OOSQRT2, ret, OOSQRT2);
550
}
551
552
553
float  _tenAnisoEval_Mode_f(const float  _eval[3]) {
554
  float n, d, mn, e[3], ret;
555
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
556
  ELL_3V_SET(e, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
557
  n = (e[0] + e[1] - 2*e[2])*(2*e[0] - e[1] - e[2])*(e[0] - 2*e[1] + e[2]);
558
  d = (e[0]*e[0] + e[1]*e[1] + e[2]*e[2]
559
       - e[0]*e[1] - e[1]*e[2] - e[0]*e[2]);
560
  d = AIR_CAST(float, sqrt(AIR_MAX(0, d)));
561
  d = 2*d*d*d;
562
  ret = d ? AIR_CAST(float, n/d) : 0.0f;
563
  return AIR_CLAMP(-1, ret, 1);
564
}
565
double _tenAnisoEval_Mode_d(const double _eval[3]) {
566
  double n, d, mn, e[3], ret;
567
  mn = (_eval[0] + _eval[1] + _eval[2])/3;
568
  ELL_3V_SET(e, _eval[0] - mn, _eval[1] - mn, _eval[2] - mn);
569
  n = (e[0] + e[1] - 2*e[2])*(2*e[0] - e[1] - e[2])*(e[0] - 2*e[1] + e[2]);
570
  d = (e[0]*e[0] + e[1]*e[1] + e[2]*e[2]
571
       - e[0]*e[1] - e[1]*e[2] - e[0]*e[2]);
572
  d = sqrt(AIR_MAX(0, d));
573
  d = 2*d*d*d;
574
  ret = d ? n/d : 0.0;
575
  return AIR_CLAMP(-1, ret, 1);
576
}
577
float  _tenAnisoTen_Mode_f(const float  tt[7]) {
578
  float mn, dev[7], tmp, ret;
579
  mn = TEN_T_TRACE(tt)/3.0f;
580
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
581
  tmp = AIR_CAST(float, TEN_T_NORM(dev));
582
  tmp = tmp ? 1.0f/tmp : 0.0f;
583
  TEN_T_SCALE(dev, tmp, dev);
584
  ret = AIR_CAST(float, 3*SQRT6*TEN_T_DET(dev));
585
  return AIR_CLAMP(-1, ret, 1);
586
}
587
double _tenAnisoTen_Mode_d(const double tt[7]) {
588
  double mn, dev[7], tmp, ret;
589
  mn = TEN_T_TRACE(tt)/3.0;
590
  TEN_T_SET(dev, tt[0], tt[1]-mn, tt[2], tt[3], tt[4]-mn, tt[5], tt[6]-mn);
591
  tmp = TEN_T_NORM(dev);
592
  tmp = tmp ? 1.0/tmp : 0.0;
593
  TEN_T_SCALE(dev, tmp, dev);
594
  ret = 3*SQRT6*TEN_T_DET(dev);
595
  return AIR_CLAMP(-1, ret, 1);
596
}
597
598
/* NOTE: yes, the AIR_CLAMPs here are needed even though
599
** the _Skew_ functions clamp their output
600
*/
601
#define SQRT2 1.41421356237309504880
602
float  _tenAnisoEval_Th_f(const float  eval[3]) {
603
  float tmp;
604
  tmp = AIR_CAST(float, SQRT2*_tenAnisoEval_Skew_f(eval));
605
  return AIR_CAST(float, acos(AIR_CLAMP(-1, tmp, 1))/3);
606
}
607
double _tenAnisoEval_Th_d(const double eval[3]) {
608
  double tmp;
609
  tmp = SQRT2*_tenAnisoEval_Skew_d(eval);
610
  return acos(AIR_CLAMP(-1, tmp, 1))/3;
611
}
612
float  _tenAnisoTen_Th_f(const float  ten[7]) {
613
  float tmp;
614
  tmp = AIR_CAST(float, SQRT2*_tenAnisoTen_Skew_f(ten));
615
  return AIR_CAST(float, acos(AIR_CLAMP(-1, tmp, 1))/3);
616
}
617
double _tenAnisoTen_Th_d(const double ten[7]) {
618
  double tmp;
619
  tmp = SQRT2*_tenAnisoTen_Skew_d(ten);
620
  return acos(AIR_CLAMP(-1, tmp, 1))/3;
621
}
622
623
624
float  _tenAnisoEval_Omega_f(const float  eval[3]) {
625
  return _tenAnisoEval_FA_f(eval)*(1.0f+_tenAnisoEval_Mode_f(eval))/2.0f;
626
}
627
double _tenAnisoEval_Omega_d(const double eval[3]) {
628
  return _tenAnisoEval_FA_d(eval)*(1.0f+_tenAnisoEval_Mode_d(eval))/2.0f;
629
}
630
float  _tenAnisoTen_Omega_f(const float  ten[7]) {
631
  return _tenAnisoTen_FA_f(ten)*(1.0f+_tenAnisoTen_Mode_f(ten))/2.0f;
632
}
633
double _tenAnisoTen_Omega_d(const double ten[7]) {
634
  return _tenAnisoTen_FA_d(ten)*(1.0f+_tenAnisoTen_Mode_d(ten))/2.0f;
635
}
636
637
638
float  _tenAnisoEval_Det_f(const float  eval[3]) {
639
  return eval[0]*eval[1]*eval[2];
640
}
641
double _tenAnisoEval_Det_d(const double eval[3]) {
642
  return eval[0]*eval[1]*eval[2];
643
}
644
float  _tenAnisoTen_Det_f(const float  ten[7]) {
645
  return TEN_T_DET(ten);
646
}
647
double _tenAnisoTen_Det_d(const double ten[7]) {
648
  return TEN_T_DET(ten);
649
}
650
651
652
float  _tenAnisoEval_Tr_f(const float  eval[3]) {
653
  return eval[0] + eval[1] + eval[2];
654
}
655
double _tenAnisoEval_Tr_d(const double eval[3]) {
656
  return eval[0] + eval[1] + eval[2];
657
}
658
float  _tenAnisoTen_Tr_f(const float  ten[7]) {
659
  return TEN_T_TRACE(ten);
660
}
661
double _tenAnisoTen_Tr_d(const double ten[7]) {
662
  return TEN_T_TRACE(ten);
663
}
664
665
666
float  _tenAnisoEval_eval0_f(const float  eval[3]) { return eval[0]; }
667
double _tenAnisoEval_eval0_d(const double eval[3]) { return eval[0]; }
668
float  _tenAnisoTen_eval0_f(const float  ten[7]) {
669
  float eval[3];
670
  tenEigensolve_f(eval, NULL, ten);
671
  return eval[0];
672
}
673
double _tenAnisoTen_eval0_d(const double ten[7]) {
674
  double eval[3];
675
  tenEigensolve_d(eval, NULL, ten);
676
  return eval[0];
677
}
678
679
float  _tenAnisoEval_eval1_f(const float  eval[3]) { return eval[1]; }
680
double _tenAnisoEval_eval1_d(const double eval[3]) { return eval[1]; }
681
float  _tenAnisoTen_eval1_f(const float  ten[7]) {
682
  float eval[3];
683
  tenEigensolve_f(eval, NULL, ten);
684
  return eval[1];
685
}
686
double _tenAnisoTen_eval1_d(const double ten[7]) {
687
  double eval[3];
688
  tenEigensolve_d(eval, NULL, ten);
689
  return eval[1];
690
}
691
692
693
float  _tenAnisoEval_eval2_f(const float  eval[3]) { return eval[2]; }
694
double _tenAnisoEval_eval2_d(const double eval[3]) { return eval[2]; }
695
float  _tenAnisoTen_eval2_f(const float  ten[7]) {
696
  float eval[3];
697
  tenEigensolve_f(eval, NULL, ten);
698
  return eval[2];
699
}
700
double _tenAnisoTen_eval2_d(const double ten[7]) {
701
  double eval[3];
702
  tenEigensolve_d(eval, NULL, ten);
703
  return eval[2];
704
}
705
706
707
float  (*_tenAnisoEval_f[TEN_ANISO_MAX+1])(const float  eval[3]) = {
708
  NULL,
709
  _tenAnisoEval_Conf_f,
710
  _tenAnisoEval_Cl1_f,
711
  _tenAnisoEval_Cp1_f,
712
  _tenAnisoEval_Ca1_f,
713
  _tenAnisoEval_Clpmin1_f,
714
  _tenAnisoEval_Cs1_f,
715
  _tenAnisoEval_Ct1_f,
716
  _tenAnisoEval_Cl2_f,
717
  _tenAnisoEval_Cp2_f,
718
  _tenAnisoEval_Ca2_f,
719
  _tenAnisoEval_Clpmin2_f,
720
  _tenAnisoEval_Cs2_f,
721
  _tenAnisoEval_Ct2_f,
722
  _tenAnisoEval_RA_f,
723
  _tenAnisoEval_FA_f,
724
  _tenAnisoEval_VF_f,
725
  _tenAnisoEval_B_f,
726
  _tenAnisoEval_Q_f,
727
  _tenAnisoEval_R_f,
728
  _tenAnisoEval_S_f,
729
  _tenAnisoEval_Skew_f,
730
  _tenAnisoEval_Mode_f,
731
  _tenAnisoEval_Th_f,
732
  _tenAnisoEval_Omega_f,
733
  _tenAnisoEval_Det_f,
734
  _tenAnisoEval_Tr_f,
735
  _tenAnisoEval_eval0_f,
736
  _tenAnisoEval_eval1_f,
737
  _tenAnisoEval_eval2_f
738
};
739
740
double (*_tenAnisoEval_d[TEN_ANISO_MAX+1])(const double eval[3]) = {
741
  NULL,
742
  _tenAnisoEval_Conf_d,
743
  _tenAnisoEval_Cl1_d,
744
  _tenAnisoEval_Cp1_d,
745
  _tenAnisoEval_Ca1_d,
746
  _tenAnisoEval_Clpmin1_d,
747
  _tenAnisoEval_Cs1_d,
748
  _tenAnisoEval_Ct1_d,
749
  _tenAnisoEval_Cl2_d,
750
  _tenAnisoEval_Cp2_d,
751
  _tenAnisoEval_Ca2_d,
752
  _tenAnisoEval_Clpmin2_d,
753
  _tenAnisoEval_Cs2_d,
754
  _tenAnisoEval_Ct2_d,
755
  _tenAnisoEval_RA_d,
756
  _tenAnisoEval_FA_d,
757
  _tenAnisoEval_VF_d,
758
  _tenAnisoEval_B_d,
759
  _tenAnisoEval_Q_d,
760
  _tenAnisoEval_R_d,
761
  _tenAnisoEval_S_d,
762
  _tenAnisoEval_Skew_d,
763
  _tenAnisoEval_Mode_d,
764
  _tenAnisoEval_Th_d,
765
  _tenAnisoEval_Omega_d,
766
  _tenAnisoEval_Det_d,
767
  _tenAnisoEval_Tr_d,
768
  _tenAnisoEval_eval0_d,
769
  _tenAnisoEval_eval1_d,
770
  _tenAnisoEval_eval2_d
771
};
772
773
float  (*_tenAnisoTen_f[TEN_ANISO_MAX+1])(const float  ten[7]) = {
774
  NULL,
775
  _tenAnisoTen_Conf_f,
776
  _tenAnisoTen_Cl1_f,
777
  _tenAnisoTen_Cp1_f,
778
  _tenAnisoTen_Ca1_f,
779
  _tenAnisoTen_Clpmin1_f,
780
  _tenAnisoTen_Cs1_f,
781
  _tenAnisoTen_Ct1_f,
782
  _tenAnisoTen_Cl2_f,
783
  _tenAnisoTen_Cp2_f,
784
  _tenAnisoTen_Ca2_f,
785
  _tenAnisoTen_Clpmin2_f,
786
  _tenAnisoTen_Cs2_f,
787
  _tenAnisoTen_Ct2_f,
788
  _tenAnisoTen_RA_f,
789
  _tenAnisoTen_FA_f,
790
  _tenAnisoTen_VF_f,
791
  _tenAnisoTen_B_f,
792
  _tenAnisoTen_Q_f,
793
  _tenAnisoTen_R_f,
794
  _tenAnisoTen_S_f,
795
  _tenAnisoTen_Skew_f,
796
  _tenAnisoTen_Mode_f,
797
  _tenAnisoTen_Th_f,
798
  _tenAnisoTen_Omega_f,
799
  _tenAnisoTen_Det_f,
800
  _tenAnisoTen_Tr_f,
801
  _tenAnisoTen_eval0_f,
802
  _tenAnisoTen_eval1_f,
803
  _tenAnisoTen_eval2_f
804
};
805
806
double (*_tenAnisoTen_d[TEN_ANISO_MAX+1])(const double ten[7]) = {
807
  NULL,
808
  _tenAnisoTen_Conf_d,
809
  _tenAnisoTen_Cl1_d,
810
  _tenAnisoTen_Cp1_d,
811
  _tenAnisoTen_Ca1_d,
812
  _tenAnisoTen_Clpmin1_d,
813
  _tenAnisoTen_Cs1_d,
814
  _tenAnisoTen_Ct1_d,
815
  _tenAnisoTen_Cl2_d,
816
  _tenAnisoTen_Cp2_d,
817
  _tenAnisoTen_Ca2_d,
818
  _tenAnisoTen_Clpmin2_d,
819
  _tenAnisoTen_Cs2_d,
820
  _tenAnisoTen_Ct2_d,
821
  _tenAnisoTen_RA_d,
822
  _tenAnisoTen_FA_d,
823
  _tenAnisoTen_VF_d,
824
  _tenAnisoTen_B_d,
825
  _tenAnisoTen_Q_d,
826
  _tenAnisoTen_R_d,
827
  _tenAnisoTen_S_d,
828
  _tenAnisoTen_Skew_d,
829
  _tenAnisoTen_Mode_d,
830
  _tenAnisoTen_Th_d,
831
  _tenAnisoTen_Omega_d,
832
  _tenAnisoTen_Det_d,
833
  _tenAnisoTen_Tr_d,
834
  _tenAnisoTen_eval0_d,
835
  _tenAnisoTen_eval1_d,
836
  _tenAnisoTen_eval2_d
837
};
838
839
float
840
tenAnisoEval_f(const float  eval[3], int aniso) {
841
842
  return (AIR_IN_OP(tenAnisoUnknown, aniso, tenAnisoLast)
843
          ? _tenAnisoEval_f[aniso](eval)
844
          : 0);
845
}
846
847
double
848
tenAnisoEval_d(const double eval[3], int aniso) {
849
850
  return (AIR_IN_OP(tenAnisoUnknown, aniso, tenAnisoLast)
851
          ? _tenAnisoEval_d[aniso](eval)
852
          : 0);
853
}
854
855
float
856
tenAnisoTen_f(const float  ten[7], int aniso) {
857
858
3113280
  return (AIR_IN_OP(tenAnisoUnknown, aniso, tenAnisoLast)
859
778320
          ? _tenAnisoTen_f[aniso](ten)
860
          : 0);
861
}
862
863
double
864
tenAnisoTen_d(const double ten[7], int aniso) {
865
866
  return (AIR_IN_OP(tenAnisoUnknown, aniso, tenAnisoLast)
867
          ? _tenAnisoTen_d[aniso](ten)
868
          : 0);
869
}
870
871
#if 0
872
/*
873
******** tenAnisoCalc_f
874
**
875
** !!! THIS FUNCTION HAS BEEN MADE OBSOLETE BY THE NEW
876
** !!! tenAnisoEval_{f,d} AND tenAnisoTen_{f,d} FUNCTIONS
877
** !!! THIS WILL LIKELY BE REMOVED FROM FUTURE RELEASES
878
**
879
** Because this function does not subtract out the eigenvalue mean
880
** when computing quantities like Skew and Mode, it has really lousy
881
** accuracy on those measures compared to tenAnisoEval_{f,d}.
882
**
883
** given an array of three SORTED (descending) eigenvalues "e",
884
** calculates the anisotropy coefficients of Westin et al.,
885
** as well as various others.
886
**
887
** NOTE: with time, so many metrics have ended up here that under
888
** no cases should this be used in any kind of time-critical operations
889
**
890
** This does NOT use biff.
891
*/
892
void
893
tenAnisoCalc_f(float c[TEN_ANISO_MAX+1], const float e[3]) {
894
  float e0, e1, e2, stdv, mean, sum, cl, cp, ca, ra, fa, vf, denom;
895
  float A, B, C, R, Q, N, D;
896
897
  if (!( e[0] >= e[1] && e[1] >= e[2] )) {
898
    fprintf(stderr, "tenAnisoCalc_f: eigen values not sorted: "
899
            "%g %g %g (%d %d)\n",
900
            e[0], e[1], e[2], e[0] >= e[1], e[1] >= e[2]);
901
  }
902
  if ((tenVerbose > 1) && !( e[0] >= 0 && e[1] >= 0 && e[2] >= 0 )) {
903
    fprintf(stderr, "tenAnisoCalc_f: eigen values not all >= 0: %g %g %g\n",
904
            e[0], e[1], e[2]);
905
  }
906
  e0 = AIR_MAX(e[0], 0);
907
  e1 = AIR_MAX(e[1], 0);
908
  e2 = AIR_MAX(e[2], 0);
909
  sum = e0 + e1 + e2;
910
911
  /* first version of cl, cp, cs */
912
  cl = sum ? (e0 - e1)/sum : 0.0f;
913
  c[tenAniso_Cl1] = cl;
914
  cp = sum ? 2*(e1 - e2)/sum : 0.0f;
915
  c[tenAniso_Cp1] = cp;
916
  ca = cl + cp;
917
  c[tenAniso_Ca1] = ca;
918
  c[tenAniso_Clpmin1] = AIR_MIN(cl, cp);
919
  /* extra logic here for equality with expressions above */
920
  c[tenAniso_Cs1] = sum ? 1 - ca : 0.0f;
921
  c[tenAniso_Ct1] = ca ? cp/ca : 0;
922
  /* second version of cl, cp, cs */
923
  cl = e0 ? (e0 - e1)/e0 : 0.0f;
924
  c[tenAniso_Cl2] = cl;
925
  cp = e0 ? (e1 - e2)/e0 : 0.0f;
926
  c[tenAniso_Cp2] = cp;
927
  ca = cl + cp;
928
  c[tenAniso_Ca2] = ca;
929
  c[tenAniso_Clpmin2] = AIR_MIN(cl, cp);
930
  /* extra logic here for equality with expressions above */
931
  c[tenAniso_Cs2] = e0 ? 1 - ca : 0.0f;
932
  c[tenAniso_Ct2] = ca ? cp/ca : 0.0f;
933
  /* non-westin anisos */
934
  mean = sum/3.0f;
935
  stdv = AIR_CAST(float,
936
                  sqrt((mean-e0)*(mean-e0) /* okay, not exactly standard dev */
937
                       + (mean-e1)*(mean-e1)
938
                       + (mean-e2)*(mean-e2)));
939
  ra = mean ? AIR_CAST(float, stdv/(mean*SQRT6)) : 0.0f;
940
  ra = AIR_CLAMP(0.0f, ra, 1.0f);
941
  c[tenAniso_RA] = ra;
942
  denom = 2.0f*(e0*e0 + e1*e1 + e2*e2);
943
  if (denom) {
944
    fa = AIR_CAST(float, stdv*sqrt(3.0/denom));
945
    fa = AIR_CLAMP(0.0f, fa, 1.0f);
946
  } else {
947
    fa = 0.0f;
948
  }
949
  c[tenAniso_FA] = fa;
950
  vf = 1 - (mean ? e0*e1*e2/(mean*mean*mean) : 0.0f);
951
  vf = AIR_CLAMP(0.0f, vf, 1.0f);
952
  c[tenAniso_VF] = vf;
953
954
  A = (-e0 - e1 - e2);
955
  B = c[tenAniso_B] = e0*e1 + e0*e2 + e1*e2;
956
  C = -e0*e1*e2;
957
  Q = c[tenAniso_Q] = (A*A - 3*B)/9;
958
  R = c[tenAniso_R] = (-2*A*A*A + 9*A*B - 27*C)/54;
959
  c[tenAniso_S] = e0*e0 + e1*e1 + e2*e2;
960
  c[tenAniso_Skew] = Q ? AIR_CAST(float, R/(Q*sqrt(2*Q))) : 0.0f;
961
  c[tenAniso_Skew] = AIR_CLAMP(-OOSQRT2, c[tenAniso_Skew], OOSQRT2);
962
  N = (e0 + e1 - 2*e2)*(2*e0 - e1 - e2)*(e0 - 2*e1 + e2);
963
  D = AIR_CAST(float, sqrt(e0*e0+e1*e1+e2*e2 - e0*e1-e1*e2-e0*e2));
964
  c[tenAniso_Mode] = D ? N/(2*D*D*D) : 0.0f;
965
  c[tenAniso_Mode] = AIR_CLAMP(-1, c[tenAniso_Mode], 1);
966
  c[tenAniso_Th] =
967
    AIR_CAST(float, acos(AIR_CLAMP(-1, sqrt(2)*c[tenAniso_Skew], 1))/3);
968
  c[tenAniso_Omega] = c[tenAniso_FA]*(1+c[tenAniso_Mode])/2;
969
  c[tenAniso_Det] = e0*e1*e2;
970
  c[tenAniso_Tr] = e0 + e1 + e2;
971
  c[tenAniso_eval0] = e0;
972
  c[tenAniso_eval1] = e1;
973
  c[tenAniso_eval2] = e2;
974
  return;
975
}
976
#endif
977
978
int
979
tenAnisoPlot(Nrrd *nout, int aniso, unsigned int res,
980
             int hflip, int whole, int nanout) {
981
  static const char me[]="tenAnisoMap";
982
  float *out, tmp;
983
  unsigned int x, y;
984
  float m0[3], m1[3], m2[3], c0, c1, c2, e[3];
985
  float S = 1/3.0f, L = 1.0f, P = 1/2.0f;  /* these make Westin's original
986
                                              (cl,cp,cs) align with the
987
                                              barycentric coordinates */
988
989
  if (airEnumValCheck(tenAniso, aniso)) {
990
    biffAddf(TEN, "%s: invalid aniso (%d)", me, aniso);
991
    return 1;
992
  }
993
  if (!(res > 2)) {
994
    biffAddf(TEN, "%s: resolution (%d) invalid", me, res);
995
    return 1;
996
  }
997
  if (nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 2,
998
                        AIR_CAST(size_t, res), AIR_CAST(size_t, res))) {
999
    biffMovef(TEN, NRRD, "%s: ", me);
1000
    return 1;
1001
  }
1002
  out = (float *)nout->data;
1003
  if (whole) {
1004
    ELL_3V_SET(m0, 1, 0, 0);
1005
    ELL_3V_SET(m1, 0, 1, 0);
1006
    ELL_3V_SET(m2, 0, 0, 1);
1007
  } else {
1008
    ELL_3V_SET(m0, S, S, S);
1009
    if (hflip) {
1010
      ELL_3V_SET(m1, P, P, 0);
1011
      ELL_3V_SET(m2, L, 0, 0);
1012
    } else {
1013
      ELL_3V_SET(m1, L, 0, 0);
1014
      ELL_3V_SET(m2, P, P, 0);
1015
    }
1016
  }
1017
  for (y=0; y<res; y++) {
1018
    for (x=0; x<=y; x++) {
1019
      /* (c0,c1,c2) are the barycentric coordinates */
1020
      c0 = AIR_CAST(float, 1.0 - AIR_AFFINE(-0.5, y, res-0.5, 0.0, 1.0));
1021
      c2 = AIR_CAST(float, AIR_AFFINE(-0.5, x, res-0.5, 0.0, 1.0));
1022
      c1 = 1 - c0 - c2;
1023
      e[0] = c0*m0[0] + c1*m1[0] + c2*m2[0];
1024
      e[1] = c0*m0[1] + c1*m1[1] + c2*m2[1];
1025
      e[2] = c0*m0[2] + c1*m1[2] + c2*m2[2];
1026
      ELL_SORT3(e[0], e[1], e[2], tmp); /* got some warnings w/out this */
1027
      out[x + res*y] = tenAnisoEval_f(e, aniso);
1028
    }
1029
    if (nanout) {
1030
      for (x=y+1; x<res; x++) {
1031
        out[x + res*y] = AIR_NAN;
1032
      }
1033
    }
1034
  }
1035
1036
  return 0;
1037
}
1038
1039
int
1040
tenAnisoVolume(Nrrd *nout, const Nrrd *nin, int aniso, double confThresh) {
1041
  static const char me[]="tenAnisoVolume";
1042
  size_t N, I;
1043
  float *out, *in, *tensor;
1044
16
  int map[NRRD_DIM_MAX];
1045
8
  size_t sx, sy, sz, size[3];
1046
1047
8
  if (tenTensorCheck(nin, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) {
1048
    biffAddf(TEN, "%s: didn't get a tensor nrrd", me);
1049
    return 1;
1050
  }
1051
8
  if (airEnumValCheck(tenAniso, aniso)) {
1052
    biffAddf(TEN, "%s: invalid aniso (%d)", me, aniso);
1053
    return 1;
1054
  }
1055
24
  confThresh = AIR_CLAMP(0.0, confThresh, 1.0);
1056
1057
8
  size[0] = sx = nin->axis[1].size;
1058
8
  size[1] = sy = nin->axis[2].size;
1059
8
  size[2] = sz = nin->axis[3].size;
1060
8
  N = sx*sy*sz;
1061
8
  if (nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 3, sx, sy, sz)) {
1062
    biffMovef(TEN, NRRD, "%s: trouble", me);
1063
    return 1;
1064
  }
1065
8
  out = (float *)nout->data;
1066
8
  in = (float *)nin->data;
1067
1556656
  for (I=0; I<=N-1; I++) {
1068
    /* tenVerbose = (I == 911327); */
1069
778320
    tensor = in + I*7;
1070

1556640
    if (tenAniso_Conf != aniso && tensor[0] < confThresh) {
1071
      out[I] = 0.0;
1072
      continue;
1073
    }
1074
    /* no longer used
1075
    tenEigensolve_f(eval, NULL, tensor);
1076
    if (!(AIR_EXISTS(eval[0]) && AIR_EXISTS(eval[1]) && AIR_EXISTS(eval[2]))) {
1077
      NRRD_COORD_GEN(coord, size, 3, I);
1078
      biffAddf(TEN, "%s: not all eigenvalues exist (%g,%g,%g) at sample "
1079
               "%d = (%d,%d,%d)",
1080
               me, eval[0], eval[1], eval[2], (int)I,
1081
               (int)coord[0], (int)coord[1], (int)coord[2]);
1082
      return 1;
1083
    }
1084
    */
1085
778320
    out[I] = tenAnisoTen_f(tensor, aniso);
1086
778320
    if (!AIR_EXISTS(out[I])) {
1087
      size_t coord[3];
1088
      NRRD_COORD_GEN(coord, size, 3, I);
1089
      biffAddf(TEN, "%s: generated non-existent aniso %g from tensor "
1090
               "(%g) %g %g %g   %g %g   %g at sample %u = (%u,%u,%u)", me,
1091
               out[I],
1092
               tensor[0], tensor[1], tensor[2], tensor[3],
1093
               tensor[4], tensor[5], tensor[6],
1094
               AIR_CAST(unsigned int, I),
1095
               AIR_CAST(unsigned int, coord[0]),
1096
               AIR_CAST(unsigned int, coord[1]),
1097
               AIR_CAST(unsigned int, coord[2]));
1098
      return 1;
1099
    }
1100
  }
1101
8
  ELL_3V_SET(map, 1, 2, 3);
1102
8
  if (nrrdAxisInfoCopy(nout, nin, map, NRRD_AXIS_INFO_SIZE_BIT)) {
1103
    biffMovef(TEN, NRRD, "%s: trouble", me);
1104
    return 1;
1105
  }
1106
8
  if (nrrdBasicInfoCopy(nout, nin,
1107
                        NRRD_BASIC_INFO_ALL ^ NRRD_BASIC_INFO_SPACE)) {
1108
    biffAddf(NRRD, "%s:", me);
1109
    return 1;
1110
  }
1111
1112
8
  return 0;
1113
8
}
1114
1115
int
1116
tenAnisoHistogram(Nrrd *nout, const Nrrd *nin, const Nrrd *nwght,
1117
                  int right, int version, unsigned int res) {
1118
  static const char me[]="tenAnisoHistogram";
1119
  size_t N, I;
1120
  int csIdx, clIdx, cpIdx;
1121
  float *tdata, *out, eval[3],
1122
    cs, cl, cp, (*wlup)(const void *data, size_t idx), weight;
1123
  unsigned int yres, xi, yi;
1124
1125
  if (tenTensorCheck(nin, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) {
1126
    biffAddf(TEN, "%s: didn't get a tensor nrrd", me);
1127
    return 1;
1128
  }
1129
  if (nwght) {
1130
    if (nrrdCheck(nwght)) {
1131
      biffMovef(TEN, NRRD, "%s: trouble with weighting nrrd", me);
1132
      return 1;
1133
    }
1134
    if (nrrdElementNumber(nwght)
1135
        != nrrdElementNumber(nin)/nrrdKindSize(nrrdKind3DMaskedSymMatrix) ) {
1136
      char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
1137
      size_t numten;
1138
      numten = nrrdElementNumber(nin)/nrrdKindSize(nrrdKind3DMaskedSymMatrix);
1139
      biffAddf(TEN, "%s: # elements in weight nrrd (%s) != # tensors (%s)", me,
1140
               airSprintSize_t(stmp1, nrrdElementNumber(nwght)),
1141
               airSprintSize_t(stmp2, numten));
1142
      return 1;
1143
    }
1144
  }
1145
  if (!( 1 == version || 2 == version )) {
1146
    biffAddf(TEN, "%s: version (%d) wasn't 1 or 2", me, version);
1147
    return 1;
1148
  }
1149
  if (!(res > 10)) {
1150
    biffAddf(TEN, "%s: resolution (%d) invalid", me, res);
1151
    return 1;
1152
  }
1153
  if (right) {
1154
    yres = AIR_CAST(unsigned int, AIR_CAST(double, res)/sqrt(3));
1155
  } else {
1156
    yres = res;
1157
  }
1158
  if (nwght) {
1159
    wlup = nrrdFLookup[nwght->type];
1160
  } else {
1161
    wlup = NULL;
1162
  }
1163
  if (nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 2,
1164
                        AIR_CAST(size_t, res), AIR_CAST(size_t, yres))) {
1165
    biffMovef(TEN, NRRD, "%s: ", me);
1166
    return 1;
1167
  }
1168
  out = (float *)nout->data;
1169
  tdata = (float *)nin->data;
1170
  if (right || 1 == version) {
1171
    clIdx = tenAniso_Cl1;
1172
    cpIdx = tenAniso_Cp1;
1173
    csIdx = tenAniso_Cs1;
1174
  } else {
1175
    clIdx = tenAniso_Cl2;
1176
    cpIdx = tenAniso_Cp2;
1177
    csIdx = tenAniso_Cs2;
1178
  }
1179
  N = nrrdElementNumber(nin)/nrrdKindSize(nrrdKind3DMaskedSymMatrix);
1180
  for (I=0; I<N; I++) {
1181
    tenEigensolve_f(eval, NULL, tdata);
1182
    cl = tenAnisoEval_f(eval, clIdx);
1183
    cp = tenAnisoEval_f(eval, cpIdx);
1184
    cs = tenAnisoEval_f(eval, csIdx);
1185
    if (right) {
1186
      xi = AIR_CAST(unsigned int, cs*0 + cl*(res-1) + cp*0);
1187
      yi = AIR_CAST(unsigned int, cs*0 + cl*(yres-1) + cp*(yres-1));
1188
    } else {
1189
      xi = AIR_CAST(unsigned int, cs*0 + cl*0 + cp*(res-1));
1190
      yi = AIR_CAST(unsigned int, cs*0 + cl*(res-1) + cp*(res-1));
1191
    }
1192
    weight = wlup ? wlup(nwght->data, I) : 1.0f;
1193
    if (xi < res && yi < yres-1) {
1194
      out[xi + res*yi] += tdata[0]*weight;
1195
    }
1196
    tdata += nrrdKindSize(nrrdKind3DMaskedSymMatrix);
1197
  }
1198
1199
  return 0;
1200
}
1201
1202
tenEvecRGBParm *
1203
tenEvecRGBParmNew() {
1204
  tenEvecRGBParm *rgbp;
1205
1206
2
  rgbp = AIR_CAST(tenEvecRGBParm *, calloc(1, sizeof(tenEvecRGBParm)));
1207
1
  if (rgbp) {
1208
1
    rgbp->which = 0;
1209
1
    rgbp->aniso = tenAniso_Cl2;
1210
1
    rgbp->confThresh = 0.5;
1211
1
    rgbp->anisoGamma = 1.0;
1212
1
    rgbp->gamma = 1.0;
1213
1
    rgbp->bgGray = 0.0;
1214
1
    rgbp->isoGray = 0.0;
1215
1
    rgbp->maxSat = 1.0;
1216
1
    rgbp->typeOut = nrrdTypeFloat;
1217
1
    rgbp->genAlpha = AIR_FALSE;
1218
1
  }
1219
1
  return rgbp;
1220
}
1221
1222
tenEvecRGBParm *
1223
tenEvecRGBParmNix(tenEvecRGBParm *rgbp) {
1224
1225
2
  if (rgbp) {
1226
1
    airFree(rgbp);
1227
1
  }
1228
1
  return NULL;
1229
}
1230
1231
int
1232
tenEvecRGBParmCheck(const tenEvecRGBParm *rgbp) {
1233
  static const char me[]="tenEvecRGBParmCheck";
1234
1235
  if (!rgbp) {
1236
    biffAddf(TEN, "%s: got NULL pointer", me);
1237
    return 1;
1238
  }
1239
  if (!( rgbp->which <= 2 )) {
1240
    biffAddf(TEN, "%s: which must be 0, 1, or 2 (not %u)", me, rgbp->which);
1241
    return 1;
1242
  }
1243
  if (airEnumValCheck(tenAniso, rgbp->aniso)) {
1244
    biffAddf(TEN, "%s: anisotropy metric %d not valid", me, rgbp->aniso);
1245
    return 1;
1246
  }
1247
  if (nrrdTypeDefault != rgbp->typeOut
1248
      && airEnumValCheck(nrrdType, rgbp->typeOut)) {
1249
    biffAddf(TEN, "%s: output type (%d) not valid", me, rgbp->typeOut);
1250
    return 1;
1251
  }
1252
  return 0;
1253
}
1254
1255
float
1256
_tenEvecRGBComp_f(float conf, float aniso, float comp,
1257
                  const tenEvecRGBParm *rgbp) {
1258
  double X;
1259
1260
  X = AIR_ABS(comp);
1261
  X = pow(X, 1.0/rgbp->gamma);
1262
  X = AIR_LERP(rgbp->maxSat*aniso, rgbp->isoGray, X);
1263
  return AIR_CAST(float, conf > rgbp->confThresh ? X : rgbp->bgGray);
1264
}
1265
1266
double
1267
_tenEvecRGBComp_d(double conf, double aniso, double comp,
1268
                  const tenEvecRGBParm *rgbp) {
1269
  double X;
1270
1271
  X = AIR_ABS(comp);
1272
  X = pow(X, 1.0/rgbp->gamma);
1273
  X = AIR_LERP(rgbp->maxSat*aniso, rgbp->isoGray, X);
1274
  return conf > rgbp->confThresh ? X : rgbp->bgGray;
1275
}
1276
1277
void
1278
tenEvecRGBSingle_f(float RGB[3], float conf, const float eval[3],
1279
                   const float evec[3], const tenEvecRGBParm *rgbp) {
1280
  float aniso;
1281
1282
  if (RGB && eval && rgbp) {
1283
    aniso = tenAnisoEval_f(eval, rgbp->aniso);
1284
    aniso = AIR_CAST(float, pow(aniso, 1.0/rgbp->anisoGamma));
1285
    ELL_3V_SET(RGB,
1286
               _tenEvecRGBComp_f(conf, aniso, evec[0], rgbp),
1287
               _tenEvecRGBComp_f(conf, aniso, evec[1], rgbp),
1288
               _tenEvecRGBComp_f(conf, aniso, evec[2], rgbp));
1289
  }
1290
  return;
1291
}
1292
1293
void
1294
tenEvecRGBSingle_d(double RGB[3], double conf, const double eval[3],
1295
                   const double evec[3], const tenEvecRGBParm *rgbp) {
1296
  double aniso;
1297
1298
  if (RGB && eval && rgbp) {
1299
    aniso = tenAnisoEval_d(eval, rgbp->aniso);
1300
    aniso = pow(aniso, 1.0/rgbp->anisoGamma);
1301
    ELL_3V_SET(RGB,
1302
               _tenEvecRGBComp_d(conf, aniso, evec[0], rgbp),
1303
               _tenEvecRGBComp_d(conf, aniso, evec[1], rgbp),
1304
               _tenEvecRGBComp_d(conf, aniso, evec[2], rgbp));
1305
  }
1306
  return;
1307
}
1308