GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/superset.c Lines: 123 307 40.1 %
Date: 2017-05-26 Branches: 90 216 41.7 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "nrrd.h"
25
#include "privateNrrd.h"
26
27
/*
28
******** nrrdSplice()
29
**
30
** (opposite of nrrdSlice): replaces one slice of a nrrd with
31
** another nrrd.  Will allocate memory for output only if nout != nin.
32
*/
33
int
34
nrrdSplice(Nrrd *nout, const Nrrd *nin, const Nrrd *nslice,
35
           unsigned int axis, size_t pos) {
36
  static const char me[]="nrrdSplice", func[]="splice";
37
  size_t
38
    I,
39
    rowLen,                  /* length of segment */
40
    colStep,                 /* distance between start of each segment */
41
    colLen;                  /* number of periods */
42
  unsigned int ai;
43
  char *src, *dest, *sliceCont;
44
16
  char stmp[2][AIR_STRLEN_SMALL];
45
46
8
  if (!(nin && nout && nslice)) {
47
    biffAddf(NRRD, "%s: got NULL pointer", me);
48
    return 1;
49
  }
50
8
  if (nout == nslice) {
51
    biffAddf(NRRD, "%s: nout==nslice disallowed", me);
52
    return 1;
53
  }
54
55
  /* check that desired slice location is legit */
56
8
  if (!( axis < nin->dim )) {
57
    biffAddf(NRRD, "%s: slice axis %d out of bounds (0 to %d)",
58
             me, axis, nin->dim-1);
59
    return 1;
60
  }
61
8
  if (!( pos < nin->axis[axis].size )) {
62
    biffAddf(NRRD, "%s: position %s out of bounds (0 to %s)", me,
63
             airSprintSize_t(stmp[0], pos),
64
             airSprintSize_t(stmp[1], nin->axis[axis].size-1));
65
    return 1;
66
  }
67
68
  /* check that slice will fit in nin */
69

16
  if (nrrdCheck(nslice) || nrrdCheck(nin)) {
70
    biffAddf(NRRD, "%s: input or slice not valid nrrd", me);
71
    return 1;
72
  }
73
8
  if (!( nin->dim-1 == nslice->dim )) {
74
    biffAddf(NRRD, "%s: dim of slice (%d) not one less than "
75
             "dim of input (%d)", me, nslice->dim, nin->dim);
76
    return 1;
77
  }
78
8
  if (!( nin->type == nslice->type )) {
79
    biffAddf(NRRD, "%s: type of slice (%s) != type of input (%s)",
80
             me, airEnumStr(nrrdType, nslice->type),
81
             airEnumStr(nrrdType, nin->type));
82
    return 1;
83
  }
84
8
  if (nrrdTypeBlock == nin->type) {
85
    if (!( nin->blockSize == nslice->blockSize )) {
86
      biffAddf(NRRD, "%s: input's blockSize (%s) != subvolume's (%s)", me,
87
               airSprintSize_t(stmp[0], nin->blockSize),
88
               airSprintSize_t(stmp[1], nslice->blockSize));
89
      return 1;
90
    }
91
  }
92
64
  for (ai=0; ai<nslice->dim; ai++) {
93
24
    const unsigned int indexOffset = (ai >= axis);
94
    unsigned int foundExitCondition = 0;
95
24
    if(indexOffset){
96
24
      if( nin->axis[ai + 1].size != nslice ->axis[ai].size ) foundExitCondition = 1;
97
    }
98
    else if( nin->axis[ai].size != nslice ->axis[ai].size ) foundExitCondition = 1;
99
24
    if ( foundExitCondition ) {
100
      biffAddf(NRRD, "%s: input ax %u size (%s) != slices ax %u size (%s)",
101
               me, ai + indexOffset,
102
               airSprintSize_t(stmp[0], nin->axis[ai + indexOffset].size), ai,
103
               airSprintSize_t(stmp[1], nslice->axis[ai].size));
104
      return 1;
105
    }
106
24
  }
107
108
8
  if (nout != nin) {
109
8
    if (nrrdCopy(nout, nin)) {
110
      biffAddf(NRRD, "%s:", me);
111
      return 1;
112
    }
113
  }
114
  /* else we're going to splice in place */
115
116
  /* the following was copied from nrrdSlice() */
117
  /* set up control variables */
118
  rowLen = colLen = 1;
119
80
  for (ai=0; ai<nin->dim; ai++) {
120
32
    if (ai < axis) {
121
      rowLen *= nin->axis[ai].size;
122
32
    } else if (ai > axis) {
123
24
      colLen *= nin->axis[ai].size;
124
24
    }
125
  }
126
8
  rowLen *= nrrdElementSize(nin);
127
8
  colStep = rowLen*nin->axis[axis].size;
128
129
  /* the skinny */
130
8
  src = (char *)nout->data;    /* switched src,dest from nrrdSlice() */
131
8
  dest = (char *)nslice->data;
132
8
  src += rowLen*pos;
133
1556656
  for (I=0; I<colLen; I++) {
134
    /* HEY: replace with AIR_MEMCPY() or similar, when applicable */
135
778320
    memcpy(src, dest, rowLen);  /* switched src,dest from nrrdSlice() */
136
778320
    src += colStep;
137
778320
    dest += rowLen;
138
  }
139
140
8
  sliceCont = _nrrdContentGet(nslice);
141
8
  if (nrrdContentSet_va(nout, func, nin, "%s,%d,%s", sliceCont, axis,
142
8
                        airSprintSize_t(stmp[0], pos))) {
143
    biffAddf(NRRD, "%s:", me);
144
    free(sliceCont); return 1;
145
  }
146
8
  free(sliceCont);
147
  /* basic info copied by nrrdCopy above */
148
149
8
  return 0;
150
8
}
151
152
/*
153
******** nrrdInset()
154
**
155
** (opposite of nrrdCrop()) replace some sub-volume inside a nrrd with
156
** another given nrrd.
157
**
158
*/
159
int
160
nrrdInset(Nrrd *nout, const Nrrd *nin, const Nrrd *nsub, const size_t *min) {
161
  static const char me[]="nrrdInset", func[] = "inset";
162
  char buff1[NRRD_DIM_MAX*30], buff2[AIR_STRLEN_SMALL];
163
  unsigned int ai;
164
  size_t I,
165
    lineSize,                /* #bytes in one scanline to be copied */
166
    typeSize,                /* size of data type */
167
    cIn[NRRD_DIM_MAX],       /* coords for line start, in input */
168
    cOut[NRRD_DIM_MAX],      /* coords for line start, in output */
169
    szIn[NRRD_DIM_MAX],
170
    szOut[NRRD_DIM_MAX],
171
    idxIn, idxOut,           /* linear indices for input and output */
172
    numLines;                /* number of scanlines in output nrrd */
173
  char *dataIn, *dataOut, *subCont, stmp[3][AIR_STRLEN_SMALL];
174
175
  /* errors */
176
  if (!(nout && nin && nsub && min)) {
177
    biffAddf(NRRD, "%s: got NULL pointer", me);
178
    return 1;
179
  }
180
  if (nout == nsub) {
181
    biffAddf(NRRD, "%s: nout==nsub disallowed", me);
182
    return 1;
183
  }
184
  if (nrrdCheck(nin)) {
185
    biffAddf(NRRD, "%s: input not valid nrrd", me);
186
    return 1;
187
  }
188
  if (nrrdCheck(nsub)) {
189
    biffAddf(NRRD, "%s: subvolume not valid nrrd", me);
190
    return 1;
191
  }
192
  if (!( nin->dim == nsub->dim )) {
193
    biffAddf(NRRD, "%s: input's dim (%d) != subvolume's dim (%d)",
194
             me, nin->dim, nsub->dim);
195
    return 1;
196
  }
197
  if (!( nin->type == nsub->type )) {
198
    biffAddf(NRRD, "%s: input's type (%s) != subvolume's type (%s)", me,
199
             airEnumStr(nrrdType, nin->type),
200
             airEnumStr(nrrdType, nsub->type));
201
    return 1;
202
  }
203
  if (nrrdTypeBlock == nin->type) {
204
    if (!( nin->blockSize == nsub->blockSize )) {
205
      biffAddf(NRRD, "%s: input's blockSize (%s) != subvolume's (%s)", me,
206
               airSprintSize_t(stmp[0], nin->blockSize),
207
               airSprintSize_t(stmp[1], nsub->blockSize));
208
      return 1;
209
    }
210
  }
211
  for (ai=0; ai<nin->dim; ai++) {
212
    if (!( min[ai] + nsub->axis[ai].size - 1 <= nin->axis[ai].size - 1)) {
213
      biffAddf(NRRD, "%s: axis %d range of inset indices [%s,%s] not within "
214
               "input indices [0,%s]", me, ai,
215
               airSprintSize_t(stmp[0], min[ai]),
216
               airSprintSize_t(stmp[1], min[ai] + nsub->axis[ai].size - 1),
217
               airSprintSize_t(stmp[2], nin->axis[ai].size - 1));
218
      return 1;
219
    }
220
  }
221
222
  if (nout != nin) {
223
    if (nrrdCopy(nout, nin)) {
224
      biffAddf(NRRD, "%s:", me);
225
      return 1;
226
    }
227
  }
228
  /* else we're going to inset in place */
229
230
  /* WARNING: following code copied/modified from nrrdCrop(),
231
     so the meanings of "in"/"out", "src"/"dest" are all messed up */
232
233
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn);
234
  nrrdAxisInfoGet_nva(nsub, nrrdAxisInfoSize, szOut);
