GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gage/ctx.c Lines: 235 435 54.0 %
Date: 2017-05-26 Branches: 151 318 47.5 %

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
typedef union {
28
  void **vd;
29
  gagePerVolume ***pvl;
30
} perVolumeUnion;
31
32
33
/*
34
******** gageContextNew()
35
**
36
** doesn't use biff
37
*/
38
gageContext *
39
gageContextNew() {
40
  gageContext *ctx;
41
  perVolumeUnion pvu;
42
  int ii;
43
44
226
  ctx = AIR_CALLOC(1, gageContext);
45
113
  if (ctx) {
46
113
    ctx->verbose = gageDefVerbose;
47
113
    gageParmReset(&ctx->parm);
48
1808
    for (ii=gageKernelUnknown+1; ii<gageKernelLast; ii++) {
49
791
      ctx->ksp[ii] = NULL;
50
    }
51
113
    ctx->pvl = NULL;
52
113
    ctx->pvlNum = 0;
53
113
    pvu.pvl = &(ctx->pvl);
54
113
    ctx->pvlArr = airArrayNew(pvu.vd, &(ctx->pvlNum),
55
                              sizeof(gagePerVolume*),
56
                              GAGE_PERVOLUME_ARR_INCR);
57
113
    gageKernelReset(ctx); /* placed here for logic of kernel flag */
58
113
    ctx->shape = gageShapeNew();
59
1582
    for (ii=gageCtxFlagUnknown+1; ii<gageCtxFlagLast; ii++) {
60
678
      ctx->flag[ii] = AIR_FALSE;
61
    }
62
113
    ctx->stackPos = NULL;
63
113
    ctx->stackFsl = NULL;
64
113
    ctx->stackFw = NULL;
65
904
    for (ii=0; ii<=GAGE_DERIV_MAX; ii++) {
66
339
      ctx->needD[ii] = AIR_FALSE;
67
    }
68
1808
    for (ii=gageKernelUnknown+1; ii<gageKernelLast; ii++) {
69
791
      ctx->needK[ii] = AIR_FALSE;
70
    }
71
113
    ctx->radius = 0;
72
113
    ctx->fsl = ctx->fw = NULL;
73
113
    ctx->off = NULL;
74
113
    gagePointReset(&ctx->point);
75
113
    strcpy(ctx->errStr, "");
76
113
    ctx->errNum = gageErrNone;
77
113
    ctx->edgeFrac = 0;
78
113
  }
79
113
  return ctx;
80
}
81
82
/*
83
******** gageContextCopy()
84
**
85
** gives you a new context, which behaves the same as the given context,
86
** with newly allocated pervolumes attached.  With the avoidance of
87
** padding to create a private copy of the volume, the gageContext is
88
** light-weight enough that there is no reason that this function can't
89
** return an independent and fully functioning copy of the context (whereas
90
** before you weren't allowed to do anything but gageProbe() on the
91
** copied context).
92
*/
93
gageContext * /*Teem: biff if (!ret) */
94
gageContextCopy(gageContext *ctx) {
95
  static const char me[]="gageContextCopy";
96
  gageContext *ntx;
97
  unsigned int fd, pvlIdx;
98
  perVolumeUnion pvu;
99
  int ki;
100
101
148
  ntx = AIR_CALLOC(1, gageContext);
102
74
  if (!ntx) {
103
    biffAddf(GAGE, "%s: couldn't make a gageContext", me);
104
    return NULL;
105
  }
106
  /* we should probably restrict ourselves to gage API calls, but given the
107
     constant state of gage construction, this seems much simpler.
108
     Pointers are fixed below */
109
74
  memcpy(ntx, ctx, sizeof(gageContext));
110
1184
  for (ki=gageKernelUnknown+1; ki<gageKernelLast; ki++) {
111
518
    ntx->ksp[ki] = nrrdKernelSpecCopy(ctx->ksp[ki]);
112
  }
113
74
  pvu.pvl = &(ntx->pvl);
114
74
  ntx->pvlArr = airArrayNew(pvu.vd, &(ntx->pvlNum),
115
                            sizeof(gagePerVolume*),
116
                            GAGE_PERVOLUME_ARR_INCR);
117
74
  airArrayLenSet(ntx->pvlArr, ctx->pvlNum);
118
74
  if (!ntx->pvl) {
119
    biffAddf(GAGE, "%s: couldn't allocate new pvl array", me);
120
    return NULL;
121
  }
122
764
  for (pvlIdx=0; pvlIdx<ntx->pvlNum; pvlIdx++) {
123
308
    ntx->pvl[pvlIdx] = _gagePerVolumeCopy(ctx->pvl[pvlIdx], 2*ctx->radius);
124
308
    if (!ntx->pvl[pvlIdx]) {
125
      biffAddf(GAGE, "%s: trouble copying pervolume %u", me, pvlIdx);
126
      return NULL;
127
    }
128
  }
129

74
  if (ctx->stackPos && ctx->stackFsl && ctx->stackFw) {
130
    ntx->stackPos = AIR_CALLOC(ctx->pvlNum-1, double);
131
    ntx->stackFsl = AIR_CALLOC(ctx->pvlNum-1, double);
132
    ntx->stackFw = AIR_CALLOC(ctx->pvlNum-1, double);
133
    if (!( ntx->stackPos && ntx->stackFsl && ntx->stackFw )) {
134
      biffAddf(GAGE, "%s: couldn't allocate stack Pos, Fsl, Fw", me);
135
      return NULL;
136
    }
137
    for (pvlIdx=0; pvlIdx<ntx->pvlNum-1; pvlIdx++) {
138
      ntx->stackPos[pvlIdx] = ctx->stackPos[pvlIdx];
139
      ntx->stackFsl[pvlIdx] = ctx->stackFsl[pvlIdx];
140
      ntx->stackFw[pvlIdx] = ctx->stackFw[pvlIdx];
141
    }
142
  } else {
143
74
    ntx->stackPos = NULL;
144
74
    ntx->stackFsl = NULL;
145
74
    ntx->stackFw = NULL;
146
  }
147
74
  ntx->shape = gageShapeCopy(ctx->shape);
148
74
  fd = 2*ntx->radius;
149
74
  ntx->fsl = AIR_CALLOC(fd*3, double);
150
74
  ntx->fw = AIR_CALLOC(fd*3*(GAGE_KERNEL_MAX+1), double);
151
74
  ntx->off = AIR_CALLOC(fd*fd*fd, unsigned int);
152

222
  if (!( ntx->fsl && ntx->fw && ntx->off )) {
153
    biffAddf(GAGE, "%s: couldn't allocate new filter caches for fd=%d",
154
             me, fd);
155
    return NULL;
156
  }
157
  /* the content of the offset array needs to be copied because
158
     it won't be refilled simply by calls to gageProbe() */
159
74
  memcpy(ntx->off, ctx->off, fd*fd*fd*sizeof(unsigned int));
160
161
  /* make sure gageProbe() has to refill caches */
162
74
  gagePointReset(&ntx->point);
163
164
74
  return ntx;
165
74
}
166
167
/*
168
******** gageContextNix()
169
**
170
** responsible for freeing and clearing up everything hanging off a
171
** context so that things can be returned to the way they were prior
172
** to gageContextNew().
173
**
174
** does not use biff
175
*/
176
gageContext *
177
gageContextNix(gageContext *ctx) {
178
  /* static const char me[]="gageContextNix"; */
179
  unsigned int pvlIdx;
180
181
354
  if (ctx) {
182
177
    gageKernelReset(ctx);
183
1464
    for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
184
555
      gagePerVolumeNix(ctx->pvl[pvlIdx]);
185
      /* no point in doing a detach, the whole context is going bye-bye */
186
    }
187
177
    airArrayNuke(ctx->pvlArr);
188
177
    ctx->shape = gageShapeNix(ctx->shape);
189
177
    ctx->stackPos = AIR_CAST(double *, airFree(ctx->stackPos));
190
177
    ctx->stackFsl = AIR_CAST(double *, airFree(ctx->stackFsl));
191
177
    ctx->stackFw = AIR_CAST(double *, airFree(ctx->stackFw));
192
177
    ctx->fw = AIR_CAST(double *, airFree(ctx->fw));
193
177
    ctx->fsl = AIR_CAST(double *, airFree(ctx->fsl));
194
177
    ctx->off = AIR_CAST(unsigned int *, airFree(ctx->off));
195
177
  }
