GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/kernel.c Lines: 1060 1218 87.0 %
Date: 2017-05-26 Branches: 1147 1418 80.9 %

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
26
/*
27
** summary of information about how the kernel parameter vector is set:
28
** Note that, annoyingly, nrrdKernelUsesScale (at end of this file)
29
** has to be updated to record which kernels (including their derivatives)
30
** use parm[0] for scale.
31
32
                                 numParm  parm[0]   parm[1]   parm[2]
33
                 nrrdKernelHann    2      scale    cut-off
34
             nrrdKernelBlackman    2      scale    cut-off
35
           nrrdKernelCatmullRom    0
36
             nrrdKernelBSpline3    0
37
nrrdKernelBSpline3ApproxInverse    0
38
             nrrdKernelBSpline5    0
39
nrrdKernelBSpline5ApproxInverse    0
40
             nrrdKernelBSpline7    0
41
nrrdKernelBSpline7ApproxInverse    0
42
                 nrrdKernelZero    1      scale
43
                  nrrdKernelBox    1      scale
44
nrrdKernelCatmullRomSupportDebug   1      support
45
      nrrdKernelBoxSupportDebug    1      support
46
     nrrdKernelCos4SupportDebug    1      support
47
                nrrdKernelCheap    1      scale
48
nrrdKernelHermiteScaleSpaceFlag    0
49
                 nrrdKernelTent    1      scale
50
             nrrdKernelForwDiff    1      scale
51
             nrrdKernelCentDiff    1      scale
52
              nrrdKernelBCCubic    3      scale       B        C
53
             nrrdKernelAQuartic    2      scale       A
54
            nrrdKernelC3Quintic    0
55
              nrrdKernelC4Hexic    0
56
 nrrdKernelC4HexicApproxInverse    0
57
             nrrdKernelC5Septic    0
58
             nrrdKernelGaussian    2      sigma    cut-off
59
     nrrdKernelDiscreteGaussian    2      sigma    cut-off
60
            nrrdKernelTMF[][][]    1       a
61
62
** Note that when parm[0] is named "scale", that parameter is optional,
63
** and the default is 1.0, when given in string form
64
** E.g. "tent" is understood as "tent:1",
65
** but "gauss:4" isn't complete and won't parse; while "gauss:1,4" is good
66
** See note above about nrrdKernelUsesScale (at end of this file)
67
*/
68
69
/* these functions replace what had been a lot of
70
   identical functions for similar kernels */
71
72
static double
73
returnZero(const double *parm) {
74
  AIR_UNUSED(parm);
75
580
  return 0.0;
76
}
77
78
static double
79
returnOne(const double *parm) {
80
  AIR_UNUSED(parm);
81
7128
  return 1.0;
82
}
83
84
static double
85
returnTwo(const double *parm) {
86
  AIR_UNUSED(parm);
87
22
  return 2.0;
88
}
89
90
static double
91
returnThree(const double *parm) {
92
  AIR_UNUSED(parm);
93
376
  return 3.0;
94
}
95
96
static double
97
returnFour(const double *parm) {
98
  AIR_UNUSED(parm);
99
16
  return 4.0;
100
}
101
102
/* ------------------------------------------------------------ */
103
104
/* learned: if you copy/paste the macros for these kernels into
105
** other code, you *have* to make sure that the arguments for the
106
** kernels that are supposed to be reals, are not passed as an
107
** integral type (had this problem trying to re-use _BCCUBIC
108
** with constant B="1" and C="0" and had trouble figuring out
109
** why the kernel was give garbage results
110
*/
111
112
/* the "zero" kernel is here more as a template than for anything else
113
   (as well as when you need the derivative of nrrdKernelForwDiff or
114
   any other piece-wise constant kernels)
115
   In particular the support method is pretty silly. */
116
117
#define _ZERO(x) 0
118
119
static double
120
_nrrdZeroSup(const double *parm) {
121
  double S;
122
123
68
  S = parm[0];
124
34
  return S;
125
}
126
127
static double
128
_nrrdZero1_d(double x, const double *parm) {
129
  double S;
130
131
480024
  S = parm[0];
132
240012
  x = AIR_ABS(x)/S;
133
240012
  return _ZERO(x)/S;
134
}
135
136
static float
137
_nrrdZero1_f(float x, const double *parm) {
138
  float S;
139
140
480000
  S = AIR_CAST(float, parm[0]);
141
240000
  x = AIR_ABS(x)/S;
142
240000
  return _ZERO(x)/S;
143
}
144
145
static void
146
_nrrdZeroN_d(double *f, const double *x, size_t len, const double *parm) {
147
  double S;
148
  double t;
149
  size_t i;
150
151
129460
  S = parm[0];
152
1386196
  for (i=0; i<len; i++) {
153
628368
    t = x[i]; t = AIR_ABS(t)/S;
154
628368
    f[i] = _ZERO(t)/S;
155
  }
156
64730
}
157
158
static void
159
_nrrdZeroN_f(float *f, const float *x, size_t len, const double *parm) {
160
  float t, S;
161
  size_t i;
162
163
4
  S = AIR_CAST(float, parm[0]);
164
480004
  for (i=0; i<len; i++) {
165
240000
    t = x[i]; t = AIR_ABS(t)/S;
166
240000
    f[i] = _ZERO(t)/S;
167
  }
168
2
}
169
170
static NrrdKernel
171
_nrrdKernelZero = {
172
  "zero",
173
  1, _nrrdZeroSup, returnZero,
174
  _nrrdZero1_f, _nrrdZeroN_f, _nrrdZero1_d, _nrrdZeroN_d
175
};
176
NrrdKernel *const
177
nrrdKernelZero = &_nrrdKernelZero;
178
179
/* ------------------------------------------------------------ */
180
181
#define _BOX(x) (x > 0.5 ? 0 : (x < 0.5 ? 1 : 0.5))
182
183
static double
184
_nrrdBoxSup(const double *parm) {
185
  double S;
186
187
8
  S = parm[0];
188
  /* adding the 0.5 is to ensure that weights computed within the
189
     support really do catch all the non-zero values */
190
4
  return S/2 + 0.5;
191
}
192
193
static double
194
_nrrdBox1_d(double x, const double *parm) {
195
  double S;
196
197
480024
  S = parm[0];
198
240012
  x = AIR_ABS(x)/S;
199
624024
  return _BOX(x)/S;
200
}
201
202
static float
203
_nrrdBox1_f(float x, const double *parm) {
204
  float S;
205
206
480000
  S = AIR_CAST(float, parm[0]);
207
240000
  x = AIR_ABS(x)/S;
208
624000
  return AIR_CAST(float, _BOX(x)/S);
209
}
210
211
static void
212
_nrrdBoxN_d(double *f, const double *x, size_t len, const double *parm) {
213
  double S;
214
  double t;
215
  size_t i;
216
217
6
  S = parm[0];
218
480018
  for (i=0; i<len; i++) {
219
240006
    t = x[i]; t = AIR_ABS(t)/S;
220
624015
    f[i] = _BOX(t)/S;
221
  }
222
3
}
223
224
static void
225
_nrrdBoxN_f(float *f, const float *x, size_t len, const double *parm) {
226
  float t, S;
227
  size_t i;
228
229
4
  S = AIR_CAST(float, parm[0]);
230
480004
  for (i=0; i<len; i++) {
231
240000
    t = x[i]; t = AIR_ABS(t)/S;
232
624000
    f[i] = AIR_CAST(float, _BOX(t)/S);
233
  }
234
2
}
235
236
static NrrdKernel
237
_nrrdKernelBox = {
238
  "box",
239
  1, _nrrdBoxSup, returnOne,
240
  _nrrdBox1_f,  _nrrdBoxN_f,  _nrrdBox1_d,  _nrrdBoxN_d
241
};
242
NrrdKernel *const
243
nrrdKernelBox = &_nrrdKernelBox;
244
245
/* ------------------------------------------------------------ */
246
247
static double
248
_nrrdBoxSDSup(const double *parm) {
249
250
76
  return parm[0];
251
}
252
253
static double
254
_nrrdBoxSD1_d(double x, const double *parm) {
255
  AIR_UNUSED(parm);
256
480024
  x = AIR_ABS(x);
257
565738
  return _BOX(x);
258
}
259
260
static float
261
_nrrdBoxSD1_f(float x, const double *parm) {
262
  AIR_UNUSED(parm);
263
480000
  x = AIR_ABS(x);
264
565714
  return AIR_CAST(float, _BOX(x));
265
}
266
267
static void
268
_nrrdBoxSDN_d(double *f, const double *x, size_t len, const double *parm) {
269
  size_t i;
270
  AIR_UNUSED(parm);
271
1410546
  for (i=0; i<len; i++) {
272
    double t;
273
642780
    t = AIR_ABS(x[i]);
274
1496614
    f[i] = _BOX(t);
275
  }
276
41662
}
277
278
static void
279
_nrrdBoxSDN_f(float *f, const float *x, size_t len, const double *parm) {
280
  size_t i;
281
  AIR_UNUSED(parm);
282
480006
  for (i=0; i<len; i++) {
283
    float t;
284
240000
    t = AIR_ABS(x[i]);
285
565714
    f[i] = AIR_CAST(float, _BOX(t));
286
  }
287
2
}
288
289
static NrrdKernel
290
_nrrdKernelBoxSupportDebug = {
291
  "boxsup",
292
  1, _nrrdBoxSDSup, returnOne,
293
  _nrrdBoxSD1_f,  _nrrdBoxSDN_f,  _nrrdBoxSD1_d,  _nrrdBoxSDN_d
294
};
295
NrrdKernel *const
296
nrrdKernelBoxSupportDebug = &_nrrdKernelBoxSupportDebug;
297
298
/* ------------------------------------------------------------ */
299
300
#define COS4(x) (x > 0.5 \
301
                 ? 0.0 \
302
                 : cos(AIR_PI*x)*cos(AIR_PI*x)*cos(AIR_PI*x)*cos(AIR_PI*x))
303
304
static double
305
_nrrdCos4SDInt(const double *parm) {
306
  AIR_UNUSED(parm);
307
108
  return 3.0/8.0;
308
}
309
310
static double
311
_nrrdCos4SDSup(const double *parm) {
312
313
212
  return parm[0];
314
}
315
316
static double
317
_nrrdCos4SD1_d(double x, const double *parm) {
318
  AIR_UNUSED(parm);
319
1440024
  x = AIR_ABS(x);
320
1697170
  return COS4(x);
321
}
322
323
static float
324
_nrrdCos4SD1_f(float x, const double *parm) {
325
  AIR_UNUSED(parm);
326
480000
  x = AIR_ABS(x);
327
565714
  return AIR_CAST(float, COS4(x));
328
}
329
330
static void
331
_nrrdCos4SDN_d(double *f, const double *x, size_t len, const double *parm) {
332
  size_t i;
333
  AIR_UNUSED(parm);
334
4016946
  for (i=0; i<len; i++) {
335
    double t;
336
1837980
    t = AIR_ABS(x[i]);
337
4103014
    f[i] = COS4(t);
338
  }
339
113662
}
340
341
static void
342
_nrrdCos4SDN_f(float *f, const float *x, size_t len, const double *parm) {
343
  size_t i;
344
  AIR_UNUSED(parm);
345
480006
  for (i=0; i<len; i++) {
346
    float t;
347
240000
    t = AIR_ABS(x[i]);
348
565714
    f[i] = AIR_CAST(float, COS4(t));
349
  }
350
2
}
351
352
static NrrdKernel
353
_nrrdKernelCos4SupportDebug = {
354
  "cos4sup",
355
  1, _nrrdCos4SDSup, _nrrdCos4SDInt,
356
  _nrrdCos4SD1_f,  _nrrdCos4SDN_f,  _nrrdCos4SD1_d,  _nrrdCos4SDN_d
357
};
358
NrrdKernel *const
359
nrrdKernelCos4SupportDebug = &_nrrdKernelCos4SupportDebug;
360
361
/* ------------------------------------------------------------ */
362
363
#define DCOS4(x) (x > 0.5                                               \
364
                  ? 0.0                                                 \
365
                  : -4*AIR_PI*(cos(AIR_PI*x)*cos(AIR_PI*x)*cos(AIR_PI*x) \
366
                               *sin(AIR_PI*x)))
367
368
static double
369
_nrrdDCos4SDSup(const double *parm) {
370
204
  return parm[0];
371
}
372
373
static double
374
_nrrdDCos4SD1_d(double x, const double *parm) {
375
  int sgn;
376
  AIR_UNUSED(parm);
377
1800029
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
378
1697170
  return sgn*DCOS4(x);
379
}
380
381
static float
382
_nrrdDCos4SD1_f(float x, const double *parm) {
383
  int sgn;
384
  AIR_UNUSED(parm);
385
600000
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
386
565714
  return AIR_CAST(float, sgn*DCOS4(x));
387
}
388
389
static void
390
_nrrdDCos4SDN_d(double *f, const double *x, size_t len, const double *parm) {
391
  int sgn;
392
  double t;
393
  size_t i;
394
  AIR_UNUSED(parm);
395
3432846
  for (i=0; i<len; i++) {
396
1566180
    t = x[i];
397
2349270
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
398
3518914
    f[i] = sgn*DCOS4(t);
399
  }
400
100162
}
401
402
static void
403
_nrrdDCos4SDN_f(float *f, const float *x, size_t len, const double *parm) {
404
  int sgn;
405
  float t;
406
  size_t i;
407
  AIR_UNUSED(parm);
408
480006
  for (i=0; i<len; i++) {
409
240000
    t = x[i];
410
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
411
565714
    f[i] = AIR_CAST(float, sgn*DCOS4(t));
412
  }
413
2
}
414
415
static NrrdKernel
416
_nrrdKernelCos4SupportDebugD = {
417
  "cos4supD",
418
  1, _nrrdDCos4SDSup, returnZero,
419
  _nrrdDCos4SD1_f,   _nrrdDCos4SDN_f,   _nrrdDCos4SD1_d,   _nrrdDCos4SDN_d
420
};
421
NrrdKernel *const
422
nrrdKernelCos4SupportDebugD = &_nrrdKernelCos4SupportDebugD;
423
424
/* ------------------------------------------------------------ */
425
426
#define DDCOS4(x) (x > 0.5                                              \
427
                   ? 0.0                                                \
428
                   : -2*AIR_PI*AIR_PI*(cos(AIR_PI*2*x) + cos(AIR_PI*4*x)))
429
430
static double
431
_nrrdDDCos4SDSup(const double *parm) {
432
204
  return parm[0];
433
}
434
435
static double
436
_nrrdDDCos4SD1_d(double x, const double *parm) {
437
  AIR_UNUSED(parm);
438
1440024
  x = AIR_ABS(x);
439
1697170
  return DDCOS4(x);
440
}
441
442
static float
443
_nrrdDDCos4SD1_f(float x, const double *parm) {
444
  AIR_UNUSED(parm);
445
480000
  x = AIR_ABS(x);
446
565714
  return AIR_CAST(float, DDCOS4(x));
447
}
448
449
static void
450
_nrrdDDCos4SDN_d(double *f, const double *x, size_t len, const double *parm) {
451
  size_t i;
452
  AIR_UNUSED(parm);
453
3432846
  for (i=0; i<len; i++) {
454
    double t;
455
1566180
    t = AIR_ABS(x[i]);
456
3518914
    f[i] = DDCOS4(t);
457
  }
458
100162
}
459
460
static void
461
_nrrdDDCos4SDN_f(float *f, const float *x, size_t len, const double *parm) {
462
  size_t i;
463
  AIR_UNUSED(parm);
464
480006
  for (i=0; i<len; i++) {
465
    float t;
466
240000
    t = AIR_ABS(x[i]);
467
565714
    f[i] = AIR_CAST(float, DDCOS4(t));
468
  }
469
2
}
470
471
static NrrdKernel
472
_nrrdKernelCos4SupportDebugDD = {
473
  "cos4supDD",
474
  1, _nrrdDDCos4SDSup, returnZero,
475
  _nrrdDDCos4SD1_f,  _nrrdDDCos4SDN_f,  _nrrdDDCos4SD1_d,  _nrrdDDCos4SDN_d
476
};
477
NrrdKernel *const
478
nrrdKernelCos4SupportDebugDD = &_nrrdKernelCos4SupportDebugDD;
479
480
/* ------------------------------------------------------------ */
481
482
#define DDDCOS4(x) (x > 0.5                                             \
483
                    ? 0.0                                               \
484
                    : 4*AIR_PI*AIR_PI*AIR_PI*(sin(2*AIR_PI*x) + 2*sin(4*AIR_PI*x)))
485
486
static double
487
_nrrdDDDCos4SDSup(const double *parm) {
488
4
  return parm[0];
489
}
490
491
static double
492
_nrrdDDDCos4SD1_d(double x, const double *parm) {
493
  int sgn;
494
  AIR_UNUSED(parm);
495
600030
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
496
565738
  return sgn*DDDCOS4(x);
497
}
498
499
static float
500
_nrrdDDDCos4SD1_f(float x, const double *parm) {
501
  int sgn;
502
  AIR_UNUSED(parm);
503
600000
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
504
565714
  return AIR_CAST(float, sgn*DDDCOS4(x));
505
}
506
507
static void
508
_nrrdDDDCos4SDN_d(double *f, const double *x, size_t len, const double *parm) {
509
  int sgn;
510
  double t;
511
  size_t i;
512
  AIR_UNUSED(parm);
513
480006
  for (i=0; i<len; i++) {
514
240000
    t = x[i];
515
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
516
565714
    f[i] = sgn*DDDCOS4(t);
517
  }
518
2
}
519
520
static void
521
_nrrdDDDCos4SDN_f(float *f, const float *x, size_t len, const double *parm) {
522
  int sgn;
523
  float t;
524
  size_t i;
525
  AIR_UNUSED(parm);
526
480006
  for (i=0; i<len; i++) {
527
240000
    t = x[i];
528
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
529
565714
    f[i] = AIR_CAST(float, sgn*DDDCOS4(t));
530
  }
531
2
}
532
533
static NrrdKernel
534
_nrrdKernelCos4SupportDebugDDD = {
535
  "cos4supDDD",
536
  1, _nrrdDDDCos4SDSup, returnZero,
537
  _nrrdDDDCos4SD1_f, _nrrdDDDCos4SDN_f, _nrrdDDDCos4SD1_d, _nrrdDDDCos4SDN_d
538
};
539
NrrdKernel *const
540
nrrdKernelCos4SupportDebugDDD = &_nrrdKernelCos4SupportDebugDDD;
541
542
/* ------------------------------------------------------------ */
543
544
/* The point here is that post-kernel-evaluation, we need to see
545
   which sample is closest to the origin, and this is one way of
546
   enabling that
547
   SO: this kernel will not usefully report its integral or support! */
