GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/measure.c Lines: 0 511 0.0 %
Date: 2017-05-26 Branches: 0 413 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "nrrd.h"
25
#include "privateNrrd.h"
26
27
/* the non-histogram measures assume that there will be no NaNs in data */
28
void
29
_nrrdMeasureUnknown(void *ans, int ansType,
30
                    const void *line, int lineType,
31
                    size_t len, double axmin, double axmax) {
32
  static const char me[]="_nrrdMeasureUnknown";
33
34
  AIR_UNUSED(line);
35
  AIR_UNUSED(lineType);
36
  AIR_UNUSED(len);
37
  AIR_UNUSED(axmin);
38
  AIR_UNUSED(axmax);
39
  fprintf(stderr, "%s: Need To Specify A Measure !!! \n", me);
40
  nrrdDStore[ansType](ans, AIR_NAN);
41
}
42
43
void
44
_nrrdMeasureMin(void *ans, int ansType,
45
                const void *line, int lineType, size_t len,
46
                double axmin, double axmax) {
47
  double val, M, (*lup)(const void*, size_t);
48
  size_t ii;
49
50
  AIR_UNUSED(axmin);
51
  AIR_UNUSED(axmax);
52
  lup = nrrdDLookup[lineType];
53
  if (nrrdTypeIsIntegral[lineType]) {
54
    M = lup(line, 0);
55
    for (ii=1; ii<len; ii++) {
56
      val = lup(line, ii);
57
      M = AIR_MIN(M, val);
58
    }
59
  } else {
60
    M = AIR_NAN;
61
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
62
      M = lup(line, ii);
63
    }
64
    for (; ii<len; ii++) {
65
      val = lup(line, ii);
66
      if (AIR_EXISTS(val)) {
67
        M = AIR_MIN(M, val);
68
      }
69
    }
70
  }
71
  nrrdDStore[ansType](ans, M);
72
}
73
74
75
void
76
_nrrdMeasureMax(void *ans, int ansType,
77
                const void *line, int lineType, size_t len,
78
                double axmin, double axmax) {
79
  double val, M, (*lup)(const void*, size_t);
80
  size_t ii;
81
82
  AIR_UNUSED(axmin);
83
  AIR_UNUSED(axmax);
84
  lup = nrrdDLookup[lineType];
85
  if (nrrdTypeIsIntegral[lineType]) {
86
    M = lup(line, 0);
87
    for (ii=1; ii<len; ii++) {
88
      val = lup(line, ii);
89
      M = AIR_MAX(M, val);
90
    }
91
  } else {
92
    M = AIR_NAN;
93
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
94
      M = lup(line, ii);
95
    }
96
    for (; ii<len; ii++) {
97
      val = lup(line, ii);
98
      if (AIR_EXISTS(val)) {
99
        M = AIR_MAX(M, val);
100
      }
101
    }
102
  }
103
  nrrdDStore[ansType](ans, M);
104
}
105
106
void
107
_nrrdMeasureProduct(void *ans, int ansType,
108
                    const void *line, int lineType, size_t len,
109
                    double axmin, double axmax) {
110
  double val, P, (*lup)(const void*, size_t);
111
  size_t ii;
112
113
  AIR_UNUSED(axmin);
114
  AIR_UNUSED(axmax);
115
  lup = nrrdDLookup[lineType];
116
  if (nrrdTypeIsIntegral[lineType]) {
117
    P = 1.0;
118
    for (ii=0; ii<len; ii++) {
119
      P *= lup(line, ii);
120
    }
121
  } else {
122
    P = AIR_NAN;
123
    /* the point of this is to ensure that that if there are NO
124
       existent values, then the return is NaN */
125
    for (ii=0; !AIR_EXISTS(P) && ii<len; ii++) {
126
      P = lup(line, ii);
127
    }
128
    for (; ii<len; ii++) {
129
      val = lup(line, ii);
130
      if (AIR_EXISTS(val)) {
131
        P *= val;
132
      }
133
    }
134
  }
135
  nrrdDStore[ansType](ans, P);
136
}
137
138
void
139
_nrrdMeasureSum(void *ans, int ansType,
140
                const void *line, int lineType, size_t len,
141
                double axmin, double axmax) {
142
  double val, S, (*lup)(const void*, size_t);
143
  size_t ii;
144
145
  AIR_UNUSED(axmin);
146
  AIR_UNUSED(axmax);
147
  lup = nrrdDLookup[lineType];
148
  if (nrrdTypeIsIntegral[lineType]) {
149
    S = 0.0;
150
    for (ii=0; ii<len; ii++) {
151
      S += lup(line, ii);
152
    }
153
  } else {
154
    S = AIR_NAN;
155
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++)
156
      S = lup(line, ii);
157
    for (; ii<len; ii++) {
158
      val = lup(line, ii);
159
      if (AIR_EXISTS(val)) {
160
        S += val;
161
      }
162
    }
163
  }
164
  nrrdDStore[ansType](ans, S);
165
}
166
167
void
168
_nrrdMeasureMean(void *ans, int ansType,
169
                 const void *line, int lineType, size_t len,
170
                 double axmin, double axmax) {
171
  double val, S, M, (*lup)(const void*, size_t);
172
  size_t ii, count;
173
174
  AIR_UNUSED(axmin);
175
  AIR_UNUSED(axmax);
176
  lup = nrrdDLookup[lineType];
177
  if (nrrdTypeIsIntegral[lineType]) {
178
    S = 0.0;
179
    for (ii=0; ii<len; ii++) {
180
      S += lup(line, ii);
181
    }
182
    M = S/len;
183
  } else {
184
    S = AIR_NAN;
185
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
186
      S = lup(line, ii);
187
    }
188
    if (AIR_EXISTS(S)) {
189
      /* there was an existent value */
190
      count = 1;
191
      for (; ii<len; ii++) {
192
        val = lup(line, ii);
193
        if (AIR_EXISTS(val)) {
194
          count++;
195
          S += val;
196
        }
197
      }
198
      M = S/count;
199
    } else {
200
      /* there were NO existent values */
201
      M = AIR_NAN;
202
    }
203
  }