196
177
  airFree(ctx);
197
177
  return NULL;
198
}
199
200
/*
201
******** gageKernelSet()
202
**
203
** sets one kernel in a gageContext; but the value of this function
204
** is all the error checking it does.
205
**
206
** Refers to ctx->checkIntegrals and acts appropriately.
207
**
208
** Does use biff.
209
*/
210
int
211
gageKernelSet(gageContext *ctx,
212
              int which, const NrrdKernel *k, const double *kparm) {
213
  static const char me[]="gageKernelSet";
214
  int numParm;
215
  double support, integral;
216
217
742
  if (!(ctx && k && kparm)) {
218
    biffAddf(GAGE, "%s: got NULL pointer", me);
219
    return 1;
220
  }
221
371
  if (airEnumValCheck(gageKernel, which)) {
222
    biffAddf(GAGE, "%s: \"which\" (%d) not in range [%d,%d]", me,
223
             which, gageKernelUnknown+1, gageKernelLast-1);
224
    return 1;
225
  }
226
371
  if (ctx->verbose) {
227
    fprintf(stderr, "%s: which = %d -> %s\n", me, which,
228
            airEnumStr(gageKernel, which));
229
  }
230
371
  numParm = k->numParm;
231
371
  if (!(AIR_IN_CL(0, numParm, NRRD_KERNEL_PARMS_NUM))) {
232
    biffAddf(GAGE, "%s: kernel's numParm (%d) not in range [%d,%d]",
233
             me, numParm, 0, NRRD_KERNEL_PARMS_NUM);
234
    return 1;
235
  }
236
371
  support = k->support(kparm);
237
371
  if (!( support > 0 )) {
238
    biffAddf(GAGE, "%s: kernel's support (%g) not > 0", me, support);
239
    return 1;
240
  }
241
371
  if (ctx->parm.checkIntegrals) {
242
371
    integral = k->integral(kparm);
243


1855
    if (gageKernel00 == which ||
244
371
        gageKernel10 == which ||
245
371
        gageKernel20 == which ||
246
371
        gageKernelStack == which) {
247
504
      if (!( integral > 0 )) {
248
        biffAddf(GAGE, "%s: reconstruction kernel's integral (%g) not > 0.0",
249
                 me, integral);
250
        return 1;
251
      }
252
    } else {
253
      /* its a derivative, so integral must be near zero */
254
238
      if (!( AIR_ABS(integral) <= ctx->parm.kernelIntegralNearZero )) {
255
        char str[AIR_STRLEN_LARGE]="";
256
        nrrdKernelSprint(str, k, kparm);
257
        biffAddf(GAGE, "%s: derivative %s kernel (%s) integral %g not within "
258
                 "%g of 0.0", me, airEnumStr(gageKernel, which), str,
259
                 integral, ctx->parm.kernelIntegralNearZero);
260
        return 1;
261
      }
262
    }
263
  }
264
265
  /* okay, enough enough, go set the kernel */
266
371
  if (!ctx->ksp[which]) {
267
351
    ctx->ksp[which] = nrrdKernelSpecNew();
268
351
  }
269
371
  nrrdKernelSpecSet(ctx->ksp[which], k, kparm);
270
371
  ctx->flag[gageCtxFlagKernel] = AIR_TRUE;
271
272
371
  return 0;
273
371
}
274
275
/*
276
******** gageKernelReset()
277
**
278
** reset kernels (including the stack ksp) and parameters.
279
*/
280
void
281
gageKernelReset(gageContext *ctx) {
282
  /* static const char me[]="gageKernelReset"; */
283
  int i;
284
285
580
  if (ctx) {
286
4640
    for(i=gageKernelUnknown+1; i<gageKernelLast; i++) {
287
2030
      ctx->ksp[i] = nrrdKernelSpecNix(ctx->ksp[i]);
288
    }
289
290
    ctx->flag[gageCtxFlagKernel] = AIR_TRUE;
290
290
  }
291
  return;
292
290
}
293
294
/*
295
******** gageParmSet()
296
**
297
** for setting the boolean-ish flags in the context in a safe and
298
** intelligent manner, since changing some of them can have many
299
** consequences
300
*/
301
void
302
gageParmSet(gageContext *ctx, int which, double val) {
303
  static const char me[]="gageParmSet";
304
  unsigned int pvlIdx;
305
306




550
  switch (which) {
307
  case gageParmVerbose:
308
    ctx->verbose = AIR_CAST(int, val);
309
    if (ctx->verbose > 3) {
310
      fprintf(stderr, "%s(%p): ctx->verbose now %d\n", me,
311
              AIR_CAST(void *, ctx), ctx->verbose);
312
    }
313
    for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
314
      ctx->pvl[pvlIdx]->verbose = AIR_CAST(int, val);
315
      if (ctx->pvl[pvlIdx]->verbose > 3) {
316
        fprintf(stderr, "%s: ctx->pvl[%u]->verbose now %d\n", me, pvlIdx,
317
                ctx->pvl[pvlIdx]->verbose);
318
      }
319
    }
320
    break;
321
  case gageParmRenormalize:
322
133
    ctx->parm.renormalize = val ? AIR_TRUE : AIR_FALSE;
323
    /* we have to make sure that any existing filter weights
324
       are not re-used; because gageUpdage() is not called mid-probing,
325
       we don't use the flag machinery.  Instead we just invalidate
326
       the last known fractional probe locations */
327
133
    gagePointReset(&ctx->point);
328
133
    break;
329
  case gageParmCheckIntegrals:
330
133
    ctx->parm.checkIntegrals = val ? AIR_TRUE : AIR_FALSE;
331
    /* no flags to set, simply affects future calls to gageKernelSet() */
332
133
    break;
333
  case gageParmK3Pack:
334
    ctx->parm.k3pack = val ? AIR_TRUE : AIR_FALSE;
335
    ctx->flag[gageCtxFlagK3Pack] = AIR_TRUE;
336
    break;
337
  case gageParmGradMagCurvMin:
338
    ctx->parm.gradMagCurvMin = val;
339
    /* no flag to set, simply affects future calls to gageProbe() */
340
    break;
341
  case gageParmCurvNormalSide:
342
    ctx->parm.curvNormalSide = AIR_CAST(int, val);
343
    /* no flag to set, simply affects future calls to gageProbe() */
344
    break;
345
  case gageParmKernelIntegralNearZero:
346
    ctx->parm.kernelIntegralNearZero = val;
347
    /* no flag to set, simply affects future calls to gageKernelSet() */
348
    break;
349
  case gageParmDefaultCenter:
350
    ctx->parm.defaultCenter = AIR_CAST(int, val);
351
    /* no flag to set, I guess, although the value here effects the
352
       action of _gageShapeSet when called by gagePerVolumeAttach . . . */
353
    break;
354
  case gageParmStackUse:
355
    ctx->parm.stackUse = AIR_CAST(int, val);
356
    /* no flag to set, right? simply affects future calls to gageProbe()? */
357
    /* HEY: no? because if you're turning on the stack behavior, you now
358
       should be doing the error checking to make sure that all the pvls
359
       have the same kind!  This should be caught by gageUpdate(), which is
360
       supposed to be called after changing anything, prior to gageProbe() */
361
    break;
362
  case gageParmStackNormalizeRecon:
363
    ctx->parm.stackNormalizeRecon = AIR_CAST(int, val);
364
    break;
365
  case gageParmStackNormalizeDeriv:
366
    ctx->parm.stackNormalizeDeriv = AIR_CAST(int, val);
367
    break;
368
  case gageParmStackNormalizeDerivBias:
369
    ctx->parm.stackNormalizeDerivBias = val;
370
    break;
371
  case gageParmOrientationFromSpacing:
372
9
    ctx->parm.orientationFromSpacing = AIR_CAST(int, val);
373
    /* affects future calls to _gageShapeSet */
374
9
    break;
375
  case gageParmGenerateErrStr:
376
    ctx->parm.generateErrStr = AIR_CAST(int, val);
377
    break;
378
  case gageParmTwoDimZeroZ:
379
    ctx->parm.twoDimZeroZ = AIR_CAST(int, val);
380
    break;
381
  default:
382
    fprintf(stderr, "\n%s: sorry, which = %d not valid\n\n", me, which);
383
    break;
384
  }