548
#define _CHEAP(x) AIR_ABS(x)
549
550
static double
551
_nrrdCheapSup(const double *parm) {
552
  double S;
553
554
4
  S = parm[0];
555
  /* adding the 0.5 is to insure that weights computed within the
556
     support really do catch all the non-zero values */
557
2
  return S/2 + 0.5;
558
}
559
560
static double
561
_nrrdCheap1_d(double x, const double *parm) {
562
563
480004
  return _CHEAP(x)/parm[0];
564
}
565
566
static float
567
_nrrdCheap1_f(float x, const double *parm) {
568
569
480000
  return AIR_CAST(float, _CHEAP(x)/parm[0]);
570
}
571
572
static void
573
_nrrdCheapN_d(double *f, const double *x, size_t len, const double *parm) {
574
  double t;
575
  size_t i;
576
577
480006
  for (i=0; i<len; i++) {
578
240000
    t = x[i];
579
240000
    f[i] = _CHEAP(t)/parm[0];
580
  }
581
2
}
582
583
static void
584
_nrrdCheapN_f(float *f, const float *x, size_t len, const double *parm) {
585
  float t;
586
  size_t i;
587
588
480006
  for (i=0; i<len; i++) {
589
240000
    t = x[i];
590
240000
    f[i] = AIR_CAST(float, _CHEAP(t)/parm[0]);
591
  }
592
2
}
593
594
static NrrdKernel
595
_nrrdKernelCheap = {
596
  "cheap",
597
  1, _nrrdCheapSup, returnOne,
598
  _nrrdCheap1_f,  _nrrdCheapN_f,  _nrrdCheap1_d,  _nrrdCheapN_d
599
};
600
NrrdKernel *const
601
nrrdKernelCheap = &_nrrdKernelCheap;
602
603
/* ------------------------------------------------------------ */
604
605
#define _TENT(x) (x >= 1 ? 0 : 1 - x)
606
607
static double
608
_nrrdTentSup(const double *parm) {
609
  double S;
610
611
12
  S = parm[0];
612
6
  return S;
613
}
614
615
static double
616
_nrrdTent1_d(double x, const double *parm) {
617
  double S;
618
619
480024
  S = parm[0];
620
240012
  x = AIR_ABS(x)/S;
621
720036
  return S ? _TENT(x)/S : x == 0;
622
}
623
624
static float
625
_nrrdTent1_f(float x, const double *parm) {
626
  float S;
627
628
480000
  S = AIR_CAST(float, parm[0]);
629
240000
  x = AIR_ABS(x)/S;
630
720000
  return S ? _TENT(x)/S : x == 0;
631
}
632
633
static void
634
_nrrdTentN_d(double *f, const double *x, size_t len, const double *parm) {
635
  double S;
636
  double t;
637
  size_t i;
638
639
3462
  S = parm[0];
640
504210
  for (i=0; i<len; i++) {
641
250374
    t = x[i]; t = AIR_ABS(t)/S;
642
751122
    f[i] = S ? _TENT(t)/S : t == 0;
643
  }
644
1731
}
645
646
static void
647
_nrrdTentN_f(float *f, const float *x, size_t len, const double *parm) {
648
  float t, S;
649
  size_t i;
650
651
4
  S = AIR_CAST(float, parm[0]);
652
480004
  for (i=0; i<len; i++) {
653
240000
    t = x[i]; t = AIR_ABS(t)/S;
654
720000
    f[i] = S ? _TENT(t)/S : t == 0;
655
  }
656
2
}
657
658
static NrrdKernel
659
_nrrdKernelTent = {
660
  "tent",
661
  1, _nrrdTentSup, returnOne,
662
  _nrrdTent1_f, _nrrdTentN_f, _nrrdTent1_d, _nrrdTentN_d
663
};
664
NrrdKernel *const
665
nrrdKernelTent = &_nrrdKernelTent;
666
667
/* ------------------------------------------------------------ */
668
669
/*
670
** NOTE: THERE IS NOT REALLY A HERMITE KERNEL (at least not yet,
671
** because it takes both values and derivatives as arguments, which
672
** the NrrdKernel currently can't handle).  This isn't really a
673
** kernel, its mostly a flag (hence the name), but it also has the
674
** role of generating weights according to linear interpolation, which
675
** is useful for the eventual spline evaluation.
676
**
677
** This hack is in sinister collusion with gage, to enable Hermite
678
** interpolation for its stack reconstruction.
679
*/
680
681
static double
682
_nrrdHermite1_d(double x, const double *parm) {
683
  AIR_UNUSED(parm);
684
240012
  x = AIR_ABS(x);
685
120006
  return _TENT(x);
686
}
687
688
static float
689
_nrrdHermite1_f(float x, const double *parm) {
690
  AIR_UNUSED(parm);
691
240000
  x = AIR_ABS(x);
692
120000
  return _TENT(x);
693
}
694
695
static void
696
_nrrdHermiteN_d(double *f, const double *x, size_t len, const double *parm) {
697
  double t;
698
  size_t i;
699
  AIR_UNUSED(parm);
700
240003
  for (i=0; i<len; i++) {
701
120000
    t = x[i]; t = AIR_ABS(t);
702
120000
    f[i] = _TENT(t);
703
  }
704
1
}
705
706
static void
707
_nrrdHermiteN_f(float *f, const float *x, size_t len, const double *parm) {
708
  float t;
709
  size_t i;
710
  AIR_UNUSED(parm);
711
240003
  for (i=0; i<len; i++) {
712
120000
    t = x[i]; t = AIR_ABS(t);
713
120000
    f[i] = _TENT(t);
714
  }
715
1
}
716
717
/* HEY: should just re-use fields from nrrdKernelTent, instead
718
   of creating new functions */
719
static NrrdKernel
720
_nrrdKernelHermiteScaleSpaceFlag = {
721
  "hermiteSS",
722
  0, returnOne, returnOne,
723
  _nrrdHermite1_f, _nrrdHermiteN_f, _nrrdHermite1_d, _nrrdHermiteN_d
724
};
725
NrrdKernel *const
726
nrrdKernelHermiteScaleSpaceFlag = &_nrrdKernelHermiteScaleSpaceFlag;
727
728
/* ------------------------------------------------------------ */
729
730
#define _FORDIF(x) (x < -1 ?  0.0f :        \
731
                   (x <  0 ?  1.0f :        \
732
                   (x <  1 ? -1.0f : 0.0f )))
733
734
static double
735
_nrrdFDSup(const double *parm) {
736
  double S;
737
738
8
  S = parm[0];
739
4
  return S+0.0001;  /* sigh */
740
}
741
742
static double
743
_nrrdFD1_d(double x, const double *parm) {
744
  double t, S;
745
746
480024
  S = parm[0];
747
240012
  t = x/S;
748

840027
  return _FORDIF(t)/(S*S);
749
}
750
751
static float
752
_nrrdFD1_f(float x, const double *parm) {
753
  float t, S;
754
755
480000
  S = AIR_CAST(float, parm[0]);
756
240000
  t = x/S;
757

839991
  return _FORDIF(t)/(S*S);
758
}
759
760
static void
761
_nrrdFDN_d(double *f, const double *x, size_t len, const double *parm) {
762
  double t, S;
763
  size_t i;
764
765
3460
  S = parm[0];
766
504196
  for (i=0; i<len; i++) {
767
250368
    t = x[i]/S;
768

876279
    f[i] = _FORDIF(t)/(S*S);
769
  }
770
1730
}
771
772
static void
773
_nrrdFDN_f(float *f, const float *x, size_t len, const double *parm) {
774
  float t, S;
775
  size_t i;
776
777
4
  S = AIR_CAST(float, parm[0]);
778
480004
  for (i=0; i<len; i++) {
779
240000
    t = x[i]/S;
780

839991
    f[i] = _FORDIF(t)/(S*S);
781
  }
782
2
}
783
784
static NrrdKernel
785
_nrrdKernelFD = {
786
  "fordif",
787
  1, _nrrdFDSup, returnZero,
788
  _nrrdFD1_f,   _nrrdFDN_f,   _nrrdFD1_d,   _nrrdFDN_d
789
};
790
NrrdKernel *const
791
nrrdKernelForwDiff = &_nrrdKernelFD;
792
793
/* ------------------------------------------------------------ */
794
795
#define _CENDIF(x) (x <= -2 ?  0         :        \
796
                   (x <= -1 ?  0.5*x + 1 :        \
797
                   (x <=  1 ? -0.5*x     :        \
798
                   (x <=  2 ?  0.5*x - 1 : 0 ))))
799
800
static double
801
_nrrdCDSup(const double *parm) {
802
  double S;
803
804
4
  S = parm[0];
805
2
  return 2*S;
806
}
807
808
static double
809
_nrrdCD1_d(double x, const double *parm) {
810
  double S;
811
812
480024
  S = parm[0];
813
240012
  x /= S;
814


1200042
  return _CENDIF(x)/(S*S);
815
}
816
817
static float
818
_nrrdCD1_f(float x, const double *parm) {
819
  float S;
820
821
480000
  S = AIR_CAST(float, parm[0]);
822
240000
  x /= S;
823


1200000
  return AIR_CAST(float, _CENDIF(x)/(S*S));
824
}
825
826
static void
827
_nrrdCDN_d(double *f, const double *x, size_t len, const double *parm) {
828
  double S;
829
  double t;
830
  size_t i;
831
832
4
  S = parm[0];
833
480004
  for (i=0; i<len; i++) {
834
240000
    t = x[i]/S;
835


1200000
    f[i] = _CENDIF(t)/(S*S);
836
  }
837
2
}
838
839
static void
840
_nrrdCDN_f(float *f, const float *x, size_t len, const double *parm) {
841
  float t, S;
842
  size_t i;
843
844
4
  S = AIR_CAST(float, parm[0]);
845
480004
  for (i=0; i<len; i++) {
846
240000
    t = x[i]/S;
847


1200000
    f[i] = AIR_CAST(float, _CENDIF(t)/(S*S));
848
  }
849
2
}
850
851
static NrrdKernel
852
_nrrdKernelCD = {
853
  "cendif",
854
  1, _nrrdCDSup, returnZero,
855
  _nrrdCD1_f,   _nrrdCDN_f,   _nrrdCD1_d,   _nrrdCDN_d
856
};
857
NrrdKernel *const
858
nrrdKernelCentDiff = &_nrrdKernelCD;
859
860
/* ------------------------------------------------------------ */
861
862
#define _BCCUBIC(x, B, C)                                     \
863
  (x >= 2.0 ? 0 :                                             \
864
  (x >= 1.0                                                   \
865
   ? (((-B/6 - C)*x + B + 5*C)*x -2*B - 8*C)*x + 4*B/3 + 4*C  \
866
   : ((2 - 3*B/2 - C)*x - 3 + 2*B + C)*x*x + 1 - B/3))
867
868
static double
869
_nrrdBCSup(const double *parm) {
870
  double S;
871
872
24
  S = parm[0];
873
12
  return 2*S;
874
}
875
876
static double
877
_nrrdBC1_d(double x, const double *parm) {
878
  double S;
879
  double B, C;
880
881
5760096
  S = parm[0]; B = parm[1]; C = parm[2];
882
2880048
  x = AIR_ABS(x)/S;
883

11520064
  return _BCCUBIC(x, B, C)/S;
884
}
885
886
static float
887
_nrrdBC1_f(float x, const double *parm) {
888
  float B, C, S;
889
890
1920000
  S = AIR_CAST(float, parm[0]);
891
960000
  B = AIR_CAST(float, parm[1]);
892
960000
  C = AIR_CAST(float, parm[2]);
893
960000
  x = AIR_ABS(x)/S;
894

3840000
  return _BCCUBIC(x, B, C)/S;
895
}
896
897
static void
898
_nrrdBCN_d(double *f, const double *x, size_t len, const double *parm) {
899
  double S;
900
  double t, B, C;
901
  size_t i;
902
903
3474
  S = parm[0]; B = parm[1]; C = parm[2];
904
2006442
  for (i=0; i<len; i++) {
905
1001484
    t = x[i];
906
1001484
    t = AIR_ABS(t)/S;
907

4004202
    f[i] = _BCCUBIC(t, B, C)/S;
908
  }
909
1737
}
910
911
static void
912
_nrrdBCN_f(float *f, const float *x, size_t len, const double *parm) {
913
  float S, t, B, C;
914
  size_t i;
915
916
16
  S = AIR_CAST(float, parm[0]);
917
8
  B = AIR_CAST(float, parm[1]);
918
8
  C = AIR_CAST(float, parm[2]);
919
1920016
  for (i=0; i<len; i++) {
920
960000
    t = x[i];
921
960000
    t = AIR_ABS(t)/S;
922

3840000
    f[i] = _BCCUBIC(t, B, C)/S;
923
  }
924
8
}
925
926
static NrrdKernel
927
_nrrdKernelBC = {
928
  "BCcubic",
929
  3, _nrrdBCSup, returnOne,
930
  _nrrdBC1_f,   _nrrdBCN_f,   _nrrdBC1_d,   _nrrdBCN_d
931
};
932
NrrdKernel *const
933
nrrdKernelBCCubic = &_nrrdKernelBC;
934
935
/* ------------------------------------------------------------ */
936
937
#define _DBCCUBIC(x, B, C)                        \
938
   (x >= 2.0 ? 0.0 :                              \
939
   (x >= 1.0                                      \
940
    ? ((-B/2 - 3*C)*x + 2*B + 10*C)*x -2*B - 8*C  \
941
    : ((6 - 9*B/2 - 3*C)*x - 6 + 4*B + 2*C)*x))
942
943
static double
944
_nrrdDBCSup(const double *parm) {
945
  double S;
946
947
20
  S = parm[0];
948
10
  return 2*S;
949
}
950
951
static double
952
_nrrdDBC1_d(double x, const double *parm) {
953
  double S;
954
  double B, C;
955
  int sgn = 1;
956
957
5760096
  S = parm[0]; B = parm[1]; C = parm[2];
958
4320068
  if (x < 0) { x = -x; sgn = -1; }
959
2880048
  x /= S;
960

11520064
  return sgn*_DBCCUBIC(x, B, C)/(S*S);
961
}
962
963
static float
964
_nrrdDBC1_f(float x, const double *parm) {
965
  float B, C, S;
966
  int sgn = 1;
967
968
1920000
  S = AIR_CAST(float, parm[0]);
969
960000
  B = AIR_CAST(float, parm[1]);
970
960000
  C = AIR_CAST(float, parm[2]);
971
1440000
  if (x < 0) { x = -x; sgn = -1; }
972
960000
  x /= S;
973

4800000
  return AIR_CAST(float, sgn*_DBCCUBIC(x, B, C)/(S*S));
974
}
975
976
static void
977
_nrrdDBCN_d(double *f, const double *x, size_t len, const double *parm) {
978
  double S;
979
  double t, B, C;
980
  size_t i;
981
  int sgn;
982
983
3472
  S = parm[0]; B = parm[1]; C = parm[2];
984
2006416
  for (i=0; i<len; i++) {
985
1001472
    t = x[i]/S;
986
1502208
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
987

4004160
    f[i] = sgn*_DBCCUBIC(t, B, C)/(S*S);
988
  }
989
1736
}
990
991
static void
992
_nrrdDBCN_f(float *f, const float *x, size_t len, const double *parm) {
993
  float S, t, B, C;
994
  int sgn;
995
  size_t i;
996
997
16
  S = AIR_CAST(float, parm[0]);
998
8
  B = AIR_CAST(float, parm[1]);
999
8
  C = AIR_CAST(float, parm[2]);
1000
1920016
  for (i=0; i<len; i++) {
1001
960000
    t = x[i]/S;
1002
1440000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1003

4800000
    f[i] = AIR_CAST(float, sgn*_DBCCUBIC(t, B, C)/(S*S));
1004
  }
1005
8
}
1006
1007
static NrrdKernel
1008
_nrrdKernelDBC = {
1009
  "BCcubicD",
1010
  3, _nrrdDBCSup, returnZero,
1011
  _nrrdDBC1_f,  _nrrdDBCN_f,  _nrrdDBC1_d,  _nrrdDBCN_d
1012
};
1013
NrrdKernel *const
1014
nrrdKernelBCCubicD = &_nrrdKernelDBC;
1015
1016
/* ------------------------------------------------------------ */
1017
1018
#define _DDBCCUBIC(x, B, C)                    \
1019
   (x >= 2.0 ? 0 :                             \
1020
   (x >= 1.0                                   \
1021
    ? (-B - 6*C)*x + 2*B + 10*C                \
1022
    : (12 - 9*B - 6*C)*x - 6 + 4*B + 2*C  ))