204
  nrrdDStore[ansType](ans, M);
205
}
206
207
/* stupid little forward declaration */
208
void
209
_nrrdMeasureHistoMode(void *ans, int ansType,
210
                      const void *line, int lineType, size_t len,
211
                      double axmin, double axmax);
212
213
void
214
_nrrdMeasureMode(void *ans, int ansType,
215
                 const void *_line, int lineType, size_t len,
216
                 double axmin, double axmax) {
217
  Nrrd *nline, *nhist;
218
  void *line;
219
220
  AIR_UNUSED(axmin);
221
  AIR_UNUSED(axmax);
222
  line = calloc(len, nrrdTypeSize[lineType]);
223
  if (line) {
224
    memcpy(line, _line, len*nrrdTypeSize[lineType]);
225
226
    nline = nrrdNew();
227
    if (nrrdWrap_va(nline, line, lineType, 1, len)) {
228
      free(biffGetDone(NRRD));
229
      nrrdNix(nline);
230
      nrrdDStore[ansType](ans, AIR_NAN);
231
      return;
232
    }
233
    nhist = nrrdNew();
234
    if (nrrdHisto(nhist, nline, NULL, NULL,
235
                  nrrdStateMeasureModeBins, nrrdTypeInt)) {
236
      free(biffGetDone(NRRD));
237
      nrrdNuke(nhist);
238
      nrrdNix(nline);
239
      nrrdDStore[ansType](ans, AIR_NAN);
240
      return;
241
    }
242
243
    /* now we pass this histogram off to histo-mode */
244
    _nrrdMeasureHistoMode(ans, ansType,
245
                          nhist->data, nrrdTypeInt, nrrdStateMeasureModeBins,
246
                          nhist->axis[0].min, nhist->axis[0].max);
247
    nrrdNuke(nhist);
248
    nrrdNix(nline);
249
  } else {
250
    nrrdDStore[ansType](ans, 0);
251
  }
252
  return;
253
}
254
255
void
256
_nrrdMeasureMedian(void *ans, int ansType,
257
                   const void *_line, int lineType, size_t len,
258
                   double axmin, double axmax) {
259
  double M=0, (*lup)(const void*, size_t);
260
  size_t ii, mid;
261
  void *line;
262
263
  AIR_UNUSED(axmin);
264
  AIR_UNUSED(axmax);
265
  lup = nrrdDLookup[lineType];
266
  line = calloc(len, nrrdTypeSize[lineType]);
267
  if (line) {
268
    memcpy(line, _line, len*nrrdTypeSize[lineType]);
269
270
    /* yes, I know, this is not the fastest median.  I'll get to it ... */
271
    qsort(line, len, nrrdTypeSize[lineType], nrrdValCompare[lineType]);
272
    M = AIR_NAN;
273
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
274
      M = lup(line, ii);
275
    }
276
277
    if (AIR_EXISTS(M)) {
278
      /* i is index AFTER first existent value */
279
      ii--;
280
      len -= ii;
281
      mid = len/2;
282
      if (len % 2) {
283
        /* len is odd, there is a middle value, its at mid */
284
        M = lup(line, ii+mid);
285
      } else {
286
        /* len is even, two middle values are at mid-1 and mid */
287
        M = (lup(line, ii+mid-1) + lup(line, ii+mid))/2;
288
      }
289
    }
290
  }
291
  nrrdDStore[ansType](ans, M);
292
}
293
294
void
295
_nrrdMeasureL1(void *ans, int ansType,
296
               const void *line, int lineType, size_t len,
297
               double axmin, double axmax) {
298
  double val, S, (*lup)(const void*, size_t);
299
  size_t ii;
300
301
  AIR_UNUSED(axmin);
302
  AIR_UNUSED(axmax);
303
  lup = nrrdDLookup[lineType];
304
  if (nrrdTypeIsIntegral[lineType]) {
305
    S = 0.0;
306
    for (ii=0; ii<len; ii++) {
307
      val = lup(line, ii);
308
      S += AIR_ABS(val);
309
    }
310
  } else {
311
    S = AIR_NAN;
312
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
313
      S = lup(line, ii);
314
    }
315
    S = AIR_ABS(S);
316
    for (; ii<len; ii++) {
317
      val = lup(line, ii);
318
      if (AIR_EXISTS(val)) {
319
        S += AIR_ABS(val);
320
      }
321
    }
322
  }
323
  nrrdDStore[ansType](ans, S);
324
}
325
326
#define L2_BODY(FOUR)                            \
327
  AIR_UNUSED(axmin);                             \
328
  AIR_UNUSED(axmax);                             \
329
  lup = nrrdDLookup[lineType];                   \
330
  if (nrrdTypeIsIntegral[lineType]) {            \
331
    S = 0.0;                                     \
332
    count = len;                                 \
333
    for (ii=0; ii<len; ii++) {                   \
334
      val = lup(line, ii);                       \
335
      S += (FOUR) ? val*val*val*val : val*val;   \
336
    }                                            \
337
  } else {                                       \
338
    S = AIR_NAN;                                 \
339
    count = 0;                                   \
340
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { \
341
      S = lup(line, ii);                         \
342
    }                                            \
343
    if (AIR_EXISTS(S)) {                         \
344
      /* there's at least one existing value */  \
345
      count = 1;                                 \
346
      S *= (FOUR) ? S*S*S : S ;                  \
347
      for (; ii<len; ii++) {                     \
348
        val = lup(line, ii);                     \
349
        if (AIR_EXISTS(val)) {                   \
350
          count++;                               \
351
          S += (FOUR) ? val*val*val*val : val*val; \
352
        }                                        \
353
      }                                          \
354
    }                                            \
355
  }