385
  return;
386
275
}
387
388
/*
389
******** gagePerVolumeIsAttached()
390
**
391
*/
392
int
393
gagePerVolumeIsAttached(const gageContext *ctx, const gagePerVolume *pvl) {
394
  int ret;
395
  unsigned int pvlIdx;
396
397
  ret = AIR_FALSE;
398
3205
  for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
399
1082
    if (pvl == ctx->pvl[pvlIdx]) {
400
      ret = AIR_TRUE;
401
    }
402
  }
403
347
  return ret;
404
}
405
406
/*
407
******** gagePerVolumeAttach()
408
**
409
** attaches a pervolume to a context, which actually involves
410
** very little work
411
*/
412
int
413
gagePerVolumeAttach(gageContext *ctx, gagePerVolume *pvl) {
414
  static const char me[]="gagePerVolumeAttach";
415
  gageShape *shape;
416
  unsigned int newidx;
417
418
694
  if (!( ctx && pvl )) {
419
    biffAddf(GAGE, "%s: got NULL pointer", me);
420
    return 1;
421
  }
422
347
  if (gagePerVolumeIsAttached(ctx, pvl)) {
423
    biffAddf(GAGE, "%s: given pervolume already attached", me);
424
    return 1;
425
  }
426
427
347
  if (0 == ctx->pvlNum) {
428
    /* the volume "shape" is context state that we set now, because unlike
429
       everything else (handled by gageUpdate()), it does not effect
430
       the kind or amount of padding done */
431
113
    if (_gageShapeSet(ctx, ctx->shape, pvl->nin, pvl->kind->baseDim)) {
432
      biffAddf(GAGE, "%s: trouble", me);
433
      return 1;
434
    }
435
113
    ctx->flag[gageCtxFlagShape] = AIR_TRUE;
436
113
  } else {
437
    /* have to check to that new pvl matches first one.  Since all
438
       attached pvls were at some point the "new" one, they all
439
       should match each other */
440
234
    shape = gageShapeNew();
441
234
    if (_gageShapeSet(ctx, shape, pvl->nin, pvl->kind->baseDim)) {
442
      biffAddf(GAGE, "%s: trouble", me);
443
      return 1;
444
    }
445
234
    if (!gageShapeEqual(ctx->shape, "existing context", shape, "new volume")) {
446
      biffAddf(GAGE, "%s: trouble", me);
447
      gageShapeNix(shape); return 1;
448
    }
449
234
    gageShapeNix(shape);
450
  }
451
  /* here we go */
452
347
  newidx = airArrayLenIncr(ctx->pvlArr, 1);
453
347
  if (!ctx->pvl) {
454
    biffAddf(GAGE, "%s: couldn't increase length of pvl", me);
455
    return 1;
456
  }
457
347
  ctx->pvl[newidx] = pvl;
458
347
  pvl->verbose = ctx->verbose;
459
460
347
  return 0;
461
347
}
462
463
/*
464
******** gagePerVolumeDetach()
465
**
466
** detaches a pervolume from a context, but does nothing else
467
** with the pervolume; caller may want to call gagePerVolumeNix
468
** if this pervolume will no longer be used
469
*/
470
int
471
gagePerVolumeDetach(gageContext *ctx, gagePerVolume *pvl) {
472
  static const char me[]="gagePerVolumeDetach";
473
  unsigned int pvlIdx, foundIdx=0;
474
475
  if (!( ctx && pvl )) {
476
    biffAddf(GAGE, "%s: got NULL pointer", me);
477
    return 1;
478
  }
479
  if (!gagePerVolumeIsAttached(ctx, pvl)) {
480
    biffAddf(GAGE, "%s: given pervolume not currently attached", me);
481
    return 1;
482
  }
483
  for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
484
    if (pvl == ctx->pvl[pvlIdx]) {
485
      foundIdx = pvlIdx;
486
    }
487
  }