1023
1024
static double
1025
_nrrdDDBCSup(const double *parm) {
1026
  double S;
1027
1028
20
  S = parm[0];
1029
10
  return 2*S;
1030
}
1031
1032
static double
1033
_nrrdDDBC1_d(double x, const double *parm) {
1034
  double S;
1035
  double B, C;
1036
1037
1920096
  S = parm[0]; B = parm[1]; C = parm[2];
1038
960048
  x = AIR_ABS(x)/S;
1039

3840096
  return _DDBCCUBIC(x, B, C)/(S*S*S);
1040
}
1041
1042
static float
1043
_nrrdDDBC1_f(float x, const double *parm) {
1044
  float B, C, S;
1045
1046
1920000
  S = AIR_CAST(float, parm[0]);
1047
960000
  B = AIR_CAST(float, parm[1]);
1048
960000
  C = AIR_CAST(float, parm[2]);
1049
960000
  x = AIR_ABS(x)/S;
1050

3840000
  return _DDBCCUBIC(x, B, C)/(S*S*S);
1051
}
1052
1053
static void
1054
_nrrdDDBCN_d(double *f, const double *x, size_t len, const double *parm) {
1055
  double S;
1056
  double t, B, C;
1057
  size_t i;
1058
1059
3472
  S = parm[0]; B = parm[1]; C = parm[2];
1060
2006416
  for (i=0; i<len; i++) {
1061
1001472
    t = x[i];
1062
1001472
    t = AIR_ABS(t)/S;
1063

4004160
    f[i] = _DDBCCUBIC(t, B, C)/(S*S*S);
1064
  }
1065
1736
}
1066
1067
static void
1068
_nrrdDDBCN_f(float *f, const float *x, size_t len, const double *parm) {
1069
  float S, t, B, C;
1070
  size_t i;
1071
1072
16
  S = AIR_CAST(float, parm[0]);
1073
8
  B = AIR_CAST(float, parm[1]);
1074
8
  C = AIR_CAST(float, parm[2]);
1075
1920016
  for (i=0; i<len; i++) {
1076
960000
    t = x[i];
1077
960000
    t = AIR_ABS(t)/S;
1078

3840000
    f[i] = _DDBCCUBIC(t, B, C)/(S*S*S);
1079
  }
1080
8
}
1081
1082
static NrrdKernel
1083
_nrrdKernelDDBC = {
1084
  "BCcubicDD",
1085
  3, _nrrdDDBCSup, returnZero,
1086
  _nrrdDDBC1_f, _nrrdDDBCN_f, _nrrdDDBC1_d, _nrrdDDBCN_d
1087
};
1088
NrrdKernel *const
1089
nrrdKernelBCCubicDD = &_nrrdKernelDDBC;
1090
1091
/* ------------------------------------------------------------ */
1092
1093
/* if you've got the definition already, why not use it */
1094
#define _CTMR(x) _BCCUBIC(x, 0.0, 0.5)
1095
1096
static double
1097
_nrrdCTMR1_d(double x, const double *parm) {
1098
  AIR_UNUSED(parm);
1099
2160036
  x = AIR_ABS(x);
1100

4217172
  return _CTMR(x);
1101
}
1102
1103
static float
1104
_nrrdCTMR1_f(float x, const double *parm) {
1105
  AIR_UNUSED(parm);
1106
720000
  x = AIR_ABS(x);
1107

1405716
  return AIR_CAST(float, _CTMR(x));
1108
}
1109
1110
static void
1111
_nrrdCTMRN_d(double *f, const double *x, size_t len, const double *parm) {
1112
  double t;
1113
  size_t i;
1114
  AIR_UNUSED(parm);
1115
4932036
  for (i=0; i<len; i++) {
1116
2325612
    t = x[i];
1117
2325612
    t = AIR_ABS(t);
1118

7583358
    f[i] = _CTMR(t);
1119
  }
1120
93604
}
1121
1122
static void
1123
_nrrdCTMRN_f(float *f, const float *x, size_t len, const double *parm) {
1124
  float t;
1125
  size_t i;
1126
  AIR_UNUSED(parm);
1127
720009
  for (i=0; i<len; i++) {
1128
360000
    t = x[i];
1129
360000
    t = AIR_ABS(t);
1130

1405716
    f[i] = AIR_CAST(float, _CTMR(t));
1131
  }
1132
3
}
1133
1134
static NrrdKernel
1135
_nrrdKernelCatmullRom = {
1136
  "catmull-rom",
1137
  0, returnTwo, returnOne,
1138
  _nrrdCTMR1_f,   _nrrdCTMRN_f,   _nrrdCTMR1_d,   _nrrdCTMRN_d
1139
};
1140
NrrdKernel *const
1141
nrrdKernelCatmullRom = &_nrrdKernelCatmullRom;
1142
1143
1144
static double
1145
_nrrdCtmrSDSup(const double *parm) {
1146
1147
501
  return AIR_MAX(2.0, parm[0]);
1148
}
1149
1150
static NrrdKernel
1151
_nrrdKernelCatmullRomSupportDebug = {
1152
  "ctmrsup",
1153
  1, _nrrdCtmrSDSup, returnOne,
1154
  _nrrdCTMR1_f,   _nrrdCTMRN_f,   _nrrdCTMR1_d,   _nrrdCTMRN_d
1155
};
1156
NrrdKernel *const
1157
nrrdKernelCatmullRomSupportDebug = &_nrrdKernelCatmullRomSupportDebug;
1158
1159
/* ------------------------------------------------------------ */
1160
1161
/* if you've got the definition already, why not use it */
1162
#define _DCTMR(x) _DBCCUBIC(x, 0.0, 0.5)
1163
1164
static double
1165
_nrrdDCTMR1_d(double x, const double *parm) {
1166
  int sgn;
1167
  AIR_UNUSED(parm);
1168
2700044
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
1169

4217172
  return sgn*_DCTMR(x);
1170
}
1171
1172
static float
1173
_nrrdDCTMR1_f(float x, const double *parm) {
1174
  int sgn;
1175
  AIR_UNUSED(parm);
1176
900000
  if (x < 0) { x = -x; sgn = -1; } else { sgn = 1; }
1177

1405716
  return AIR_CAST(float, sgn*_DCTMR(x));
1178
}
1179
1180
static void
1181
_nrrdDCTMRN_d(double *f, const double *x, size_t len, const double *parm) {
1182
  int sgn;
1183
  double t;
1184
  size_t i;
1185
  AIR_UNUSED(parm);
1186
4194909
  for (i=0; i<len; i++) {
1187
1974600
    t = x[i];
1188
2961900
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1189

6600516
    f[i] = sgn*_DCTMR(t);
1190
  }
1191
81903
}
1192
1193
static void
1194
_nrrdDCTMRN_f(float *f, const float *x, size_t len, const double *parm) {
1195
  int sgn;
1196
  float t;
1197
  size_t i;
1198
  AIR_UNUSED(parm);
1199
720009
  for (i=0; i<len; i++) {
1200
360000
    t = x[i];
1201
540000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1202

1405716
    f[i] = AIR_CAST(float, sgn*_DCTMR(t));
1203
  }
1204
3
}
1205
1206
static NrrdKernel
1207
_nrrdKernelCatmullRomD = {
1208
  "catmull-romD",
1209
  0, returnTwo, returnZero,
1210
  _nrrdDCTMR1_f,   _nrrdDCTMRN_f,   _nrrdDCTMR1_d,   _nrrdDCTMRN_d
1211
};
1212
NrrdKernel *const
1213
nrrdKernelCatmullRomD = &_nrrdKernelCatmullRomD;
1214
1215
static NrrdKernel
1216
_nrrdKernelCatmullRomSupportDebugD = {
1217
  "ctmrsupD",
1218
  1, _nrrdCtmrSDSup, returnZero,
1219
  _nrrdDCTMR1_f,   _nrrdDCTMRN_f,   _nrrdDCTMR1_d,   _nrrdDCTMRN_d
1220
};
1221
NrrdKernel *const
1222
nrrdKernelCatmullRomSupportDebugD = &_nrrdKernelCatmullRomSupportDebugD;
1223
1224
/* ------------------------------------------------------------ */
1225
1226
/* if you've got the definition already, why not use it */
1227
#define _DDCTMR(x) _DDBCCUBIC(x, 0.0, 0.5)
1228
1229
static double
1230
_nrrdDDCTMR1_d(double x, const double *parm) {
1231
  AIR_UNUSED(parm);
1232
720036
  x = AIR_ABS(x);
1233

1405752
  return _DDCTMR(x);
1234
}
1235
1236
static float
1237
_nrrdDDCTMR1_f(float x, const double *parm) {
1238
  AIR_UNUSED(parm);
1239
720000
  x = AIR_ABS(x);
1240

1405716
  return AIR_CAST(float, _DDCTMR(x));
1241
}
1242
1243
static void
1244
_nrrdDDCTMRN_d(double *f, const double *x, size_t len, const double *parm) {
1245
  double t;
1246
  size_t i;
1247
  AIR_UNUSED(parm);
1248
4194909
  for (i=0; i<len; i++) {
1249
1974600
    t = x[i];
1250
1974600
    t = AIR_ABS(t);
1251

6600516
    f[i] = _DDCTMR(t);
1252
  }
1253
81903
}
1254
1255
static void
1256
_nrrdDDCTMRN_f(float *f, const float *x, size_t len, const double *parm) {
1257
  float t;
1258
  size_t i;
1259
  AIR_UNUSED(parm);
1260
720009
  for (i=0; i<len; i++) {
1261
360000
    t = x[i];
1262
360000
    t = AIR_ABS(t);
1263

1405716
    f[i] = AIR_CAST(float, _DDCTMR(t));
1264
  }
1265
3
}
1266
1267
static NrrdKernel
1268
_nrrdKernelCatmullRomDD = {
1269
  "catmull-romDD",
1270
  0, returnTwo, returnZero,
1271
  _nrrdDDCTMR1_f,   _nrrdDDCTMRN_f,   _nrrdDDCTMR1_d,   _nrrdDDCTMRN_d
1272
};
1273
NrrdKernel *const
1274
nrrdKernelCatmullRomDD = &_nrrdKernelCatmullRomDD;
1275
1276
static NrrdKernel
1277
_nrrdKernelCatmullRomSupportDebugDD = {
1278
  "ctmrsupDD",
1279
  1, _nrrdCtmrSDSup, returnZero,
1280
  _nrrdDDCTMR1_f,   _nrrdDDCTMRN_f,   _nrrdDDCTMR1_d,   _nrrdDDCTMRN_d
1281
};
1282
NrrdKernel *const
1283
nrrdKernelCatmullRomSupportDebugDD = &_nrrdKernelCatmullRomSupportDebugDD;
1284
1285
/* ------------------------------------------------------------ */
1286
1287
#define _AQUARTIC(x, A) \
1288
   (x >= 3.0 ? 0 :      \
1289
   (x >= 2.0            \
1290
    ? A*(-54 + x*(81 + x*(-45 + x*(11 - x)))) \
1291
    : (x >= 1.0                               \
1292
       ? 4 - 6*A + x*(-10 + 25*A + x*(9 - 33*A                         \
1293
                                 + x*(-3.5 + 17*A + x*(0.5 - 3*A))))   \
1294
       : 1 + x*x*(-3 + 6*A + x*((2.5 - 10*A) + x*(-0.5 + 4*A))))))
1295
1296
static double
1297
_nrrdA4Sup(const double *parm) {
1298
  double S;
1299
1300
8
  S = parm[0];
1301
4
  return 3*S;
1302
}
1303
1304
static double
1305
_nrrdA41_d(double x, const double *parm) {
1306
  double S;
1307
  double A;
1308
1309
2880048
  S = parm[0]; A = parm[1];
1310
1440024
  x = AIR_ABS(x)/S;
1311

6720030
  return _AQUARTIC(x, A)/S;
1312
}
1313
1314
static float
1315
_nrrdA41_f(float x, const double *parm) {
1316
  float A, S;
1317
1318
960000
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1319
480000
  x = AIR_ABS(x)/S;
1320

2240000
  return AIR_CAST(float, _AQUARTIC(x, A)/S);
1321
}
1322
1323
static void
1324
_nrrdA4N_d(double *f, const double *x, size_t len, const double *parm) {
1325
  double S;
1326
  double t, A;
1327
  size_t i;
1328
1329
8
  S = parm[0]; A = parm[1];
1330
960008
  for (i=0; i<len; i++) {
1331
480000
    t = x[i];
1332
480000
    t = AIR_ABS(t)/S;
1333

2240000
    f[i] = _AQUARTIC(t, A)/S;
1334
  }
1335
4
}
1336
1337
static void
1338
_nrrdA4N_f(float *f, const float *x, size_t len, const double *parm) {
1339
  float S, t, A;
1340
  size_t i;
1341
1342
8
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1343
960008
  for (i=0; i<len; i++) {
1344
480000
    t = x[i];
1345
480000
    t = AIR_ABS(t)/S;
1346

2240000
    f[i] = AIR_CAST(float, _AQUARTIC(t, A)/S);
1347
  }
1348
4
}
1349
1350
static NrrdKernel
1351
_nrrdKernelA4 = {
1352
  "Aquartic",
1353
  2, _nrrdA4Sup, returnOne,
1354
  _nrrdA41_f,   _nrrdA4N_f,   _nrrdA41_d,   _nrrdA4N_d
1355
};
1356
NrrdKernel *const
1357
nrrdKernelAQuartic = &_nrrdKernelA4;
1358
1359
/* ------------------------------------------------------------ */
1360
1361
#define _DAQUARTIC(x, A) \
1362
   (x >= 3.0 ? 0 :       \
1363
   (x >= 2.0             \
1364
    ? A*(81 + x*(-90 + x*(33 - 4*x))) \
1365
    : (x >= 1.0                       \
1366
       ? -10 + 25*A + x*(18 - 66*A + x*(-10.5 + 51*A + x*(2 - 12*A))) \
1367
       : x*(-6 + 12*A + x*(7.5 - 30*A + x*(-2 + 16*A))))))
1368
1369
static double
1370
_nrrdDA4Sup(const double *parm) {
1371
  double S;
1372
1373
8
  S = parm[0];
1374
4
  return 3*S;
1375
}
1376
1377
static double
1378
_nrrdDA41_d(double x, const double *parm) {
1379
  double S;
1380
  double A;
1381
  int sgn = 1;
1382
1383
2880048
  S = parm[0]; A = parm[1];
1384
2160036
  if (x < 0) { x = -x; sgn = -1; }
1385
1440024
  x /= S;
1386

6720030
  return sgn*_DAQUARTIC(x, A)/(S*S);
1387
}
1388
1389
static float
1390
_nrrdDA41_f(float x, const double *parm) {
1391
  float A, S;
1392
  int sgn = 1;
1393
1394
960000
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1395
720000
  if (x < 0) { x = -x; sgn = -1; }
1396
480000
  x /= S;
1397

2240000
  return AIR_CAST(float, sgn*_DAQUARTIC(x, A)/(S*S));
1398
}
1399
1400
static void
1401
_nrrdDA4N_d(double *f, const double *x, size_t len, const double *parm) {
1402
  double S;
1403
  double t, A;
1404
  size_t i;
1405
  int sgn;
1406
1407
8
  S = parm[0]; A = parm[1];
1408
960008
  for (i=0; i<len; i++) {
1409
480000
    t = x[i]/S;
1410
720000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1411

2240000
    f[i] = sgn*_DAQUARTIC(t, A)/(S*S);
1412
  }
1413
4
}
1414
1415
static void
1416
_nrrdDA4N_f(float *f, const float *x, size_t len, const double *parm) {
1417
  float S, t, A;
1418
  size_t i;
1419
  int sgn;
1420
1421
8
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1422
960008
  for (i=0; i<len; i++) {
1423
480000
    t = x[i]/S;
1424
720000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1425

2240000
    f[i] = AIR_CAST(float, sgn*_DAQUARTIC(t, A)/(S*S));
1426
  }
1427
4
}
1428
1429
static NrrdKernel
1430
_nrrdKernelDA4 = {
1431
  "AquarticD",
1432
  2, _nrrdDA4Sup, returnZero,
1433
  _nrrdDA41_f,  _nrrdDA4N_f,  _nrrdDA41_d,  _nrrdDA4N_d
1434
};
1435
NrrdKernel *const
1436
nrrdKernelAQuarticD = &_nrrdKernelDA4;
1437
1438
/* ------------------------------------------------------------ */
1439
1440
#define _DDAQUARTIC(x, A) \
1441
   (x >= 3.0 ? 0 :        \
1442
   (x >= 2.0              \
1443
    ? A*(-90 + x*(66 - x*12)) \
1444
    : (x >= 1.0               \
1445
       ? 18 - 66*A + x*(-21 + 102*A + x*(6 - 36*A))   \
1446
       : -6 + 12*A + x*(15 - 60*A + x*(-6 + 48*A)))))
1447
1448
static double
1449
_nrrdDDA4Sup(const double *parm) {
1450
  double S;
1451
1452
8
  S = parm[0];
1453
4
  return 3*S;
1454
}
1455
1456
static double
1457
_nrrdDDA41_d(double x, const double *parm) {
1458
  double S;
1459
  double A;
1460
1461
960048
  S = parm[0]; A = parm[1];
1462
480024
  x = AIR_ABS(x)/S;
1463

2240048
  return _DDAQUARTIC(x, A)/(S*S*S);
1464
}
1465
1466
static float
1467
_nrrdDDA41_f(float x, const double *parm) {
1468
  float S, A;
1469
1470
960000
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1471
480000
  x = AIR_ABS(x)/S;
1472

2240000
  return _DDAQUARTIC(x, A)/(S*S*S);
1473
}
1474
1475
static void
1476
_nrrdDDA4N_d(double *f, const double *x, size_t len, const double *parm) {
1477
  double S;
1478
  double t, A;
1479
  size_t i;
1480
1481
8
  S = parm[0]; A = parm[1];
1482
960008
  for (i=0; i<len; i++) {
1483
480000
    t = x[i];
1484
480000
    t = AIR_ABS(t)/S;
1485

2240000
    f[i] = _DDAQUARTIC(t, A)/(S*S*S);
1486
  }
1487
4
}
1488
1489
static void
1490
_nrrdDDA4N_f(float *f, const float *x, size_t len, const double *parm) {
1491
  float S, t, A;
1492
  size_t i;
1493
1494
8
  S = AIR_CAST(float, parm[0]); A = AIR_CAST(float, parm[1]);
1495
960008
  for (i=0; i<len; i++) {
1496
480000
    t = x[i];
1497
480000
    t = AIR_ABS(t)/S;
1498

2240000
    f[i] = _DDAQUARTIC(t, A)/(S*S*S);
1499
  }
1500
4
}
1501
1502
static NrrdKernel
1503
_nrrdKernelDDA4 = {
1504
  "AquarticDD",
1505
  2, _nrrdDDA4Sup, returnZero,
1506
  _nrrdDDA41_f, _nrrdDDA4N_f, _nrrdDDA41_d, _nrrdDDA4N_d
1507
};
1508
NrrdKernel *const
1509
nrrdKernelAQuarticDD = &_nrrdKernelDDA4;
1510
1511
/* ------------------------------------------------------------ */
1512
1513
/*
1514
** This is the unique, four-sample support, quintic, C^3 kernel, with 1st and
1515
** 3rd derivatives zero at origin, which integrates to unity on [-2,2], which
1516
** exactly reconstructs 0th and 1st order polynomials.  Unfortunately it does
1517
** NOT reconstruct 2nd order polynomials, so its not very useful.  It worse
1518
** than "one step down" from c4hexic (see below), since while its support and
1519
** polynomial power is one less than c4hexic, it cannot reconstruct
1520
** parabolas; c4hexic can reconstruct cubics.
1521
**
1522
** The same kernel is also available as nrrdKernelTMF w/ D,C,A = -1,3,2 ==
1523
** TMF_dn_c3_2ef == "tmf:n,3,2" == nrrdKernelTMF[0][4][2], the only advantage
1524
** here being that you have access to the first and second derivatives of
1525
** this quintic kernel as nrrdKernelC3QuinticD and nrrdKernelC3QuinticDD.
1526
**
1527
** By the way, TMF_d0_c3_3ef == TMF_dn_c3_3ef == "tmf:n,3,3", which can (by
1528
** definition) reconstruct parabolas, has four-sample support, and has
1529
** piecewise polynomial order *seven*
1530
*/
1531
1532
#define _C3QUINTIC(x) \
1533
  (x >= 2.0 ? 0 :                                             \
1534
  (x >= 1.0                                                   \
1535
   ? 0.8 + x*x*(-2 + x*(2 + x*(-0.75 + x*0.1)))               \
1536
   : 0.7 + x*x*(-1 + x*x*(0.75 - x*0.3))))
1537
1538
static double
1539
_c3quint1_d(double x, const double *parm) {
1540
  AIR_UNUSED(parm);
1541
1440024
  x = AIR_ABS(x);
1542

2880016
  return _C3QUINTIC(x);
1543
}
1544
1545
static float
1546
_c3quint1_f(float x, const double *parm) {
1547
  AIR_UNUSED(parm);
1548
480000
  x = AIR_ABS(x);
1549

960000
  return AIR_CAST(float, _C3QUINTIC(x));
1550
}
1551
1552
static void
1553
_c3quintN_d(double *f, const double *x, size_t len, const double *parm) {
1554
  double t;
1555
  size_t i;
1556
  AIR_UNUSED(parm);
1557
480006
  for (i=0; i<len; i++) {
1558
240000
    t = x[i];
1559
240000
    t = AIR_ABS(t);
1560

960000
    f[i] = _C3QUINTIC(t);
1561
  }
1562
2
}
1563
1564
static void
1565
_c3quintN_f(float *f, const float *x, size_t len, const double *parm) {
1566
  float t;
1567
  size_t i;
1568
  AIR_UNUSED(parm);
1569
480006
  for (i=0; i<len; i++) {
1570
240000
    t = x[i];
1571
240000
    t = AIR_ABS(t);
1572

960000
    f[i] = AIR_CAST(float, _C3QUINTIC(t));
1573
  }
1574
2
}
1575
1576
static NrrdKernel
1577
_c3quint = {
1578
  "C3Quintic",
1579
  0, returnTwo, returnOne,
1580
  _c3quint1_f,   _c3quintN_f,   _c3quint1_d,   _c3quintN_d
1581
};
1582
NrrdKernel *const
1583
nrrdKernelC3Quintic = &_c3quint;
1584
1585
/* ------------------------------------------------------------ */
1586
1587
#define _DC3QUINTIC(x) \
1588
  (x >= 2.0 ? 0 :                                             \
1589
  (x >= 1.0                                                   \
1590
   ? x*(-4 + x*(6 + x*(-3 + x*0.5)))                          \
1591
   : x*(-2 + x*x*(3 - x*1.5))))
1592
1593
static double
1594
_Dc3quint1_d(double x, const double *parm) {
1595
  int sgn = 1;
1596
  AIR_UNUSED(parm);
1597
1800030
  if (x < 0) { x = -x; sgn = -1; }
1598

3600012
  return sgn*_DC3QUINTIC(x);
1599
}
1600
1601
static float
1602
_Dc3quint1_f(float x, const double *parm) {
1603
  int sgn = 1;
1604
  AIR_UNUSED(parm);
1605
600000
  if (x < 0) { x = -x; sgn = -1; }
1606

1200000
  return AIR_CAST(float, sgn*_DC3QUINTIC(x));
1607
}
1608
1609
static void
1610
_Dc3quintN_d(double *f, const double *x, size_t len, const double *parm) {
1611
  double t;
1612
  size_t i;
1613
  int sgn;
1614
  AIR_UNUSED(parm);
1615
480006
  for (i=0; i<len; i++) {
1616
240000
    t = x[i];
1617
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1618

1200000
    f[i] = sgn*_DC3QUINTIC(t);
1619
  }
1620
2
}
1621
1622
static void
1623
_Dc3quintN_f(float *f, const float *x, size_t len, const double *parm) {
1624
  float t;
1625
  size_t i;
1626
  int sgn;
1627
  AIR_UNUSED(parm);
1628
480006
  for (i=0; i<len; i++) {
1629
240000
    t = x[i];
1630
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1631

1200000
    f[i] = AIR_CAST(float, sgn*_DC3QUINTIC(t));
1632
  }
1633
2
}
1634
1635
static NrrdKernel
1636
_nrrdKernelDC3Quintic = {
1637
  "C3QuinticD",
1638
  0, returnTwo, returnZero,
1639
  _Dc3quint1_f,  _Dc3quintN_f,  _Dc3quint1_d,  _Dc3quintN_d
1640
};
1641
NrrdKernel *const
1642
nrrdKernelC3QuinticD = &_nrrdKernelDC3Quintic;
1643
1644
/* ------------------------------------------------------------ */
1645
1646
#define _DDC3QUINTIC(x) \
1647
  (x >= 2.0 ? 0 :                                             \
1648
  (x >= 1.0                                                   \
1649
   ? -4 + x*(12 + x*(-9 + x*2))                               \
1650
   : -2 + x*x*(9 - x*6)))