356
357
void
358
_nrrdMeasureL2(void *ans, int ansType,
359
               const void *line, int lineType, size_t len,
360
               double axmin, double axmax) {
361
  double val, S, aa, (*lup)(const void*, size_t);
362
  size_t ii, count;
363
364
  L2_BODY(AIR_FALSE);
365
  if (AIR_EXISTS(S)) {
366
    aa = sqrt(S);
367
  } else {
368
    aa = AIR_NAN;
369
  }
370
  nrrdDStore[ansType](ans, aa);
371
}
372
373
void
374
_nrrdMeasureL4(void *ans, int ansType,
375
               const void *line, int lineType, size_t len,
376
               double axmin, double axmax) {
377
  double val, S, aa, (*lup)(const void*, size_t);
378
  size_t ii, count;
379
380
  L2_BODY(AIR_TRUE);
381
  if (AIR_EXISTS(S)) {
382
    aa = sqrt(sqrt(S));
383
  } else {
384
    aa = AIR_NAN;
385
  }
386
  nrrdDStore[ansType](ans, aa);
387
}
388
389
void
390
_nrrdMeasureNormalizedL2(void *ans, int ansType,
391
                         const void *line, int lineType, size_t len,
392
                         double axmin, double axmax) {
393
  double val, S, aa, (*lup)(const void*, size_t);
394
  size_t ii, count;
395
396
  L2_BODY(AIR_FALSE);
397
  if (AIR_EXISTS(S)) {
398
    aa = sqrt(S)/count;
399
  } else {
400
    aa = AIR_NAN;
401
  }
402
  nrrdDStore[ansType](ans, aa);
403
}
404
405
void
406
_nrrdMeasureRootMeanSquare(void *ans, int ansType,
407
                           const void *line, int lineType, size_t len,
408
                           double axmin, double axmax) {
409
  double val, S, aa, (*lup)(const void*, size_t);
410
  size_t ii, count;
411
412
  L2_BODY(AIR_FALSE);
413
  if (AIR_EXISTS(S)) {
414
    aa = sqrt(S/count);
415
  } else {
416
    aa = AIR_NAN;
417
  }
418
  nrrdDStore[ansType](ans, aa);
419
}
420
421
void
422
_nrrdMeasureLinf(void *ans, int ansType,
423
                 const void *line, int lineType, size_t len,
424
                 double axmin, double axmax) {
425
  double val, M, (*lup)(const void*, size_t);
426
  size_t ii;
427
428
  AIR_UNUSED(axmin);
429
  AIR_UNUSED(axmax);
430
  lup = nrrdDLookup[lineType];
431
  if (nrrdTypeIsIntegral[lineType]) {
432
    val = lup(line, 0);
433
    M = AIR_ABS(val);
434
    for (ii=1; ii<len; ii++) {
435
      val = lup(line, ii);
436
      val = AIR_ABS(val);
437
      M = AIR_MAX(M, val);
438
    }
439
  } else {
440
    M = AIR_NAN;
441
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
442
      M = lup(line, ii);
443
    }
444
    M = AIR_ABS(M);
445
    for (; ii<len; ii++) {
446
      val = lup(line, ii);
447
      if (AIR_EXISTS(val)) {
448
        val = AIR_ABS(val);
449
        M = AIR_MAX(M, val);
450
      }
451
    }
452
  }
453
  nrrdDStore[ansType](ans, M);
454
}
455
456
/* ========================================================== */
457
#if 0 /* two variance functions:
458
         0 for new two-pass (more accurate)
459
         1 for old single-pass */
460
461
void
462
_nrrdMeasureVariance(void *ans, int ansType,
463
                     const void *line, int lineType, size_t len,
464
                     double axmin, double axmax) {
465
  double val, S, SS, (*lup)(const void*, size_t);
466
  size_t ii, count;
467
468
  AIR_UNUSED(axmin);
469
  AIR_UNUSED(axmax);
470
  SS = S = 0.0;
471
  lup = nrrdDLookup[lineType];
472
  if (nrrdTypeIsIntegral[lineType]) {
473
    for (ii=0; ii<len; ii++) {
474
      val = lup(line, ii);
475
      S += val;
476
      SS += val*val;
477
    }
478
    S /= len;
479
    SS /= len;
480
  } else {
481
    count = 0;
482
    for (ii=0; ii<len; ii++) {
483
      val = lup(line, ii);
484
      if (AIR_EXISTS(val)) {
485
        count++;
486
        S += val;
487
        SS += val*val;
488
      }
489
    }
490
    if (count) {
491
      S /= count;
492
      SS /= count;
493
    } else {
494
      S = SS = AIR_NAN;
495
    }
496
  }
497
  /* HEY: the AIR_MAX is needed because precision errors
498
     can produce a negative value for SS - S*S;
499
     this may be a sign of the false economy of doing
500
     the variance calculation in a single pass */
501
  nrrdDStore[ansType](ans, AIR_MAX(0.0, SS - S*S));
502
}
503
504
#else /* ========================================================== */
505
506
void
507
_nrrdMeasureVariance(void *ans, int ansType,
508
                     const void *line, int lineType, size_t len,
509
                     double axmin, double axmax) {
510
  double vari, mean, val, (*lup)(const void*, size_t);
511
  size_t ii, count;
512
513
  AIR_UNUSED(axmin);
514
  AIR_UNUSED(axmax);
515
  mean = vari = 0.0;
516
  lup = nrrdDLookup[lineType];
517
  if (nrrdTypeIsIntegral[lineType]) {
518
    for (ii=0; ii<len; ii++) {
519
      mean += lup(line, ii);
520
    }
521
    mean /= len;
522
    for (ii=0; ii<len; ii++) {
523
      val = lup(line, ii);
524
      vari += (val-mean)*(val-mean);
525
    }
526
    vari /= len;
527
  } else {
528
    count = 0;
529
    for (ii=0; ii<len; ii++) {
530
      val = lup(line, ii);
531
      if (AIR_EXISTS(val)) {
532
        count++;
533
        mean += val;
534
      }
535
    }
536
    if (count) {
537
      mean /= count;
538
      for (ii=0; ii<len; ii++) {
539
        val = lup(line, ii);
540
        if (AIR_EXISTS(val)) {
541
          vari += (val-mean)*(val-mean);
542
        }
543
      }
544
      vari /= count;
545
    } else {
546
      vari = AIR_NAN;
547
    }
548
  }
549
  nrrdDStore[ansType](ans, vari);
550
}
551
552
#endif
553
/* ========================================================== */
554
555
void
556
_nrrdMeasureSD(void *ans, int ansType,
557
               const void *line, int lineType, size_t len,
558
               double axmin, double axmax) {
559
  double var;
560
561
  _nrrdMeasureVariance(ans, ansType, line, lineType, len, axmin, axmax);
562
  var = nrrdDLoad[ansType](ans);
563
  nrrdDStore[ansType](ans, sqrt(var));
564
}
565
566
void
567
_nrrdMeasureCoV(void *ans, int ansType,
568
                const void *line, int lineType, size_t len,
569
                double axmin, double axmax) {
570
  double val, S, M, (*lup)(const void*, size_t), diff, stdv;
571
  size_t ii, count;
572
573
  AIR_UNUSED(axmin);
574
  AIR_UNUSED(axmax);
575
  lup = nrrdDLookup[lineType];
576
  if (nrrdTypeIsIntegral[lineType]) {
577
    S = 0.0;
578
    for (ii=0; ii<len; ii++) {
579
      S += lup(line, ii);
580
    }
581
    M = S/len;
582
    diff = 0.0;
583
    for (ii=0; ii<len; ii++) {
584
      val = lup(line, ii);
585
      diff += (M-val)*(M-val);
586
    }
587
    stdv = sqrt(diff/len);
588
  } else {
589
    S = AIR_NAN;
590
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
591
      S = lup(line, ii);
592
    }
593
    if (AIR_EXISTS(S)) {
594
      /* there was an existent value */
595
      count = 1;
596
      for (; ii<len; ii++) {
597
        val = lup(line, ii);
598
        if (AIR_EXISTS(val)) {
599
          count++;
600
          S += val;
601
        }
602
      }
603
      M = S/count;
604
      diff = 0.0;
605
      for (ii=0; ii<len; ii++) {
606
        val = lup(line, ii);
607
        if (AIR_EXISTS(val)) {
608
          diff += (M-val)*(M-val);
609
        }
610
      }
611
      stdv = sqrt(diff/count);
612
    } else {
613
      /* there were NO existent values */
614
      M = stdv = AIR_NAN;
615
    }
616
  }