488
  for (pvlIdx=foundIdx+1; pvlIdx<ctx->pvlNum; pvlIdx++) {
489
    ctx->pvl[pvlIdx-1] = ctx->pvl[pvlIdx];
490
  }
491
  ctx->pvl[ctx->pvlNum-1] = NULL;
492
  airArrayLenIncr(ctx->pvlArr, -1);
493
  if (0 == ctx->pvlNum) {
494
    /* leave things the way that they started */
495
    gageShapeReset(ctx->shape);
496
    ctx->flag[gageCtxFlagShape] = AIR_TRUE;
497
  }
498
  return 0;
499
}
500
501
/*
502
** gageIv3Fill()
503
**
504
** based on ctx's shape and radius, and the (xi,yi,zi) determined from
505
** the probe location, fills the iv3 cache in the given pervolume
506
**
507
** This function is a bottleneck for so many things, so forcing off
508
** the verbose comments seems like one way of trying to speed it up.
509
** However, temporarily if-def'ing out unused branches of the
510
** "switch(pvl->kind->valLen)", and #define'ing fddd to 64 (for 4x4x4
511
** neighborhoods) did not noticeably speed anything up.
512
**
513
*/
514
void
515
gageIv3Fill(gageContext *ctx, gagePerVolume *pvl) {
516
  static const char me[]="gageIv3Fill";
517
  int lx, ly, lz, hx, hy, hz, _xx, _yy, _zz;
518
  unsigned int xx, yy, zz,
519
    fr, cacheIdx, dataIdx, fddd;
520
  unsigned int sx, sy, sz;
521
  char *data, *here;
522
  unsigned int tup;
523
524
1947038
  sx = ctx->shape->size[0];
525
973519
  sy = ctx->shape->size[1];
526
973519
  sz = ctx->shape->size[2];
527
973519
  fr = ctx->radius;
528
  /* idx[0]-1: see Thu Jan 14 comment in filter.c */
529
973519
  lx = ctx->point.idx[0]-1 - (fr - 1);
530
973519
  ly = ctx->point.idx[1]-1 - (fr - 1);
531
973519
  lz = ctx->point.idx[2]-1 - (fr - 1);
532
973519
  hx = lx + 2*fr - 1;
533
973519
  hy = ly + 2*fr - 1;
534
973519
  hz = lz + 2*fr - 1;
535
973519
  fddd = 2*fr*2*fr*2*fr;
536
973519
  if (ctx->verbose > 1) {
537
    fprintf(stderr, "%s: ___ hello; s %u %u %u; fr %u\n", me,
538
            sx, sy, sz, fr);
539
    fprintf(stderr, "%s:     point.idx %u %u %u\n", me,
540
            ctx->point.idx[0], ctx->point.idx[1], ctx->point.idx[2]);
541
    fprintf(stderr, "%s:     l %d %d %d; h %d %d %d; fddd %u\n", me,
542
            lx, ly, lz, hx, hy, hz, fddd);
543
  }
544
973519
  data = (char*)pvl->nin->data;
545

1857055
  if (lx >= 0 && ly >= 0 && lz >= 0
546
912434
      && hx < AIR_CAST(int, sx)
547
1809439
      && hy < AIR_CAST(int, sy)
548
1780541
      && hz < AIR_CAST(int, sz)) {
549
    /* all the samples we need are inside the existing volume */
550
867380
    dataIdx = lx + sx*(ly + sy*(lz));
551
867380
    if (ctx->verbose > 1) {
552
      fprintf(stderr, "%s:     hello, valLen = %d, pvl->nin = %p, data = %p\n",
553
              me, pvl->kind->valLen,
554
              AIR_CVOIDP(pvl->nin), pvl->nin->data);
555
    }
556
867380
    here = data + dataIdx*pvl->kind->valLen*nrrdTypeSize[pvl->nin->type];
557
867380
    if (ctx->verbose > 1) {
558
      fprintf(stderr, "%s:     size = (%u,%u,%u);\n"
559
              "%s:     fd = %d; coord = (%u,%u,%u) --> dataIdx = %d\n",
560
              me, sx, sy, sz, me, 2*fr,
561
              ctx->point.idx[0], ctx->point.idx[1], ctx->point.idx[2],
562
              dataIdx);
563
      fprintf(stderr, "%s:     here = %p; iv3 = %p; off[0,1,2,3,4,5,6,7] = "
564
              "%d,%d,%d,%d,%d,%d,%d,%d\n",
565
              me, here, AIR_CAST(void*, pvl->iv3),
566
              ctx->off[0], ctx->off[1], ctx->off[2], ctx->off[3],
567
              ctx->off[4], ctx->off[5], ctx->off[6], ctx->off[7]);
568
    }
569

867380
    switch(pvl->kind->valLen) {
570
    case 1:
571
184537680
      for (cacheIdx=0; cacheIdx<fddd; cacheIdx++) {
572
91490560
        pvl->iv3[cacheIdx] = pvl->lup(here, ctx->off[cacheIdx]);
573
      }
574
      break;
575
      /* NOTE: the tuple axis is being shifted from the fastest to
576
         the slowest axis, to anticipate component-wise filtering
577
         operations */
578
    case 3:
579
81712200
      for (cacheIdx=0; cacheIdx<fddd; cacheIdx++) {
580
40826400
        pvl->iv3[cacheIdx + fddd*0] = pvl->lup(here, 0 + 3*ctx->off[cacheIdx]);
581
40826400
        pvl->iv3[cacheIdx + fddd*1] = pvl->lup(here, 1 + 3*ctx->off[cacheIdx]);
582
40826400
        pvl->iv3[cacheIdx + fddd*2] = pvl->lup(here, 2 + 3*ctx->off[cacheIdx]);
583
      }
584
      break;
585
    case 7:
586
      /* this might come in handy for tenGage . . . */
587
81712200
      for (cacheIdx=0; cacheIdx<fddd; cacheIdx++) {
588
40826400
        pvl->iv3[cacheIdx + fddd*0] = pvl->lup(here, 0 + 7*ctx->off[cacheIdx]);
589
40826400
        pvl->iv3[cacheIdx + fddd*1] = pvl->lup(here, 1 + 7*ctx->off[cacheIdx]);
590
40826400
        pvl->iv3[cacheIdx + fddd*2] = pvl->lup(here, 2 + 7*ctx->off[cacheIdx]);
591
40826400
        pvl->iv3[cacheIdx + fddd*3] = pvl->lup(here, 3 + 7*ctx->off[cacheIdx]);
592
40826400
        pvl->iv3[cacheIdx + fddd*4] = pvl->lup(here, 4 + 7*ctx->off[cacheIdx]);
593
40826400
        pvl->iv3[cacheIdx + fddd*5] = pvl->lup(here, 5 + 7*ctx->off[cacheIdx]);
594
40826400
        pvl->iv3[cacheIdx + fddd*6] = pvl->lup(here, 6 + 7*ctx->off[cacheIdx]);
595
      }
596
      break;
597
    default:
598
81712200
      for (cacheIdx=0; cacheIdx<fddd; cacheIdx++) {
599
979833600
        for (tup=0; tup<pvl->kind->valLen; tup++) {
600
449090400
          pvl->iv3[cacheIdx + fddd*tup] =
601
449090400
            pvl->lup(here, tup + pvl->kind->valLen*ctx->off[cacheIdx]);
602
        }
603
      }
604
      break;
605
    }
606
867380
    ctx->edgeFrac = 0;
607
867380
  } else {
608
    unsigned int edgeNum, dataStride, valLen;
609
    /* the query requires samples which don't actually lie
610
       within the volume- more care has to be taken */
611
    double *iv3;
612
    cacheIdx = 0;
613
    edgeNum = 0;
614
106139
    valLen = pvl->kind->valLen;
615
106139
    dataStride = AIR_UINT(valLen*nrrdTypeSize[pvl->nin->type]);
616
106139
    iv3 = pvl->iv3;
617
106139
    if (1 == sz) {
618
      /* working with 2D images is now common enough that we try to make
619
         simplifications for that (HEY copy and paste). We first do the
620
         needed lup()s to fill first slice of iv3 ... */
621
      for (_yy=ly; _yy<=hy; _yy++) {
622
        yy = AIR_CLAMP(0, _yy, AIR_CAST(int, sy-1));
623
        for (_xx=lx; _xx<=hx; _xx++) {
624
          xx = AIR_CLAMP(0, _xx, AIR_CAST(int, sx-1));
625
          edgeNum += ((1 != sy && (AIR_CAST(int, yy) != _yy))
626
                      || (AIR_CAST(int, xx) != _xx));
627
          dataIdx = xx + sx*yy;
628
          here = data+dataIdx*dataStride;
629
          for (tup=0; tup<valLen; tup++) {
630
            iv3[cacheIdx + fddd*tup] = pvl->lup(here, tup);
631
          }
632
          cacheIdx++;
633
        }
634
      }
635
      /* ... and then copy from first slice into rest of iv3 */
636
      for (_zz=lz+1; _zz<=hz; _zz++) {
637
        unsigned int z0ci;
638
        z0ci = 0;
639
        for (_yy=ly; _yy<=hy; _yy++) {
640
          for (_xx=lx; _xx<=hx; _xx++) {
641
            for (tup=0; tup<valLen; tup++) {
642
              iv3[cacheIdx + fddd*tup] = iv3[z0ci + fddd*tup];
643
            }
644
            cacheIdx++;
645
            z0ci++;
646
          }
647
        }
648
      }
649
      /* we would have been outside for all the other z slices besides
650
         z=0, but don't report this if the whole point is to pretend
651
         that we're working with 2D data */
652
      if (!(ctx->parm.twoDimZeroZ)) {
653
        edgeNum += (2*fr - 1)*2*fr*2*fr;
654
      }
655
    } else {
656
      /* sz > 1 */
657
2455146
      for (_zz=lz; _zz<=hz; _zz++) {
658
3263232
        zz = AIR_CLAMP(0, _zz, AIR_CAST(int, sz-1));
659
33126684
        for (_yy=ly; _yy<=hy; _yy++) {
660
45090312
          yy = AIR_CLAMP(0, _yy, AIR_CAST(int, sy-1));
661
514438392
          for (_xx=lx; _xx<=hx; _xx++) {
662
700799692
            xx = AIR_CLAMP(0, _xx, AIR_CAST(int, sx-1));
663
483554576
            edgeNum += ((AIR_CAST(int, zz) != _zz)
664
437315772
                        || (AIR_CAST(int, yy) != _yy)
665
598702590
                        || (AIR_CAST(int, xx) != _xx));
666
241777288
            dataIdx = xx + sx*(yy + sy*zz);
667
241777288
            here = data+dataIdx*pvl->kind->valLen*nrrdTypeSize[pvl->nin->type];
668
241777288
            if (ctx->verbose > 2) {
669
              fprintf(stderr, "%s:    (%d,%d,%d) --clamp--> (%u,%u,%u)\n", me,
670
                      _xx, _yy, _zz, xx, yy, zz);
671
              fprintf(stderr, "    --> dataIdx = %d; data = %p -> here = %p\n",
672
                      dataIdx, data, here);
673
            }
674
967109152
            for (tup=0; tup<pvl->kind->valLen; tup++) {
675
241777288
              iv3[cacheIdx + fddd*tup] = pvl->lup(here, tup);
676
241777288
              if (ctx->verbose > 3) {
677
                fprintf(stderr, "%s:    iv3[%u + %u*%u=%u] = %g\n", me,
678
                        cacheIdx, fddd, tup, cacheIdx + fddd*tup,
679
                        iv3[cacheIdx + fddd*tup]);
680
              }
681
            }
682
241777288
            cacheIdx++;
683
          }
684
        }
685
      }
686
    }
687
106139
    ctx->edgeFrac = AIR_CAST(double, edgeNum)/fddd;
688
  }
689
973519
  if (ctx->verbose > 1) {
690
    fprintf(stderr, "%s: ^^^ bye\n", me);
691
  }
692
  return;
693
973519
}
694
695
/*
696
** _gageProbe
697
**
698
** how to do probing.  (x,y,z) position is *index space* position.
699
** Note, however, that derivatives (gradients and hessians) will
700
** effectively be computed in *world space*.
701
**
702
** doesn't actually do much more than call callbacks in the gageKind
703
** structs of the attached pervolumes
704
**
705
** NOTE: the stack filter weights are (like the spatial filter weights)
706
** computed inside _gageLocationSet()
707
*/
708
int
709
_gageProbe(gageContext *ctx, double _xi, double _yi, double _zi, double _si) {
710
  static const char me[]="_gageProbe";
711
  unsigned int oldIdx[4], oldNnz=0, pvlIdx;
712
  int idxChanged;
713
714
682650
  if (!ctx) {
715
    return 1;
716
  }
717
341325
  if (ctx->verbose > 3) {
718
    fprintf(stderr, "%s: hello(%g,%g,%g,%g) _____________ \n", me,
719
            _xi, _yi, _zi, _si);
720
  }
721
341325
  ELL_4V_COPY(oldIdx, ctx->point.idx);
722
341325
  oldNnz = ctx->point.stackFwNonZeroNum;
723
341325
  if (_gageLocationSet(ctx, _xi, _yi, _zi, _si)) {
724
    /* we're outside the volume; leave ctx->errNum and ctx->errStr set;
725
       as they have just been set by _gageLocationSet() */
726
    /* GLK had added but not checked in the following line;
727
       the logic of this has to be studied further */
728
    /* ctx->edgeFrac = 0.666; */
729
    return 1;
730
  }
731
732
  /* if necessary, refill the iv3 cache */
733
341325
  idxChanged = (oldIdx[0] != ctx->point.idx[0]
734
344832
                || oldIdx[1] != ctx->point.idx[1]
735
346136
                || oldIdx[2] != ctx->point.idx[2]);
736
341325
  if (ctx->parm.stackUse) {
737
    idxChanged |= oldIdx[3] != ctx->point.idx[3];
738
    /* this is subtle (and the source of a difficult bug): even if
739
       point.idx[3] has not changed, you can still have a change in
740
       which of the stackFw[] are non-zero, which in turn determines
741
       which iv3s have to be refilled.  For example, changing _si
742
       from 0.0 to 0.1, using tent or hermite reconstruction, will
743
       newly require pvl[1]'s iv3 to be refilled.  To catch this kind
744
       of situation, we could keep a list of which iv3s are active and
745
       look for changes in that, or, we could just look for changes in
746
       point.idx[3] AND changes in stackFwNonZeroNum */
747
    idxChanged |= oldNnz != ctx->point.stackFwNonZeroNum;
748
  }
749
341325
  if (ctx->verbose > 3) {
750
    fprintf(stderr, "%s: oldIdx %u %u %u %u, point.idx %u %u %u %u --> %d\n",
751
            me, oldIdx[0], oldIdx[1], oldIdx[2], oldIdx[3],
752
            ctx->point.idx[0], ctx->point.idx[1],
753
            ctx->point.idx[2], ctx->point.idx[3], idxChanged);
754
  }
755
341325
  if (idxChanged) {
756
340279
    if (!ctx->parm.stackUse) {
757
2287317
      for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
758
973519
        if (ctx->verbose > 3) {
759
          fprintf(stderr, "%s: gageIv3Fill(pvl[%u/%u] %s): .......\n", me,
760
                  pvlIdx, ctx->pvlNum, ctx->pvl[pvlIdx]->kind->name);
761
        }
762
973519
        gageIv3Fill(ctx, ctx->pvl[pvlIdx]);
763
      }
764
    } else {
765
      for (pvlIdx=0; pvlIdx<ctx->pvlNum-1; pvlIdx++) {
766
        /* note that we only fill the cache for the stack samples that
767
           have a non-zero weight. HEY, however, it would be nice to
768
           only refill the iv3 that we have to, based on the change in
769
           scale, instead of refilling all of them in the support of
770
           the stack recon */
771
        if (ctx->stackFw[pvlIdx]) {
772
          if (ctx->verbose > 3) {
773
            fprintf(stderr, "%s: stackFw[%u] == %g -> iv3fill needed\n", me,
774
                    pvlIdx, ctx->stackFw[pvlIdx]);
775
          }
776
          gageIv3Fill(ctx, ctx->pvl[pvlIdx]);
777
        } else {
778
          if (ctx->verbose > 3) {
779
            fprintf(stderr, "%s: stackFw[%u] == %g -> NO iv3fill\n", me,
780
                    pvlIdx, ctx->stackFw[pvlIdx]);
781
          }
782
        }
783
      }
784
    }
785
  }