1651
1652
static double
1653
_DDc3quint1_d(double x, const double *parm) {
1654
  AIR_UNUSED(parm);
1655
480024
  x = AIR_ABS(x);
1656

960024
  return _DDC3QUINTIC(x);
1657
}
1658
1659
static float
1660
_DDc3quint1_f(float x, const double *parm) {
1661
  AIR_UNUSED(parm);
1662
480000
  x = AIR_ABS(x);
1663

960000
  return AIR_CAST(float, _DDC3QUINTIC(x));
1664
}
1665
1666
static void
1667
_DDc3quintN_d(double *f, const double *x, size_t len, const double *parm) {
1668
  double t;
1669
  size_t i;
1670
  AIR_UNUSED(parm);
1671
480006
  for (i=0; i<len; i++) {
1672
240000
    t = x[i];
1673
240000
    t = AIR_ABS(t);
1674

960000
    f[i] = _DDC3QUINTIC(t);
1675
  }
1676
2
}
1677
1678
static void
1679
_DDc3quintN_f(float *f, const float *x, size_t len, const double *parm) {
1680
  float t;
1681
  size_t i;
1682
  AIR_UNUSED(parm);
1683
480006
  for (i=0; i<len; i++) {
1684
240000
    t = x[i];
1685
240000
    t = AIR_ABS(t);
1686

960000
    f[i] = AIR_CAST(float, _DDC3QUINTIC(t));
1687
  }
1688
2
}
1689
1690
static NrrdKernel
1691
_DDc3quint = {
1692
  "C3QuinticDD",
1693
  0, returnTwo, returnZero,
1694
  _DDc3quint1_f,   _DDc3quintN_f,   _DDc3quint1_d,   _DDc3quintN_d
1695
};
1696
NrrdKernel *const
1697
nrrdKernelC3QuinticDD = &_DDc3quint;
1698
1699
/* ------------------------------------------------------------ */
1700
1701
/*
1702
** This is the unique, 6-sample support, hexic, C^4 kernel, with 1st and 3rd
1703
** derivatives zero at origin, which integrates to unity on [-3,3], with 3rd
1704
** order Taylor accuracy (errors start showing up when reconstructing 4th
1705
** order polynomials) It doesn't interpolate, but its close, and it rings
1706
** once.
1707
**
1708
** this is awfully close to, but not quite the same as, "tmf:n,3,4" ==
1709
** TMF_dn_c3_4ef == nrrdKernelTMF[0][4][4], which is only C^3 smooth
1710
*/
1711
1712
#define _C4HEXIC(x) \
1713
  (x >= 3.0 \
1714
   ? 0 \
1715
   : (x >= 2.0 \
1716
      ? 1539.0/160.0 + x*(-189.0/8.0 + x*(747.0/32.0 + x*(-12.0 + x*(109.0/32.0 + x*(-61.0/120.0 + x/32.0))))) \
1717
      : (x >= 1.0 \
1718
         ? 3.0/160.0 + x*(35.0/8.0 + x*(-341.0/32.0 + x*(10.0 + x*(-147.0/32.0 + x*(25.0/24.0 - x*3.0/32.0))))) \
1719
         : 69.0/80.0 + x*x*(-23.0/16.0 + x*x*(19.0/16.0 + x*(-7.0/12.0 + x/16.0)))  )))
1720
1721
static double
1722
_c4hex1_d(double x, const double *parm) {
1723
  AIR_UNUSED(parm);
1724
1440024
  x = AIR_ABS(x);
1725

3360012
  return _C4HEXIC(x);
1726
}
1727
1728
static float
1729
_c4hex1_f(float x, const double *parm) {
1730
  AIR_UNUSED(parm);
1731
480000
  x = AIR_ABS(x);
1732

1120000
  return AIR_CAST(float, _C4HEXIC(x));
1733
}
1734
1735
static void
1736
_c4hexN_d(double *f, const double *x, size_t len, const double *parm) {
1737
  double t;
1738
  size_t i;
1739
  AIR_UNUSED(parm);
1740
525441
  for (i=0; i<len; i++) {
1741
260970
    t = x[i];
1742
260970
    t = AIR_ABS(t);
1743

1217860
    f[i] = _C4HEXIC(t);
1744
  }
1745
1167
}
1746
1747
static void
1748
_c4hexN_f(float *f, const float *x, size_t len, const double *parm) {
1749
  float t;
1750
  size_t i;
1751
  AIR_UNUSED(parm);
1752
480006
  for (i=0; i<len; i++) {
1753
240000
    t = x[i];
1754
240000
    t = AIR_ABS(t);
1755

1120000
    f[i] = AIR_CAST(float, _C4HEXIC(t));
1756
  }
1757
2
}
1758
1759
static NrrdKernel
1760
_c4hex = {
1761
  "C4Hexic",
1762
  0, returnThree, returnOne,
1763
  _c4hex1_f,   _c4hexN_f,   _c4hex1_d,   _c4hexN_d
1764
};
1765
NrrdKernel *const
1766
nrrdKernelC4Hexic = &_c4hex;
1767
1768
/* ------------------------------------------------------------ */
1769
1770
#define _DC4HEXIC(x) \
1771
  (x >= 3.0 \
1772
   ? 0 \
1773
   : (x >= 2.0 \
1774
      ? -189.0/8.0 + x*(747.0/16.0 + x*(-36.0 + x*(109.0/8.0 + x*(-61.0/24.0 + x*(3.0/16.0))))) \
1775
      : (x >= 1.0 \
1776
         ? 35.0/8.0 + x*(-341.0/16.0 + x*(30 + x*(-147.0/8.0 + x*(125.0/24.0 + x*(-9.0/16.0))))) \
1777
         : x*(-23.0/8.0 + x*x*(19.0/4.0 + x*(-35.0/12.0 + x*(3.0/8.0))))  )))
1778
1779
static double
1780
_Dc4hex1_d(double x, const double *parm) {
1781
  int sgn = 1;
1782
  AIR_UNUSED(parm);
1783
1800030
  if (x < 0) { x = -x; sgn = -1; }
1784

3360012
  return sgn*_DC4HEXIC(x);
1785
}
1786
1787
static float
1788
_Dc4hex1_f(float x, const double *parm) {
1789
  int sgn = 1;
1790
  AIR_UNUSED(parm);
1791
600000
  if (x < 0) { x = -x; sgn = -1; }
1792

1120000
  return AIR_CAST(float, sgn*_DC4HEXIC(x));
1793
}
1794
1795
static void
1796
_Dc4hexN_d(double *f, const double *x, size_t len, const double *parm) {
1797
  double t;
1798
  size_t i;
1799
  int sgn;
1800
  AIR_UNUSED(parm);
1801
525441
  for (i=0; i<len; i++) {
1802
260970
    t = x[i];
1803
391455
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1804

1217860
    f[i] = sgn*_DC4HEXIC(t);
1805
  }
1806
1167
}
1807
1808
static void
1809
_Dc4hexN_f(float *f, const float *x, size_t len, const double *parm) {
1810
  float t;
1811
  size_t i;
1812
  int sgn;
1813
  AIR_UNUSED(parm);
1814
480006
  for (i=0; i<len; i++) {
1815
240000
    t = x[i];
1816
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1817

1120000
    f[i] = AIR_CAST(float, sgn*_DC4HEXIC(t));
1818
  }
1819
2
}
1820
1821
static NrrdKernel
1822
_nrrdKernelDC4hexic = {
1823
  "C4HexicD",
1824
  0, returnThree, returnZero,
1825
  _Dc4hex1_f,  _Dc4hexN_f,  _Dc4hex1_d,  _Dc4hexN_d
1826
};
1827
NrrdKernel *const
1828
nrrdKernelC4HexicD = &_nrrdKernelDC4hexic;
1829
1830
/* ------------------------------------------------------------ */
1831
1832
#define _DDC4HEXIC(x) \
1833
  (x >= 3.0 \
1834
   ? 0 \
1835
   : (x >= 2.0 \
1836
      ? 747.0/16.0 + x*(-72.0 + x*(327.0/8.0 + x*(-61.0/6.0 + x*15.0/16.0))) \
1837
      : (x >= 1.0 \
1838
         ? -341.0/16.0 + x*(60 + x*(-441.0/8.0 + x*(125.0/6.0 - x*45.0/16.0))) \
1839
         : -23.0/8.0 + x*x*(57.0/4.0 + x*(-35.0/3.0 + x*(15.0/8.0)))  )))
1840
1841
static double
1842
_DDc4hex1_d(double x, const double *parm) {
1843
  AIR_UNUSED(parm);
1844
1440024
  x = AIR_ABS(x);
1845

3360012
  return _DDC4HEXIC(x);
1846
}
1847
1848
static float
1849
_DDc4hex1_f(float x, const double *parm) {
1850
  AIR_UNUSED(parm);
1851
480000
  x = AIR_ABS(x);
1852

1120000
  return AIR_CAST(float, _DDC4HEXIC(x));
1853
}
1854
1855
static void
1856
_DDc4hexN_d(double *f, const double *x, size_t len, const double *parm) {
1857
  double t;
1858
  size_t i;
1859
  AIR_UNUSED(parm);
1860
525441
  for (i=0; i<len; i++) {
1861
260970
    t = x[i];
1862
260970
    t = AIR_ABS(t);
1863

1217860
    f[i] = _DDC4HEXIC(t);
1864
  }
1865
1167
}
1866
1867
static void
1868
_DDc4hexN_f(float *f, const float *x, size_t len, const double *parm) {
1869
  float t;
1870
  size_t i;
1871
  AIR_UNUSED(parm);
1872
480006
  for (i=0; i<len; i++) {
1873
240000
    t = x[i];
1874
240000
    t = AIR_ABS(t);
1875

1120000
    f[i] = AIR_CAST(float, _DDC4HEXIC(t));
1876
  }
1877
2
}
1878
1879
static NrrdKernel
1880
_DDc4hex = {
1881
  "C4HexicDD",
1882
  0, returnThree, returnZero,
1883
  _DDc4hex1_f,   _DDc4hexN_f,   _DDc4hex1_d,   _DDc4hexN_d
1884
};
1885
NrrdKernel *const
1886
nrrdKernelC4HexicDD = &_DDc4hex;
1887
1888
/* ------------------------------------------------------------ */
1889
1890
#define _DDDC4HEXIC(x)                                                  \
1891
  (x >= 3.0                                                             \
1892
   ? 0                                                                  \
1893
   : (x >= 2.0                                                          \
1894
      ? -72.0 + x*(327.0/4.0 + x*(-61.0/2.0 + 15*x/4))                  \
1895
      : (x >= 1.0                                                       \
1896
         ? 60 + x*(-441.0/4.0 + x*(125.0/2.0 - 45*x/4))                 \
1897
         : x*(57.0/2.0  + x*(-35 + 15*x/2))                             \
1898
         )))
1899
1900
static double
1901
_DDDc4hex1_d(double x, const double *parm) {
1902
  int sgn = 1;
1903
  AIR_UNUSED(parm);
1904
600030
  if (x < 0) { x = -x; sgn = -1; }
1905

1120024
  return sgn*_DDDC4HEXIC(x);
1906
}
1907
1908
static float
1909
_DDDc4hex1_f(float x, const double *parm) {
1910
  int sgn = 1;
1911
  AIR_UNUSED(parm);
1912
600000
  if (x < 0) { x = -x; sgn = -1; }
1913

1120000
  return AIR_CAST(float, sgn*_DDDC4HEXIC(x));
1914
}
1915
1916
static void
1917
_DDDc4hexN_d(double *f, const double *x, size_t len, const double *parm) {
1918
  double t;
1919
  size_t i;
1920
  int sgn;
1921
  AIR_UNUSED(parm);
1922
480006
  for (i=0; i<len; i++) {
1923
240000
    t = x[i];
1924
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1925

1120000
    f[i] = sgn*_DDDC4HEXIC(t);
1926
  }
1927
2
}
1928
1929
static void
1930
_DDDc4hexN_f(float *f, const float *x, size_t len, const double *parm) {
1931
  float t;
1932
  size_t i;
1933
  int sgn;
1934
  AIR_UNUSED(parm);
1935
480006
  for (i=0; i<len; i++) {
1936
240000
    t = x[i];
1937
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
1938

1120000
    f[i] = AIR_CAST(float, sgn*_DDDC4HEXIC(t));
1939
  }
1940
2
}
1941
1942
static NrrdKernel
1943
_nrrdKernelDDDC4hexic = {
1944
  "C4HexicDDD",
1945
  0, returnThree, returnZero,
1946
  _DDDc4hex1_f,  _DDDc4hexN_f,  _DDDc4hex1_d,  _DDDc4hexN_d
1947
};
1948
NrrdKernel *const
1949
nrrdKernelC4HexicDDD = &_nrrdKernelDDDC4hexic;
1950
1951
1952
/* ------------- approximate inverse of c4h ------------------------- */
1953
/* see comments around "_bspl3_ANI" in bsplKernel.c */
1954
1955
static double
1956
_c4hex_ANI_kvals[12] = {
1957
  1.1906949847244948336,
1958
  -0.13537708971729194940,
1959
  0.047024535491780434571,
1960
  -0.0088462060502312555095,
1961
  0.0022443498051487024049,
1962
  -0.00048639680369511914410,
1963
  0.00011421848629250278186,
1964
  -0.000025727759438407893986,
1965
  5.9204264168395963454e-6,
1966
  -1.3468552403175349134e-6,
1967
  3.0637649910394681441e-7,
1968
  -5.5762487950611026674e-8};
1969
1970
static double
1971
_c4hex_ANI_sup(const double *parm) {
1972
  AIR_UNUSED(parm);
1973
2
  return 12.5;
1974
}
1975
1976
#define C4HEX_ANI(ret, tmp, x)                  \
1977
  tmp = AIR_CAST(unsigned int, x+0.5);          \
1978
  if (tmp < 12) {                               \
1979
    ret = _c4hex_ANI_kvals[tmp];                \
1980
  } else {                                      \
1981
    ret = 0.0;                                  \
1982
  }
1983
1984
static double
1985
_c4hex_ANI_1d(double x, const double *parm) {
1986
  double ax, r; unsigned int tmp;
1987
  AIR_UNUSED(parm);
1988
240012
  ax = AIR_ABS(x);
1989
230406
  C4HEX_ANI(r, tmp, ax);
1990
120006
  return r;
1991
}
1992
1993
static float
1994
_c4hex_ANI_1f(float x, const double *parm) {
1995
  double ax, r; unsigned int tmp;
1996
  AIR_UNUSED(parm);
1997
240000
  ax = AIR_ABS(x);
1998
230400
  C4HEX_ANI(r, tmp, ax);
1999
120000
  return AIR_CAST(float, r);
2000
}
2001
2002
static void
2003
_c4hex_ANI_Nd(double *f, const double *x, size_t len, const double *parm) {
2004
  double ax, r; unsigned int tmp;
2005
  size_t i;
2006
  AIR_UNUSED(parm);
2007
240003
  for (i=0; i<len; i++) {
2008
120000
    ax = x[i]; ax = AIR_ABS(ax);
2009
230400
    C4HEX_ANI(r, tmp, ax);
2010
120000
    f[i] = r;
2011
  }
2012
1
}
2013
2014
static void
2015
_c4hex_ANI_Nf(float *f, const float *x, size_t len, const double *parm) {
2016
  double ax, r; unsigned int tmp;
2017
  size_t i;
2018
  AIR_UNUSED(parm);
2019
240003
  for (i=0; i<len; i++) {
2020
120000
    ax = x[i]; ax = AIR_ABS(ax);
2021
230400
    C4HEX_ANI(r, tmp, ax);
2022
120000
    f[i] = AIR_CAST(float, r);
2023
  }
2024
1
}
2025
2026
static NrrdKernel
2027
_nrrdKernelC4HexicApproxInverse = {
2028
  "C4HexicAI", 0,
2029
  _c4hex_ANI_sup, returnOne,
2030
  _c4hex_ANI_1f, _c4hex_ANI_Nf,
2031
  _c4hex_ANI_1d, _c4hex_ANI_Nd
2032
};
2033
NrrdKernel *const
2034
nrrdKernelC4HexicApproxInverse = &_nrrdKernelC4HexicApproxInverse;
2035
2036
/* ------------------------- c5septic ------------------------------ */
2037
2038
/*
2039
** This is the unique, 8-sample support, C^5 kernel, piecewise order-7
2040
** with 4th order Taylor accuracy (errors start showing up when
2041
** reconstructing 5th order polynomials).  Coincidentally, it has zero
2042
** 1st and 3rd deriv at the origin, and it integrates to unity on
2043
** [-4,4]. It doesn't interpolate, but its close; it rings twice.  */
2044
2045
#define _C5SEPT0(x) (0.9379776601998824 + x*x*(-1.654320987654321 + x*x*(1.073045267489712 + x*x*(-0.44997427983539096 + x*0.13978909465020575))))
2046
#define _C5SEPT1(x) (0.04651675485008818 + x*(-0.7377829218106996 + x*(0.9699074074074074 + x*(0.18531378600823045 + x*(-0.7839506172839507 + x*(0.2357253086419753 + x*(0.12021604938271604 - x*0.054552469135802466)))))))
2047
#define _C5SEPT2(x) (-0.01860670194003527 + x*(0.14022633744855967 + x*(-0.16296296296296298 + x*(-0.09825102880658436 + x*(0.28858024691358025 + x*(-0.18858024691358025 + x*(0.04405864197530864 - x*0.0013631687242798354)))))))
2048
#define _C5SEPT3(x) (0.003101116990005879 + x*(-0.014223251028806585 + x*(0.02021604938271605 + x*(0.003729423868312757 + x*(-0.0411522633744856 + x*(0.04714506172839506 + x*(-0.023199588477366254 + x*0.004383450911228689)))))))
2049
#define _C5SEPT(i, x)                           \
2050
  (0 == i ? _C5SEPT0(x)                         \
2051
   : (1 == i ? _C5SEPT1(x)                      \
2052
      : (2 == i ? _C5SEPT2(x)                   \
2053
         : (3 == i ? _C5SEPT3(x)                \
2054
            : 0.0))))