235
  numLines = 1;
236
  for (ai=1; ai<nin->dim; ai++) {
237
    numLines *= szOut[ai];
238
  }
239
  lineSize = szOut[0]*nrrdElementSize(nin);
240
241
  /* the skinny */
242
  typeSize = nrrdElementSize(nin);
243
  dataIn = (char *)nout->data;
244
  dataOut = (char *)nsub->data;
245
  for (ai=0; ai<NRRD_DIM_MAX; ai++) {
246
    cOut[ai] = 0;
247
  }
248
  for (I=0; I<numLines; I++) {
249
    for (ai=0; ai<nin->dim; ai++) {
250
      cIn[ai] = cOut[ai] + min[ai];
251
    }
252
    NRRD_INDEX_GEN(idxOut, cOut, szOut, nin->dim);
253
    NRRD_INDEX_GEN(idxIn, cIn, szIn, nin->dim);
254
    memcpy(dataIn + idxIn*typeSize, dataOut + idxOut*typeSize, lineSize);
255
    /* the lowest coordinate in cOut[] will stay zero, since we are
256
       copying one (1-D) scanline at a time */
257
    NRRD_COORD_INCR(cOut, szOut, nin->dim, 1);
258
  }
259
260
  /* HEY: before Teem version 2.0 figure out nrrdKind stuff here */