786
341325
  if (ctx->parm.stackUse) {
787
    unsigned int baseIdx, vi;
788
    baseIdx = ctx->pvlNum - 1;
789
    if (ctx->verbose > 3) {
790
      for (vi=0; vi<baseIdx; vi++) {
791
        fprintf(stderr, "%s: (stack) pvl[%u]'s value cache at "
792
                "coords = %u,%u,%u:\n", me, vi,
793
                ctx->point.idx[0], ctx->point.idx[1], ctx->point.idx[2]);
794
        ctx->pvl[vi]->kind->iv3Print(stderr, ctx, ctx->pvl[vi]);
795
      }
796
    }
797
    _gageStackBaseIv3Fill(ctx);
798
    if (ctx->verbose > 3) {
799
      fprintf(stderr, "%s: (stack) base pvl's value cache at "
800
              "coords = %u,%u,%u:\n", me,
801
              ctx->point.idx[0], ctx->point.idx[1], ctx->point.idx[2]);
802
      ctx->pvl[baseIdx]->kind->iv3Print(stderr, ctx, ctx->pvl[baseIdx]);
803
    }
804
    ctx->pvl[baseIdx]->kind->filter(ctx, ctx->pvl[baseIdx]);
805
    ctx->pvl[baseIdx]->kind->answer(ctx, ctx->pvl[baseIdx]);
806
  } else {
807
2650500
    for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) {
808
983925
      if (ctx->verbose > 3) {
809
        fprintf(stderr, "%s: pvl[%u/%u %s]'s value cache at "
810
                "coords = %u,%u,%u:\n", me, pvlIdx, ctx->pvlNum,
811
                ctx->pvl[pvlIdx]->kind->name,
812
                ctx->point.idx[0], ctx->point.idx[1], ctx->point.idx[2]);
813
        ctx->pvl[pvlIdx]->kind->iv3Print(stderr, ctx, ctx->pvl[pvlIdx]);
814
      }
815
983925
      ctx->pvl[pvlIdx]->kind->filter(ctx, ctx->pvl[pvlIdx]);
816
983925
      ctx->pvl[pvlIdx]->kind->answer(ctx, ctx->pvl[pvlIdx]);
817
    }