2055
2056
static double
2057
_c5sept1_d(double x, const double *parm) {
2058
  unsigned int xi;
2059
  AIR_UNUSED(parm);
2060
1440024
  x = AIR_ABS(x);
2061
720012
  xi = AIR_CAST(unsigned int, x);
2062
720012
  x -= xi;
2063


3240060
  return _C5SEPT(xi, x);
2064
}
2065
2066
static float
2067
_c5sept1_f(float x, const double *parm) {
2068
  unsigned int xi;
2069
  AIR_UNUSED(parm);
2070
480000
  x = AIR_ABS(x);
2071
240000
  xi = AIR_CAST(unsigned int, x);
2072
240000
  x -= AIR_CAST(float, xi);
2073


1080000
  return AIR_CAST(float, _C5SEPT(xi, x));
2074
}
2075
2076
static void
2077
_c5septN_d(double *f, const double *x, size_t len, const double *parm) {
2078
  unsigned int ti;
2079
  double t;
2080
  size_t i;
2081
  AIR_UNUSED(parm);
2082
480006
  for (i=0; i<len; i++) {
2083
240000
    t = x[i];
2084
240000
    t = AIR_ABS(t);
2085
240000
    ti = AIR_CAST(unsigned int, t);
2086
240000
    t -= ti;
2087


1080000
    f[i] = _C5SEPT(ti, t);
2088
  }
2089
2
}
2090
2091
static void
2092
_c5septN_f(float *f, const float *x, size_t len, const double *parm) {
2093
  unsigned int ti;
2094
  float t;
2095
  size_t i;
2096
  AIR_UNUSED(parm);
2097
480006
  for (i=0; i<len; i++) {
2098
240000
    t = x[i];
2099
240000
    t = AIR_ABS(t);
2100
240000
    ti = AIR_CAST(unsigned int, t);
2101
240000
    t -= AIR_CAST(float, ti);
2102


1080000
    f[i] = AIR_CAST(float, _C5SEPT(ti, t));
2103
  }
2104
2
}
2105
2106
static NrrdKernel
2107
_c5sept = {
2108
  "C5Septic",
2109
  0, returnFour, returnOne,
2110
  _c5sept1_f,   _c5septN_f,   _c5sept1_d,   _c5septN_d
2111
};
2112
NrrdKernel *const
2113
nrrdKernelC5Septic = &_c5sept;
2114
2115
#define _DC5SEPT0(x) (x*(-3.308641975308642 + x*x*(4.292181069958848 + x*x*(-2.6998456790123457 + x*0.9785236625514403))))
2116
#define _DC5SEPT1(x) (-0.7377829218106996 + x*(1.9398148148148149 + x*(0.5559413580246914 + x*(-3.1358024691358026 + x*(1.1786265432098766 + x*(0.7212962962962963 - x*0.3818672839506173))))))
2117
#define _DC5SEPT2(x) (0.14022633744855967 + x*(-0.32592592592592595 + x*(-0.29475308641975306 + x*(1.154320987654321 + x*(-0.9429012345679012 + x*(0.26435185185185184 - x*0.009542181069958848))))))
2118
#define _DC5SEPT3(x) (-0.014223251028806585 + x*(0.0404320987654321 + x*(0.011188271604938271 + x*(-0.1646090534979424 + x*(0.2357253086419753 + x*(-0.13919753086419753 + x*0.03068415637860082))))))
2119
#define _DC5SEPT(i, x)                           \
2120
  (0 == i ? _DC5SEPT0(x)                         \
2121
   : (1 == i ? _DC5SEPT1(x)                      \
2122
      : (2 == i ? _DC5SEPT2(x)                   \
2123
         : (3 == i ? _DC5SEPT3(x)                \
2124
            : 0.0))))
2125
2126
static double
2127
_dc5sept1_d(double x, const double *parm) {
2128
  unsigned int xi;
2129
  int sgn = 1;
2130
  AIR_UNUSED(parm);
2131
1800030
  if (x < 0) { x = -x; sgn = -1; }
2132
720012
  xi = AIR_CAST(unsigned int, x);
2133
720012
  x -= xi;
2134


3240060
  return sgn*_DC5SEPT(xi, x);
2135
}
2136
2137
static float
2138
_dc5sept1_f(float x, const double *parm) {
2139
  unsigned int xi;
2140
  int sgn = 1;
2141
  AIR_UNUSED(parm);
2142
600000
  if (x < 0) { x = -x; sgn = -1; }
2143
240000
  xi = AIR_CAST(unsigned int, x);
2144
240000
  x -= AIR_CAST(float, xi);
2145


1080000
  return AIR_CAST(float, sgn*_DC5SEPT(xi, x));
2146
}
2147
2148
static void
2149
_dc5septN_d(double *f, const double *x, size_t len, const double *parm) {
2150
  unsigned int ti;
2151
  double t;
2152
  size_t i;
2153
  int sgn;
2154
  AIR_UNUSED(parm);
2155
480006
  for (i=0; i<len; i++) {
2156
240000
    t = x[i];
2157
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2158
240000
    ti = AIR_CAST(unsigned int, t);
2159
240000
    t -= ti;
2160


1080000
    f[i] = sgn*_DC5SEPT(ti, t);
2161
  }
2162
2
}
2163
2164
static void
2165
_dc5septN_f(float *f, const float *x, size_t len, const double *parm) {
2166
  unsigned int ti;
2167
  float t;
2168
  size_t i;
2169
  int sgn = 1;
2170
  AIR_UNUSED(parm);
2171
480006
  for (i=0; i<len; i++) {
2172
240000
    t = x[i];
2173
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2174
240000
    ti = AIR_CAST(unsigned int, t);
2175
240000
    t -= AIR_CAST(float, ti);
2176


1080000
    f[i] = AIR_CAST(float, sgn*_DC5SEPT(ti, t));
2177
  }
2178
2
}
2179
2180
static NrrdKernel
2181
_dc5sept = {
2182
  "C5SepticD",
2183
  0, returnFour, returnZero,
2184
  _dc5sept1_f,   _dc5septN_f,   _dc5sept1_d,   _dc5septN_d
2185
};
2186
NrrdKernel *const
2187
nrrdKernelC5SepticD = &_dc5sept;
2188
2189
#define _DDC5SEPT0(x) (-3.308641975308642 + x*x*(12.876543209876543 + x*x*(-13.499228395061728 + x*5.871141975308642)))
2190
#define _DDC5SEPT1(x) (1.9398148148148149 + x*(1.1118827160493827 + x*(-9.407407407407407 + x*(4.714506172839506 + x*(3.6064814814814814 - x*2.2912037037037036)))))
2191
#define _DDC5SEPT2(x) (-0.32592592592592595 + x*(-0.5895061728395061 + x*(3.462962962962963 + x*(-3.771604938271605 + x*(1.3217592592592593 - x*0.05725308641975309)))))
2192
#define _DDC5SEPT3(x) (0.0404320987654321 + x*(0.022376543209876542 + x*(-0.49382716049382713 + x*(0.9429012345679012 + x*(-0.6959876543209876 + x*0.18410493827160493)))))
2193
#define _DDC5SEPT(i, x)                           \
2194
  (0 == i ? _DDC5SEPT0(x)                         \
2195
   : (1 == i ? _DDC5SEPT1(x)                      \
2196
      : (2 == i ? _DDC5SEPT2(x)                   \
2197
         : (3 == i ? _DDC5SEPT3(x)                \
2198
            : 0.0))))
2199
2200
static double
2201
_ddc5sept1_d(double x, const double *parm) {
2202
  unsigned int xi;
2203
  AIR_UNUSED(parm);
2204
1440024
  x = AIR_ABS(x);
2205
720012
  xi = AIR_CAST(unsigned int, x);
2206
720012
  x -= xi;
2207


3240060
  return _DDC5SEPT(xi, x);
2208
}
2209
2210
static float
2211
_ddc5sept1_f(float x, const double *parm) {
2212
  unsigned int xi;
2213
  AIR_UNUSED(parm);
2214
480000
  x = AIR_ABS(x);
2215
240000
  xi = AIR_CAST(unsigned int, x);
2216
240000
  x -= AIR_CAST(float, xi);
2217


1080000
  return AIR_CAST(float, _DDC5SEPT(xi, x));
2218
}
2219
2220
static void
2221
_ddc5septN_d(double *f, const double *x, size_t len, const double *parm) {
2222
  unsigned int ti;
2223
  double t;
2224
  size_t i;
2225
  AIR_UNUSED(parm);
2226
480006
  for (i=0; i<len; i++) {
2227
240000
    t = x[i];
2228
240000
    t = AIR_ABS(t);
2229
240000
    ti = AIR_CAST(unsigned int, t);
2230
240000
    t -= ti;
2231


1080000
    f[i] = _DDC5SEPT(ti, t);
2232
  }
2233
2
}
2234
2235
static void
2236
_ddc5septN_f(float *f, const float *x, size_t len, const double *parm) {
2237
  unsigned int ti;
2238
  float t;
2239
  size_t i;
2240
  AIR_UNUSED(parm);
2241
480006
  for (i=0; i<len; i++) {
2242
240000
    t = x[i];
2243
240000
    t = AIR_ABS(t);
2244
240000
    ti = AIR_CAST(unsigned int, t);
2245
240000
    t -= AIR_CAST(float, ti);
2246


1080000
    f[i] = AIR_CAST(float, _DDC5SEPT(ti, t));
2247
  }
2248
2
}
2249
2250
static NrrdKernel
2251
_ddc5sept = {
2252
  "C5SepticDD",
2253
  0, returnFour, returnZero,
2254
  _ddc5sept1_f,   _ddc5septN_f,   _ddc5sept1_d,   _ddc5septN_d
2255
};
2256
NrrdKernel *const
2257
nrrdKernelC5SepticDD = &_ddc5sept;
2258
2259
#define _DDDC5SEPT0(x) (x*(25.75308641975309 + x*x*(-53.99691358024691 + x*29.35570987654321)))
2260
#define _DDDC5SEPT1(x) (1.111882716049383 + x*(-18.81481481481481 + x*(14.14351851851852 + x*(14.42592592592593 - x*11.45601851851852))))
2261
#define _DDDC5SEPT2(x) (-0.5895061728395062 + x*(6.925925925925926 + x*(-11.31481481481481 + x*(5.287037037037037 - x*0.2862654320987654))))
2262
#define _DDDC5SEPT3(x) (0.02237654320987654 + x*(-0.9876543209876543 + x*(2.828703703703704 + x*(-2.783950617283951 + x*0.9205246913580247))))
2263
#define _DDDC5SEPT(i, x)                           \
2264
  (0 == i ? _DDDC5SEPT0(x)                         \
2265
   : (1 == i ? _DDDC5SEPT1(x)                      \
2266
      : (2 == i ? _DDDC5SEPT2(x)                   \
2267
         : (3 == i ? _DDDC5SEPT3(x)                \
2268
            : 0.0))))
2269
2270
static double
2271
_dddc5sept1_d(double x, const double *parm) {
2272
  unsigned int xi;
2273
  int sgn = 1;
2274
  AIR_UNUSED(parm);
2275
600030
  if (x < 0) { x = -x; sgn = -1; }
2276
240012
  xi = AIR_CAST(unsigned int, x);
2277
240012
  x -= xi;
2278


1080060
  return sgn*_DDDC5SEPT(xi, x);
2279
}
2280
2281
static float
2282
_dddc5sept1_f(float x, const double *parm) {
2283
  unsigned int xi;
2284
  int sgn = 1;
2285
  AIR_UNUSED(parm);
2286
600000
  if (x < 0) { x = -x; sgn = -1; }
2287
240000
  xi = AIR_CAST(unsigned int, x);
2288
240000
  x -= AIR_CAST(float, xi);
2289


1080000
  return AIR_CAST(float, sgn*_DDDC5SEPT(xi, x));
2290
}
2291
2292
static void
2293
_dddc5septN_d(double *f, const double *x, size_t len, const double *parm) {
2294
  unsigned int ti;
2295
  double t;
2296
  size_t i;
2297
  int sgn;
2298
  AIR_UNUSED(parm);
2299
480006
  for (i=0; i<len; i++) {
2300
240000
    t = x[i];
2301
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2302
240000
    ti = AIR_CAST(unsigned int, t);
2303
240000
    t -= ti;
2304


1080000
    f[i] = sgn*_DDDC5SEPT(ti, t);
2305
  }
2306
2
}
2307
2308
static void
2309
_dddc5septN_f(float *f, const float *x, size_t len, const double *parm) {
2310
  unsigned int ti;
2311
  float t;
2312
  size_t i;
2313
  int sgn = 1;
2314
  AIR_UNUSED(parm);
2315
480006
  for (i=0; i<len; i++) {
2316
240000
    t = x[i];
2317
360000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2318
240000
    ti = AIR_CAST(unsigned int, t);
2319
240000
    t -= AIR_CAST(float, ti);
2320


1080000
    f[i] = AIR_CAST(float, sgn*_DDDC5SEPT(ti, t));
2321
  }
2322
2
}
2323
2324
static NrrdKernel
2325
_dddc5sept = {
2326
  "C5SepticDDD",
2327
  0, returnFour, returnZero,
2328
  _dddc5sept1_f,   _dddc5septN_f,   _dddc5sept1_d,   _dddc5septN_d
2329
};
2330
NrrdKernel *const
2331
nrrdKernelC5SepticDDD = &_dddc5sept;
2332
2333
/* note that this implies a much more accurate inverse than is given
2334
   for the splines or other kernels; this is a consequence of GLK
2335
   re-purposing the Mathematica expressions for the bpsln7 inverse,
2336
   which is unfortunate: c5septic is nearly interpolating, so far
2337
   fewer terms would suffice */
2338
#define C5SEPT_AI_LEN 26
2339
static double
2340
_c5sept_ANI_kvals[C5SEPT_AI_LEN] = {
2341
  1.072662863909143543451743,
2342
  -0.05572032001443187610952953,
2343
  0.02453993146603215267432700,
2344
  -0.005922375635530229254855750,
2345
  0.0009781882769025851448681918,
2346
  -0.0002499281491108793120774480,
2347
  0.00005196973116762945530292666,
2348
  -0.00001090007030248955413371701,
2349
  2.425581976693179040189747e-6,
2350
  -5.143328756144314306529358e-7,
2351
  1.109572595055083858393193e-7,
2352
  -2.400323559797703961855318e-8,
2353
  5.151959978856239469272136e-9,
2354
  -1.111431289951609447815300e-9,
2355
  2.394624249806782312051293e-10,
2356
  -5.155654818408366273965675e-11,
2357
  1.111091879440261302739584e-11,
2358
  -2.393303168472914213194646e-12,
2359
  5.155527554392687415035171e-13,
2360
  -1.110707782883835600110634e-13,
2361
  2.392644268109899456937863e-14,
2362
  -5.154377464414088544322752e-15,
2363
  1.110376957658466603291262e-15,
2364
  -2.391459139266885907929865e-16,
2365
  5.137528165538909945741180e-17,
2366
  -9.024576392408067896802608e-18};
2367
2368
static double
2369
_c5sept_ANI_sup(const double *parm) {
2370
  AIR_UNUSED(parm);
2371
2
  return C5SEPT_AI_LEN + 0.5;
2372
}
2373
2374
static double
2375
_c5sept_ANI_int(const double *parm) {
2376
  AIR_UNUSED(parm);
2377
2
  return 1.0;
2378
}
2379
2380
#define C5SEPT_ANI(ret, tmp, x)                  \
2381
  tmp = AIR_CAST(unsigned int, x+0.5);           \
2382
  if (tmp < C5SEPT_AI_LEN) {                     \
2383
    ret = _c5sept_ANI_kvals[tmp];                \
2384
  } else {                                       \
2385
    ret = 0.0;                                   \
2386
  }
2387
2388
static double
2389
_c5sept_ANI_1d(double x, const double *parm) {
2390
  double ax, r; unsigned int tmp;
2391
  AIR_UNUSED(parm);
2392
2393
240012
  ax = AIR_ABS(x);
2394
235478
  C5SEPT_ANI(r, tmp, ax);
2395
120006
  return r;
2396
}
2397
2398
static float
2399
_c5sept_ANI_1f(float x, const double *parm) {
2400
  double ax, r; unsigned int tmp;
2401
  AIR_UNUSED(parm);
2402
2403
240000
  ax = AIR_ABS(x);
2404
235472
  C5SEPT_ANI(r, tmp, ax);
2405
120000
  return AIR_CAST(float, r);
2406
}
2407
2408
static void
2409
_c5sept_ANI_Nd(double *f, const double *x, size_t len, const double *parm) {
2410
  double ax, r; unsigned int tmp;
2411
  size_t i;
2412
  AIR_UNUSED(parm);
2413
2414
240003
  for (i=0; i<len; i++) {
2415
120000
    ax = x[i]; ax = AIR_ABS(ax);
2416
235472
    C5SEPT_ANI(r, tmp, ax);
2417
120000
    f[i] = r;
2418
  }
2419
1
}
2420
2421
static void
2422
_c5sept_ANI_Nf(float *f, const float *x, size_t len, const double *parm) {
2423
  double ax, r; unsigned int tmp;
2424
  size_t i;
2425
  AIR_UNUSED(parm);
2426
2427
240003
  for (i=0; i<len; i++) {
2428
120000
    ax = x[i]; ax = AIR_ABS(ax);
2429
235472
    C5SEPT_ANI(r, tmp, ax);
2430
120000
    f[i] = AIR_CAST(float, r);
2431
  }
2432
1
}
2433
2434
static NrrdKernel
2435
_nrrdKernelC5SepticApproxInverse = {
2436
  "C5SepticAI", 0,
2437
  _c5sept_ANI_sup, _c5sept_ANI_int,
2438
  _c5sept_ANI_1f, _c5sept_ANI_Nf,
2439
  _c5sept_ANI_1d, _c5sept_ANI_Nd
2440
};
2441
NrrdKernel *const
2442
nrrdKernelC5SepticApproxInverse = &_nrrdKernelC5SepticApproxInverse;
2443
2444
/* ------------------------------------------------------------ */
2445
2446
#define _GAUSS(x, sig, cut) ( \
2447
   x >= sig*cut ? 0           \
2448
   : exp(-x*x/(2.0*sig*sig))/(sig*2.50662827463100050241))
2449
2450
static double
2451
_nrrdGInt(const double *parm) {
2452
  double cut;
2453
2454
3470
  cut = parm[1];
2455
1735
  return airErf(cut/sqrt(2.0));
2456
}
2457
2458
static double
2459
_nrrdGSup(const double *parm) {
2460
  double sig, cut;
2461
2462
16
  sig = parm[0];
2463
8
  cut = parm[1];
2464
8
  return sig*cut;
2465
}
2466
2467
static double
2468
_nrrdG1_d(double x, const double *parm) {
2469
  double sig, cut;
2470
2471
4320072
  sig = parm[0];
2472
2160036
  cut = parm[1];
2473
2160036
  x = AIR_ABS(x);
2474
6480062
  return _GAUSS(x, sig, cut);
2475
}
2476
2477
static float
2478
_nrrdG1_f(float x, const double *parm) {
2479
  float sig, cut;
2480
2481
1440000
  sig = AIR_CAST(float, parm[0]);
2482
720000
  cut = AIR_CAST(float, parm[1]);
2483
720000
  x = AIR_ABS(x);
2484
2160000
  return AIR_CAST(float, _GAUSS(x, sig, cut));
2485
}
2486
2487
static void
2488
_nrrdGN_d(double *f, const double *x, size_t len, const double *parm) {
2489
  double sig, cut, t;
2490
  size_t i;
2491
2492
3468
  sig = parm[0];
2493
1734
  cut = parm[1];
2494
1567884
  for (i=0; i<len; i++) {
2495
782208
    t = x[i];
2496
782208
    t = AIR_ABS(t);
2497
2345760
    f[i] = _GAUSS(t, sig, cut);
2498
  }
2499
1734
}
2500
2501
static void
2502
_nrrdGN_f(float *f, const float *x, size_t len, const double *parm) {
2503
  float sig, cut, t;
2504
  size_t i;
2505
2506
12
  sig = AIR_CAST(float, parm[0]);
2507
6
  cut = AIR_CAST(float, parm[1]);
2508
1440012
  for (i=0; i<len; i++) {
2509
720000
    t = x[i];
2510
720000
    t = AIR_ABS(t);
2511
2160000
    f[i] = AIR_CAST(float, _GAUSS(t, sig, cut));
2512
  }
2513
6
}
2514
2515
static NrrdKernel
2516
_nrrdKernelG = {
2517
  "gauss",
2518
  2, _nrrdGSup,  _nrrdGInt,
2519
  _nrrdG1_f,   _nrrdGN_f,   _nrrdG1_d,   _nrrdGN_d
2520
};
2521
NrrdKernel *const
2522
nrrdKernelGaussian = &_nrrdKernelG;
2523
2524
/* ------------------------------------------------------------ */
2525
2526
#define _DISCRETEGAUSS(xx, sig, abscut)                         \
2527
  (sig > 0                                                      \
2528
   ? (xx > abscut                                               \
2529
      ? 0                                                       \
2530
      : airBesselInExpScaled(AIR_CAST(int, xx + 0.5), sig*sig)) \
2531
   : xx <= 0.5)
