GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/limn/splineEval.c Lines: 0 126 0.0 %
Date: 2017-05-26 Branches: 0 98 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
25
#include "limn.h"
26
27
void
28
_limnSplineIntervalFind_Unknown(int *ii, double *ff,
29
                                limnSpline *spline, double tt) {
30
  static const char me[]="_limnSplineIntervalFind_Unknown";
31
32
  AIR_UNUSED(ii);
33
  AIR_UNUSED(ff);
34
  AIR_UNUSED(spline);
35
  AIR_UNUSED(tt);
36
  fprintf(stderr, "%s: WARNING: spline type unset somewhere\n", me);
37
  return;
38
}
39
40
void
41
_limnSplineIntervalFind_NonWarp(int *ii, double *ff,
42
                                limnSpline *spline, double tt) {
43
  int N;
44
45
  N = spline->ncpt->axis[2].size + (spline->loop ? 1 : 0);
46
  tt = AIR_CLAMP(0, tt, N-1);
47
  *ii = (int)tt;
48
  *ff = tt - *ii;
49
  return;
50
}
51
52
void
53
_limnSplineIntervalFind_Warp(int *ii, double *ff,
54
                             limnSpline *spline, double tt) {
55
  int N;
56
57
  N = spline->ncpt->axis[2].size;
58
  tt = AIR_CLAMP(spline->time[0], tt, spline->time[N-1]);
59
  *ii = AIR_CLAMP(0, *ii, N-2);
60
  /* the last value of ii may be the right one */
61
  if (!AIR_IN_CL(spline->time[*ii], tt, spline->time[*ii+1])) {
62
    /* HEY: make this a binary search */
63
    for (*ii=0; *ii<N-2; (*ii)++) {
64
      if (AIR_IN_CL(spline->time[*ii], tt, spline->time[*ii+1])) {
65
        break;
66
      }
67
    }
68
  }
69
  *ff = (tt - spline->time[*ii])/(spline->time[*ii+1] - spline->time[*ii]);
70
  return;
71
}
72
73
typedef void (*_limnSplineIntervalFind_t)(int *, double *,
74
                                          limnSpline *, double);
75
_limnSplineIntervalFind_t
76
_limnSplineIntervalFind[LIMN_SPLINE_TYPE_MAX+1] = {
77
  _limnSplineIntervalFind_Unknown,
78
  _limnSplineIntervalFind_NonWarp,
79
  _limnSplineIntervalFind_Warp,
80
  _limnSplineIntervalFind_NonWarp,
81
  _limnSplineIntervalFind_NonWarp,
82
  _limnSplineIntervalFind_NonWarp
83
};
84
85
void
86
_limnSplineWeightsFind_Unknown(double *wght, limnSpline *spline, double f) {
87
  static const char me[]="_limnSplineWeights_Unknown";
88
89
  AIR_UNUSED(wght);
90
  AIR_UNUSED(spline);
91
  AIR_UNUSED(f);
92
  fprintf(stderr, "%s: WARNING: spline type unset somewhere\n", me);
93
  return;
94
}
95
96
void
97
_limnSplineWeightsFind_Linear(double *wght, limnSpline *spline, double f) {
98
99
  AIR_UNUSED(spline);
100
  ELL_4V_SET(wght, 0, 1-f, f, 0);
101
  /*
102
  fprintf(stderr, "%g ----> %g %g %g %g\n", f,
103
          wght[0], wght[1], wght[2], wght[3]);
104
  */
105
  return;
106
}
107
108
void
109
_limnSplineWeightsFind_Hermite(double *wght, limnSpline *spline, double f) {
110
  double f3, f2;
111
112
  AIR_UNUSED(spline);
113
  f3 = f*(f2 = f*f);
114
  ELL_4V_SET(wght,
115
             2*f3 - 3*f2 + 1,
116
             f3 - 2*f2 + f,
117
             f3 - f2,
118
             -2*f3 + 3*f2);
119
  return;
120
}
121
122
void
123
_limnSplineWeightsFind_CubicBezier(double *wght,
124
                                   limnSpline *spline, double f) {
125
  double g;
126
127
  AIR_UNUSED(spline);
128
  g = 1 - f;
129
  ELL_4V_SET(wght,
130
             g*g*g,
131
             3*g*g*f,
132
             3*g*f*f,
133
             f*f*f);
134
  return;
135
}
136
137
/* lifted from nrrd/kernel.c */
138
#define _BCCUBIC(x, B, C)                                           \
139
  ((x) >= 2.0 ? 0 :                                                 \
140
  ((x) >= 1.0                                                       \
141
   ? (((-B/6 - C)*(x) + B + 5*C)*(x) -2*B - 8*C)*(x) + 4*B/3 + 4*C  \
142
   : ((2 - 3*B/2 - C)*(x) - 3 + 2*B + C)*(x)*(x) + 1 - B/3))