261
262
  strcpy(buff1, "[");
263
  for (ai=0; ai<nin->dim; ai++) {
264
    sprintf(buff2, "%s%s", (ai ? "," : ""),
265
            airSprintSize_t(stmp[0], min[ai]));
266
    strcat(buff1, buff2);
267
  }
268
  strcat(buff1, "]");
269
  subCont = _nrrdContentGet(nsub);
270
  if (nrrdContentSet_va(nout, func, nin, "%s,%s", subCont, buff1)) {
271
    biffAddf(NRRD, "%s:", me);
272
    free(subCont); return 1;
273
  }
274
  free(subCont);
275
  /* basic info copied by nrrdCopy above */
276
277
  return 0;
278
}
279
280
#define MIRROR(N, I, M) \
281
  M = (I < 0 ? -I : I); \
282
  M = M % (2*N);        \
283
  M = (M >= N           \
284
       ? 2*N - 1 - M    \
285
       : M)             \
286
287
size_t
288
_nrrdMirror_64(size_t N, ptrdiff_t I) {
289
  size_t M;
290
291
  M = (I < 0 ? -I : I);
292
  M = M % (2*N);
293
  M = (M >= N
294
       ? 2*N - 1 - M
295
       : M);
296
  return M;
297
}
298
299
unsigned int
300
_nrrdMirror_32(unsigned int N, int I) {
301
  unsigned int M;
302
303
  M = (I < 0 ? -I : I);
304
  M = M % (2*N);
305
  M = (M >= N
306
       ? 2*N - 1 - M
307
       : M);
308
  return M;
309
}
310
311
/*
312
******** nrrdPad_va()
313
**
314
** strictly for padding
315
*/
316
int
317
nrrdPad_va(Nrrd *nout, const Nrrd *nin,
318
           const ptrdiff_t *min, const ptrdiff_t *max, int boundary, ...) {
319
  static const char me[]="nrrdPad_va", func[]="pad";
320
48
  char buff1[NRRD_DIM_MAX*30], buff2[AIR_STRLEN_MED];
321
24
  double padValue=AIR_NAN;
322
  int outside; /* whether current sample in output has any coordinates
323
                  that are outside the input volume (this is per-sample,
324
                  not per-axis) */
325
  unsigned int ai;
326
24
  ptrdiff_t
327
    cIn[NRRD_DIM_MAX];       /* coords for line start, in input */
328
24
  size_t
329
    typeSize,
330
    idxIn, idxOut,           /* linear indices for input and output */
331
    numOut,                  /* number of elements in output nrrd */
332
    szIn[NRRD_DIM_MAX],
333
    szOut[NRRD_DIM_MAX],
334
    cOut[NRRD_DIM_MAX];      /* coords for line start, in output */
335
24
  va_list ap;
336
  char *dataIn, *dataOut;
337
24
  char stmp[2][AIR_STRLEN_SMALL];
338
339
24
  if (!(nout && nin && min && max)) {
340
    biffAddf(NRRD, "%s: got NULL pointer", me);
341
    return 1;
342
  }
343
24
  if (nout == nin) {
344
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
345
    return 1;
346
  }
347
24
  if (!AIR_IN_OP(nrrdBoundaryUnknown, boundary, nrrdBoundaryLast)) {
348
    biffAddf(NRRD, "%s: boundary behavior %d invalid", me, boundary);
349
    return 1;
350
  }
351
24
  if (nrrdBoundaryWeight == boundary) {
352
    biffAddf(NRRD, "%s: boundary strategy %s not applicable here", me,
353
             airEnumStr(nrrdBoundary, boundary));
354
    return 1;
355
  }
356
24
  if (nrrdTypeBlock == nin->type && nrrdBoundaryPad == boundary) {
357
    biffAddf(NRRD, "%s: with nrrd type %s, boundary %s not valid", me,
358
             airEnumStr(nrrdType, nrrdTypeBlock),
359
             airEnumStr(nrrdBoundary, nrrdBoundaryPad));
360
    return 1;
361
  }
362
24
  va_start(ap, boundary);
363
24
  if (nrrdBoundaryPad == boundary) {
364
48
    padValue = va_arg(ap, double);
365
16
  }
366
24
  va_end(ap);
367

24
  switch(boundary) {
368
  case nrrdBoundaryPad:
369
  case nrrdBoundaryBleed:
370
  case nrrdBoundaryWrap:
371
  case nrrdBoundaryMirror:
372
    break;
373
  default:
374
    biffAddf(NRRD, "%s: sorry boundary %s (%d) unimplemented\n",
375
             me, airEnumStr(nrrdBoundary, boundary), boundary);
376
    return 1;
377
  }
378
  /*
379
  printf("!%s: boundary = %d, padValue = %g\n", me, boundary, padValue);
380
  */
381
382
24
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn);
383
208
  for (ai=0; ai<nin->dim; ai++) {
384
80
    if (!( min[ai] <= 0 )) {
385
      biffAddf(NRRD, "%s: axis %d min (%s) not <= 0", me, ai,
386
               airSprintPtrdiff_t(stmp[0], min[ai]));
387
      return 1;
388
    }
389
80
    if (!( (size_t)max[ai] >= szIn[ai]-1)) {
390
      biffAddf(NRRD, "%s: axis %d max (%s) not >= size-1 (%s)", me, ai,
391
               airSprintPtrdiff_t(stmp[0], max[ai]),
392
               airSprintSize_t(stmp[1], szIn[ai]-1));
393
      return 1;
394
    }
395
  }