2532
2533
/* the last line used to be AIR_MAX(0.5, (ret)), but the problem was
2534
   that even for reasonable cutoffs, like sigma=6, there would be a
2535
   sudden change in the non-zero values at the edge of the kernel with
2536
   slowly increasing sigma. The real solution is to have a smarter way
2537
   of determining where to cut-off this particular kernel, the
2538
   discrete gaussian, when the values are at the low level one would
2539
   expect with "sigma=6" when talking about a continuous Gaussian */
2540
#define _DGABSCUT(ret, sig, cut) \
2541
  (ret) = 0.5 + ceil((sig)*(cut));  \
2542
  (ret) = AIR_MAX(2.5, (ret))
2543
2544
static double
2545
_nrrdDiscGaussianSup(const double *parm) {
2546
  double ret;
2547
2548
12
  _DGABSCUT(ret, parm[0], parm[1]);
2549
6
  return ret;
2550
}
2551
2552
/* the functions are out of their usual definition order because we
2553
   use the function evaluation to determine the integral, rather than
2554
   trying to do it analytically */
2555
2556
static double
2557
_nrrdDiscGaussian1_d(double xx, const double *parm) {
2558
  double sig, cut;
2559
2560
1440204
  sig = parm[0];
2561
720102
  _DGABSCUT(cut, sig, parm[1]);
2562
720102
  xx = AIR_ABS(xx);
2563

2880372
  return _DISCRETEGAUSS(xx, sig, cut);
2564
}
2565
2566
static double
2567
_nrrdDiscGaussianInt(const double *parm) {
2568
  double sum, cut;
2569
  int ii, supp;
2570
2571
12
  _DGABSCUT(cut, parm[0], parm[1]);
2572
6
  supp = AIR_CAST(int, cut);
2573
  sum = 0.0;
2574
144
  for (ii=-supp; ii<=supp; ii++) {
2575
66
    sum += _nrrdDiscGaussian1_d(ii, parm);
2576
  }
2577
6
  return sum;
2578
}
2579
2580
static float
2581
_nrrdDiscGaussian1_f(float xx, const double *parm) {
2582
  double sig, cut;
2583
2584
1440000
  sig = parm[0];
2585
720000
  _DGABSCUT(cut, sig, parm[1]);
2586
720000
  xx = AIR_ABS(xx);
2587

2880000
  return AIR_CAST(float, _DISCRETEGAUSS(xx, sig, cut));
2588
}
2589
2590
static void
2591
_nrrdDiscGaussianN_d(double *f, const double *x,
2592
                  size_t len, const double *parm) {
2593
  double sig, cut, tt;
2594
  size_t ii;
2595
2596
12
  sig = parm[0];
2597
6
  _DGABSCUT(cut, sig, parm[1]);
2598
1440012
  for (ii=0; ii<len; ii++) {
2599
720000
    tt = AIR_ABS(x[ii]);
2600

2880000
    f[ii] = _DISCRETEGAUSS(tt, sig, cut);
2601
  }
2602
6
}
2603
2604
static void
2605
_nrrdDiscGaussianN_f(float *f, const float *x, size_t len, const double *parm) {
2606
  double sig, cut, tt;
2607
  size_t ii;
2608
2609
12
  sig = parm[0];
2610
6
  _DGABSCUT(cut, sig, parm[1]);
2611
1440012
  for (ii=0; ii<len; ii++) {
2612
720000
    tt = AIR_ABS(x[ii]);
2613

2880000
    f[ii] = AIR_CAST(float, _DISCRETEGAUSS(tt, sig, cut));
2614
  }
2615
6
}
2616
2617
static NrrdKernel
2618
_nrrdKernelDiscreteGaussian = {
2619
  "discretegauss", 2,
2620
  _nrrdDiscGaussianSup,  _nrrdDiscGaussianInt,
2621
  _nrrdDiscGaussian1_f, _nrrdDiscGaussianN_f,
2622
  _nrrdDiscGaussian1_d, _nrrdDiscGaussianN_d
2623
};
2624
NrrdKernel *const
2625
nrrdKernelDiscreteGaussian = &_nrrdKernelDiscreteGaussian;
2626
2627
/* The current implementation of nrrdKernelDiscreteGaussian, with the current
2628
   implementation of airBesselInExpScaled, has problems for large
2629
   sigma. Until those are fixed, this is a suggested limit on how big sigma
2630
   (kparm[0]) can be and still have an accurate blurring kernel.  This
2631
   problem can be avoided completely by doing the blurring in frequency
2632
   space, which is implemented in teem/src/gage/stackBlur.c's
2633
   _stackBlurDiscreteGaussFFT(), although that has its own problem: in places
2634
   where a signal really should zero, the FFT can produce some very
2635
   low-amplitude noise (and hence new extrema) */
2636
const double nrrdKernelDiscreteGaussianGoodSigmaMax = 6.0;
2637
2638
/* ------------------------------------------------------------ */
2639
2640
#define _DGAUSS(x, sig, cut) (                                               \
2641
   x >= sig*cut ? 0                                                          \
2642
   : -exp(-x*x/(2.0*sig*sig))*x/(sig*sig*sig*2.50662827463100050241))
2643
2644
static double
2645
_nrrdDGInt(const double *parm) {
2646
  AIR_UNUSED(parm);
2647
14
  return 0;
2648
}
2649
2650
static double
2651
_nrrdDGSup(const double *parm) {
2652
  double sig, cut;
2653
2654
16
  sig = parm[0];
2655
8
  cut = parm[1];
2656
8
  return sig*cut;
2657
}
2658
2659
static double
2660
_nrrdDG1_d(double x, const double *parm) {
2661
  double sig, cut;
2662
  int sgn = 1;
2663
2664
4320072
  sig = parm[0];
2665
2160036
  cut = parm[1];
2666
3240054
  if (x < 0) { x = -x; sgn = -1; }
2667
6480062
  return sgn*_DGAUSS(x, sig, cut);
2668
}
2669
2670
static float
2671
_nrrdDG1_f(float x, const double *parm) {
2672
  float sig, cut;
2673
  int sgn = 1;
2674
2675
1440000
  sig = AIR_CAST(float, parm[0]);
2676
720000
  cut = AIR_CAST(float, parm[1]);
2677
1080000
  if (x < 0) { x = -x; sgn = -1; }
2678
2160000
  return AIR_CAST(float, sgn*_DGAUSS(x, sig, cut));
2679
}
2680
2681
static void
2682
_nrrdDGN_d(double *f, const double *x, size_t len, const double *parm) {
2683
  double sig, cut, t;
2684
  size_t i;
2685
  int sgn;
2686
2687
3468
  sig = parm[0];
2688
1734
  cut = parm[1];
2689
1567884
  for (i=0; i<len; i++) {
2690
782208
    t = x[i];
2691
1173312
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2692
2345760
    f[i] = sgn*_DGAUSS(t, sig, cut);
2693
  }
2694
1734
}
2695
2696
static void
2697
_nrrdDGN_f(float *f, const float *x, size_t len, const double *parm) {
2698
  float sig, cut, t;
2699
  size_t i;
2700
  int sgn;
2701
2702
12
  sig = AIR_CAST(float, parm[0]);
2703
6
  cut = AIR_CAST(float, parm[1]);
2704
1440012
  for (i=0; i<len; i++) {
2705
720000
    t = x[i];
2706
1080000
    if (t < 0) { t = -t; sgn = -1; } else { sgn = 1; }
2707
2160000
    f[i] = AIR_CAST(float, sgn*_DGAUSS(t, sig, cut));
2708
  }
2709
6
}
2710
2711
static NrrdKernel
2712
_nrrdKernelDG = {
2713
  "gaussD",
2714
  2, _nrrdDGSup,  _nrrdDGInt,
2715
  _nrrdDG1_f,   _nrrdDGN_f,   _nrrdDG1_d,   _nrrdDGN_d
2716
};
2717
NrrdKernel *const
2718
nrrdKernelGaussianD = &_nrrdKernelDG;
2719
2720
/* ------------------------------------------------------------ */
2721
2722
#define _DDGAUSS(x, sig, cut) ( \
2723
   x >= sig*cut ? 0             \
2724
   : exp(-x*x/(2.0*sig*sig))*(x*x-sig*sig) /       \
2725
     (sig*sig*sig*sig*sig*2.50662827463100050241))
2726
2727
static double
2728
_nrrdDDGInt(const double *parm) {
2729
  double sig, cut;
2730
2731
14
  sig = parm[0];
2732
7
  cut = parm[1];
2733
7
  return -0.79788456080286535587*cut*exp(-cut*cut/2)/(sig*sig);
2734
}
2735
2736
static double
2737
_nrrdDDGSup(const double *parm) {
2738
  double sig, cut;
2739
2740
16
  sig = parm[0];
2741
8
  cut = parm[1];
2742
8
  return sig*cut;
2743
}
2744
2745
static double
2746
_nrrdDDG1_d(double x, const double *parm) {
2747
  double sig, cut;
2748
2749
1440072
  sig = parm[0];
2750
720036
  cut = parm[1];
2751
720036
  x = AIR_ABS(x);
2752
2160072
  return _DDGAUSS(x, sig, cut);
2753
}
2754
2755
static float
2756
_nrrdDDG1_f(float x, const double *parm) {
2757
  float sig, cut;
2758
2759
1440000
  sig = AIR_CAST(float, parm[0]);
2760
720000
  cut = AIR_CAST(float, parm[1]);
2761
720000
  x = AIR_ABS(x);
2762
2160000
  return AIR_CAST(float, _DDGAUSS(x, sig, cut));
2763
}
2764
2765
static void
2766
_nrrdDDGN_d(double *f, const double *x, size_t len, const double *parm) {
2767
  double sig, cut, t;
2768
  size_t i;
2769
2770
3468
  sig = parm[0];
2771
1734
  cut = parm[1];
2772
1567884
  for (i=0; i<len; i++) {
2773
782208
    t = x[i];
2774
782208
    t = AIR_ABS(t);
2775
2345760
    f[i] = _DDGAUSS(t, sig, cut);
2776
  }
2777
1734
}
2778
2779
static void
2780
_nrrdDDGN_f(float *f, const float *x, size_t len, const double *parm) {
2781
  float sig, cut, t;
2782
  size_t i;
2783
2784
12
  sig = AIR_CAST(float, parm[0]);
2785
6
  cut = AIR_CAST(float, parm[1]);
2786
1440012
  for (i=0; i<len; i++) {
2787
720000
    t = x[i];
2788
720000
    t = AIR_ABS(t);
2789
2160000
    f[i] = AIR_CAST(float, _DDGAUSS(t, sig, cut));
2790
  }
2791
6
}
2792
2793
static NrrdKernel
2794
_nrrdKernelDDG = {
2795
  "gaussDD",
2796
  2, _nrrdDDGSup,  _nrrdDDGInt,
2797
  _nrrdDDG1_f,   _nrrdDDGN_f,   _nrrdDDG1_d,   _nrrdDDGN_d
2798
};
2799
NrrdKernel *const
2800
nrrdKernelGaussianDD = &_nrrdKernelDDG;
2801
2802
2803
/* ------------------------------------------------------------ */
2804
2805
NrrdKernel *
2806
_nrrdKernelStrToKern(char *str) {
2807
2808
744
  if (!strcmp("zero", str))       return nrrdKernelZero;
2809
370
  if (!strcmp("box", str))        return nrrdKernelBox;
2810
366
  if (!strcmp("boxsup", str))     return nrrdKernelBoxSupportDebug;
2811
362
  if (!strcmp("cos4sup", str))    return nrrdKernelCos4SupportDebug;
2812
358
  if (!strcmp("cos4supd", str))   return nrrdKernelCos4SupportDebugD;
2813
354
  if (!strcmp("cos4supdd", str))  return nrrdKernelCos4SupportDebugDD;
2814
350
  if (!strcmp("cos4supddd", str)) return nrrdKernelCos4SupportDebugDDD;
2815
346
  if (!strcmp("cheap", str))      return nrrdKernelCheap;
2816
338
  if (!strcmp("hermiteflag", str))    return nrrdKernelHermiteScaleSpaceFlag;
2817
338
  if (!strcmp("hermite", str))    return nrrdKernelHermiteScaleSpaceFlag;
2818
340
  if (!strcmp("hermitess", str))    return nrrdKernelHermiteScaleSpaceFlag;
2819
336
  if (!strcmp("herm", str))       return nrrdKernelHermiteScaleSpaceFlag;
2820
340
  if (!strcmp("tent", str))       return nrrdKernelTent;
2821
332
  if (!strcmp("tentd", str))      return nrrdKernelForwDiff;
2822
332
  if (!strcmp("forwdiff", str))   return nrrdKernelForwDiff;
2823
336
  if (!strcmp("fordif", str))     return nrrdKernelForwDiff;
2824
328
  if (!strcmp("centdiff", str))   return nrrdKernelCentDiff;
2825
332
  if (!strcmp("cendif", str))     return nrrdKernelCentDiff;
2826
340
  if (!strcmp("bccubic", str))    return nrrdKernelBCCubic;
2827
308
  if (!strcmp("cubic", str))      return nrrdKernelBCCubic;
2828
324
  if (!strcmp("bccubicd", str))   return nrrdKernelBCCubicD;
2829
292
  if (!strcmp("cubicd", str))     return nrrdKernelBCCubicD;
2830
308
  if (!strcmp("bccubicdd", str))  return nrrdKernelBCCubicDD;
2831
276
  if (!strcmp("cubicdd", str))    return nrrdKernelBCCubicDD;
2832
276
  if (!strcmp("ctmr", str))       return nrrdKernelCatmullRom;
2833
278
  if (!strcmp("catmull-rom", str)) return nrrdKernelCatmullRom;
2834
274
  if (!strcmp("ctmrd", str))       return nrrdKernelCatmullRomD;
2835
276
  if (!strcmp("catmull-romd", str)) return nrrdKernelCatmullRomD;
2836
272
  if (!strcmp("ctmrdd", str))     return nrrdKernelCatmullRomDD;
2837
274
  if (!strcmp("catmull-romdd", str)) return nrrdKernelCatmullRomDD;
2838
274
  if (!strcmp("ctmrsup", str))    return nrrdKernelCatmullRomSupportDebug;
2839
270
  if (!strcmp("ctmrsupd", str))   return nrrdKernelCatmullRomSupportDebugD;
2840
266
  if (!strcmp("ctmrsupdd", str))   return nrrdKernelCatmullRomSupportDebugDD;
2841
266
  if (!strcmp("aquartic", str))   return nrrdKernelAQuartic;
2842
250
  if (!strcmp("quartic", str))    return nrrdKernelAQuartic;
2843
258
  if (!strcmp("aquarticd", str))  return nrrdKernelAQuarticD;
2844
242
  if (!strcmp("quarticd", str))   return nrrdKernelAQuarticD;
2845
250
  if (!strcmp("aquarticdd", str)) return nrrdKernelAQuarticDD;
2846
234
  if (!strcmp("quarticdd", str))  return nrrdKernelAQuarticDD;
2847
238
  if (!strcmp("c3quintic", str))  return nrrdKernelC3Quintic;
2848
230
  if (!strcmp("c3q", str))        return nrrdKernelC3Quintic;
2849
234
  if (!strcmp("c3quinticd", str)) return nrrdKernelC3QuinticD;
2850
226
  if (!strcmp("c3qd", str))       return nrrdKernelC3QuinticD;
2851
230
  if (!strcmp("c3quinticdd", str)) return nrrdKernelC3QuinticDD;
2852
222
  if (!strcmp("c3qdd", str))      return nrrdKernelC3QuinticDD;
2853
226
  if (!strcmp("c4hexic", str))    return nrrdKernelC4Hexic;
2854
218
  if (!strcmp("c4hai", str))      return nrrdKernelC4HexicApproxInverse;
2855
220
  if (!strcmp("c4hexicai", str))  return nrrdKernelC4HexicApproxInverse;
2856
216
  if (!strcmp("c4h", str))        return nrrdKernelC4Hexic;
2857
220
  if (!strcmp("c4hexicd", str))   return nrrdKernelC4HexicD;
2858
212
  if (!strcmp("c4hd", str))       return nrrdKernelC4HexicD;
2859
216
  if (!strcmp("c4hexicdd", str))  return nrrdKernelC4HexicDD;
2860
208
  if (!strcmp("c4hdd", str))      return nrrdKernelC4HexicDD;
2861
212
  if (!strcmp("c4hexicddd", str)) return nrrdKernelC4HexicDDD;
2862
204
  if (!strcmp("c4hddd", str))     return nrrdKernelC4HexicDDD;
2863
208
  if (!strcmp("c5septic", str))   return nrrdKernelC5Septic;
2864
204
  if (!strcmp("c5septicd", str))  return nrrdKernelC5SepticD;
2865
200
  if (!strcmp("c5septicdd", str)) return nrrdKernelC5SepticDD;
2866
196
  if (!strcmp("c5septicddd", str))return nrrdKernelC5SepticDDD;
2867
190
  if (!strcmp("c5septicai", str)) return nrrdKernelC5SepticApproxInverse;
2868
186
  if (!strcmp("gaussian", str))   return nrrdKernelGaussian;
2869
198
  if (!strcmp("gauss", str))      return nrrdKernelGaussian;
2870
174
  if (!strcmp("gaussiand", str))  return nrrdKernelGaussianD;
2871
186
  if (!strcmp("gaussd", str))     return nrrdKernelGaussianD;
2872
162
  if (!strcmp("gd", str))         return nrrdKernelGaussianD;
2873
162
  if (!strcmp("gaussiandd", str)) return nrrdKernelGaussianDD;
2874
174
  if (!strcmp("gaussdd", str))    return nrrdKernelGaussianDD;
2875
150
  if (!strcmp("gdd", str))        return nrrdKernelGaussianDD;
2876
150
  if (!strcmp("ds", str))         return nrrdKernelDiscreteGaussian;
2877
150
  if (!strcmp("dscale", str))     return nrrdKernelDiscreteGaussian;
2878
159
  if (!strcmp("dg", str))         return nrrdKernelDiscreteGaussian;
2879
141
  if (!strcmp("dgauss", str))     return nrrdKernelDiscreteGaussian;
2880
141
  if (!strcmp("dgaussian", str))  return nrrdKernelDiscreteGaussian;
2881
153
  if (!strcmp("discretegauss", str))  return nrrdKernelDiscreteGaussian;
2882
141
  if (!strcmp("hann", str))       return nrrdKernelHann;
2883
129
  if (!strcmp("hannd", str))      return nrrdKernelHannD;
2884
117
  if (!strcmp("hanndd", str))     return nrrdKernelHannDD;
2885
93
  if (!strcmp("bkmn", str))       return nrrdKernelBlackman;
2886
93
  if (!strcmp("black", str))      return nrrdKernelBlackman;
2887
105
  if (!strcmp("blackman", str))   return nrrdKernelBlackman;
2888
81
  if (!strcmp("bkmnd", str))      return nrrdKernelBlackmanD;
2889
81
  if (!strcmp("blackd", str))     return nrrdKernelBlackmanD;
2890
93
  if (!strcmp("blackmand", str))  return nrrdKernelBlackmanD;
2891
69
  if (!strcmp("bkmndd", str))     return nrrdKernelBlackmanDD;
2892
69
  if (!strcmp("blackdd", str))    return nrrdKernelBlackmanDD;
2893
81
  if (!strcmp("blackmandd", str)) return nrrdKernelBlackmanDD;
2894
59
  if (!strcmp("bspl1", str))      return nrrdKernelBSpline1;
2895
55
  if (!strcmp("bspln1", str))     return nrrdKernelBSpline1;
2896
57
  if (!strcmp("bspl1d", str))     return nrrdKernelBSpline1D;
2897
53
  if (!strcmp("bspln1d", str))    return nrrdKernelBSpline1D;
2898
55
  if (!strcmp("bspl2", str))      return nrrdKernelBSpline2;
2899
51
  if (!strcmp("bspln2", str))     return nrrdKernelBSpline2;
2900
53
  if (!strcmp("bspl2d", str))     return nrrdKernelBSpline2D;
2901
49
  if (!strcmp("bspln2d", str))    return nrrdKernelBSpline2D;
2902
51
  if (!strcmp("bspl2dd", str))    return nrrdKernelBSpline2DD;
2903
47
  if (!strcmp("bspln2dd", str))   return nrrdKernelBSpline2DD;
2904
49
  if (!strcmp("bspl3", str))      return nrrdKernelBSpline3;
2905
45
  if (!strcmp("bspln3", str))     return nrrdKernelBSpline3;
2906
47
  if (!strcmp("bspl3ai", str))    return nrrdKernelBSpline3ApproxInverse;
2907
43
  if (!strcmp("bspln3ai", str))   return nrrdKernelBSpline3ApproxInverse;
2908
45
  if (!strcmp("bspl3d", str))     return nrrdKernelBSpline3D;
2909
41
  if (!strcmp("bspln3d", str))    return nrrdKernelBSpline3D;
2910
43
  if (!strcmp("bspl3dd", str))    return nrrdKernelBSpline3DD;
2911
39
  if (!strcmp("bspln3dd", str))   return nrrdKernelBSpline3DD;
2912
41
  if (!strcmp("bspl3ddd", str))   return nrrdKernelBSpline3DDD;
2913
37
  if (!strcmp("bspln3ddd", str))  return nrrdKernelBSpline3DDD;
2914
39
  if (!strcmp("bspl4", str))      return nrrdKernelBSpline4;
2915
35
  if (!strcmp("bspln4", str))     return nrrdKernelBSpline4;
2916
37
  if (!strcmp("bspl4d", str))     return nrrdKernelBSpline4D;
2917
33
  if (!strcmp("bspln4d", str))    return nrrdKernelBSpline4D;
2918
35
  if (!strcmp("bspl4dd", str))    return nrrdKernelBSpline4DD;
2919
31
  if (!strcmp("bspln4dd", str))   return nrrdKernelBSpline4DD;
2920
33
  if (!strcmp("bspl4ddd", str))   return nrrdKernelBSpline4DDD;
2921
29
  if (!strcmp("bspln4ddd", str))  return nrrdKernelBSpline4DDD;
2922
31
  if (!strcmp("bspl5", str))      return nrrdKernelBSpline5;
2923
27
  if (!strcmp("bspln5", str))     return nrrdKernelBSpline5;
2924
29
  if (!strcmp("bspl5ai", str))    return nrrdKernelBSpline5ApproxInverse;
2925
25
  if (!strcmp("bspln5ai", str))   return nrrdKernelBSpline5ApproxInverse;
2926
27
  if (!strcmp("bspl5d", str))     return nrrdKernelBSpline5D;
2927
23
  if (!strcmp("bspln5d", str))    return nrrdKernelBSpline5D;
2928
25
  if (!strcmp("bspl5dd", str))    return nrrdKernelBSpline5DD;
2929
21
  if (!strcmp("bspln5dd", str))   return nrrdKernelBSpline5DD;
2930
23
  if (!strcmp("bspl5ddd", str))   return nrrdKernelBSpline5DDD;
2931
19
  if (!strcmp("bspln5ddd", str))  return nrrdKernelBSpline5DDD;
2932
21
  if (!strcmp("bspl6", str))      return nrrdKernelBSpline6;
2933
17
  if (!strcmp("bspln6", str))     return nrrdKernelBSpline6;
2934
19
  if (!strcmp("bspl6d", str))     return nrrdKernelBSpline6D;
2935
15
  if (!strcmp("bspln6d", str))    return nrrdKernelBSpline6D;
2936
17
  if (!strcmp("bspl6dd", str))    return nrrdKernelBSpline6DD;
2937
13
  if (!strcmp("bspln6dd", str))   return nrrdKernelBSpline6DD;
2938
15
  if (!strcmp("bspl6ddd", str))   return nrrdKernelBSpline6DDD;
2939
11
  if (!strcmp("bspln6ddd", str))  return nrrdKernelBSpline6DDD;
2940
13
  if (!strcmp("bspl7", str))      return nrrdKernelBSpline7;
2941
9
  if (!strcmp("bspln7", str))     return nrrdKernelBSpline7;
2942
11
  if (!strcmp("bspl7ai", str))    return nrrdKernelBSpline7ApproxInverse;
2943
7
  if (!strcmp("bspln7ai", str))   return nrrdKernelBSpline7ApproxInverse;
2944
9
  if (!strcmp("bspl7d", str))     return nrrdKernelBSpline7D;
2945
5
  if (!strcmp("bspln7d", str))    return nrrdKernelBSpline7D;
2946
7
  if (!strcmp("bspl7dd", str))    return nrrdKernelBSpline7DD;
2947
3
  if (!strcmp("bspln7dd", str))   return nrrdKernelBSpline7DD;
2948
5
  if (!strcmp("bspl7ddd", str))   return nrrdKernelBSpline7DDD;
2949
1
  if (!strcmp("bspln7ddd", str))  return nrrdKernelBSpline7DDD;
2950
1
  return NULL;
2951
370
}
2952
2953
/* this returns a number between -1 and max;
2954
   it does NOT do the increment-by-one;
2955
   it does NOT do range checking */