143
144
void
145
_limnSplineWeightsFind_BC(double *wght, limnSpline *spline, double f) {
146
  double B, C, f0, f1, f2, f3;
147
148
  B = spline->B;
149
  C = spline->C;
150
  f0 = f+1;
151
  f1 = f;
152
  f2 = AIR_ABS(f-1);
153
  f3 = AIR_ABS(f-2);
154
  ELL_4V_SET(wght,
155
             _BCCUBIC(f0, B, C),
156
             _BCCUBIC(f1, B, C),
157
             _BCCUBIC(f2, B, C),
158
             _BCCUBIC(f3, B, C));
159
  return;
160
}
161
162
typedef void (*_limnSplineWeightsFind_t)(double *, limnSpline *, double);
163
164
_limnSplineWeightsFind_t
165
_limnSplineWeightsFind[LIMN_SPLINE_TYPE_MAX+1] = {
166
  _limnSplineWeightsFind_Unknown,
167
  _limnSplineWeightsFind_Linear,
168
  _limnSplineWeightsFind_Hermite, /* TimeWarp */
169
  _limnSplineWeightsFind_Hermite,
170
  _limnSplineWeightsFind_CubicBezier,
171
  _limnSplineWeightsFind_BC
172
};
173
174
void
175
_limnSplineIndexFind(int *idx, limnSpline *spline, int ii) {
176
  int N, ti[4];
177
178
  N = spline->ncpt->axis[2].size;
179
  if (limnSplineTypeHasImplicitTangents[spline->type]) {
180
    if (spline->loop) {
181
      ELL_4V_SET(ti,
182
                 AIR_MOD(ii-1, N),
183
                 AIR_MOD(ii+0, N),
184
                 AIR_MOD(ii+1, N),
185
                 AIR_MOD(ii+2, N));
186
    } else {
187
      ELL_4V_SET(ti,
188
                 AIR_CLAMP(0, ii-1, N-1),
189
                 AIR_CLAMP(0, ii+0, N-1),
190
                 AIR_CLAMP(0, ii+1, N-1),
191
                 AIR_CLAMP(0, ii+2, N-1));
192
    }
193
    ELL_4V_SET(idx, 1 + 3*ti[0], 1 + 3*ti[1], 1 + 3*ti[2], 1 + 3*ti[3]);
194
  } else {
195
    if (spline->loop) {
196
      ELL_4V_SET(ti,
197
                 AIR_MOD(ii+0, N),
198
                 AIR_MOD(ii+0, N),
199
                 AIR_MOD(ii+1, N),
200
                 AIR_MOD(ii+1, N));
201
    } else {
202
      ELL_4V_SET(ti,
203
                 AIR_CLAMP(0, ii+0, N-1),
204
                 AIR_CLAMP(0, ii+0, N-1),
205
                 AIR_CLAMP(0, ii+1, N-1),
206
                 AIR_CLAMP(0, ii+1, N-1));
207
    }
208
    ELL_4V_SET(idx, 1 + 3*ti[0], 2 + 3*ti[1], 0 + 3*ti[2], 1 + 3*ti[3]);
209
  }
210
}
211
212
void
213
_limnSplineFinish_Unknown(double *out, limnSpline *spline,
214
                          int ii, double *wght) {
215
  static const char me[]="_limnSplineFinish_Unknown";
216
217
  AIR_UNUSED(out);
218
  AIR_UNUSED(spline);
219
  AIR_UNUSED(ii);
220
  AIR_UNUSED(wght);
221
  fprintf(stderr, "%s: WARNING: spline info unset somewhere\n", me);
222
  return;
223
}
224
225
void
226
_limnSplineFinish_Scalar(double *out, limnSpline *spline,
227
                         int ii, double *wght) {
228
  int idx[4];
229
  double *cpt;
230
231
  cpt = (double*)(spline->ncpt->data);
232
  _limnSplineIndexFind(idx, spline, ii);
233
  *out = (  wght[0]*cpt[idx[0]] + wght[1]*cpt[idx[1]]
234
          + wght[2]*cpt[idx[2]] + wght[3]*cpt[idx[3]]);
235
  return;
236
}
237
238
void
239
_limnSplineFinish_2Vec(double *out, limnSpline *spline,
240
                       int ii, double *wght) {
241
  int idx[4];
242
  double *cpt;
243
244
  cpt = (double*)(spline->ncpt->data);
245
  _limnSplineIndexFind(idx, spline, ii);
246
  out[0] = (  wght[0]*cpt[0 + 2*idx[0]] + wght[1]*cpt[0 + 2*idx[1]]
247
            + wght[2]*cpt[0 + 2*idx[2]] + wght[3]*cpt[0 + 2*idx[3]]);
248
  out[1] = (  wght[0]*cpt[1 + 2*idx[0]] + wght[1]*cpt[1 + 2*idx[1]]
249
            + wght[2]*cpt[1 + 2*idx[2]] + wght[3]*cpt[1 + 2*idx[3]]);
250
  return;
251
}
252
253
void
254
_limnSplineFinish_3Vec(double *out, limnSpline *spline,
255
                       int ii, double *wght) {
256
  int idx[4];
257
  double *cpt;
258
259
  cpt = (double*)(spline->ncpt->data);
260
  _limnSplineIndexFind(idx, spline, ii);
261
  out[0] = (  wght[0]*cpt[0 + 3*idx[0]] + wght[1]*cpt[0 + 3*idx[1]]
262
            + wght[2]*cpt[0 + 3*idx[2]] + wght[3]*cpt[0 + 3*idx[3]]);
263
  out[1] = (  wght[0]*cpt[1 + 3*idx[0]] + wght[1]*cpt[1 + 3*idx[1]]
264
            + wght[2]*cpt[1 + 3*idx[2]] + wght[3]*cpt[1 + 3*idx[3]]);
265
  out[2] = (  wght[0]*cpt[2 + 3*idx[0]] + wght[1]*cpt[2 + 3*idx[1]]
266
            + wght[2]*cpt[2 + 3*idx[2]] + wght[3]*cpt[2 + 3*idx[3]]);
267
  return;
268
}
269
270
void
271
_limnSplineFinish_Normal(double *out, limnSpline *spline,
272
                         int ii, double *wght) {
273
274
  AIR_UNUSED(out);
275
  AIR_UNUSED(spline);
276
  AIR_UNUSED(ii);
277
  AIR_UNUSED(wght);
278
  fprintf(stderr, "%s: NOT IMPLEMENTED\n", "_limnSplineFinish_Normal");
279
  return;
280
}
281
282
void
283
_limnSplineFinish_4Vec(double *out, limnSpline *spline,
284
                       int ii, double *wght) {
285
  int idx[4];
286
  double *cpt;
287
288
  cpt = (double*)(spline->ncpt->data);
289
  _limnSplineIndexFind(idx, spline, ii);
290
  out[0] = (  wght[0]*cpt[0 + 4*idx[0]] + wght[1]*cpt[0 + 4*idx[1]]
291
            + wght[2]*cpt[0 + 4*idx[2]] + wght[3]*cpt[0 + 4*idx[3]]);
292
  out[1] = (  wght[0]*cpt[1 + 4*idx[0]] + wght[1]*cpt[1 + 4*idx[1]]
293
            + wght[2]*cpt[1 + 4*idx[2]] + wght[3]*cpt[1 + 4*idx[3]]);
294
  out[2] = (  wght[0]*cpt[2 + 4*idx[0]] + wght[1]*cpt[2 + 4*idx[1]]
295
            + wght[2]*cpt[2 + 4*idx[2]] + wght[3]*cpt[2 + 4*idx[3]]);
296
  out[3] = (  wght[0]*cpt[3 + 4*idx[0]] + wght[1]*cpt[3 + 4*idx[1]]
297
            + wght[2]*cpt[3 + 4*idx[2]] + wght[3]*cpt[3 + 4*idx[3]]);
298
  return;
299
}
300
301
/*
302
** HEY: I have no whether Hermite splines work with this
303
*/
304
void
305
_limnSplineFinish_Quaternion(double *out, limnSpline *spline,
306
                             int ii, double *wght) {
307
  int idx[4];
308
  double *cpt;
309
310
  cpt = (double*)(spline->ncpt->data);
311
  _limnSplineIndexFind(idx, spline, ii);
312
  ell_q_avg4_d(out, NULL,
313
               cpt + 4*idx[0], cpt + 4*idx[1],
314
               cpt + 4*idx[2], cpt + 4*idx[3],
315
               wght, LIMN_SPLINE_Q_AVG_EPS, 30 /* maxIter */);
316
  return;
317
}
318
319
typedef void (*_limnSplineFinish_t)(double *, limnSpline *, int, double *);
320
_limnSplineFinish_t
321
_limnSplineFinish[LIMN_SPLINE_INFO_MAX+1] = {
322
  _limnSplineFinish_Unknown,
323
  _limnSplineFinish_Scalar,
324
  _limnSplineFinish_2Vec,
325
  _limnSplineFinish_3Vec,
326
  _limnSplineFinish_Normal,
327
  _limnSplineFinish_4Vec,
328
  _limnSplineFinish_Quaternion
329
};
330
331
void
332
limnSplineEvaluate(double *out, limnSpline *spline, double tt) {
333
  int ii=0;
334
  double ff, wght[4];
335
336
  if (out && spline) {
337
    _limnSplineIntervalFind[spline->type](&ii, &ff, spline, tt);
338
    _limnSplineWeightsFind[spline->type](wght, spline, ff);
339
    _limnSplineFinish[spline->info](out, spline, ii, wght);
340
  }
341
  return;
342
}
343
344
int
345
limnSplineNrrdEvaluate(Nrrd *nout, limnSpline *spline, Nrrd *nin) {
346
  static const char me[]="limnSplineNrrdEvaluate";
347
  double tt, *out, (*lup)(const void *, size_t);
348
  int odim, infoSize;
349
  size_t I, M, size[NRRD_DIM_MAX+1];
350
351
  if (!(nout && spline && nin)) {
352
    biffAddf(LIMN, "%s: got NULL pointer", me);
353
    return 1;
354
  }
355
  if (limnSplineInfoScalar == spline->info) {
356
    nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size);
357
    infoSize = 1;
358
    odim = nin->dim;
359
  } else {
360
    nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size+1);