617
  nrrdDStore[ansType](ans, stdv/M);
618
}
619
620
void
621
_nrrdMeasureLineFit(double *intc, double *slope,
622
                    const void *line, int lineType, size_t len,
623
                    double axmin, double axmax) {
624
  double x, y, xi=0, yi=0, xiyi=0, xisq=0, det, (*lup)(const void*, size_t);
625
  size_t ii;
626
627
  lup = nrrdDLookup[lineType];
628
  if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) {
629
    axmin = 0;
630
    axmax = AIR_CAST(double, len-1);
631
  }
632
  if (1 == len) {
633
    *slope = 0;
634
    *intc = lup(line, 0);
635
  } else {
636
    for (ii=0; ii<len; ii++) {
637
      x = NRRD_NODE_POS(axmin, axmax, len, ii);
638
      y = lup(line, ii);
639
      xi += x;
640
      yi += y;
641
      xiyi += x*y;
642
      xisq += x*x;
643
    }
644
    det = len*xisq - xi*xi;
645
    *slope = (len*xiyi - xi*yi)/det;
646
    *intc = (-xi*xiyi + xisq*yi)/det;
647
  }
648
}
649
650
void
651
_nrrdMeasureLineSlope(void *ans, int ansType,
652
                      const void *line, int lineType, size_t len,
653
                      double axmin, double axmax) {
654
  double slope, intc;
655
656
  _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax);
657
  nrrdDStore[ansType](ans, slope);
658
}
659
660
void
661
_nrrdMeasureLineIntercept(void *ans, int ansType,
662
                          const void *line, int lineType, size_t len,
663
                          double axmin, double axmax) {
664
  double slope, intc;
665
666
  _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax);
667
  nrrdDStore[ansType](ans, intc);
668
}
669
670
void
671
_nrrdMeasureLineError(void *ans, int ansType,
672
                      const void *line, int lineType, size_t len,
673
                      double axmin, double axmax) {
674
  double x, y, slope, intc, tmp, err=0, (*lup)(const void*, size_t);
675
  size_t ii;
676
677
  _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax);
678
679
  if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) {
680
    axmin = 0;
681
    axmax = AIR_CAST(double, len-1);
682
  }
683
  lup = nrrdDLookup[lineType];
684
  for (ii=0; ii<len; ii++) {
685
    x = NRRD_NODE_POS(axmin, axmax, len, ii);
686
    y = lup(line, ii);
687
    tmp = slope*x + intc - y;
688
    err += tmp*tmp;
689
  }
690
  nrrdDStore[ansType](ans, err);