396
  /* this shouldn't actually be necessary .. */
397
24
  if (!nrrdElementSize(nin)) {
398
    biffAddf(NRRD, "%s: nrrd reports zero element size!", me);
399
    return 1;
400
  }
401
402
  /* allocate */
403
  numOut = 1;
404
208
  for (ai=0; ai<nin->dim; ai++) {
405
80
    numOut *= (szOut[ai] = -min[ai] + max[ai] + 1);
406
  }
407
24
  nout->blockSize = nin->blockSize;
408
24
  if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, szOut)) {
409
    biffAddf(NRRD, "%s:", me);
410
    return 1;
411
  }
412
413
  /* the skinny */
414
24
  typeSize = nrrdElementSize(nin);
415
24
  dataIn = (char *)nin->data;
416
24
  dataOut = (char *)nout->data;
417
816
  for (ai=0; ai<NRRD_DIM_MAX; ai++) {
418
384
    cOut[ai] = 0;
419
  }
420
7783456
  for (idxOut=0; idxOut<numOut; idxOut++) {
421
    outside = 0;
422
38916624
    for (ai=0; ai<nin->dim; ai++) {
423
31133216
      cIn[ai] = cOut[ai] + min[ai];
424

31133216
      switch(boundary) {
425
      case nrrdBoundaryPad: /* HEY, this shouldn't result in any
426
                               input coordinate being set */
427
      case nrrdBoundaryBleed:
428

30354872
        if (!AIR_IN_CL(0, cIn[ai], (ptrdiff_t)szIn[ai]-1)) {
429

7783248
          cIn[ai] = AIR_CLAMP(0, cIn[ai], (ptrdiff_t)szIn[ai]-1);
430
          outside = 1;
431
2334984
        }
432
        break;
433
      case nrrdBoundaryWrap:
434
        if (!AIR_IN_CL(0, cIn[ai], (ptrdiff_t)szIn[ai]-1)) {
435
          /* HEY: shouldn't have to cast szIn[ai] to ptrdiff_t */
436
          cIn[ai] = AIR_MOD(cIn[ai], (ptrdiff_t)szIn[ai]);
437
          outside = 1;
438
        }
439
        break;
440
      case nrrdBoundaryMirror:
441
        if (!AIR_IN_CL(0, cIn[ai], (ptrdiff_t)szIn[ai]-1)) {
442
          cIn[ai] = _nrrdMirror_64(szIn[ai], cIn[ai]);
443
          outside = 1;
444
        }
445
        break;
446
      }
447
    }
448
38916624
    NRRD_INDEX_GEN(idxIn, cIn, szIn, nin->dim);
449
3891704
    if (!outside) {
450
      /* the cIn coords are within the input nrrd: do memcpy() of whole
451
         1-D scanline, then artificially bump for-loop to the end of
452
         the scanline */
453
1556720
      memcpy(dataOut + idxOut*typeSize, dataIn + idxIn*typeSize,
454
             szIn[0]*typeSize);
455
1556720
      idxOut += nin->axis[0].size-1;
456
1556720
      cOut[0] += nin->axis[0].size-1;
457
1556720
    } else {
458
      /* we copy only a single value */
459
2334984
      if (nrrdBoundaryPad == boundary) {
460
1556664
        nrrdDInsert[nout->type](dataOut, idxOut, padValue);
461
1556664
      } else {
462
778320
        memcpy(dataOut + idxOut*typeSize, dataIn + idxIn*typeSize, typeSize);
463
      }
464
    }
465


39800712
    NRRD_COORD_INCR(cOut, szOut, nin->dim, 0);
466
  }
