GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/arith.c Lines: 89 470 18.9 %
Date: 2017-05-26 Branches: 41 290 14.1 %

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 "nrrd.h"
25
#include "privateNrrd.h"
26
27
/*
28
******** nrrdArithGamma()
29
**
30
** map the values in a nrrd through a power function; essentially:
31
** val = pow(val, 1/gamma), but this is after the val has been normalized
32
** to be in the range of 0.0 to 1.0 (assuming that the given min and
33
** max really are the full range of the values in the nrrd).  Thus,
34
** the given min and max values are fixed points of this
35
** transformation.  Using a negative gamma means that after the pow()
36
** function has been applied, the value is inverted with respect to
37
** min and max (like in xv).
38
*/
39
int
40
nrrdArithGamma(Nrrd *nout, const Nrrd *nin,
41
               const NrrdRange *_range, double Gamma) {
42
  static const char me[]="nrrdArithGamma", func[]="gamma";
43
  double val, min, max;
44
  size_t I, num;
45
  NrrdRange *range;
46
  airArray *mop;
47
  double (*lup)(const void *, size_t);
48
  double (*ins)(void *, size_t, double);
49
50
  if (!(nout && nin)) {
51
    /* _range can be NULL */
52
    biffAddf(NRRD, "%s: got NULL pointer", me);
53
    return 1;
54
  }
55
  if (!( AIR_EXISTS(Gamma) )) {
56
    biffAddf(NRRD, "%s: gamma doesn't exist", me);
57
    return 1;
58
  }
59
  if (!( nrrdTypeBlock != nin->type && nrrdTypeBlock != nout->type )) {
60
    biffAddf(NRRD, "%s: can't deal with %s type", me,
61
             airEnumStr(nrrdType, nrrdTypeBlock));
62
    return 1;
63
  }
64
  if (nout != nin) {
65
    if (nrrdCopy(nout, nin)) {
66
      biffAddf(NRRD, "%s: couldn't initialize by copy to output", me);
67
      return 1;
68
    }
69
  }
70
  mop = airMopNew();
71
  if (_range) {
72
    range = nrrdRangeCopy(_range);
73
    nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState);
74
  } else {
75
    range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeTrue);
76
  }
77
  airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways);
78
  min = range->min;
79
  max = range->max;
80
  if (min == max) {
81
    /* this is stupid.  We want min < max to avoid making NaNs */
82
    max += 1;
83
  }
84
  lup = nrrdDLookup[nin->type];
85
  ins = nrrdDInsert[nout->type];
86
  Gamma = 1/Gamma;
87
  num = nrrdElementNumber(nin);
88
  if (Gamma < 0.0) {
89
    Gamma = -Gamma;
90
    for (I=0; I<num; I++) {
91
      val = lup(nin->data, I);
92
      val = AIR_AFFINE(min, val, max, 0.0, 1.0);
93
      val = pow(val, Gamma);
94
      val = AIR_AFFINE(1.0, val, 0.0, min, max);
95
      ins(nout->data, I, val);
96
    }
97
  } else {
98
    for (I=0; I<num; I++) {
99
      val = lup(nin->data, I);
100
      val = AIR_AFFINE(min, val, max, 0.0, 1.0);
101
      val = pow(val, Gamma);
102
      val = AIR_AFFINE(0.0, val, 1.0, min, max);
103
      ins(nout->data, I, val);
104
    }
105
  }
106
  if (nrrdContentSet_va(nout, func, nin, "%g,%g,%g", min, max, Gamma)) {
107
    biffAddf(NRRD, "%s:", me);
108
    airMopError(mop); return 1;
109
  }
110
  if (nout != nin) {
111
    nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE);
112
  }
113
  /* basic info handled by nrrdCopy above */
114
115
  airMopOkay(mop);
116
  return 0;
117
}
118
119
/* ---------------------------- unary -------------- */
120
121
static double _nrrdUnaryOpNegative(double a)   {return -a;}
122
static double _nrrdUnaryOpReciprocal(double a) {return 1.0/a;}
123
static double _nrrdUnaryOpSin(double a)        {return sin(a);}
124
static double _nrrdUnaryOpCos(double a)        {return cos(a);}
125
static double _nrrdUnaryOpTan(double a)        {return tan(a);}
126
static double _nrrdUnaryOpAsin(double a)       {return asin(a);}
127
static double _nrrdUnaryOpAcos(double a)       {return acos(a);}
128
static double _nrrdUnaryOpAtan(double a)       {return atan(a);}
129
static double _nrrdUnaryOpExp(double a)        {return exp(a);}
130
static double _nrrdUnaryOpLog(double a)        {return log(a);}
131
static double _nrrdUnaryOpLog2(double a)       {return log(a)/0.69314718;}
132
static double _nrrdUnaryOpLog10(double a)      {return log10(a);}
133
/* This code for log1p and expm1 comes from
134
   http://www.plunk.org/~hatch/rightway.php which in turn references
135
   http://www.cs.berkeley.edu/~wkahan/Math128/Sumnfp.pdf from the
136
   great Kahan of IEEE 754 fame, but sadly that URL no longer works
137
   (though the Math128 directory is still there, as are other documents) */