818
  }
819
820
341325
  if (ctx->verbose > 3) {
821
    fprintf(stderr, "%s: bye ^^^^^^^^^^^^^ \n\n", me);
822
  }
823
341325
  return 0;
824
341325
}
825
826
/*
827
******** gageProbe()
828
**
829
** bummer: the non-stack gageProbe function is now just a wrapper
830
** around the stack-based gageProbe
831
*/
832
int
833
gageProbe(gageContext *ctx, double xi, double yi, double zi) {
834
835
  return _gageProbe(ctx, xi, yi, zi, 0.0);
836
}
837
838
int
839
_gageProbeSpace(gageContext *ctx, double xx, double yy, double zz, double ss,
840
               int indexSpace, int clamp) {
841
  static const char me[]="_gageProbeSpace";
842
  unsigned int *size;
843
  double xi, yi, zi, si;
844
845
682650
  if (ctx->verbose > 3) {
846
    fprintf(stderr, "%s: hi; pos=(%g,%g,%g,%g) in %s space %s clamping\n", me,
847
            xx, yy, zz, ss, indexSpace ? "index" : "world",
848
            clamp ? "WITH" : "w/out");
849
  }
850
341325
  size = ctx->shape->size;
851
341325
  if (indexSpace) {
852
    xi = xx;
853
    yi = yy;
854
    zi = zz;
855
340160
    if (ctx->parm.stackUse) {
856
      si = ss;
857
    } else {
858
      si = 0;
859
    }
860
340160
    if (ctx->verbose > 3) {
861
      fprintf(stderr, "%s: staying at ipos (%g,%g,%g)\n", me,
862
              xi, yi, zi);
863
    }
864
  } else {
865
    /* have to convert from world to index.  NOTE: the [4]s here are
866
       for homogeneous coordinates, not for anything stack-related */
867
    double icoord[4]; double wcoord[4];
868
    ELL_4V_SET(wcoord, xx, yy, zz, 1);
869
1165
    ELL_4MV_MUL(icoord, ctx->shape->WtoI, wcoord);
870
1165
    ELL_4V_HOMOG(icoord, icoord);
871
    xi = icoord[0];
872
    yi = icoord[1];
873
    zi = icoord[2];
874
1165
    if (ctx->parm.stackUse) {
875
      unsigned int sidx;
876
      /* HEY: this is a stupid linear search! */
877
      if (ss < ctx->stackPos[0]) {
878
        /* we'll extrapolate from stackPos[0] and [1]. um, actually the
879
         extrapolation is overkill because we're either going to clamp
880
         out-of-range scale index positions, or they'll cause a
881
         gageErrStackBounds error downstream */
882
        sidx = 0;
883
      } else if (ss > ctx->stackPos[ctx->pvlNum-2]) {
884
        /* extrapolate from stackPos[ctx->pvlNum-3] and [ctx->pvlNum-2];
885
           gageStackPerVolumeAttach ensures that we there are at least
886
           two blurrings pvls and one base pvl */
887
        sidx = ctx->pvlNum-3;
888
      } else {
889
        for (sidx=0; sidx<ctx->pvlNum-2; sidx++) {
890
          if (AIR_IN_CL(ctx->stackPos[sidx], ss, ctx->stackPos[sidx+1])) {
891
            break;
892
          }
893
        }
894
        if (sidx == ctx->pvlNum-2) {
895
          if (ctx->parm.generateErrStr) {
896
            sprintf(ctx->errStr, "%s: search failure for ss = %g", me, ss);
897
          } else {
898
            strcpy(ctx->errStr, _GAGE_NON_ERR_STR);
899
          }
900
          ctx->errNum = gageErrStackSearch;
901
          return 1;
902
        }
903
      }
904
      si = AIR_AFFINE(ctx->stackPos[sidx], ss, ctx->stackPos[sidx+1],
905
                      sidx, sidx+1);
906
      if (ctx->verbose > 3) {
907
        fprintf(stderr, "%s: si = affine(%g, %g, %g  -> %u %u) = %g\n", me,
908
                ctx->stackPos[sidx], ss, ctx->stackPos[sidx+1],
909
                sidx, sidx+1, si);
910
      }
911
    } else {
912
      si = 0;
913
    }
914
1165
    if (ctx->verbose > 3) {
915
      fprintf(stderr, "%s: wpos (%g,%g,%g) --> ipos (%g,%g,%g)\n", me,
916
              xx, yy, zz, xi, yi, zi);
917
    }
918
1165
  }
919
341325
  if (clamp) {
920
13165
    if (nrrdCenterNode == ctx->shape->center) {
921
      xi = AIR_CLAMP(0, xi, size[0]-1);
922
      yi = AIR_CLAMP(0, yi, size[1]-1);
923
      zi = AIR_CLAMP(0, zi, size[2]-1);
924
    } else {
925

52414
      xi = AIR_CLAMP(-0.5, xi, size[0]-0.5);
926

52416
      yi = AIR_CLAMP(-0.5, yi, size[1]-0.5);
927

52412
      zi = AIR_CLAMP(-0.5, zi, size[2]-0.5);
928
    }
929
13165
    if (ctx->parm.stackUse) {
930
      si = AIR_CLAMP(0, si, ctx->pvlNum-2);
931
    }
932
13165
    if (ctx->verbose > 3) {
933
      fprintf(stderr, "%s: with clamping --> ipos (%g,%g,%g)\n", me,
934
              xi, yi, zi);
935
    }
936
  }
937
341325
  return _gageProbe(ctx, xi, yi, zi, si);
938
341325
}
939
940
int
941
gageProbeSpace(gageContext *ctx, double xx, double yy, double zz,
942
               int indexSpace, int clamp) {
943
944
682650
  return _gageProbeSpace(ctx, xx, yy, zz, AIR_NAN, indexSpace, clamp);
945
}