GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gage/stack.c Lines: 0 187 0.0 %
Date: 2017-05-26 Branches: 0 130 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 "gage.h"
25
#include "privateGage.h"
26
27
double
28
gageStackWtoI(gageContext *ctx, double swrl, int *outside) {
29
  double si;
30
31
  if (ctx && ctx->parm.stackUse && outside) {
32
    unsigned int sidx;
33
    if (swrl < ctx->stackPos[0]) {
34
      /* we'll extrapolate from stackPos[0] and [1] */
35
      sidx = 0;
36
      *outside = AIR_TRUE;
37
    } else if (swrl > ctx->stackPos[ctx->pvlNum-2]) {
38
      /* extrapolate from stackPos[ctx->pvlNum-3] and [ctx->pvlNum-2];
39
         gageStackPerVolumeAttach ensures that we there are at least two
40
         blurrings pvls & one base pvl ==> pvlNum >= 3 ==> pvlNum-3 >= 0 */
41
      sidx = ctx->pvlNum-3;
42
      *outside = AIR_TRUE;
43
    } else {
44
      /* HEY: stupid linear search */
45
      for (sidx=0; sidx<ctx->pvlNum-2; sidx++) {
46
        if (AIR_IN_CL(ctx->stackPos[sidx], swrl, ctx->stackPos[sidx+1])) {
47
          break;
48
        }
49
      }
50
      if (sidx == ctx->pvlNum-2) {
51
        /* search failure */
52
        *outside = AIR_FALSE;
53
        return AIR_NAN;
54
      }
55
      *outside = AIR_FALSE;
56
    }
57
    si = AIR_AFFINE(ctx->stackPos[sidx], swrl, ctx->stackPos[sidx+1],
58
                    sidx, sidx+1);
59
  } else {
60
    si = AIR_NAN;
61
  }
62
  return si;
63
}
64
65
double
66
gageStackItoW(gageContext *ctx, double si, int *outside) {
67
  unsigned int sidx;
68
  double swrl, sfrac;
69
70
  if (ctx && ctx->parm.stackUse && outside) {
71
    if (si < 0) {
72
      sidx = 0;
73
      *outside = AIR_TRUE;
74
    } else if (si > ctx->pvlNum-2) {
75
      sidx = ctx->pvlNum-3;
76
      *outside = AIR_TRUE;
77
    } else {
78
      sidx = AIR_CAST(unsigned int, si);
79
      *outside = AIR_FALSE;
80
    }
81
    sfrac = si - sidx;
82
    swrl = AIR_AFFINE(0, sfrac, 1, ctx->stackPos[sidx], ctx->stackPos[sidx+1]);
83
    /*
84
    fprintf(stderr, "!%s: si %g (%u) --> %u + %g --> [%g,%g] -> %g\n", me,
85
            si, ctx->pvlNum, sidx, sfrac,
86
            ctx->stackPos[sidx], ctx->stackPos[sidx+1], swrl);
87
    */
88
  } else {
89
    swrl = AIR_NAN;
90
  }
91
  return swrl;
92
}
93
94
/*
95
** this is a little messy: the given pvlStack array has to be allocated
96
** by the caller to hold blNum gagePerVolume pointers, BUT, the values
97
** of pvlStack[i] shouldn't be set to anything: as with gagePerVolumeNew(),
98
** gage allocates the pervolume itself.
99
*/
100
int
101
gageStackPerVolumeNew(gageContext *ctx,
102
                      gagePerVolume **pvlStack,
103
                      const Nrrd *const *nblur, unsigned int blNum,
104
                      const gageKind *kind) {
105
  static const char me[]="gageStackPerVolumeNew";
106
  unsigned int blIdx;
107
108
  if (!( ctx && pvlStack && nblur && kind )) {
109
    biffAddf(GAGE, "%s: got NULL pointer", me);
110
    return 1;
111
  }
112
  if (!blNum) {
113
    biffAddf(GAGE, "%s: need non-zero num", me);
114
    return 1;
115
  }
116
117
  for (blIdx=0; blIdx<blNum; blIdx++) {
118
    if (!( pvlStack[blIdx] = gagePerVolumeNew(ctx, nblur[blIdx], kind) )) {
119
      biffAddf(GAGE, "%s: on pvl %u of %u", me, blIdx, blNum);
120
      return 1;
121
    }
122
  }
123
124
  return 0;
125
}
126
127
/*
128
** the "base" pvl is the LAST pvl, ctx->pvl[pvlNum-1]
129
*/
130
int
131
gageStackPerVolumeAttach(gageContext *ctx, gagePerVolume *pvlBase,
132
                         gagePerVolume **pvlStack, const double *stackPos,
133
                         unsigned int blNum) {
134
  static const char me[]="gageStackPerVolumeAttach";
135
  unsigned int blIdx;
136
137
  if (!(ctx && pvlBase && pvlStack && stackPos)) {
138
    biffAddf(GAGE, "%s: got NULL pointer %p %p %p %p", me,
139
             AIR_VOIDP(ctx), AIR_VOIDP(pvlBase),
140
             AIR_VOIDP(pvlStack), AIR_CVOIDP(stackPos));
141
    return 1;
142
  }
143
  if (!( blNum >= 2 )) {
144
    /* this constraint is important for the logic of stack reconstruction:
145
       minimum number of node-centered samples is 2, and the number of
146
       pvls has to be at least 3 (two blurrings + one base pvl) */
147
    biffAddf(GAGE, "%s: need at least two samples along stack", me);
148
    return 1;
149
  }
150
  if (ctx->pvlNum) {
151
    biffAddf(GAGE, "%s: can't have pre-existing volumes (%u) "
152
             "prior to stack attachment", me, ctx->pvlNum);
153
    return 1;
154
  }
155
  for (blIdx=0; blIdx<blNum; blIdx++) {
156
    if (!AIR_EXISTS(stackPos[blIdx])) {
157
      biffAddf(GAGE, "%s: stackPos[%u] = %g doesn't exist", me, blIdx,
158
               stackPos[blIdx]);
159
      return 1;
160
    }
161
    if (blIdx < blNum-1) {
162
      if (!( stackPos[blIdx] < stackPos[blIdx+1] )) {
163
        biffAddf(GAGE, "%s: stackPos[%u] = %g not < stackPos[%u] = %g", me,
164
                 blIdx, stackPos[blIdx], blIdx+1, stackPos[blIdx+1]);
165
        return 1;
166
      }
167
    }
168
  }
169
170
  /* the base volume is LAST, after all the stack samples */
171
  for (blIdx=0; blIdx<blNum; blIdx++) {
172
    if (gagePerVolumeAttach(ctx, pvlStack[blIdx])) {
173
      biffAddf(GAGE, "%s: on pvl %u of %u", me, blIdx, blNum);
174
      return 1;
175
    }
176
  }
177
  if (gagePerVolumeAttach(ctx, pvlBase)) {
178
    biffAddf(GAGE, "%s: on base pvl", me);
179
    return 1;
180
  }
181
182
  airFree(ctx->stackPos);
183
  airFree(ctx->stackFsl);
184
  airFree(ctx->stackFw);
185
  ctx->stackPos = AIR_CALLOC(blNum, double);
186
  ctx->stackFsl = AIR_CALLOC(blNum, double);
187
  ctx->stackFw = AIR_CALLOC(blNum, double);
188
  if (!( ctx->stackPos && ctx->stackFsl && ctx->stackFw )) {
189
    biffAddf(GAGE, "%s: couldn't allocate stack buffers (%p %p %p)", me,
190
             AIR_CAST(void *, ctx->stackPos),
191
             AIR_CAST(void *, ctx->stackFsl),
192
             AIR_CAST(void *, ctx->stackFw));
193
    return 1;
194
  }
195
  for (blIdx=0; blIdx<blNum; blIdx++) {
196
    ctx->stackPos[blIdx] = stackPos[blIdx];
197
  }
198
199
  return 0;
200
}
201
202
/*
203
** _gageStackBaseIv3Fill
204
**
205
** after the individual iv3's in the stack have been filled, this does
206
** the across-stack filtering to fill the iv3 of pvl[pvlNum-1] (the
207
** "base" pvl)
208
*/
209
int
210
_gageStackBaseIv3Fill(gageContext *ctx) {
211
  static const char me[]="_gageStackBaseIv3Fill";
212
  unsigned int fd, pvlIdx, cacheIdx, cacheLen, baseIdx, valLen;
213
214
  fd = 2*ctx->radius;
215
  /* the "base" pvl is the LAST pvl */
216
  baseIdx = ctx->pvlNum - 1;
217
  cacheLen = fd*fd*fd*ctx->pvl[0]->kind->valLen;
218
  if (ctx->verbose > 2) {
219
    fprintf(stderr, "%s: cacheLen = %u\n", me, cacheLen);
220
  }
221
  if (nrrdKernelHermiteScaleSpaceFlag  == ctx->ksp[gageKernelStack]->kernel) {
222
    unsigned int iii, xi, yi, zi, blurIdx, valIdx, fdd, sz, sy;
223
    double xx, *iv3, *iv30, *iv31, sigma0, sigma1,
224
      val0, val1, drv0, drv1, lapl0, lapl1;
225
226
    fdd = fd*fd;
227
    /* initialize the output iv3 to all zeros, since we won't be
228
       usefully setting the values on the boundary (the boundary which
229
       is required in the rest of the stack's iv3s in order to do the
230
       laplacian-based spline recon), and we can't have any
231
       non-existent values creeping in.  We shouldn't need to do any
232
       kind of nrrdBoundaryBleed thing here, because the kernel
233
       weights really should be zero on the boundary. */
234
    iv3 = ctx->pvl[baseIdx]->iv3;
235
    for (cacheIdx=0; cacheIdx<cacheLen; cacheIdx++) {
236
      iv3[cacheIdx] = 0;
237
    }
238
239
    /* find the interval in the pre-blurred volumes containing the
240
       desired scale location */
241
    for (pvlIdx=0; pvlIdx<ctx->pvlNum-1; pvlIdx++) {
242
      if (ctx->stackFw[pvlIdx]) {
243
        /* has to be non-zero somewhere, since _gageLocationSet()
244
           gives an error if there aren't non-zero stackFw[i] */
245
        break;
246
      }
247
    }
248
    /* so no way that pvlIdx == pvlNum-1 */
249
    if (pvlIdx == ctx->pvlNum-2) {
250
      /* pvlNum-2 is pvl index of last pre-blurred volume */
251
      /* gageStackPerVolumeAttach() enforces getting at least two
252
         pre-blurred volumes --> pvlNum >= 3 --> blurIdx >= 0 */
253
      blurIdx = pvlIdx-1;
254
      xx = 1;
255
    } else {
256
      blurIdx = pvlIdx;
257
      /* by design, the hermite non-kernel generates the same values as
258
         the tent kernel (with scale forced == 1), so we can use those
259
         to control the interpolation */
260
      xx = 1 - ctx->stackFw[pvlIdx];
261
    }
262
    iv30 = ctx->pvl[blurIdx]->iv3;
263
    iv31 = ctx->pvl[blurIdx+1]->iv3;
264
    sigma0 = ctx->stackPos[blurIdx];
265
    sigma1 = ctx->stackPos[blurIdx+1];
266
    valLen = ctx->pvl[baseIdx]->kind->valLen;
267
    sy = ctx->shape->size[1];
268
    sz = ctx->shape->size[2];
269
    if (1 == sz) {
270
      if (1 == sy) {
271
        /* (1-D data: HEY copy and paste; see 2D case below) */
272
        for (valIdx=0; valIdx<valLen; valIdx++) {
273
          /* nixed "for zi" and "for yi" loop; zi==yi==1 */
274
          for (xi=1; xi<fd-1; xi++) {
275
            iii = xi + fd*(1 /* yi */ + fd*(1 /* zi */ + fd*valIdx));
276
            val0 = iv30[iii];
277
            /* can do a 1D instead of 2D discrete laplacian */
278
            lapl0 = (iv30[iii+1] + iv30[iii-1] - 2*val0);
279
            val1 = iv31[iii];
280
            lapl1 = (iv31[iii+1] + iv31[iii-1] - 2*val1);
281
            drv0 = sigma0*lapl0*(sigma1 - sigma0);
282
            drv1 = sigma1*lapl1*(sigma1 - sigma0);
283
            iv3[iii] = val0 + xx*(drv0 + xx*(drv0*(-2 + xx) + drv1*(-1 + xx)
284
                                             + (val0 - val1)*(-3 + 2*xx)));
285
            /*
286
            fprintf(stderr, "!%s: (%u): val %g %g, lapl %g %g, sigma %g %g, drv %g %g --> iv3[%u] = %g\n", me,
287
                    xi, val0, val1, lapl0, lapl1, sigma0, sigma1, drv0, drv1, iii, iv3[iii]);
288
            fprintf(stderr, "!%s: lapl0 %g = %g + %g + %g + %g - 4*%g\n", me, lapl0,
289
                    iv30[iii+1] , iv30[iii-1] , iv30[iii+fd] , iv30[iii-fd] , val0);
290
            fprintf(stderr, "!%s: lapl1 %g = %g + %g + %g + %g - 4*%g\n", me, lapl1,
291
                    iv31[iii+1] , iv31[iii-1] , iv31[iii+fd] , iv31[iii-fd] , val1);
292
            */
293
          }
294
          for (zi=  2  ; zi<fd-1; zi++) {
295
            for (yi=  2  ; yi<fd-1; yi++) {
296
              for (xi=1; xi<fd-1; xi++) {
297
                iii =          xi + fd*(yi + fd*(zi + fd*valIdx));
298
                iv3[iii] = iv3[xi + fd*(1  + fd*(1  + fd*valIdx))];
299
              }
300
            }
301
          }
302
        }
303
      } else {
304
        /* as in gageIv3Fill; we do some special-case-ing for 2-D images;
305
           (HEY copy and paste; see sz > 1 below for explanatory comments) */
306
        for (valIdx=0; valIdx<valLen; valIdx++) {
307
          /* nixed "for zi" loop; zi==1 */
308
          for (yi=1; yi<fd-1; yi++) {
309
            for (xi=1; xi<fd-1; xi++) {
310
              iii = xi + fd*(yi + fd*(1 /* zi */ + fd*valIdx));
311
              val0 = iv30[iii];
312
              /* can do a 2D instead of 3D discrete laplacian */
313
              lapl0 = (iv30[iii+1]   + iv30[iii-1] +
314
                       iv30[iii+fd]  + iv30[iii-fd] - 4*val0);
315
              val1 = iv31[iii];
316
              lapl1 = (iv31[iii+1]   + iv31[iii-1] +
317
                       iv31[iii+fd]  + iv31[iii-fd] - 4*val1);
318
              drv0 = sigma0*lapl0*(sigma1 - sigma0);
319
              drv1 = sigma1*lapl1*(sigma1 - sigma0);
320
              iv3[iii] = val0 + xx*(drv0 + xx*(drv0*(-2 + xx) + drv1*(-1 + xx)
321
                                               + (val0 - val1)*(-3 + 2*xx)));
322
              /*
323
              fprintf(stderr, "!%s: (%u,%u): val %g %g, lapl %g %g, sigma %g %g, drv %g %g --> iv3[%u] = %g\n", me,
324
                      xi, yi, val0, val1, lapl0, lapl1, sigma0, sigma1, drv0, drv1, iii, iv3[iii]);
325
              fprintf(stderr, "!%s: lapl0 %g = %g + %g + %g + %g - 4*%g\n", me, lapl0,
326
                      iv30[iii+1] , iv30[iii-1] , iv30[iii+fd] , iv30[iii-fd] , val0);
327
              fprintf(stderr, "!%s: lapl1 %g = %g + %g + %g + %g - 4*%g\n", me, lapl1,
328
                      iv31[iii+1] , iv31[iii-1] , iv31[iii+fd] , iv31[iii-fd] , val1);
329
              */
330
            }
331
          }
332
          for (zi=  2  ; zi<fd-1; zi++) {
333
            for (yi=1; yi<fd-1; yi++) {
334
              for (xi=1; xi<fd-1; xi++) {
335
                iii =          xi + fd*(yi + fd*(zi + fd*valIdx));
336
                iv3[iii] = iv3[xi + fd*(yi + fd*(1  + fd*valIdx))];
337
              }
338
            }
339
          }
340
        }
341
      }
342
    } else {
343
      /* sz > 1 */
344
      for (valIdx=0; valIdx<valLen; valIdx++) {
345
        for (zi=1; zi<fd-1; zi++) {
346
          for (yi=1; yi<fd-1; yi++) {
347
            for (xi=1; xi<fd-1; xi++) {
348
              /* note that iv3 axis ordering is x, y, z, tuple */
349
              iii = xi + fd*(yi + fd*(zi + fd*valIdx));
350
              val0 = iv30[iii];
351
              lapl0 = (iv30[iii+1]   + iv30[iii-1] +
352
                       iv30[iii+fd]  + iv30[iii-fd] +
353
                       iv30[iii+fdd] + iv30[iii-fdd] - 6*val0);
354
              val1 = iv31[iii];
355
              lapl1 = (iv31[iii+1]   + iv31[iii-1] +
356
                       iv31[iii+fd]  + iv31[iii-fd] +
357
                       iv31[iii+fdd] + iv31[iii-fdd] - 6*val1);
358
              /* the (sigma1 - sigma0) factor is needed to convert the
359
                 derivative with respect to sigma (sigma*lapl) into the
360
                 derivative with respect to xx (ranges from 0 to 1) */
361
              drv0 = sigma0*lapl0*(sigma1 - sigma0);
362
              drv1 = sigma1*lapl1*(sigma1 - sigma0);
363
              /* This inner loop is the bottleneck for some uses of
364
                 scale-space; a re-arrangement of the Hermite spline
365
                 evaluation (thanks Mathematica) does save a little time */
366
              iv3[iii] = val0 + xx*(drv0 + xx*(drv0*(-2 + xx) + drv1*(-1 + xx)
367
                                               + (val0 - val1)*(-3 + 2*xx)));
368
            }
369
          }
370
        }
371
      }
372
    }
373
  } else {
374
    /* we're doing simple convolution-based recon on the stack */
375
    /* NOTE we are treating the 4D fd*fd*fd*valLen iv3 as a big 1-D array */
376
    double wght, val;
377
    for (cacheIdx=0; cacheIdx<cacheLen; cacheIdx++) {
378
      val = 0;
379
      for (pvlIdx=0; pvlIdx<ctx->pvlNum-1; pvlIdx++) {
380
        wght = ctx->stackFw[pvlIdx];
381
        val += (wght
382
                ? wght*ctx->pvl[pvlIdx]->iv3[cacheIdx]
383
                : 0);
384
      }
385
      ctx->pvl[baseIdx]->iv3[cacheIdx] = val;
386
    }
387
  }
388
  return 0;
389
}
390
391
/*
392
******** gageStackProbe()
393
*/
394
int
395
gageStackProbe(gageContext *ctx,
396
               double xi, double yi, double zi, double stackIdx) {
397
  static const char me[]="gageStackProbe";
398
399
  if (!ctx) {
400
    return 1;
401
  }
402
  if (!ctx->parm.stackUse) {
403
    if (ctx->parm.generateErrStr) {
404
      sprintf(ctx->errStr, "%s: can't probe stack without parm.stackUse", me);
405
    } else {
406
      strcpy(ctx->errStr, _GAGE_NON_ERR_STR);
407
    }
408
    ctx->errNum = gageErrStackUnused;
409
    return 1;
410
  }
411
  return _gageProbe(ctx, xi, yi, zi, stackIdx);
412
}
413
414
int
415
gageStackProbeSpace(gageContext *ctx,
416
                    double xx, double yy, double zz, double ss,
417
                    int indexSpace, int clamp) {
418
  static const char me[]="gageStackProbeSpace";
419
  int ret;
420
  /*
421
  fprintf(stderr, "!%s(%g,%g,%g,%g, %d,%d): hello\n", me,
422
          xx, yy, zz, ss, indexSpace, clamp);
423
  if (AIR_ABS(-98.2539 - xx) < 0.1 && AIR_ABS(yy) < 0.1 && AIR_ABS(zz) < 0.1 && AIR_ABS(495.853 - ss)) {
424
    ctx->verbose += 10;
425
  }
426
  */
427
  if (!ctx) {
428
    return 1;
429
  }
430
  if (!ctx->parm.stackUse) {
431
    if (ctx->parm.generateErrStr) {
432
      sprintf(ctx->errStr, "%s: can't probe stack without parm.stackUse", me);
433
    } else {
434
      strcpy(ctx->errStr, _GAGE_NON_ERR_STR);
435
    }
436
    ctx->errNum = gageErrStackUnused;
437
    return 1;
438
  }
439
  ret = _gageProbeSpace(ctx, xx, yy, zz, ss, indexSpace, clamp);
440
  /* fprintf(stderr, "!%s: returning %d\n", me, ret); */
441
  return ret;
442
}
443