138
static double _nrrdUnaryOpLog1p(double a) {
139
  double b;
140
141
  b = 1.0 + a;
142
  if (b == 1.0) {
143
    /* "a" was so close to zero that we had underflow when adding to 1,
144
       resulting in something that is exactly equal to 1.  So, use the
145
       first term of Taylor expansion of log(x+1) around 0 == x */
146
    return a;
147
  }
148
  /* else "a" was not so near zero; but GLK doesn't fully grasp
149
     the design of this expression */
150
  return log(b)*a/(b-1);
151
}
152
static double _nrrdUnaryOpExpm1(double x) {
153
  double u;
154
155
  u = exp(x);
156
  if (u == 1.0) {
157
    /* "x" was so close to 0.0 that exp return exactly 1; subtracting
158
       1 from this will give a constant for a range of x's.  Instead,
159
       use the Taylor expansion of exp(x)-1 around 0 == x */
160
    return x;
161
  } else if (u-1.0 == -1.0) {
162
    /* "x" was close enough to -inf that exp returned something so close
163
       to 0 that subtracting 1 resulted in exactly -1; return that */
164
    return -1.0;
165
  }
166
  /* else "x" was neither near 0.0 or -inf, but GLK doesn't fully grasp
167
     the design of this expression */
168
  return (u-1.0)*x/log(u);
169
}
170
static double _nrrdUnaryOpSqrt(double a)       {return sqrt(a);}
171
static double _nrrdUnaryOpCbrt(double a)       {return airCbrt(a);}
172
static double _nrrdUnaryOpErf(double a)        {return airErf(a);}
173
static double _nrrdUnaryOpNerf(double a)       {return (1+airErf(a))/2;}
174
static double _nrrdUnaryOpCeil(double a)       {return ceil(a);}
175
static double _nrrdUnaryOpFloor(double a)      {return floor(a);}
176
static double _nrrdUnaryOpRoundUp(double a)    {return AIR_ROUNDUP(a);}
177
static double _nrrdUnaryOpRoundDown(double a)  {return AIR_ROUNDDOWN(a);}
178
static double _nrrdUnaryOpAbs(double a)        {return AIR_ABS(a);}
179
static double _nrrdUnaryOpSgn(double a) {
180
  return (a < 0.0 ? -1 : (a > 0.0 ? 1 : 0));}
