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 |
|
|
|