467
24
  if (nrrdAxisInfoCopy(nout, nin, NULL, (NRRD_AXIS_INFO_SIZE_BIT |
468
                                         NRRD_AXIS_INFO_MIN_BIT |
469
                                         NRRD_AXIS_INFO_MAX_BIT ))) {
470
    biffAddf(NRRD, "%s:", me);
471
    return 1;
472
  }
473
208
  for (ai=0; ai<nin->dim; ai++) {
474
160
    nrrdAxisInfoPosRange(&(nout->axis[ai].min), &(nout->axis[ai].max),
475
80
                         nin, ai, AIR_CAST(double, min[ai]),
476
80
                         AIR_CAST(double, max[ai]));
477

160
    if (!nrrdStateKindNoop && nout->axis[ai].size == nin->axis[ai].size) {
478
      /* nothing changed along this axis; the kind should be preserved */
479
56
      nout->axis[ai].kind = nin->axis[ai].kind;
480
56
    } else {
481
24
      nout->axis[ai].kind = _nrrdKindAltered(nin->axis[ai].kind, AIR_FALSE);
482
    }
483
  }
484
24
  strcpy(buff1, "");
485
208
  for (ai=0; ai<nin->dim; ai++) {
486
80
    sprintf(buff2, "%s[%s,%s]", (ai ? "x" : ""),
487
            airSprintPtrdiff_t(stmp[0], min[ai]),
488
            airSprintPtrdiff_t(stmp[1], max[ai]));
489
80
    strcat(buff1, buff2);
490
  }