361
    infoSize = size[0] = limnSplineInfoSize[spline->info];
362
    odim = 1 + nin->dim;
363
  }
364
  if (nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, odim, size)) {
365
    biffMovef(LIMN, NRRD, "%s: output allocation failed", me);
366
    return 1;
367
  }
368
  lup = nrrdDLookup[nin->type];
369
  out = (double*)(nout->data);
370
  M = nrrdElementNumber(nin);
371
  for (I=0; I<M; I++) {
372
    tt = lup(nin->data, I);
373
    limnSplineEvaluate(out, spline, tt);
374
    out += infoSize;
375
  }
376
377
  /* HEY: peripheral info copying? */
378
379
  return 0;
380
}
381
382
int
383
limnSplineSample(Nrrd *nout, limnSpline *spline,
384
                 double minT, size_t M, double maxT) {
385
  static const char me[]="limnSplineSample";
386
  airArray *mop;
387
  Nrrd *ntt;
388
  double *tt;
389
  size_t I;
390
391
  if (!(nout && spline)) {
392
    biffAddf(LIMN, "%s: got NULL pointer", me);
393
    return 1;
394
  }
395
  mop = airMopNew();
396
  airMopAdd(mop, ntt=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
397
  if (nrrdMaybeAlloc_va(ntt, nrrdTypeDouble, 1,
398
                        M)) {
399
    biffMovef(LIMN, NRRD, "%s: trouble allocating tmp nrrd", me);
400
    airMopError(mop); return 1;
401
  }
402
  tt = (double*)(ntt->data);
403
  for (I=0; I<M; I++) {
404
    tt[I] = AIR_AFFINE(0, I, M-1, minT, maxT);
405
  }
406
  if (limnSplineNrrdEvaluate(nout, spline, ntt)) {
407
    biffAddf(LIMN, "%s: trouble", me);
408
    airMopError(mop); return 1;
409
  }
410
  airMopOkay(mop);
411
  return 0;
412
}
413