181
static double _nrrdUnaryOpExists(double a)     {return AIR_EXISTS(a);}
182
static double _nrrdUnaryOpRand(double a) {
183
  AIR_UNUSED(a);
184
  return airDrandMT();
185
}
186
static double _nrrdUnaryOpNormalRand(double a) {
187
  double v;
188
  AIR_UNUSED(a);
189
  airNormalRand(&v, NULL);
190
  return v;
191
}
192
static double _nrrdUnaryOpIf(double a) { return (a ? 1 : 0); }
193
static double _nrrdUnaryOpZero(double a) {
194
  AIR_UNUSED(a);
195
  return 0.0;
196
}
197
static double _nrrdUnaryOpOne(double a) {
198
  AIR_UNUSED(a);
199
  return 1.0;
200
}
201
static double _nrrdUnaryOpTauOfSigma(double s) { return airTauOfSigma(s); }
202
static double _nrrdUnaryOpSigmaOfTau(double t) { return airSigmaOfTau(t); }
203
204
double (*_nrrdUnaryOp[NRRD_UNARY_OP_MAX+1])(double) = {
205
  NULL,
206
  _nrrdUnaryOpNegative,
207
  _nrrdUnaryOpReciprocal,
208
  _nrrdUnaryOpSin,
209
  _nrrdUnaryOpCos,
210
  _nrrdUnaryOpTan,
211
  _nrrdUnaryOpAsin,
212
  _nrrdUnaryOpAcos,
213
  _nrrdUnaryOpAtan,
214
  _nrrdUnaryOpExp,
215
  _nrrdUnaryOpLog,
216
  _nrrdUnaryOpLog2,
217
  _nrrdUnaryOpLog10,
218
  _nrrdUnaryOpLog1p,
219
  _nrrdUnaryOpExpm1,
220
  _nrrdUnaryOpSqrt,
221
  _nrrdUnaryOpCbrt,
222
  _nrrdUnaryOpErf,
223
  _nrrdUnaryOpNerf,
224
  _nrrdUnaryOpCeil,
225
  _nrrdUnaryOpFloor,
226
  _nrrdUnaryOpRoundUp,
227
  _nrrdUnaryOpRoundDown,
228
  _nrrdUnaryOpAbs,
229
  _nrrdUnaryOpSgn,
230
  _nrrdUnaryOpExists,
231
  _nrrdUnaryOpRand,
232
  _nrrdUnaryOpNormalRand,
233
  _nrrdUnaryOpIf,
234
  _nrrdUnaryOpZero,
235
  _nrrdUnaryOpOne,
236
  _nrrdUnaryOpTauOfSigma,
237
  _nrrdUnaryOpSigmaOfTau
238
};
239
240
int
241
nrrdArithUnaryOp(Nrrd *nout, int op, const Nrrd *nin) {
242
  static const char me[]="nrrdArithUnaryOp";
243
  size_t N, I;
244
  int size[NRRD_DIM_MAX];
245
  double (*insert)(void *v, size_t I, double d),
246
    (*lookup)(const void *v, size_t I), (*uop)(double), val;
247
248
  if (!(nout && nin)) {
249
    biffAddf(NRRD, "%s: got NULL pointer", me);
250
    return 1;
251
  }
252
  if (nrrdTypeBlock == nin->type) {
253
    biffAddf(NRRD, "%s: can't operate on type %s", me,
254
             airEnumStr(nrrdType, nrrdTypeBlock));
255
    return 1;
256
  }
257
  if (airEnumValCheck(nrrdUnaryOp, op)) {
258
    biffAddf(NRRD, "%s: unary op %d invalid", me, op);
259
    return 1;
260
  }
261
  if (nout != nin) {
262
    if (nrrdCopy(nout, nin)) {
263
      biffAddf(NRRD, "%s:", me);
264
      return 1;
265
    }
266
  }
267
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
268
  uop = _nrrdUnaryOp[op];
269
270
  N = nrrdElementNumber(nin);
271
  lookup = nrrdDLookup[nin->type];
272
  insert = nrrdDInsert[nin->type];
273
  for (I=0; I<N; I++) {
274
    val = lookup(nin->data, I);
275
    insert(nout->data, I, uop(val));
276
  }
277
  if (nrrdContentSet_va(nout, airEnumStr(nrrdUnaryOp, op), nin, "")) {
278
    biffAddf(NRRD, "%s:", me);
279
    return 1;
280
  }
281
  nrrdBasicInfoInit(nout,
282
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
283
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
284
  return 0;
285
}
286
287
/* ---------------------------- binary -------------- */
288
289
static double _nrrdBinaryOpAdd(double a, double b)       {return a + b;}
290
256200
static double _nrrdBinaryOpSubtract(double a, double b)  {return a - b;}
291
1556640
static double _nrrdBinaryOpMultiply(double a, double b)  {return a * b;}
292
static double _nrrdBinaryOpDivide(double a, double b)    {return a / b;}
293
static double _nrrdBinaryOpPow(double a, double b)       {return pow(a,b);}
294
static double _nrrdBinaryOpSgnPow(double a, double b)  {return airSgnPow(a,b);}
295
static double _nrrdBinaryOpFlippedSgnPow(double a, double b)  {return airFlippedSgnPow(a,b);}
296
static double _nrrdBinaryOpMod(double a, double b) {
297
  return AIR_MOD((int)a,(int)b);}
298
static double _nrrdBinaryOpFmod(double a, double b)      {return fmod(a,b);}
299
static double _nrrdBinaryOpAtan2(double a, double b)     {return atan2(a,b);}
300
static double _nrrdBinaryOpMin(double a, double b)       {return AIR_MIN(a,b);}
301
static double _nrrdBinaryOpMax(double a, double b)       {return AIR_MAX(a,b);}
302
static double _nrrdBinaryOpLT(double a, double b)        {return (a < b);}
303
static double _nrrdBinaryOpLTE(double a, double b)       {return (a <= b);}
304
static double _nrrdBinaryOpGT(double a, double b)        {return (a > b);}
305
static double _nrrdBinaryOpGTE(double a, double b)       {return (a >= b);}
306
static double _nrrdBinaryOpCompare(double a, double b) {
307
  return (a < b ? -1 : (a > b ? 1 : 0));}
308
static double _nrrdBinaryOpEqual(double a, double b)     {return (a == b);}
309
static double _nrrdBinaryOpNotEqual(double a, double b)  {return (a != b);}
310
static double _nrrdBinaryOpExists(double a, double b)  {return (AIR_EXISTS(a)
311
                                                                ? a : b);}
312
static double _nrrdBinaryOpIf(double a, double b)        {return (a ? a : b);}
313
static double _nrrdBinaryOpNormalRandScaleAdd(double a, double b) {
314
10896480
  double v;
315
5448240
  airNormalRand(&v, NULL);
316
10896480
  return a + b*v;
317
5448240
}
318
static double _nrrdBinaryOpRicianRand(double a, double b) {
319
  double vr, vi, rr, ri;
320
  airNormalRand(&rr, &ri);
321
  vr = a + b*rr;
322
  vi = b*ri;
323
  return sqrt(vr*vr + vi*vi);
324
}
325
326
327
double (*_nrrdBinaryOp[NRRD_BINARY_OP_MAX+1])(double, double) = {
328
  NULL,
329
  _nrrdBinaryOpAdd,
330
  _nrrdBinaryOpSubtract,
331
  _nrrdBinaryOpMultiply,
332
  _nrrdBinaryOpDivide,
333
  _nrrdBinaryOpPow,
334
  _nrrdBinaryOpSgnPow,
335
  _nrrdBinaryOpFlippedSgnPow,
336
  _nrrdBinaryOpMod,
337
  _nrrdBinaryOpFmod,
338
  _nrrdBinaryOpAtan2,
339
  _nrrdBinaryOpMin,
340
  _nrrdBinaryOpMax,
341
  _nrrdBinaryOpLT,
342
  _nrrdBinaryOpLTE,
343
  _nrrdBinaryOpGT,
344
  _nrrdBinaryOpGTE,
345
  _nrrdBinaryOpCompare,
346
  _nrrdBinaryOpEqual,
347
  _nrrdBinaryOpNotEqual,
348
  _nrrdBinaryOpExists,
349
  _nrrdBinaryOpIf,
350
  _nrrdBinaryOpNormalRandScaleAdd,
351
  _nrrdBinaryOpRicianRand,
352
  /* for these, the clamping is actually done by the caller */
353
  _nrrdBinaryOpAdd, /* for nrrdBinaryOpAddClamp */
354
  _nrrdBinaryOpSubtract, /* for nrrdBinaryOpSubtractClamp */
355
  _nrrdBinaryOpMultiply, /* for nrrdBinaryOpMultiplyClamp */
356
};
357
358
/*
359
******** nrrdArithBinaryOp
360
**
361
** this is a simplified version of nrrdArithIterBinaryOp, written after
362
** that, in a hurry, to operate directly on two nrrds, instead with
363
** the NrrdIter nonsense
364
*/
365
int
366
nrrdArithBinaryOp(Nrrd *nout, int op, const Nrrd *ninA, const Nrrd *ninB) {
367
  static const char me[]="nrrdArithBinaryOp";
368
  char *contA, *contB;
369
2
  size_t N, I, size[NRRD_DIM_MAX];
370
  double (*ins)(void *v, size_t I, double d), (*clmp)(double d),
371
    (*lupA)(const void *v, size_t I), (*lupB)(const void *v, size_t I),
372
    (*bop)(double a, double b), valA, valB;
373
374

3
  if (!( nout && !nrrdCheck(ninA) && !nrrdCheck(ninB) )) {
375
    biffAddf(NRRD, "%s: NULL pointer or invalid args", me);
376
    return 1;
377
  }
378

2
  if (nrrdTypeBlock == ninA->type || nrrdTypeBlock == ninB->type) {
379
    biffAddf(NRRD, "%s: can't operate on type %s", me,
380
             airEnumStr(nrrdType, nrrdTypeBlock));
381
    return 1;
382
  }
383
1
  if (!nrrdSameSize(ninA, ninB, AIR_TRUE)) {
384
    biffAddf(NRRD, "%s: size mismatch between arguments", me);
385
    return 1;
386
  }
387
1
  if (airEnumValCheck(nrrdBinaryOp, op)) {
388
    biffAddf(NRRD, "%s: binary op %d invalid", me, op);
389
    return 1;
390
  }
391
392
1
  nrrdAxisInfoGet_nva(ninA, nrrdAxisInfoSize, size);
393

2
  if (!( nout == ninA || nout == ninB)) {
394
1
    if (_nrrdMaybeAllocMaybeZero_nva(nout, ninA->type, ninA->dim, size,
395
                                     AIR_FALSE /* zero when no realloc */)) {
396
      biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
397
      return 1;
398
    }
399
1
    if (nrrdAxisInfoCopy(nout, ninA, NULL, NRRD_AXIS_INFO_NONE)) {
400
      biffAddf(NRRD, "%s:", me);
401
      return 1;
402
    }
403
1
    nrrdBasicInfoCopy(nout, ninA, (NRRD_BASIC_INFO_DATA_BIT
404
                                   | NRRD_BASIC_INFO_TYPE_BIT
405
                                   | NRRD_BASIC_INFO_DIMENSION_BIT
406
                                   | NRRD_BASIC_INFO_CONTENT_BIT
407
                                   | NRRD_BASIC_INFO_COMMENTS_BIT
408
1
                                   | (nrrdStateKeyValuePairsPropagate
409
                                      ? 0
410
                                      : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
411
1
  }
412
1
  nrrdBasicInfoInit(nout,
413
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
414
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
415
1
  bop = _nrrdBinaryOp[op];
416
417
1
  N = nrrdElementNumber(ninA);
418
1
  lupA = nrrdDLookup[ninA->type];
419
1
  lupB = nrrdDLookup[ninB->type];
420
1
  ins = nrrdDInsert[nout->type];
421
1
  if (nrrdBinaryOpAddClamp == op
422

2
      || nrrdBinaryOpSubtractClamp == op
423
1
      || nrrdBinaryOpMultiplyClamp == op) {
424
    clmp = nrrdDClamp[nout->type];
425
  } else {
426
    clmp = NULL;
427
  }
428
256202
  for (I=0; I<N; I++) {
429
    double tmp;
430
    /* HEY: there is a loss of precision issue here with 64-bit ints */
431
128100
    valA = lupA(ninA->data, I);
432
128100
    valB = lupB(ninB->data, I);
433
128100
    tmp = bop(valA, valB);
434
128100
    if (clmp) {
435
      tmp = clmp(tmp);
436
    }
437
128100
    ins(nout->data, I, tmp);
438
  }
439
440
1
  contA = _nrrdContentGet(ninA);
441
1
  contB = _nrrdContentGet(ninB);
442
1
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdBinaryOp, op),
443
                         contA, "%s", contB)) {
444
    biffAddf(NRRD, "%s:", me);
445
    free(contA); free(contB); return 1;
446
  }
447
1
  free(contA);
448
1
  free(contB);
449
1
  return 0;
450
1
}
451
452
int
453
nrrdArithIterBinaryOpSelect(Nrrd *nout, int op,
454
                            NrrdIter *inA, NrrdIter *inB,
455
                            unsigned int which) {
456
  static const char me[]="nrrdArithIterBinaryOpSelect";
457
  char *contA, *contB;
458
32
  size_t N, I, size[NRRD_DIM_MAX];
459
  int type;
460
  double (*insert)(void *v, size_t I, double d), (*clmp)(double d),
461
    (*bop)(double a, double b), valA, valB;
462
  const Nrrd *nin;
463
464
16
  if (!(nout && inA && inB)) {
465
    biffAddf(NRRD, "%s: got NULL pointer", me);
466
    return 1;
467
  }
468
16
  if (airEnumValCheck(nrrdBinaryOp, op)) {
469
    biffAddf(NRRD, "%s: binary op %d invalid", me, op);
470
    return 1;
471
  }
472
16
  if (!( 0 == which || 1 == which )) {
473
    biffAddf(NRRD, "%s: which %u not 0 or 1", me, which);
474
    return 1;
475
  }
476
32
  nin = (0 == which
477
32
         ? _NRRD_ITER_NRRD(inA)
478
         : _NRRD_ITER_NRRD(inB));
479
16
  if (!nin) {
480
    biffAddf(NRRD, "%s: selected input %u is a fixed value", me, which);
481
    return 1;
482
  }
483
16
  type = nin->type;
484
16
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
485
486
16
  if (_nrrdMaybeAllocMaybeZero_nva(nout, type, nin->dim, size,
487
                                   AIR_FALSE /* zero when no realloc */)) {
488
    biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
489
    return 1;
490
  }
491
16
  nrrdBasicInfoCopy(nout, nin, (NRRD_BASIC_INFO_DATA_BIT
492
                                | NRRD_BASIC_INFO_TYPE_BIT
493
                                | NRRD_BASIC_INFO_DIMENSION_BIT
494
                                | NRRD_BASIC_INFO_CONTENT_BIT
495
                                | NRRD_BASIC_INFO_COMMENTS_BIT
496
16
                                | (nrrdStateKeyValuePairsPropagate
497
                                   ? 0
498
                                   : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
499
16
  nrrdBasicInfoInit(nout,
500
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
501
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
502
16
  bop = _nrrdBinaryOp[op];
503
504
  /*
505
  fprintf(stderr, "%s: inA->left = %d, inB->left = %d\n", me,
506
          (int)(inA->left), (int)(inB->left));
507
  */
508
16
  N = nrrdElementNumber(nin);
509
16
  insert = nrrdDInsert[type];
510
16
  if (nrrdBinaryOpAddClamp == op
511

32
      || nrrdBinaryOpSubtractClamp == op
512
16
      || nrrdBinaryOpMultiplyClamp == op) {
513
    clmp = nrrdDClamp[nout->type];
514
  } else {
515
    clmp = NULL;
516
  }
517
12453152
  for (I=0; I<N; I++) {
518
    double tmp;
519
    /* HEY: there is a loss of precision issue here with 64-bit ints */
520
6226560
    valA = nrrdIterValue(inA);
521
6226560
    valB = nrrdIterValue(inB);
522
6226560
    tmp = bop(valA, valB);
523
6226560
    if (clmp) {
524
      tmp = clmp(tmp);
525
    }
526
6226560
    insert(nout->data, I, tmp);
527
  }
528
16
  contA = nrrdIterContent(inA);
529
16
  contB = nrrdIterContent(inB);
530
16
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdBinaryOp, op),
531
                         contA, "%s", contB)) {
532
    biffAddf(NRRD, "%s:", me);
533
    free(contA); free(contB); return 1;
534
  }
535
16
  if (nout != nin) {
536
8
    nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE);
537
8
  }
538
16
  free(contA);
539
16
  free(contB);
540
16
  return 0;
541
16
}
542
543
int
544
nrrdArithIterBinaryOp(Nrrd *nout, int op, NrrdIter *inA, NrrdIter *inB) {
545
  static const char me[]="nrrdArithIterBinaryOp";
546
  unsigned int which;
547
548
32
  if (!(nout && inA && inB)) {
549
    biffAddf(NRRD, "%s: got NULL pointer", me);
550
    return 1;
551
  }
552

48
  which = (_NRRD_ITER_NRRD(inA)
553
           ? 0
554
           : (_NRRD_ITER_NRRD(inB)
555
              ? 1
556
              : 2));
557
16
  if (2 == which) {
558
    biffAddf(NRRD, "%s: can't operate on two fixed values", me);
559
    return 1;
560
  }
561
16
  if (nrrdArithIterBinaryOpSelect(nout, op, inA, inB, which)) {
562
    biffAddf(NRRD, "%s: trouble", me);
563
    return 1;
564
  }
565
16
  return 0;
566
16
}
567
568
/* ---------------------------- ternary -------------- */
569
570
static double _nrrdTernaryOpAdd(double a, double b, double c) {
571
  return a + b + c;
572
}
573
static double _nrrdTernaryOpMultiply(double a, double b, double c)  {
574
  return a * b * c;
575
}
576
static double _nrrdTernaryOpMin(double a, double b, double c) {
577
  b = AIR_MIN(b, c);
578
  return AIR_MIN(a, b);
579
}
580
/*
581
** minsmooth(x, w, M) is like min(x,M), but starting at value M-w, values
582
** are lowered (via erf), so that the output is asymptotic to M
583
*/
584
static double _nrrdTernaryOpMinSmooth(double x, double width, double max) {
585
  double tran;
586
  tran = max - width;
587
  return (tran < max          /* using the function as intended */
588
          ? (x < tran
589
             ? x
590
             : airErf((x-tran)*0.886226925452758/(max - tran))*(max - tran) + tran)
591
          : AIR_MIN(x, max)); /* transition in wrong place; revert to simple max() */
592
}
593
static double _nrrdTernaryOpMax(double a, double b, double c) {
594
  b = AIR_MAX(b, c);
595
  return AIR_MAX(a, b);
596
}
597
/*
598
** maxsmooth(m, w, x) is like max(m,x), but starting at value m+w, values
599
** are raised (via erf), so that the output is asymptotic to m
600
*/
601
static double _nrrdTernaryOpMaxSmooth(double min, double width, double x) {
602
  double tran;
603
  tran = min + width;
604
  return (min < tran          /* using the function as intended */
605
          ? (tran < x
606
             ? x
607
             : airErf((x-tran)*0.886226925452758/(min - tran))*(min - tran) + tran)
608
          : AIR_MAX(x, min)); /* transition in wrong place; revert to simple max() */
609
}
610
static double _nrrdTernaryOpLTSmooth(double a, double w, double b) {
611
  return AIR_AFFINE(-1.0, airErf((b-a)/w), 1.0, 0.0, 1.0);
612
}
613
static double _nrrdTernaryOpGTSmooth(double a, double w, double b) {
614
  return AIR_AFFINE(-1.0, airErf((a-b)/w), 1.0, 0.0, 1.0);
615
}
616
static double _nrrdTernaryOpClamp(double a, double b, double c) {
617
  return AIR_CLAMP(a, b, c);
618
}
619
static double _nrrdTernaryOpIfElse(double a, double b, double c) {
620
  return (a ? b : c);
621
}
622
static double _nrrdTernaryOpLerp(double a, double b, double c) {
623
  /* we do something more than the simple lerp here because
624
     we want to facilitate usage as something which can get around
625
     non-existent values (b and c as NaN or Inf) without
626
     getting polluted by them. */
627
628
  if (0.0 == a) {
629
    return b;
630
  } else if (1.0 == a) {
631
    return c;
632
  } else {
633
    return AIR_LERP(a, b, c);
634
  }
635
}
636
static double _nrrdTernaryOpExists(double a, double b, double c) {
637
  return (AIR_EXISTS(a) ? b : c);
638
}
639
static double _nrrdTernaryOpInOpen(double a, double b, double c) {
640
  return (AIR_IN_OP(a, b, c));
641
}
642
static double _nrrdTernaryOpInClosed(double a, double b, double c) {
643
  return (AIR_IN_CL(a, b, c));
644
}
645
static double _nrrdTernaryOpGaussian(double x, double mu, double sig) {
646
  return airGaussian(x, mu, sig);
647
}
648
static double _nrrdTernaryOpRician(double x, double mu, double sig) {
649
  return airRician(x, mu, sig);
650
}
651
double (*_nrrdTernaryOp[NRRD_TERNARY_OP_MAX+1])(double, double, double) = {
652
  NULL,
653
  _nrrdTernaryOpAdd,
654
  _nrrdTernaryOpMultiply,
655
  _nrrdTernaryOpMin,
656
  _nrrdTernaryOpMinSmooth,
657
  _nrrdTernaryOpMax,
658
  _nrrdTernaryOpMaxSmooth,
659
  _nrrdTernaryOpLTSmooth,
660
  _nrrdTernaryOpGTSmooth,
661
  _nrrdTernaryOpClamp,
662
  _nrrdTernaryOpIfElse,
663
  _nrrdTernaryOpLerp,
664
  _nrrdTernaryOpExists,
665
  _nrrdTernaryOpInOpen,
666
  _nrrdTernaryOpInClosed,
667
  _nrrdTernaryOpGaussian,
668
  _nrrdTernaryOpRician
669
};
670
671
/*
672
******** nrrdArithTerneryOp
673
**
674
** HEY: UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED
675
**
676
** this is a simplified version of nrrdArithIterTernaryOp, written after
677
** that, in a hurry, to operate directly on three nrrds, instead with
678
** the NrrdIter nonsense
679
*/
680
int
681
nrrdArithTernaryOp(Nrrd *nout, int op, const Nrrd *ninA,
682
                   const Nrrd *ninB, const Nrrd *ninC) {
683
  static const char me[]="nrrdArithTernaryOp";
684
  char *contA, *contB, *contC;
685
  size_t N, I, size[NRRD_DIM_MAX];
686
  double (*ins)(void *v, size_t I, double d),
687
    (*lupA)(const void *v, size_t I), (*lupB)(const void *v, size_t I),
688
    (*lupC)(const void *v, size_t I),
689
    (*top)(double a, double b, double c), valA, valB, valC;
690
691
  if (!( nout && !nrrdCheck(ninA) && !nrrdCheck(ninB) && !nrrdCheck(ninC) )) {
692
    biffAddf(NRRD, "%s: NULL pointer or invalid args", me);
693
    return 1;
694
  }
695
  if (!( nrrdSameSize(ninA, ninB, AIR_TRUE) &&
696
         nrrdSameSize(ninA, ninC, AIR_TRUE) )) {
697
    biffAddf(NRRD, "%s: size mismatch between arguments", me);
698
    return 1;
699
  }
700
  if (airEnumValCheck(nrrdTernaryOp, op)) {
701
    biffAddf(NRRD, "%s: ternary op %d invalid", me, op);
702
    return 1;
703
  }
704
705
  nrrdAxisInfoGet_nva(ninA, nrrdAxisInfoSize, size);
706
  if (!( nout == ninA || nout == ninB || nout == ninC)) {
707
    if (_nrrdMaybeAllocMaybeZero_nva(nout, ninA->type, ninA->dim, size,
708
                                     AIR_FALSE /* zero when no realloc */)) {
709
      biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
710
      return 1;
711
    }
712
    if (nrrdAxisInfoCopy(nout, ninA, NULL, NRRD_AXIS_INFO_NONE)) {
713
      biffAddf(NRRD, "%s:", me);
714
      return 1;
715
    }
716
    nrrdBasicInfoCopy(nout, ninA, (NRRD_BASIC_INFO_DATA_BIT
717
                                   | NRRD_BASIC_INFO_TYPE_BIT
718
                                   | NRRD_BASIC_INFO_DIMENSION_BIT
719
                                   | NRRD_BASIC_INFO_CONTENT_BIT
720
                                   | NRRD_BASIC_INFO_COMMENTS_BIT
721
                                   | (nrrdStateKeyValuePairsPropagate
722
                                      ? 0
723
                                      : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
724
  }
725
  nrrdBasicInfoInit(nout,
726
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
727
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
728
  top = _nrrdTernaryOp[op];
729
730
  N = nrrdElementNumber(ninA);
731
  lupA = nrrdDLookup[ninA->type];
732
  lupB = nrrdDLookup[ninB->type];
733
  lupC = nrrdDLookup[ninC->type];
734
  ins = nrrdDInsert[nout->type];
735
  for (I=0; I<N; I++) {
736
    /* HEY: there is a loss of precision issue here with 64-bit ints */
737
    valA = lupA(ninA->data, I);
738
    valB = lupB(ninB->data, I);
739
    valC = lupC(ninC->data, I);
740
    ins(nout->data, I, top(valA, valB, valC));
741
  }
742
743
  contA = _nrrdContentGet(ninA);
744
  contB = _nrrdContentGet(ninB);
745
  contC = _nrrdContentGet(ninC);
746
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdTernaryOp, op),
747
                         contA, "%s,%s", contB, contC)) {
748
    biffAddf(NRRD, "%s:", me);
749
    free(contA); free(contB); free(contC); return 1;
750
  }
751
  free(contA);
752
  free(contB);
753
  free(contC);
754
755
  return 0;
756
}
757
758
int
759
nrrdArithIterTernaryOpSelect(Nrrd *nout, int op,
760
                             NrrdIter *inA, NrrdIter *inB, NrrdIter *inC,
761
                             unsigned int which) {
762
  static const char me[]="nrrdArithIterTernaryOpSelect";
763
  char *contA, *contB, *contC;
764
  size_t N, I, size[NRRD_DIM_MAX];
765
  int type;
766
  double (*insert)(void *v, size_t I, double d),
767
    (*top)(double a, double b, double c), valA, valB, valC;
768
  const Nrrd *nin;
769
770
  if (!(nout && inA && inB && inC)) {
771
    biffAddf(NRRD, "%s: got NULL pointer", me);
772
    return 1;
773
  }
774
  if (airEnumValCheck(nrrdTernaryOp, op)) {
775
    biffAddf(NRRD, "%s: ternary op %d invalid", me, op);
776
    return 1;
777
  }
778
  if (!( 0 == which || 1 == which || 2 == which )) {
779
    biffAddf(NRRD, "%s: which %u not valid, want 0, 1, or 2", me, which);
780
    return 1;
781
  }
782
  nin = (0 == which
783
         ? _NRRD_ITER_NRRD(inA)
784
         : (1 == which
785
            ? _NRRD_ITER_NRRD(inB)
786
            : _NRRD_ITER_NRRD(inC)));
787
  if (!nin) {
788
    biffAddf(NRRD, "%s: selected input %u is a fixed value", me, which);
789
    return 1;
790
  }
791
  type = nin->type;
792
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
793
  if (_nrrdMaybeAllocMaybeZero_nva(nout, type, nin->dim, size,
794
                                   AIR_FALSE /* zero when no realloc */)) {
795
    biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
796
    return 1;
797
  }
798
  nrrdBasicInfoCopy(nout, nin, (NRRD_BASIC_INFO_DATA_BIT
799
                                | NRRD_BASIC_INFO_TYPE_BIT
800
                                | NRRD_BASIC_INFO_DIMENSION_BIT
801
                                | NRRD_BASIC_INFO_CONTENT_BIT
802
                                | NRRD_BASIC_INFO_COMMENTS_BIT
803
                                | (nrrdStateKeyValuePairsPropagate
804
                                   ? 0
805
                                   : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
806
  nrrdBasicInfoInit(nout,
807
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
808
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
809
  top = _nrrdTernaryOp[op];
810
811
  /*
812
  fprintf(stderr, "%!s: inA->left = %d, inB->left = %d\n", me,
813
          (int)(inA->left), (int)(inB->left));
814
  */
815
  N = nrrdElementNumber(nin);
816
  insert = nrrdDInsert[type];
817
  for (I=0; I<N; I++) {
818
    /* HEY: there is a loss of precision issue here with 64-bit ints */
819
    valA = nrrdIterValue(inA);
820
    valB = nrrdIterValue(inB);
821
    valC = nrrdIterValue(inC);
822
    /*
823
    if (!(I % 1000)) {
824
      fprintf(stderr, "!%s: %d: top(%g,%g,%g) = %g\n", me, (int)I,
825
              valA, valB, valC,
826
              top(valA, valB, valC));
827
    }
828
    */
829
    insert(nout->data, I, top(valA, valB, valC));
830
  }
831
  contA = nrrdIterContent(inA);
832
  contB = nrrdIterContent(inB);
833
  contC = nrrdIterContent(inC);
834
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdTernaryOp, op),
835
                         contA, "%s,%s", contB, contC)) {
836
    biffAddf(NRRD, "%s:", me);
837
    free(contA); free(contB); free(contC); return 1;
838
  }
839
  if (nout != nin) {
840
    nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE);
841
  }
842
  free(contA);
843
  free(contB);
844
  free(contC);
845
  return 0;
846
}
847
848
int
849
nrrdArithIterTernaryOp(Nrrd *nout, int op,
850
                       NrrdIter *inA, NrrdIter *inB, NrrdIter *inC) {
851
  static const char me[]="nrrdArithIterTernaryOp";
852
  unsigned int which;
853
854
  if (!(nout && inA && inB && inC)) {
855
    biffAddf(NRRD, "%s: got NULL pointer", me);
856
    return 1;
857
  }
858
  which = (_NRRD_ITER_NRRD(inA)
859
           ? 0
860
           : (_NRRD_ITER_NRRD(inB)
861
              ? 1
862
              : (_NRRD_ITER_NRRD(inC)
863
                 ? 2
864
                 : 3 )));
865
  if (3 == which) {
866
    biffAddf(NRRD, "%s: can't operate on 3 fixed values", me);
867
    return 1;
868
  }
869
  if (nrrdArithIterTernaryOpSelect(nout, op, inA, inB, inC, which)) {
870
    biffAddf(NRRD, "%s: trouble", me);
871
    return 1;
872
  }
873
  return 0;
874
}
875
876
int
877
nrrdArithAffine(Nrrd *nout, double minIn,
878
                const Nrrd *nin, double maxIn,
879
                double minOut, double maxOut, int clamp) {
880
  static const char me[]="nrrdArithAffine";
881
  size_t I, N;
882
  double (*ins)(void *v, size_t I, double d),
883
    (*lup)(const void *v, size_t I), mmin, mmax;
884
885
  if ( !nout || nrrdCheck(nin) ) {
886
    biffAddf(NRRD, "%s: got NULL pointer or invalid input", me);
887
    return 1;
888
  }
889
  if (nout != nin) {
890
    if (nrrdCopy(nout, nin)) {
891
      biffAddf(NRRD, "%s: couldn't initialize output", me);
892
      return 1;
893
    }
894
  }
895
  N = nrrdElementNumber(nin);
896
  ins = nrrdDInsert[nout->type];
897
  lup = nrrdDLookup[nin->type];
898
  mmin = AIR_MIN(minOut, maxOut);
899
  mmax = AIR_MAX(minOut, maxOut);
900
  for (I=0; I<N; I++) {
901
    double val;
902
    val = lup(nin->data, I);
903
    val = AIR_AFFINE(minIn, val, maxIn, minOut, maxOut);
904
    if (clamp) {
905
      val = AIR_CLAMP(mmin, val, mmax);
906
    }
907
    ins(nout->data, I, val);
908
  }
909
  /* HEY: it would be much better if the ordering here was the same as in
910
     AIR_AFFINE, but that's not easy with the way the content functions are
911
     now set up */
912
  if (nrrdContentSet_va(nout, "affine", nin,
913
                        "%g,%g,%g,%g", minIn, maxIn,
914
                        minOut, maxOut)) {
915
    biffAddf(NRRD, "%s:", me);
916
  }
917
  return 0;
918
}
919
920
int
921
nrrdArithIterAffine(Nrrd *nout, NrrdIter *minIn,
922
                    NrrdIter *in, NrrdIter *maxIn,
923
                    NrrdIter *minOut, NrrdIter *maxOut, int clamp) {
924
  static const char me[]="nrrdArithInterAffine";
925
  double (*ins)(void *v, size_t I, double d),
926
    mini, vin, maxi, mino, maxo, vout;
927
  const Nrrd *nin;
928
  char *contA, *contB, *contC, *contD, *contE;
929
  size_t I, N;
930
931
  if (!(nout && minIn && in && maxIn && minOut && maxOut)) {
932
    biffAddf(NRRD, "%s: got NULL pointer", me);
933
    return 1;
934
  }
935
  nin = (_NRRD_ITER_NRRD(in)
936
         ? _NRRD_ITER_NRRD(in)
937
         : (_NRRD_ITER_NRRD(minIn)
938
            ? _NRRD_ITER_NRRD(minIn)
939
            : (_NRRD_ITER_NRRD(maxIn)
940
               ? _NRRD_ITER_NRRD(maxIn)
941
               : (_NRRD_ITER_NRRD(minOut)
942
                  ? _NRRD_ITER_NRRD(minOut)
943
                  : _NRRD_ITER_NRRD(maxOut)))));
944
  if (!nin) {
945
    biffAddf(NRRD, "%s: can't operate solely on fixed values", me);
946
    return 1;
947
  }
948
  if (nrrdCopy(nout, nin)) {
949
    biffAddf(NRRD, "%s: couldn't initialize output", me);
950
    return 1;
951
  }
952
  N = nrrdElementNumber(nin);
953
  ins = nrrdDInsert[nout->type];
954
  for (I=0; I<N; I++) {
955
    mini = nrrdIterValue(minIn);
956
    vin = nrrdIterValue(in);
957
    maxi = nrrdIterValue(maxIn);
958
    mino = nrrdIterValue(minOut);
959
    maxo = nrrdIterValue(maxOut);
960
    vout = AIR_AFFINE(mini, vin, maxi, mino, maxo);
961
    if (clamp) {
962
      double mmin = AIR_MIN(mino, maxo);
963
      double mmax = AIR_MAX(mino, maxo);
964
      vout = AIR_CLAMP(mmin, vout, mmax);
965
    }
966
    ins(nout->data, I, vout);
967
  }
968
  contA = nrrdIterContent(in);
969
  contB = nrrdIterContent(minIn);
970
  contC = nrrdIterContent(maxIn);
971
  contD = nrrdIterContent(maxOut);
972
  contE = nrrdIterContent(maxOut);
973
  /* HEY: same annoyance about order of arguments as in function above */
974
  if (_nrrdContentSet_va(nout, "affine", contA, "%s,%s,%s,%s",
975
                         contB, contC, contD, contE)) {
976
    biffAddf(NRRD, "%s:", me);
977
    free(contA); free(contB); free(contC); free(contD); free(contE); return 1;
978
  }
979
  free(contA); free(contB); free(contC); free(contD); free(contE);
980
981
  return 0;
982
}
983
984
unsigned int
985
nrrdCRC32(const Nrrd *nin, int endian) {
986
  size_t nn;
987
988
  /* NULL nrrd or data */
989
36
  if (!nin
990
24
      || !(nin->data)
991
24
      || !(nn = nrrdElementSize(nin)*nrrdElementNumber(nin))
992
24
      || airEnumValCheck(airEndian, endian)) {
993
    return 0;
994
  }
995
996
24
  return airCRC32(AIR_CAST(const unsigned char *, nin->data),
997
12
                  nn, nrrdElementSize(nin),
998
12
                  endian == airMyEndian() ? AIR_FALSE : AIR_TRUE);
999
12
}
1000