691
}
692
693
void
694
_nrrdMeasureSkew(void *ans, int ansType,
695
                 const void *line, int lineType, size_t len,
696
                 double axmin, double axmax) {
697
  double val, diff, mean, vari, third, (*lup)(const void*, size_t);
698
  size_t ii, count;
699
700
  AIR_UNUSED(axmin);
701
  AIR_UNUSED(axmax);
702
  /* we don't try to do any one-pass short-cuts */
703
704
  /* find the mean */
705
  mean = 0;
706
  lup = nrrdDLookup[lineType];
707
  if (nrrdTypeIsIntegral[lineType]) {
708
    count = len;
709
    for (ii=0; ii<len; ii++) {
710
      val = lup(line, ii);
711
      mean += val;
712
    }
713
  } else {
714
    count = 0;
715
    for (ii=0; ii<len; ii++) {
716
      val = lup(line, ii);
717
      if (AIR_EXISTS(val)) {
718
        count++;
719
        mean += val;
720
      }
721
    }
722
  }
723
  if (0 == count) {
724
    nrrdDStore[ansType](ans, AIR_NAN);
725
    return;
726
  }
727
  mean /= count;
728
729
  /* find the variance and third moment */
730
  vari = third = 0;
731
  if (nrrdTypeIsIntegral[lineType]) {
732
    for (ii=0; ii<len; ii++) {
733
      diff = lup(line, ii) - mean;
734
      vari += diff*diff;
735
      third += diff*diff*diff;
736
    }
737
  } else {
738
    for (ii=0; ii<len; ii++) {
739
      val = lup(line, ii);
740
      if (AIR_EXISTS(val)) {
741
        diff = val - mean;
742
        vari += diff*diff;
743
        third += diff*diff*diff;
744
      }
745
    }
746
  }
747
  if (0 == vari) {
748
    /* why not have an existent value ... */
749
    nrrdDStore[ansType](ans, 0);
750
    return;
751
  }
752
  vari /= count;
753
  third /= count;
754
755
  nrrdDStore[ansType](ans, third/(vari*sqrt(vari)));
756
}
757
758
/*
759
** one thing which ALL the _nrrdMeasureHisto measures assume is that,
760
** being a histogram, the input array will not have any non-existent
761
** values.  It can be floating point, because it is plausible to have
762
** some histogram composed of fractionally weighted hits, but there is
763
** no way that it is reasonable to have NaN in a bin, and it is extremely
764
** unlikely that Inf could actually be created in a floating point
765
** histogram.
766
**
767
** Values in the histogram can be positive or negative, but negative
768
** values are always ignored.
769
**
770
** All the the  _nrrdMeasureHisto measures assume that if not both
771
** axmin and axmax are existent, then (axmin,axmax) = (-0.5,len-0.5).
772
** Exercise for the reader:  Show that
773
**
774
**    i == NRRD_POS(nrrdCenterCell, 0, len-1, len, i)
775
**
776
** This justifies that fact that when axmin and axmax are not both
777
** existent, then we can simply calculate the answer in index space,
778
** and not have to do any shifting or scaling at the end to account
779
** for the fact that we assume (axmin,axmax) = (-0.5,len-0.5).
780
*/
781
782
void
783
_nrrdMeasureHistoMedian(void *ans, int ansType,
784
                        const void *line, int lineType, size_t len,
785
                        double axmin, double axmax) {
786
  double sum, tmp, half, ansD, (*lup)(const void*, size_t);
787
  size_t ii;
788
789
  lup = nrrdDLookup[lineType];
790
  sum = 0;
791
  for (ii=0; ii<len; ii++) {
792
    tmp = lup(line, ii);
793
    sum += (tmp > 0 ? tmp : 0);
794
  }
795
  if (!sum) {
796
    nrrdDStore[ansType](ans, AIR_NAN);
797
    return;
798
  }
799
  /* else there was something in the histogram */
800
  half = sum/2;
801
  sum = 0;
802
  for (ii=0; ii<len; ii++) {
803
    tmp = lup(line, ii);
804
    sum += (tmp > 0 ? tmp : 0);
805
    if (sum >= half) {
806
      break;
807
    }
808
  }
809
  ansD = AIR_CAST(double, ii);
810
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
811
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
812
  }
813
  nrrdDStore[ansType](ans, ansD);
814
}
815
816
void
817
_nrrdMeasureHistoMode(void *ans, int ansType,
818
                      const void *line, int lineType, size_t len,
819
                      double axmin, double axmax) {
820
  double val, max, idxsum, ansD, (*lup)(const void*, size_t);
821
  size_t ii, idxcount;
822
823
  lup = nrrdDLookup[lineType];
824
  max = -DBL_MAX;
825
  for (ii=0; ii<len; ii++) {
826
    val = lup(line, ii);
827
    if (AIR_EXISTS(val)) {
828
      max = AIR_MAX(max, val);
829
    }
830
  }
831
  if (-DBL_MAX == max) {
832
    nrrdDStore[ansType](ans, AIR_NAN);
833
    return;
834
  }
835
  /* else there was something in the histogram */
836
  /* we assume that there may be multiple bins which reach the maximum
837
     height, and we average all those indices.  This may well be
838
     bone-headed, and is subject to change.  19 July 03: with the
839
     addition of the final "type" argument to nrrdProject, the
840
     bone-headedness has been alleviated somewhat, since you can pass
841
     nrrdTypeFloat or nrrdTypeDouble to get an accurate answer */
842
  idxsum = 0;
843
  idxcount = 0;
844
  for (ii=0; ii<len; ii++) {
845
    val = lup(line, ii);
846
    if (val == max) {
847
      idxcount++;
848
      idxsum += ii;
849
    }
850
  }
851
  if (max == 0 && len == idxcount) {
852
    /* entire histogram was zeros => empty distribution => no mode */
853
    nrrdDStore[ansType](ans, AIR_NAN);
854
    return;
855
  }
856
  ansD = idxsum/idxcount;
857
  /*
858
  printf("idxsum = %g; idxcount = %d --> ansD = %g --> ",
859
         (float)idxsum, idxcount, ansD);
860
  */
861
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
862
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
863
  }
864
  /*
865
  printf("%g\n", ansD);
866
  */
867
  nrrdDStore[ansType](ans, ansD);
868
}
869
870
void
871
_nrrdMeasureHistoMean(void *ans, int ansType,
872
                      const void *line, int lineType, size_t len,
873
                      double axmin, double axmax) {
874
  double count, hits, ansD, (*lup)(const void*, size_t);
875
  size_t ii;
876
877
  lup = nrrdDLookup[lineType];
878
  ansD = count = 0;
879
  for (ii=0; ii<len; ii++) {
880
    hits = lup(line, ii);
881
    hits = AIR_MAX(hits, 0);
882
    count += hits;
883
    ansD += hits*ii;
884
  }
885
  if (!count) {
886
    nrrdDStore[ansType](ans, AIR_NAN);
887
    return;
888
  }
889
  ansD /= count;
890
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
891
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
892
  }