491
24
  if (nrrdBoundaryPad == boundary) {
492
40
    sprintf(buff2, "%s(%g)", airEnumStr(nrrdBoundary, nrrdBoundaryPad),
493
            padValue);
494
16
  } else {
495
8
    strcpy(buff2, airEnumStr(nrrdBoundary, boundary));
496
  }
497
24
  if (nrrdContentSet_va(nout, func, nin, "%s,%s", buff1, buff2)) {
498
    biffAddf(NRRD, "%s:", me);
499
    return 1;
500
  }
501
24
  if (nrrdBasicInfoCopy(nout, nin,
502
                        NRRD_BASIC_INFO_DATA_BIT
503
                        | NRRD_BASIC_INFO_TYPE_BIT
504
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
505
                        | NRRD_BASIC_INFO_DIMENSION_BIT
506
                        | NRRD_BASIC_INFO_CONTENT_BIT
507
                        | NRRD_BASIC_INFO_COMMENTS_BIT
508
24
                        | (nrrdStateKeyValuePairsPropagate
509
                           ? 0
510
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
511
    biffAddf(NRRD, "%s:", me);
512
    return 1;
513
  }
514
  /* copy origin, then shift it along the spatial axes */
515
24
  nrrdSpaceVecCopy(nout->spaceOrigin, nin->spaceOrigin);
516
208
  for (ai=0; ai<nin->dim; ai++) {
517
80
    if (AIR_EXISTS(nin->axis[ai].spaceDirection[0])) {
518
48
      nrrdSpaceVecScaleAdd2(nout->spaceOrigin,
519
                            1.0, nout->spaceOrigin,
520
48
                            AIR_CAST(double, min[ai]),
521
48
                            nin->axis[ai].spaceDirection);
522
48
    }
523
  }
524
525
24
  return 0;
526
24
}
527
528
/*
529
******** nrrdPad_nva()
530
**
531
** unlike other {X_va,X_nva} pairs, nrrdPad_nva() is a wrapper around
532
** nrrdPad_va() instead of the other way around.
533
*/
534
int
535
nrrdPad_nva(Nrrd *nout, const Nrrd *nin,
536
            const ptrdiff_t *min, const ptrdiff_t *max,
537
            int boundary, double padValue) {
538
  static const char me[]="nrrdPad_nva";
539
  int E;
540
541
48
  if (!AIR_IN_OP(nrrdBoundaryUnknown, boundary, nrrdBoundaryLast)) {
542
    biffAddf(NRRD, "%s: boundary behavior %d invalid", me, boundary);
543
    return 1;
544
  }
545
24
  if (nrrdBoundaryPad == boundary) {
546
16
    E = nrrdPad_va(nout, nin, min, max, boundary, padValue);
547
16
  } else {
548
8
    E = nrrdPad_va(nout, nin, min, max, boundary);
549
  }
550
24
  if (E) {
551
    biffAddf(NRRD, "%s:", me);
552
    return 1;
553
  }
554
555
24
  return 0;
556
24
}
557
558
/*
559
******** nrrdSimplePad_va()
560
**
561
** pads by a given amount on top and bottom of EVERY axis
562
*/
563
int
564
nrrdSimplePad_va(Nrrd *nout, const Nrrd *nin, unsigned int pad,
565
                 int boundary, ...) {
566
  static const char me[]="nrrdSimplePad_va";
567
  unsigned ai;
568
  int ret;
569
  ptrdiff_t min[NRRD_DIM_MAX], max[NRRD_DIM_MAX];
570
  double padValue;
571
  va_list ap;
572
573
  if (!(nout && nin)) {
574
    biffAddf(NRRD, "%s: got NULL pointer", me);
575
    return 1;
576
  }
577
  for (ai=0; ai<nin->dim; ai++) {
578
    min[ai] = -AIR_CAST(ptrdiff_t, pad);
579
    max[ai] = nin->axis[ai].size-1 + pad;
580
  }
581
  va_start(ap, boundary);
582
  if (nrrdBoundaryPad == boundary) {
583
    padValue = va_arg(ap, double);
584
    ret = nrrdPad_va(nout, nin, min, max, boundary, padValue);
585
  } else {
586
    ret = nrrdPad_va(nout, nin, min, max, boundary);
587
  }
588
  va_end(ap);
589
  if (ret) {
590
    biffAddf(NRRD, "%s:", me);
591
    return 1;
592
  }
593
  return 0;
594
}
595
596
/*
597
******** nrrdSimplePad_nva()
598
**
599
** unlike other {X_va,X_nva} pairs, nrrdSimplePad_nva() is a wrapper
600
** around nrrdSimplePad_va() instead of the other way around.
601
*/
602
int
603
nrrdSimplePad_nva(Nrrd *nout, const Nrrd *nin, unsigned int pad,
604
                  int boundary, double padValue) {
605
  static const char me[]="nrrdSimplePad_nva";
606
  int E;
607
608
  if (!AIR_IN_OP(nrrdBoundaryUnknown, boundary, nrrdBoundaryLast)) {
609
    biffAddf(NRRD, "%s: boundary behavior %d invalid", me, boundary);
610
    return 1;
611
  }
612
  if (nrrdBoundaryPad == boundary) {
613
    E = nrrdSimplePad_va(nout, nin, pad, boundary, padValue);
614
  } else {
615
    E = nrrdSimplePad_va(nout, nin, pad, boundary);
616
  }
617
  if (E) {
618
    biffAddf(NRRD, "%s:", me);
619
    return 1;
620
  }
621
622
  return 0;
623
}