2956
int
2957
_nrrdKernelParseTMFInt(int *val, char *str) {
2958
  static const char me[]="nrrdKernelParseTMFInt";
2959
2960
1920
  if (!strcmp("n", str)) {
2961
144
    *val = -1;
2962
144
  } else {
2963
816
    if (1 != sscanf(str, "%d", val)) {
2964
      biffAddf(NRRD, "%s: couldn't parse \"%s\" as int", me, str);
2965
      return 1;
2966
    }
2967
  }
2968
960
  return 0;
2969
960
}
2970
2971
int
2972
nrrdKernelParse(const NrrdKernel **kernelP,
2973
                double *parm, const char *_str) {
2974
  static const char me[]="nrrdKernelParse";
2975
1380
  char str[AIR_STRLEN_HUGE],
2976
    kstr[AIR_STRLEN_MED], *_pstr=NULL, *pstr,
2977
690
    *tmfStr[4] = {NULL, NULL, NULL, NULL};
2978
690
  int tmfD, tmfC, tmfA;
2979
  unsigned int jj, haveParm, needParm;
2980
  airArray *mop;
2981
2982
690
  if (!(kernelP && parm && _str)) {
2983
    biffAddf(NRRD, "%s: got NULL pointer", me);
2984
    return 1;
2985
  }
2986
2987
  /* [jorik] (if i understood this correctly) parm is always of length
2988
  ** NRRD_KERNEL_PARMS_NUM. We have to clear all parameters here, since
2989
  ** nrrdKernelSet copies all arguments into its own array later, and
2990
  ** copying uninitialised memory is bad (it traps my memory debugger).
2991
  */
2992
12420
  for (jj=0; jj<NRRD_KERNEL_PARMS_NUM; jj++) {
2993
5520
    parm[jj] = 0;
2994
  }
2995
2996
690
  airStrcpy(str, AIR_STRLEN_HUGE, _str);
2997
690
  strcpy(kstr, "");
2998
  pstr = NULL;
2999
690
  pstr = strchr(str, ':');
3000
690
  if (pstr) {
3001
577
    *pstr = '\0';
3002
577
    _pstr = ++pstr;
3003
577
  }
3004
690
  strcpy(kstr, str);
3005
690
  airToLower(kstr);
3006
690
  mop = airMopNew();
3007
  /* first see if its a TMF, then try parsing it as the other stuff */
3008
690
  if (kstr == strstr(kstr, "tmf")) {
3009
320
    if (4 == airParseStrS(tmfStr, pstr, ",", 4)) {
3010
160
      airMopAdd(mop, tmfStr[0], airFree, airMopAlways);
3011
160
      airMopAdd(mop, tmfStr[1], airFree, airMopAlways);
3012
160
      airMopAdd(mop, tmfStr[2], airFree, airMopAlways);
3013
160
      airMopAdd(mop, tmfStr[3], airFree, airMopAlways);
3014
      /* a TMF with a parameter: D,C,A,a */
3015
160
      if (1 != airSingleSscanf(tmfStr[3], "%lg", parm)) {
3016
        biffAddf(NRRD, "%s: couldn't parse TMF parameter \"%s\" as double",
3017
                 me, tmfStr[3]);
3018
        airMopError(mop); return 1;
3019
      }
3020
160
    } else if (3 == airParseStrS(tmfStr, pstr, ",", 3)) {
3021
160
      airMopAdd(mop, tmfStr[0], airFree, airMopAlways);
3022
160
      airMopAdd(mop, tmfStr[1], airFree, airMopAlways);
3023
160
      airMopAdd(mop, tmfStr[2], airFree, airMopAlways);
3024
      /* a TMF without a parameter: D,C,A ==> a=0.0 */
3025
160
      parm[0] = 0.0;
3026
    } else {
3027
      biffAddf(NRRD, "%s: TMF kernels require 3 arguments D, C, A "
3028
               "in the form tmf:D,C,A", me);
3029
      airMopError(mop); return 1;
3030
    }
3031
640
    if (_nrrdKernelParseTMFInt(&tmfD, tmfStr[0])
3032
640
        || _nrrdKernelParseTMFInt(&tmfC, tmfStr[1])
3033
640
        || _nrrdKernelParseTMFInt(&tmfA, tmfStr[2])) {
3034
      biffAddf(NRRD, "%s: problem parsing \"%s,%s,%s\" as D,C,A "
3035
               "for TMF kernel", me, tmfStr[0], tmfStr[1], tmfStr[2]);
3036
      airMopError(mop); return 1;
3037
    }
3038

640
    if (!AIR_IN_CL(-1, tmfD, (int)nrrdKernelTMF_maxD)) {
3039
      biffAddf(NRRD, "%s: derivative value %d outside range [-1,%d]",
3040
               me, tmfD, nrrdKernelTMF_maxD);
3041
      airMopError(mop); return 1;
3042
    }
3043

640
    if (!AIR_IN_CL(-1, tmfC, (int)nrrdKernelTMF_maxC)) {
3044
      biffAddf(NRRD, "%s: continuity value %d outside range [-1,%d]",
3045
               me, tmfC, nrrdKernelTMF_maxC);
3046
      airMopError(mop); return 1;
3047
    }
3048

640
    if (!AIR_IN_CL(1, tmfA, (int)nrrdKernelTMF_maxA)) {
3049
      biffAddf(NRRD, "%s: accuracy value %d outside range [1,%d]",
3050
               me, tmfA, nrrdKernelTMF_maxA);
3051
      airMopError(mop); return 1;
3052
    }
3053
    /*
3054
    fprintf(stderr, "!%s: D,C,A = %d,%d,%d --> %d,%d,%d\n", me,
3055
            tmfD, tmfC, tmfA, tmfD+1, tmfC+1, tmfA);
3056
    */
3057
320
    *kernelP = nrrdKernelTMF[tmfD+1][tmfC+1][tmfA];
3058
320
  } else {
3059
    /* its not a TMF */
3060
370
    if (!(*kernelP = _nrrdKernelStrToKern(kstr))) {
3061
1
      biffAddf(NRRD, "%s: kernel \"%s\" not recognized", me, kstr);
3062
1
      airMopError(mop); return 1;
3063
    }
3064
369
    if ((*kernelP)->numParm > NRRD_KERNEL_PARMS_NUM) {
3065
      biffAddf(NRRD, "%s: kernel \"%s\" requests %d parameters > max %d",
3066
               me, kstr, (*kernelP)->numParm, NRRD_KERNEL_PARMS_NUM);
3067
      airMopError(mop); return 1;
3068
    }
3069

665
    if (*kernelP == nrrdKernelGaussian ||
3070
357
        *kernelP == nrrdKernelGaussianD ||
3071
345
        *kernelP == nrrdKernelGaussianDD ||
3072
333
        *kernelP == nrrdKernelDiscreteGaussian ||
3073
312
        *kernelP == nrrdKernelBoxSupportDebug ||
3074
308
        *kernelP == nrrdKernelCos4SupportDebug ||
3075
304
        *kernelP == nrrdKernelCos4SupportDebugD ||
3076
300
        *kernelP == nrrdKernelCos4SupportDebugDD ||
3077
296
        *kernelP == nrrdKernelCos4SupportDebugDDD) {
3078
      /* for these kernels, we need all the parameters given explicitly */
3079
77
      needParm = (*kernelP)->numParm;
3080
77
    } else {
3081
      /*  For everything else (note that TMF kernels are handled
3082
          separately), we can make do with one less than the required,
3083
          by using the default spacing  */
3084
764
      needParm = ((*kernelP)->numParm > 0
3085
180
                  ? (*kernelP)->numParm - 1
3086
                  : 0);
3087
    }
3088
369
    if (needParm > 0 && !pstr) {
3089
      biffAddf(NRRD, "%s: didn't get any of %d required doubles after "
3090
               "colon in \"%s\"",
3091
               me, needParm, kstr);
3092
      airMopError(mop); return 1;
3093
    }
3094

2625
    for (haveParm=0; haveParm<(*kernelP)->numParm; haveParm++) {
3095
875
      if (!pstr)
3096
        break;
3097
506
      if (1 != airSingleSscanf(pstr, "%lg", parm+haveParm)) {
3098
        biffAddf(NRRD, "%s: trouble parsing \"%s\" as double (in \"%s\")",
3099
                 me, _pstr, _str);
3100
        airMopError(mop); return 1;
3101
      }
3102
506
      if ((pstr = strchr(pstr, ','))) {
3103
249
        pstr++;
3104
249
        if (!*pstr) {
3105
          biffAddf(NRRD, "%s: nothing after last comma in \"%s\" (in \"%s\")",
3106
                   me, _pstr, _str);
3107
          airMopError(mop); return 1;
3108
        }
3109
      }
3110
    }
3111
    /* haveParm is now the number of parameters that were parsed. */
3112
369
    if (haveParm < needParm) {
3113
      biffAddf(NRRD, "%s: parsed only %d of %d required doubles "
3114
               "from \"%s\" (in \"%s\")",
3115
               me, haveParm, needParm, _pstr, _str);
3116
      airMopError(mop); return 1;
3117

558
    } else if (haveParm == needParm &&
3118
189
               needParm == (*kernelP)->numParm-1) {
3119
      /* shift up parsed values, and set parm[0] to default */
3120
      for (jj=haveParm; jj>=1; jj--) {
3121
        parm[jj] = parm[jj-1];
3122
      }
3123
      parm[0] = nrrdDefaultKernelParm0;
3124
    } else {
3125
369
      if (pstr) {
3126
        biffAddf(NRRD, "%s: \"%s\" (in \"%s\") has more than %d doubles",
3127
                 me, _pstr, _str, (*kernelP)->numParm);
3128
        airMopError(mop); return 1;
3129
      }
3130
    }
3131
  }
3132
  /*
3133
  fprintf(stderr, "%s: %g %g %g %g %g\n", me,
3134
          parm[0], parm[1], parm[2], parm[3], parm[4]);
3135
  */
3136
689
  airMopOkay(mop);
3137
689
  return 0;
3138
690
}
3139
3140
int
3141
nrrdKernelSpecParse(NrrdKernelSpec *ksp, const char *str) {
3142
  static const char me[]="nrrdKernelSpecParse";
3143
700
  const NrrdKernel *kern;
3144
350
  double kparm[NRRD_KERNEL_PARMS_NUM];
3145
3146
350
  if (!( ksp && str )) {
3147
    biffAddf(NRRD, "%s: got NULL pointer", me);
3148
    return 1;
3149
  }
3150
350
  if (nrrdKernelParse(&kern, kparm, str)) {
3151
1
    biffAddf(NRRD, "%s: ", me);
3152
1
    return 1;
3153
  }
3154
349
  nrrdKernelSpecSet(ksp, kern, kparm);
3155
349
  return 0;
3156
350
}
3157
3158
/*
3159
** note that the given string has to be allocated for a certain size
3160
** which is plenty big
3161
*/
3162
int
3163
nrrdKernelSpecSprint(char str[AIR_STRLEN_LARGE], const NrrdKernelSpec *ksp) {
3164
  static const char me[]="nrrdKernelSpecSprint";
3165
  unsigned int warnLen = AIR_STRLEN_LARGE/3;
3166
1364
  char stmp[AIR_STRLEN_LARGE];
3167
3168
682
  if (!( str && ksp )) {
3169
    biffAddf(NRRD, "%s: got NULL pointer", me);
3170
    return 1;
3171
  }
3172
682
  if (strlen(ksp->kernel->name) > warnLen) {
3173
    biffAddf(NRRD, "%s: kernel name (len %s) might lead to overflow", me,
3174
             airSprintSize_t(stmp, strlen(ksp->kernel->name)));
3175
    return 1;
3176
  }
3177
682
  if (strstr(ksp->kernel->name, "TMF")) {
3178
    /* these are handled differently; the identification of the
3179
       kernel is actually packaged as kernel parameters */
3180
320
    if (!(ksp->kernel->name == strstr(ksp->kernel->name, "TMF"))) {
3181
      biffAddf(NRRD, "%s: TMF kernel name %s didn't start with TMF",
3182
               me, ksp->kernel->name);
3183
      return 1;
3184
    }
3185
    /* 0123456789012 */
3186
    /* TMF_dX_cX_Xef */
3187
640
    if (!( 13 == strlen(ksp->kernel->name)
3188
640
           && '_' == ksp->kernel->name[3]
3189
640
           && '_' == ksp->kernel->name[6]
3190
640
           && '_' == ksp->kernel->name[9] )) {
3191
      biffAddf(NRRD, "%s: sorry, expected strlen(%s) = 13 with 3 _s",
3192
               me, ksp->kernel->name);
3193
      return 1;
3194
    }
3195
320
    sprintf(str, "tmf:%c,%c,%c",
3196
            ksp->kernel->name[5],
3197
            ksp->kernel->name[8],
3198
            ksp->kernel->name[10]);
3199
    /* see if the single parm should be added on */
3200
320
    if (0.0 != ksp->parm[0]) {
3201
160
      sprintf(stmp, ",%.17g", ksp->parm[0]);
3202
160
      strcat(str, stmp);
3203
160
    }
3204
  } else {
3205
362
    strcpy(str, ksp->kernel->name);
3206
362
    if (ksp->kernel->numParm) {
3207
      unsigned int pi;
3208
1484
      for (pi=0; pi<ksp->kernel->numParm; pi++) {
3209
492
        sprintf(stmp, "%c%.17g", (!pi ? ':' : ','), ksp->parm[pi]);
3210
492
        if (strlen(str) + strlen(stmp) > warnLen) {
3211
          biffAddf(NRRD, "%s: kernel parm %u could overflow", me, pi);
3212
          return 1;
3213
        }
3214
492
        strcat(str, stmp);
3215
      }
3216
250
    }
3217
  }
3218
682
  return 0;
3219
682
}
3220
3221
int
3222
nrrdKernelSprint(char str[AIR_STRLEN_LARGE], const NrrdKernel *kernel,
3223
                 const double kparm[NRRD_KERNEL_PARMS_NUM]) {
3224
  static const char me[]="nrrdKernelSprint";
3225
680
  NrrdKernelSpec ksp;
3226
3227
340
  nrrdKernelSpecSet(&ksp, kernel, kparm);
3228
340
  if (nrrdKernelSpecSprint(str, &ksp)) {
3229
    biffAddf(NRRD, "%s: trouble", me);
3230
    return 1;
3231
  }
3232
340
  return 0;
3233
340
}
3234
3235
/*
3236
** This DOES make an effort to set *differ based on "ordering" (-1 or +1)
3237
** but HEY that's very contrived; why bother?
3238
*/
3239
int
3240
nrrdKernelCompare(const NrrdKernel *kernA,
3241
                  const double parmA[NRRD_KERNEL_PARMS_NUM],
3242
                  const NrrdKernel *kernB,
3243
                  const double parmB[NRRD_KERNEL_PARMS_NUM],
3244
                  int *differ, char explain[AIR_STRLEN_LARGE]) {
3245
  static const char me[]="nrrdKernelCompare";
3246
  unsigned int pnum, pidx;
3247
3248
1364
  if (!(kernA && kernB && differ)) {
3249
    biffAddf(NRRD, "%s: got NULL pointer (%p, %p, or %p)", me,
3250
             AIR_CVOIDP(kernA), AIR_CVOIDP(kernB), AIR_VOIDP(differ));
3251
    return 1;
3252
  }
3253
682
  if (kernA != kernB) {
3254
    *differ = kernA < kernB ? -1 : 1;
3255
    if (explain) {
3256
      sprintf(explain, "kernA %s kernB", *differ < 0 ? "<" : ">");
3257
    }
3258
    return 0;
3259
  }
3260
682
  pnum = kernA->numParm;
3261
682
  if (!pnum) {
3262
    /* actually, we're done: no parms and kernels are equal */
3263
112
    *differ = 0;
3264
112
    return 0;
3265
  }
3266
570
  if (!(parmA && parmB)) {
3267
    biffAddf(NRRD, "%s: kernel %s needs %u parms but got NULL parm vectors",
3268
             me, kernA->name ? kernA->name : "(unnamed)", pnum);
3269
    return 0;
3270
  }
3271
2764
  for (pidx=0; pidx<pnum; pidx++) {
3272
812
    if (parmA[pidx] != parmB[pidx]) {
3273
      *differ = parmA[pidx] < parmB[pidx] ? -1 : 1;
3274
      if (explain) {
3275
        sprintf(explain, "parmA[%u]=%f %s parmB[%u]=%f", pidx, parmA[pidx],
3276
                *differ < 0 ? "<" : ">", pidx, parmB[pidx]);
3277
      }
3278
      return 0;
3279
    }
3280
  }
3281
3282
  /* so far nothing unequal */
3283
570
  *differ = 0;
3284
570
  return 0;
3285
682
}
3286
3287
/*
3288
** This DOES NOT make an effort to set *differ based on "ordering";
3289
*/
3290
int
3291
nrrdKernelSpecCompare(const NrrdKernelSpec *aa,
3292
                      const NrrdKernelSpec *bb,
3293
                      int *differ, char explain[AIR_STRLEN_LARGE]) {
3294
  static const char me[]="nrrdKernelSpecCompare";
3295
10
  char subexplain[AIR_STRLEN_LARGE];
3296
3297
5
  if (!( differ )) {
3298
    biffAddf(NRRD, "%s: got NULL differ", me);
3299
    return 1;
3300
  }
3301
5
  if (!!aa != !!bb) {
3302
    if (explain) {
3303
      sprintf(explain, "different NULL-ities of kspec itself %s != %s",
3304
              aa ? "non-NULL" : "NULL",
3305
              bb ? "non-NULL" : "NULL");
3306
    }
3307
    *differ = 1; return 0;
3308
  }
3309
5
  if (!aa) {
3310
    /* got two NULL kernel specs ==> equal */
3311
3
    *differ = 0; return 0;
3312
  }
3313
2
  if (!!aa->kernel != !!bb->kernel) {
3314
    if (explain) {
3315
      sprintf(explain, "different NULL-ities of kspec->kernel %s != %s",
3316
              aa->kernel ? "non-NULL" : "NULL",
3317
              bb->kernel ? "non-NULL" : "NULL");
3318
    }
3319
    *differ = 1; return 0;
3320
  }
3321
2
  if (!aa->kernel) {
3322
    /* both kernels NULL, can't do anything informative with parms */
3323
    *differ = 0; return 0;
3324
  }
3325

4
  if (nrrdKernelCompare(aa->kernel, aa->parm,
3326
2
                        bb->kernel, bb->parm,
3327
2
                        differ, subexplain)) {
3328
    biffAddf(NRRD, "%s: trouble comparing kernels", me);
3329
    return 1;
3330
  }
3331
2
  if (*differ) {
3332
    if (explain) {
3333
      sprintf(explain, "kern/parm pairs differ: %s", subexplain);
3334
    }
3335
    *differ = 1; /* losing ordering info (of dubious value) */
3336
    return 0;
3337
  }
3338
2
  *differ = 0;
3339
2
  return 0;
3340
5
}
3341
3342
/*
3343
******** nrrdKernelCheck
3344
**
3345
** Makes sure a given kernel is behaving as expected
3346
**
3347
** Tests:
3348
** nrrdKernelSprint
3349
** nrrdKernelParse
3350
** nrrdKernelCompare
3351
** nrrdKernelSpecNew
3352
** nrrdKernelSpecNix
3353
** nrrdKernelSpecSet
3354
** nrrdKernelSpecSprint
3355
** nrrdKernelSpecParse
3356
** and also exercises all the ways of evaluating the kernel and
3357
** makes sure they all agree, and agree with the integral kernel, if given
3358
*/
3359
int
3360
nrrdKernelCheck(const NrrdKernel *kern,
3361
                const double parm[NRRD_KERNEL_PARMS_NUM],
3362
                size_t evalNum, double epsilon,
3363
                unsigned int diffOkEvalMax,
3364
                unsigned int diffOkIntglMax,
3365
                const NrrdKernel *ikern,
3366
                const double iparm[NRRD_KERNEL_PARMS_NUM]) {
3367
680
  const NrrdKernel *parsedkern;
3368
340
  double parsedparm[NRRD_KERNEL_PARMS_NUM], supp, integral;
3369
  static const char me[]="nrrdKernelCheck";
3370
340
  char kstr[AIR_STRLEN_LARGE], kspstr[AIR_STRLEN_LARGE],
3371
    explain[AIR_STRLEN_LARGE], stmp[AIR_STRLEN_SMALL];
3372
340
  int differ;
3373
  size_t evalIdx;
3374
  double *dom_d, *ran_d, wee;
3375
  float *dom_f, *ran_f;
3376
  unsigned int diffOkEvalNum, diffOkIntglNum;
3377
  NrrdKernelSpec *kspA, *kspB;
3378
  airArray *mop;
3379
3380
340
  mop = airMopNew();
3381
340
  if (!kern) {
3382
    biffAddf(NRRD, "%s: got NULL kernel", me);
3383
    airMopError(mop); return 1;
3384
  }
3385
340
  if (!(evalNum > 20)) {
3386
    biffAddf(NRRD, "%s: need evalNum > 20", me);
3387
    airMopError(mop); return 1;
3388
  }
3389

1020
  if (!(kern->support && kern->integral
3390

1020
        && kern->eval1_f && kern->evalN_f
3391

1020
        && kern->eval1_d && kern->evalN_d)) {
3392
    biffAddf(NRRD, "%s: kernel has NULL fields (%d,%d,%d,%d,%d,%d)", me,
3393
             !!(kern->support), !!(kern->integral),
3394
             !!(kern->eval1_f), !!(kern->evalN_f),
3395
             !!(kern->eval1_d), !!(kern->evalN_d));
3396
    airMopError(mop); return 1;
3397
  }
3398
340
  kspA = nrrdKernelSpecNew();
3399
340
  airMopAdd(mop, kspA, (airMopper)nrrdKernelSpecNix, airMopAlways);
3400
340
  kspB = nrrdKernelSpecNew();
3401
340
  airMopAdd(mop, kspB, (airMopper)nrrdKernelSpecNix, airMopAlways);
3402
340
  nrrdKernelSpecSet(kspA, kern, parm);
3403
680
  if (nrrdKernelSprint(kstr, kern, parm)
3404
680
      || nrrdKernelSpecSprint(kspstr, kspA)) {
3405
    biffAddf(NRRD, "%s: trouble", me);
3406
    airMopError(mop); return 1;
3407
  }
3408
340
  if (strcmp(kstr, kspstr)) {
3409
    biffAddf(NRRD, "%s: sprinted kernel |%s| != kspec |%s|", me, kstr, kspstr);
3410
    airMopError(mop); return 1;
3411
  }
3412
680
  if (nrrdKernelParse(&parsedkern, parsedparm, kstr)
3413
680
      || nrrdKernelSpecParse(kspB, kstr)) {
3414
    biffAddf(NRRD, "%s: trouble parsing |%s| back to kern/parm pair or kspec",
3415
             me, kstr);
3416
    airMopError(mop); return 1;
3417
  }
3418

680
  if (nrrdKernelCompare(kern, parm, parsedkern, parsedparm,
3419
340
                        &differ, explain)) {
3420
    biffAddf(NRRD, "%s: trouble comparing kern/parm pairs", me);
3421
    airMopError(mop); return 1;
3422
  }
3423
340
  if (differ) {
3424
    biffAddf(NRRD, "%s: given and re-parsed kernels differ: %s", me, explain);
3425
    airMopError(mop); return 1;
3426
  }
3427

680
  if (nrrdKernelCompare(kspA->kernel, kspA->parm,
3428
340
                        kspB->kernel, kspB->parm,
3429
                        &differ, explain)) {
3430
    biffAddf(NRRD, "%s: trouble comparing kspecs", me);
3431
    airMopError(mop); return 1;
3432
  }
3433
340
  if (differ) {
3434
    biffAddf(NRRD, "%s: given and re-parsed kspecs differ: %s", me, explain);
3435
    airMopError(mop); return 1;
3436
  }
3437
3438
340
  supp = kern->support(parm);
3439
  /* wee is the step between evaluation points */
3440
340
  wee = 2*supp/AIR_CAST(double, evalNum);
3441

678
  if ( (kern->eval1_d)(supp+wee/1000, parm) ||
3442
338
       (kern->eval1_d)(supp+wee, parm) ||
3443
338
       (kern->eval1_d)(supp+10*wee, parm) ||
3444
338
       (kern->eval1_d)(-supp-wee/1000, parm) ||
3445
338
       (kern->eval1_d)(-supp-wee, parm) ||
3446
338
       (kern->eval1_d)(-supp-10*wee, parm) ) {
3447
2
    if (nrrdKernelCheap != kern) {
3448
      /* the "cheap" kernel alone gets a pass on reporting its support */
3449
      biffAddf(NRRD, "%s: kern %s is non-zero outside support %g",
3450
               me, kstr, supp);
3451
      airMopError(mop); return 1;
3452
    }
3453
  }
3454
  /* allocate domain and range for both float and double */
3455
340
  dom_d = AIR_CALLOC(evalNum, double);
3456
340
  airMopAdd(mop, dom_d, airFree, airMopAlways);
3457
340
  ran_d = AIR_CALLOC(evalNum, double);
3458
340
  airMopAdd(mop, ran_d, airFree, airMopAlways);
3459
340
  dom_f = AIR_CALLOC(evalNum, float);
3460
340
  airMopAdd(mop, dom_f, airFree, airMopAlways);
3461
340
  ran_f = AIR_CALLOC(evalNum, float);
3462
340
  airMopAdd(mop, ran_f, airFree, airMopAlways);
3463
340
  if (!( dom_d && ran_d && dom_f && ran_f )) {
3464
    biffAddf(NRRD, "%s: couldn't alloc buffers for %s values for %s",
3465
             me, airSprintSize_t(stmp, evalNum), kstr);
3466
    airMopError(mop); return 1;
3467
  }
3468
81600680
  for (evalIdx=0; evalIdx<evalNum; evalIdx++) {
3469
40800000
    dom_d[evalIdx] = AIR_AFFINE(-0.5, evalIdx,
3470
                                AIR_CAST(double, evalNum)-0.5,
3471
                                -supp, supp);
3472
40800000
    dom_f[evalIdx] = AIR_CAST(float, dom_d[evalIdx]);
3473
  }
3474
  /* do the vector evaluations */
3475
340
  kern->evalN_f(ran_f, dom_f, evalNum, parm);
3476
340
  kern->evalN_d(ran_d, dom_d, evalNum, parm);
3477
  /*
3478
  for (evalIdx=0; evalIdx<evalNum; evalIdx++) {
3479
    fprintf(stderr, "%u %g --> %g\n", AIR_CAST(unsigned int, evalIdx),
3480
            dom_d[evalIdx], ran_d[evalIdx]);
3481
  }
3482
  */
3483
  /* compare evaluations (and maybe derivatives) and numerically compute
3484
     integral */
3485
  diffOkEvalNum = 0;
3486
  diffOkIntglNum = 0;
3487
  integral = 0.0;
3488
81600680
  for (evalIdx=0; evalIdx<evalNum; evalIdx++) {
3489
    double single_f, single_d;
3490
40800000
    single_f = kern->eval1_f(dom_f[evalIdx], parm);
3491
40800000
    single_d = kern->eval1_d(dom_d[evalIdx], parm);
3492
40800000
    integral += single_d;
3493
    /* single float vs vector float */
3494
79440000
    if (nrrdKernelForwDiff == kern
3495
81360000
        || nrrdKernelBCCubic == kern
3496
80160000
        || nrrdKernelBCCubicDD == kern
3497
78240000
        || nrrdKernelAQuarticDD == kern) {
3498
      /* HEY this is crazy: need a special epsilon for these kernels;
3499
         WHY WHY do these kernels evaluate to different things in the
3500
         single versus the vector case? */
3501
      float specEps;
3502
2640000
      if (nrrdKernelForwDiff == kern) {
3503
        specEps = 5e-9f;
3504
2640000
      } else if (nrrdKernelBCCubic == kern) {
3505
        specEps = 5e-8f;
3506
2400000
      } else if (nrrdKernelBCCubicDD == kern) {
3507
        specEps = 5e-8f;
3508
1440000
      } else if (nrrdKernelAQuarticDD == kern) {
3509
        specEps = 5e-8f;
3510
480000
      } else {
3511
        specEps = 0.0;
3512
      }
3513
2640000
      if (fabs(single_f - ran_f[evalIdx]) > specEps) {
3514
        biffAddf(NRRD, "%s: %s (eval1_f(%.17g)=%.17g) != "
3515
                 "(evalN_f(%.17g)=%.17g) by %.17g > %.17g",
3516
                 me, kstr, dom_f[evalIdx], single_f,
3517
                 dom_f[evalIdx], ran_f[evalIdx],
3518
                 fabs(single_f - ran_f[evalIdx]), specEps);
3519
        airMopError(mop); return 1;
3520
      }
3521
2640000
    } else {
3522
38160000
      if (single_f != ran_f[evalIdx]) {
3523
        biffAddf(NRRD, "%s: %s (eval1_f(%.17g)=%.17g) != "
3524
                 "(evalN_f(%.17g)=%.17g)",
3525
                 me, kstr, dom_f[evalIdx], single_f,
3526
                 dom_f[evalIdx], ran_f[evalIdx]);
3527
        airMopError(mop); return 1;
3528
      }
3529
    }
3530
    /* single double vs vector double */
3531
40800000
    if (single_d != ran_d[evalIdx]) {
3532
      biffAddf(NRRD, "%s: %s (eval1_d(%.17g)=%.17g) != (evalN_d(%.17g)=%.17g)",
3533
               me, kstr, dom_d[evalIdx], single_d,
3534
               dom_d[evalIdx], ran_d[evalIdx]);
3535
      airMopError(mop); return 1;
3536
    }
3537
    /* single float vs single double */
3538
40800000
    if (fabs(single_f - single_d) > epsilon) {
3539
      diffOkEvalNum++;
3540
      if (diffOkEvalNum > diffOkEvalMax) {
3541
        biffAddf(NRRD,
3542
                 "%s: %s |eval1_f(%.17g)=%.17g) - (eval1_d(%.17g)=%.17g)|"
3543
                 " %.17g  >  epsilon %.17g too many times (%u > %u)", me,
3544
                 kstr, dom_f[evalIdx], single_f, dom_d[evalIdx], single_d,
3545
                 fabs(single_f - single_d), epsilon,
3546
                 diffOkEvalNum, diffOkEvalMax);
3547
        airMopError(mop); return 1;
3548
      }
3549
    }
3550
    /* check whether we're the derivative of ikern */
3551
40800000
    if (ikern) {
3552
      double forw, back, ndrv;
3553
12720000
      forw = ikern->eval1_d(dom_d[evalIdx] + wee/2, iparm);
3554
12720000
      back = ikern->eval1_d(dom_d[evalIdx] - wee/2, iparm);
3555
12720000
      ndrv = (forw - back)/wee;
3556
12720000
      if (fabs(ndrv - single_d) > epsilon) {
3557
42
        diffOkIntglNum++;
3558
42
        if (diffOkIntglNum > diffOkIntglMax) {
3559
          biffAddf(NRRD, "%s: %s(%.17g) |num deriv(%s) %.17g - %.17g| "
3560
                   "%.17g > %.17g too many times (%u > %u)",
3561
                   me, kstr, dom_d[evalIdx], ikern->name, ndrv, single_d,
3562
                   fabs(ndrv - single_d), epsilon,
3563
                   diffOkIntglNum, diffOkIntglMax);
3564
          airMopError(mop); return 1;
3565
        }
3566
      }
3567
12720000
    }
3568
40800000
  }
3569
340
  integral *= 2*supp/(AIR_CAST(double, evalNum));
3570
  /* the "cheap" kernel alone gets a pass on reporting its integral */
3571
340
  if (nrrdKernelCheap != kern) {
3572
    double hackeps=10;
3573
    /* hackeps is clearly a hack to permit the integral to have greater
3574
       error than any single evaluation; there must be a more principled
3575
       way to set this */
3576
338
    if (fabs(integral - kern->integral(parm)) > hackeps*epsilon) {
3577
      biffAddf(NRRD, "%s: %s |numerical integral %.17g - claimed %.17g| "
3578
               "%.17g > %.17g", me, kstr, integral, kern->integral(parm),
3579
               fabs(integral - kern->integral(parm)), hackeps*epsilon);
3580
      airMopError(mop); return 1;
3581
    }
3582
338
  }
3583
3584
  /* HEY check being derivative of ikern/iparm */
3585
  AIR_UNUSED(ikern);
3586
  AIR_UNUSED(iparm);
3587
3588
340
  airMopOkay(mop);
3589
340
  return 0;
3590
340
}
3591
3592
int
3593
nrrdKernelParm0IsScale(const NrrdKernel *kern) {
3594
  int ret;
3595
3596
  if (!kern) {
3597
    ret = 0;
3598
  } else if (nrrdKernelHann == kern ||
3599
             nrrdKernelHannD == kern ||
3600
             nrrdKernelHannDD == kern ||
3601
             nrrdKernelBlackman == kern ||
3602
             nrrdKernelBlackmanD == kern ||
3603
             nrrdKernelBlackmanDD == kern ||
3604
             nrrdKernelZero == kern ||
3605
             nrrdKernelBox == kern ||
3606
             nrrdKernelCheap == kern ||
3607
             nrrdKernelTent == kern ||
3608
             nrrdKernelForwDiff == kern ||
3609
             nrrdKernelCentDiff == kern ||
3610
             nrrdKernelBCCubic == kern ||
3611
             nrrdKernelBCCubicD == kern ||
3612
             nrrdKernelBCCubicDD == kern ||
3613
             nrrdKernelAQuartic == kern ||
3614
             nrrdKernelAQuarticD == kern ||
3615
             nrrdKernelAQuarticDD == kern ||
3616
             nrrdKernelGaussian == kern ||
3617
             nrrdKernelGaussianD == kern ||
3618
             nrrdKernelGaussianDD == kern ||
3619
             nrrdKernelDiscreteGaussian == kern) {
3620
    ret = 1;
3621
  } else {
3622
    ret = 0;
3623
  }
3624
  return ret;
3625
}