893
  nrrdDStore[ansType](ans, ansD);
894
}
895
896
void
897
_nrrdMeasureHistoVariance(void *ans, int ansType,
898
                          const void *line, int lineType, size_t len,
899
                          double axmin, double axmax) {
900
  double S, SS, count, hits, val, (*lup)(const void*, size_t);
901
  size_t ii;
902
903
  lup = nrrdDLookup[lineType];
904
  count = 0;
905
  SS = S = 0.0;
906
  /* we fix axmin, axmax now because GK is better safe than sorry */
907
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
908
    axmin = -0.5;
909
    axmax = len-0.5;
910
  }
911
  for (ii=0; ii<len; ii++) {
912
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
913
    hits = lup(line, ii);
914
    hits = AIR_MAX(hits, 0);
915
    count += hits;
916
    S += hits*val;
917
    SS += hits*val*val;
918
  }
919
  if (!count) {
920
    nrrdDStore[ansType](ans, AIR_NAN);
921
    return;
922
  }
923
  S /= count;
924
  SS /= count;
925
  /* HEY: the AIR_MAX is needed because precision errors
926
     can produce a negative value for SS - S*S;
927
     this may be a sign of the false economy of doing
928
     the variance calculation in a single pass */
929
  nrrdDStore[ansType](ans, AIR_MAX(0.0, SS - S*S));
930
}
931
932
void
933
_nrrdMeasureHistoSD(void *ans, int ansType,
934
                    const void *line, int lineType, size_t len,
935
                    double axmin, double axmax) {
936
  double var;
937
938
  _nrrdMeasureHistoVariance(ans, ansType, line, lineType, len, axmin, axmax);
939
  var = nrrdDLoad[ansType](ans);
940
  nrrdDStore[ansType](ans, sqrt(var));
941
}
942
943
void
944
_nrrdMeasureHistoProduct(void *ans, int ansType,
945
                         const void *line, int lineType, size_t len,
946
                         double axmin, double axmax) {
947
  double val, product, count, hits, (*lup)(const void*, size_t);
948
  size_t ii;
949
950
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
951
    axmin = -0.5;
952
    axmax = len-0.5;
953
  }
954
  lup = nrrdDLookup[lineType];
955
  product = 1.0;
956
  count = 0;
957
  for (ii=0; ii<len; ii++) {
958
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
959
    hits = lup(line, ii);
960
    hits = AIR_MAX(hits, 0);
961
    count += hits;
962
    product *= pow(val, hits);
963
  }
964
  if (!count) {
965
    nrrdDStore[ansType](ans, AIR_NAN);
966
    return;
967
  }
968
  nrrdDStore[ansType](ans, product);
969
}
970
971
void
972
_nrrdMeasureHistoSum(void *ans, int ansType,
973
                     const void *line, int lineType, size_t len,
974
                     double axmin, double axmax) {
975
  double sum, hits, val, (*lup)(const void*, size_t);
976
  size_t ii;
977
978
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
979
    axmin = -0.5;
980
    axmax = len-0.5;
981
  }
982
  lup = nrrdDLookup[lineType];
983
  sum = 0;
984
  for (ii=0; ii<len; ii++) {
985
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
986
    hits = lup(line, ii);
987
    hits = AIR_MAX(hits, 0);
988
    sum += hits*val;
989
  }
990
  nrrdDStore[ansType](ans, sum);
991
}
992
993
void
994
_nrrdMeasureHistoL2(void *ans, int ansType,
995
                    const void *line, int lineType, size_t len,
996
                    double axmin, double axmax) {
997
  double l2, count, hits, val, (*lup)(const void*, size_t);
998
  size_t ii;
999
1000
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
1001
    axmin = -0.5;
1002
    axmax = len-0.5;
1003
  }
1004
  lup = nrrdDLookup[lineType];
1005
  l2 = count = 0;
1006
  for (ii=0; ii<len; ii++) {
1007
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
1008
    hits = lup(line, ii);
1009
    hits = AIR_MAX(hits, 0);
1010
    count += hits;
1011
    l2 += hits*val*val;
1012
  }
1013
  if (!count) {
1014
    nrrdDStore[ansType](ans, AIR_NAN);
1015
    return;
1016
  }
1017
  nrrdDStore[ansType](ans, l2);
1018
}
1019
1020
void
1021
_nrrdMeasureHistoMax(void *ans, int ansType,
1022
                     const void *line, int lineType, size_t len,
1023
                     double axmin, double axmax) {
1024
  double val, (*lup)(const void*, size_t);
1025
  size_t ii;
1026
1027
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
1028
    axmin = -0.5;
1029
    axmax = len-0.5;
1030
  }
1031
  lup = nrrdDLookup[lineType];
1032
  /* we're using ii-1 as index to avoid wrap-around with size_t index */
1033
  for (ii=len; ii>0; ii--) {
1034
    if (lup(line, ii-1) > 0) {
1035
      break;
1036
    }
1037
  }
1038
  if (ii==0) {
1039
    nrrdDStore[ansType](ans, AIR_NAN);
1040
    return;
1041
  }
1042
  val = NRRD_CELL_POS(axmin, axmax, len, ii-1);
1043
  nrrdDStore[ansType](ans, val);
1044
}
1045
1046
void
1047
_nrrdMeasureHistoMin(void *ans, int ansType,
1048
                     const void *line, int lineType, size_t len,
1049
                     double axmin, double axmax) {
1050
  double val, (*lup)(const void*, size_t);
1051
  size_t ii;
1052
1053
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
1054
    axmin = -0.5;
1055
    axmax = len-0.5;
1056
  }
1057
  lup = nrrdDLookup[lineType];
1058
  for (ii=0; ii<len; ii++) {
1059
    if (lup(line, ii) > 0) {
1060
      break;
1061
    }
1062
  }
1063
  if (ii==len) {
1064
    nrrdDStore[ansType](ans, AIR_NAN);
1065
    return;
1066
  }
1067
  val = NRRD_CELL_POS(axmin, axmax, len, ii);
1068
  nrrdDStore[ansType](ans, val);
1069
}
1070
1071
void (*
1072
nrrdMeasureLine[NRRD_MEASURE_MAX+1])(void *, int,
1073
                                     const void *, int, size_t,
1074
                                     double, double) = {
1075
  _nrrdMeasureUnknown,
1076
  _nrrdMeasureMin,
1077
  _nrrdMeasureMax,
1078
  _nrrdMeasureMean,
1079
  _nrrdMeasureMedian,
1080
  _nrrdMeasureMode,
1081
  _nrrdMeasureProduct,
1082
  _nrrdMeasureSum,
1083
  _nrrdMeasureL1,
1084
  _nrrdMeasureL2,
1085
  _nrrdMeasureL4,
1086
  _nrrdMeasureNormalizedL2,
1087
  _nrrdMeasureRootMeanSquare,
1088
  _nrrdMeasureLinf,
1089
  _nrrdMeasureVariance,
1090
  _nrrdMeasureSD,
1091
  _nrrdMeasureCoV,
1092
  _nrrdMeasureSkew,
1093
  _nrrdMeasureLineSlope,
1094
  _nrrdMeasureLineIntercept,
1095
  _nrrdMeasureLineError,
1096
  _nrrdMeasureHistoMin,
1097
  _nrrdMeasureHistoMax,
1098
  _nrrdMeasureHistoMean,
1099
  _nrrdMeasureHistoMedian,
1100
  _nrrdMeasureHistoMode,
1101
  _nrrdMeasureHistoProduct,
1102
  _nrrdMeasureHistoSum,
1103
  _nrrdMeasureHistoL2,
1104
  _nrrdMeasureHistoVariance,
1105
  _nrrdMeasureHistoSD
1106
};
1107
1108
int
1109
_nrrdMeasureType(const Nrrd *nin, int measr) {
1110
  static const char me[]="_nrrdMeasureType";
1111
  int type=nrrdTypeUnknown;
1112
1113
  switch(measr) {
1114
  case nrrdMeasureMin:
1115
  case nrrdMeasureMax:
1116
  case nrrdMeasureMedian:
1117
  case nrrdMeasureMode:
1118
    type = nin->type;
1119
    break;
1120
  case nrrdMeasureMean:
1121
    /* the rational for this is that if you're after the average value
1122
       along a scanline, you probably want it in the same format as
1123
       what you started with, and if you really want an exact answer
1124
       than you can always use nrrdMeasureSum and then divide.  This may
1125
       well be bone-headed, so is subject to change */
1126
    type = nin->type;
1127
    break;
1128
  case nrrdMeasureProduct:
1129
  case nrrdMeasureSum:
1130
  case nrrdMeasureL1:
1131
  case nrrdMeasureL2:
1132
  case nrrdMeasureL4:
1133
  case nrrdMeasureNormalizedL2:
1134
  case nrrdMeasureRootMeanSquare:
1135
  case nrrdMeasureLinf:
1136
  case nrrdMeasureVariance:
1137
  case nrrdMeasureSD:
1138
  case nrrdMeasureCoV:
1139
  case nrrdMeasureSkew:
1140
  case nrrdMeasureLineSlope:
1141
  case nrrdMeasureLineIntercept:
1142
  case nrrdMeasureLineError:
1143
    type = nrrdStateMeasureType;
1144
    break;
1145
  case nrrdMeasureHistoMin:
1146
  case nrrdMeasureHistoMax:
1147
  case nrrdMeasureHistoProduct:
1148
  case nrrdMeasureHistoSum:
1149
  case nrrdMeasureHistoL2:
1150
  case nrrdMeasureHistoMean:
1151
  case nrrdMeasureHistoMedian:
1152
  case nrrdMeasureHistoMode:
1153
  case nrrdMeasureHistoVariance:
1154
  case nrrdMeasureHistoSD:
1155
    /* We (currently) don't keep track of the type of the original
1156
       values which generated the histogram, and we may not even
1157
       have access to that information.  So we end up choosing one
1158
       type for all these histogram-based measures */
1159
    type = nrrdStateMeasureHistoType;
1160
    break;
1161
  default:
1162
    fprintf(stderr, "%s: PANIC: measr %d not handled\n", me, measr);
1163
    exit(1);
1164
  }
1165
1166
  return type;
1167
}
1168
1169
int
1170
nrrdProject(Nrrd *nout, const Nrrd *cnin, unsigned int axis,
1171
            int measr, int type) {
1172
  static const char me[]="nrrdProject", func[]="project";
1173
  int iType, oType, axmap[NRRD_DIM_MAX];
1174
  unsigned int ai, ei;
1175
  size_t iElSz, oElSz, iSize[NRRD_DIM_MAX], oSize[NRRD_DIM_MAX], linLen,
1176
    rowIdx, rowNum, colIdx, colNum, colStep;
1177
  const char *ptr, *iData;
1178
  char *oData, *line;
1179
  double axmin, axmax;
1180
  Nrrd *nin;
1181
  airArray *mop;
1182
1183
  if (!(cnin && nout)) {
1184
    biffAddf(NRRD, "%s: got NULL pointer", me);
1185
    return 1;
1186
  }
1187
  if (nout == cnin) {
1188
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
1189
    return 1;
1190
  }
1191
  if (nrrdTypeBlock == cnin->type) {
1192
    biffAddf(NRRD, "%s: can't project nrrd type %s", me,
1193
             airEnumStr(nrrdType, nrrdTypeBlock));
1194
    return 1;
1195
  }
1196
  if (!AIR_IN_OP(nrrdMeasureUnknown, measr, nrrdMeasureLast)) {
1197
    biffAddf(NRRD, "%s: measure %d not recognized", me, measr);
1198
    return 1;
1199
  }
1200
  if (1 == cnin->dim) {
1201
    if (0 != axis) {
1202
      biffAddf(NRRD, "%s: axis must be 0, not %u, for 1-D array", me, axis);
1203
      return 1;
1204
    }
1205
  } else {
1206
    if (!( axis <= cnin->dim-1 )) {
1207
      biffAddf(NRRD, "%s: axis %u not in range [0,%d]", me, axis, cnin->dim-1);
1208
      return 1;
1209
    }
1210
  }
1211
  if (nrrdTypeDefault != type) {
1212
    if (!( AIR_IN_OP(nrrdTypeUnknown, type, nrrdTypeLast) )) {
1213
      biffAddf(NRRD, "%s: got invalid target type %d", me, type);
1214
      return 1;
1215
    }
1216
  }
1217
1218
  mop = airMopNew();
1219
  if (1 == cnin->dim) {
1220
    /* There are more efficient ways of dealing with this case; this way is
1221
       easy to implement because it leaves most of the established code below
1222
       only superficially changed; uniformly replacing nin with (nin ? nin :
1223
       cnin), even if pointlessly so; this expression that can't be assigned
1224
       to a new variable because of the difference in const. */
1225
    nin = nrrdNew();
1226
    airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
1227
    if (nrrdAxesInsert(nin, cnin, 1)) {
1228
      biffAddf(NRRD, "%s: trouble inserting axis on 1-D array", me);
1229
      airMopError(mop); return 1;
1230
    }
1231
  } else {
1232
    nin = NULL;
1233
  }
1234
1235
  iType = (nin ? nin : cnin)->type;
1236
  oType = (nrrdTypeDefault != type
1237
           ? type
1238
           : _nrrdMeasureType((nin ? nin : cnin), measr));
1239
  iElSz = nrrdTypeSize[iType];
1240
  oElSz = nrrdTypeSize[oType];
1241
  nrrdAxisInfoGet_nva((nin ? nin : cnin), nrrdAxisInfoSize, iSize);
1242
  colNum = rowNum = 1;
1243
  for (ai=0; ai<(nin ? nin : cnin)->dim; ai++) {
1244
    if (ai < axis) {
1245
      colNum *= iSize[ai];
1246
    } else if (ai > axis) {
1247
      rowNum *= iSize[ai];
1248
    }
1249
  }
1250
  linLen = iSize[axis];
1251
  colStep = linLen*colNum;
1252
  for (ai=0; ai<=(nin ? nin : cnin)->dim-2; ai++) {
1253
    axmap[ai] = ai + (ai >= axis);
1254
  }
1255
  for (ai=0; ai<=(nin ? nin : cnin)->dim-2; ai++) {
1256
    oSize[ai] = iSize[axmap[ai]];
1257
  }
1258
  if (nrrdMaybeAlloc_nva(nout, oType, (nin ? nin : cnin)->dim-1, oSize)) {
1259
    biffAddf(NRRD, "%s: failed to create output", me);
1260
    airMopError(mop); return 1;
1261
  }
1262
1263
  /* allocate a scanline buffer */
1264
  if (!(line = AIR_CALLOC(linLen*iElSz, char))) {
1265
    char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
1266
    biffAddf(NRRD, "%s: couldn't calloc(%s,%s) scanline buffer", me,
1267
             airSprintSize_t(stmp1, linLen),
1268
             airSprintSize_t(stmp2, iElSz));
1269
    airMopError(mop); return 1;
1270
  }
1271
  airMopAdd(mop, line, airFree, airMopAlways);
1272
1273
  /* the skinny */
1274
  axmin = (nin ? nin : cnin)->axis[axis].min;
1275
  axmax = (nin ? nin : cnin)->axis[axis].max;
1276
  iData = AIR_CAST(char *, (nin ? nin : cnin)->data);
1277
  oData = AIR_CAST(char *, nout->data);
1278
  for (rowIdx=0; rowIdx<rowNum; rowIdx++) {
1279
    for (colIdx=0; colIdx<colNum; colIdx++) {
1280
      ptr = iData + iElSz*(colIdx + rowIdx*colStep);
1281
      for (ei=0; ei<linLen; ei++) {
1282
        memcpy(line + ei*iElSz, ptr + ei*iElSz*colNum, iElSz);
1283
      }
1284
      nrrdMeasureLine[measr](oData, oType, line, iType, linLen,
1285
                             axmin, axmax);
1286
      oData += oElSz;
1287
    }
1288
  }
1289
1290
  /* copy the peripheral information */
1291
  if (nrrdAxisInfoCopy(nout, (nin ? nin : cnin), axmap, NRRD_AXIS_INFO_NONE)) {
1292
    biffAddf(NRRD, "%s:", me);
1293
    airMopError(mop); return 1;
1294
  }
1295
  if (nrrdContentSet_va(nout, func, cnin /* hide possible axinsert */,
1296
                        "%d,%s", axis, airEnumStr(nrrdMeasure, measr))) {
1297
    biffAddf(NRRD, "%s:", me);
1298
    airMopError(mop); return 1;
1299
  }
1300
  /* this will copy the space origin over directly, which is reasonable */
1301
  if (nrrdBasicInfoCopy(nout, (nin ? nin : cnin),
1302
                        NRRD_BASIC_INFO_DATA_BIT
1303
                        | NRRD_BASIC_INFO_TYPE_BIT
1304
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
1305
                        | NRRD_BASIC_INFO_DIMENSION_BIT
1306
                        | NRRD_BASIC_INFO_CONTENT_BIT
1307
                        | NRRD_BASIC_INFO_COMMENTS_BIT
1308
                        | (nrrdStateKeyValuePairsPropagate
1309
                           ? 0
1310
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
1311
    biffAddf(NRRD, "%s:", me);
1312
    airMopError(mop); return 1;
1313
  }
1314
1315
  airMopOkay(mop);
1316
  return 0;
1317
}