GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/limn/splineMisc.c Lines: 0 117 0.0 %
Date: 2017-05-26 Branches: 0 62 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
const char *
28
_limnSplineTypeStr[LIMN_SPLINE_TYPE_MAX+1] = {
29
  "(unknown_spline_type)",
30
  "linear",
31
  "timewarp",
32
  "hermite",
33
  "cubic-bezier",
34
  "BC"
35
};
36
37
const char *
38
_limnSplineTypeDesc[LIMN_SPLINE_TYPE_MAX+1] = {
39
  "unknown spline type",
40
  "simple linear interpolation between control points",
41
  "pseudo-Hermite spline for warping time to uniform (integral) "
42
    "control point locations",
43
  "Hermite cubic interpolating spline",
44
  "cubic Bezier spline",
45
  "Mitchell-Netravalli BC-family of cubic splines"
46
};
47
48
const char *
49
_limnSplineTypeStrEqv[] = {
50
  "linear", "lin", "line", "tent",
51
  "timewarp", "time-warp", "warp",
52
  "hermite",
53
  "cubicbezier", "cubic-bezier", "bezier", "bez",
54
  "BC", "BC-spline",
55
  ""
56
};
57
58
const int
59
_limnSplineTypeValEqv[] = {
60
  limnSplineTypeLinear, limnSplineTypeLinear, limnSplineTypeLinear,
61
      limnSplineTypeLinear,
62
  limnSplineTypeTimeWarp, limnSplineTypeTimeWarp, limnSplineTypeTimeWarp,
63
  limnSplineTypeHermite,
64
  limnSplineTypeCubicBezier, limnSplineTypeCubicBezier,
65
      limnSplineTypeCubicBezier, limnSplineTypeCubicBezier,
66
  limnSplineTypeBC, limnSplineTypeBC
67
};
68
69
const airEnum
70
_limnSplineType = {
71
  "spline-type",
72
  LIMN_SPLINE_TYPE_MAX,
73
  _limnSplineTypeStr,  NULL,
74
  _limnSplineTypeDesc,
75
  _limnSplineTypeStrEqv, _limnSplineTypeValEqv,
76
  AIR_FALSE
77
};
78
const airEnum *const
79
limnSplineType = &_limnSplineType;
80
81
const char *
82
_limnSplineInfoStr[LIMN_SPLINE_INFO_MAX+1] = {
83
  "(unknown_spline_info)",
84
  "scalar",
85
  "2vector",
86
  "3vector",
87
  "normal",
88
  "4vector",
89
  "quaternion"
90
};
91
92
const char *
93
_limnSplineInfoDesc[LIMN_SPLINE_INFO_MAX+1] = {
94
  "unknown spline info",
95
  "scalar",
96
  "2-vector",
97
  "3-vector",
98
  "surface normal, interpolated in S^2",
99
  "4-vector, interpolated in R^4",
100
  "quaternion, interpolated in S^3"
101
};
102
103
const char *
104
_limnSplineInfoStrEqv[] = {
105
  "scalar", "scale", "s", "t",
106
  "2-vector", "2vector", "2vec", "2v", "v2", "vec2", "vector2", "vector-2",
107
  "3-vector", "3vector", "3vec", "3v", "v3", "vec3", "vector3", "vector-3",
108
  "normal", "norm", "n",
109
  "4-vector", "4vector", "4vec", "4v", "v4", "vec4", "vector4", "vector-4",
110
  "quaternion", "quat", "q",
111
  ""
112
};
113
114
#define SISS limnSplineInfoScalar
115
#define SI2V limnSplineInfo2Vector
116
#define SI3V limnSplineInfo3Vector
117
#define SINN limnSplineInfoNormal
118
#define SI4V limnSplineInfo4Vector
119
#define SIQQ limnSplineInfoQuaternion
120
121
const int
122
_limnSplineInfoValEqv[] = {
123
  SISS, SISS, SISS, SISS,
124
  SI2V, SI2V, SI2V, SI2V, SI2V, SI2V, SI2V, SI2V,
125
  SI3V, SI3V, SI3V, SI3V, SI3V, SI3V, SI3V, SI3V,
126
  SINN, SINN, SINN,
127
  SI4V, SI4V, SI4V, SI4V, SI4V, SI4V, SI4V, SI4V,
128
  SIQQ, SIQQ, SIQQ
129
};
130
131
const airEnum
132
_limnSplineInfo = {
133
  "spline-info",
134
  LIMN_SPLINE_INFO_MAX,
135
  _limnSplineInfoStr,  NULL,
136
  _limnSplineInfoDesc,
137
  _limnSplineInfoStrEqv, _limnSplineInfoValEqv,
138
  AIR_FALSE
139
};
140
const airEnum *const
141
limnSplineInfo = &_limnSplineInfo;
142
143
/*
144
******** limnSplineInfoSize[]
145
**
146
** gives the number of scalars per "value" for each splineInfo
147
*/
148
unsigned int
149
limnSplineInfoSize[LIMN_SPLINE_INFO_MAX+1] = {
150
  0,  /* limnSplineInfoUnknown */
151
  1,  /* limnSplineInfoScalar */
152
  2,  /* limnSplineInfo2Vector */
153
  3,  /* limnSplineInfo3Vector */
154
  3,  /* limnSplineInfoNormal */
155
  4,  /* limnSplineInfo4Vector */
156
  4   /* limnSplineInfoQuaternion */
157
};
158
159
/*
160
******** limnSplineTypeHasImplicitTangents[]
161
**
162
** this is non-zero when the spline path is determined solely the
163
** main control point values, without needing additional control
164
** points (as in cubic Bezier) or tangent information (as in Hermite)
165
*/
166
int
167
limnSplineTypeHasImplicitTangents[LIMN_SPLINE_TYPE_MAX+1] = {
168
  AIR_FALSE, /* limnSplineTypeUnknown */
169
  AIR_TRUE,  /* limnSplineTypeLinear */
170
  AIR_FALSE, /* limnSplineTypeTimeWarp */
171
  AIR_FALSE, /* limnSplineTypeHermite */
172
  AIR_FALSE, /* limnSplineTypeCubicBezier */
173
  AIR_TRUE   /* limnSplineTypeBC */
174
};
175
176
int
177
limnSplineNumPoints(limnSpline *spline) {
178
  int ret;
179
180
  ret = -1;
181
  if (spline) {
182
    ret = spline->ncpt->axis[2].size;
183
  }
184
  return ret;
185
}
186
187
double
188
limnSplineMinT(limnSpline *spline) {
189
  double ret;
190
191
  ret = AIR_NAN;
192
  if (spline) {
193
    ret = spline->time ? spline->time[0] : 0;
194
  }
195
  return ret;
196
}
197
198
double
199
limnSplineMaxT(limnSpline *spline) {
200
  double ret;
201
  int N;
202
203
  ret = AIR_NAN;
204
  if (spline) {
205
    N = spline->ncpt->axis[2].size;
206
    if (spline->time) {
207
      ret = spline->time[N-1];
208
    } else {
209
      ret = spline->loop ? N : N-1;
210
    }
211
  }
212
  return ret;
213
}
214
215
void
216
limnSplineBCSet(limnSpline *spline, double B, double C) {
217
218
  if (spline) {
219
    spline->B = B;
220
    spline->C = C;
221
  }
222
}
223
224
limnSplineTypeSpec *
225
limnSplineTypeSpecParse(char *_str) {
226
  static const char me[]="limnSplineTypeSpecParse";
227
  limnSplineTypeSpec *spec;
228
  int type;
229
  double B, C;
230
  char *str, *col, *bcS;
231
  airArray *mop;
232
233
  if (!( _str && airStrlen(_str) )) {
234
    biffAddf(LIMN, "%s: got NULL or emptry string", me);
235
    return NULL;
236
  }
237
  mop = airMopNew();
238
  airMopAdd(mop, str=airStrdup(_str), airFree, airMopAlways);
239
  col = strchr(str, ':');
240
  if (col) {
241
    *col = 0;
242
    bcS = col+1;
243
  } else {
244
    bcS = NULL;
245
  }
246
  if (limnSplineTypeUnknown == (type = airEnumVal(limnSplineType, str))) {
247
    biffAddf(LIMN, "%s: couldn't parse \"%s\" as spline type", me, str);
248
    airMopError(mop); return NULL;
249
  }
250
251
  if (!( (limnSplineTypeBC == type) == !!bcS )) {
252
    biffAddf(LIMN, "%s: spline type %s %s, but %s a parameter string %s%s%s",
253
             me,
254
             (limnSplineTypeBC == type) ? "is" : "is not",
255
             airEnumStr(limnSplineType, limnSplineTypeBC),
256
             !!bcS ? "got unexpected" : "did not get",
257
             !!bcS ? "\"" : "",
258
             !!bcS ? bcS : "",
259
             !!bcS ? "\"" : "");
260
    airMopError(mop); return NULL;
261
  }
262
  if (limnSplineTypeBC == type) {
263
    if (2 != sscanf(bcS, "%lg,%lg", &B, &C)) {
264
      biffAddf(LIMN, "%s: couldn't parse \"B,C\" parameters from \"%s\"", me,
265
               bcS);
266
      airMopError(mop); return NULL;
267
    }
268
  }
269
  spec = (limnSplineTypeBC == type
270
          ? limnSplineTypeSpecNew(type, B, C)
271
          : limnSplineTypeSpecNew(type));
272
  if (!spec) {
273
    biffAddf(LIMN, "%s: limnSplineTypeSpec allocation failed", me);
274
    airMopError(mop); return NULL;
275
  }
276
277
  airMopOkay(mop);
278
  return spec;
279
}
280
281
limnSpline *
282
limnSplineParse(char *_str) {
283
  static const char me[]="limnSplineParse";
284
  char *str, *col, *fnameS, *infoS, *typeS, *tmpS;
285
  int info;
286
  limnSpline *spline;
287
  limnSplineTypeSpec *spec;
288
  Nrrd *ninA, *ninB;
289
  airArray *mop;
290
291
  if (!( _str && airStrlen(_str) )) {
292
    biffAddf(LIMN, "%s: got NULL or empty string", me);
293
    return NULL;
294
  }
295
  mop = airMopNew();
296
  airMopAdd(mop, str=airStrdup(_str), airFree, airMopAlways);
297
298
  /* find separation between filename and "<splineInfo>:<splineType>[:B,C]" */
299
  col = strchr(str, ':');
300
  if (!col) {
301
    biffAddf(LIMN, "%s: saw no colon separator (between nrrd filename and "
302
             "spline info) in \"%s\"", me, _str);
303
    airMopError(mop); return NULL;
304
  }
305
  fnameS = str;
306
  *col = 0;
307
  tmpS = col+1;
308
  airMopAdd(mop, ninA = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
309
  if (nrrdLoad(ninA, fnameS, NULL)) {
310
    biffMovef(LIMN, NRRD, "%s: couldn't read control point nrrd:\n", me);
311
    airMopError(mop); return NULL;
312
  }
313
314
  /* find separation between splineInfo and "<splineType>[:B,C]" */
315
  col = strchr(tmpS, ':');
316
  if (!col) {
317
    biffAddf(LIMN, "%s: saw no colon separator (between spline info "
318
             "and spline type) in \"%s\"", me, tmpS);
319
    airMopError(mop); return NULL;
320
  }
321
  infoS = tmpS;
322
  *col = 0;
323
  typeS = col+1;
324
  if (limnSplineInfoUnknown == (info = airEnumVal(limnSplineInfo, infoS))) {
325
    biffAddf(LIMN, "%s: couldn't parse \"%s\" as spline info", me, infoS);
326
    airMopError(mop); return NULL;
327
  }
328
329
  /* now parse <splineType>[:B,C] */
330
  if (!( spec = limnSplineTypeSpecParse(typeS) )) {
331
    biffAddf(LIMN, "%s: couldn't parse spline type in \"%s\":\n", me, typeS);
332
    airMopError(mop); return NULL;
333
  }
334
  if (limnSplineTypeTimeWarp == spec->type
335
      && limnSplineInfoScalar != info) {
336
    biffAddf(LIMN, "%s: can only time-warp %s info, not %s", me,
337
             airEnumStr(limnSplineInfo, limnSplineInfoScalar),
338
             airEnumStr(limnSplineInfo, info));
339
    airMopError(mop); return NULL;
340
  }
341
342
  airMopAdd(mop, ninB = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
343
  if (limnSplineNrrdCleverFix(ninB, ninA, info, spec->type)) {
344
    biffAddf(LIMN, "%s: couldn't reshape given nrrd:\n", me);
345
    airMopError(mop); return NULL;
346
  }
347
  if (!( spline = limnSplineNew(ninB, info, spec) )) {
348
    biffAddf(LIMN, "%s: couldn't create spline:\n", me);
349
    airMopError(mop); return NULL;
350
  }
351
352
  airMopOkay(mop);
353
  return spline;
354
}
355
356
/*
357
** the spline command-line spline type specification is of the form
358
** <splineType>[:B,C]
359
*/
360
int
361
_limnHestSplineTypeSpecParse(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
362
  static const char me[] = "_limnHestSplineTypeSpecParse";
363
  char *err2;
364
  limnSplineTypeSpec **specP;
365
366
  if (!(ptr && str && airStrlen(str))) {
367
    sprintf(err, "%s: got NULL pointer", me);
368
    return 1;
369
  }
370
  specP = (limnSplineTypeSpec **)ptr;
371
372
  if (!( *specP = limnSplineTypeSpecParse(str) )) {
373
    err2 = biffGetDone(LIMN);
374
    sprintf(err, "%s: couldn't parse \"%s\":\n", me, str);
375
    strncat(err, err2, AIR_STRLEN_HUGE-1-strlen(err));
376
    free(err2); return 1;
377
  }
378
379
  return 0;
380
}
381
382
383
hestCB
384
_limnHestSplineTypeSpec = {
385
  sizeof(limnSplineTypeSpec *),
386
  "spline type specification",
387
  _limnHestSplineTypeSpecParse,
388
  (airMopper)limnSplineTypeSpecNix
389
};
390
391
hestCB *
392
limnHestSplineTypeSpec = &_limnHestSplineTypeSpec;
393
394
/*
395
** the spline command-line specification is of the form
396
** <nrrdFileName>:<splineInfo>:<splineType>[:B,C]
397
*/
398
int
399
_limnHestSplineParse(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
400
  static const char me[] = "_limnHestSplineParse";
401
  char *err2;
402
  limnSpline **splineP;
403
404
  if (!(ptr && str)) {
405
    sprintf(err, "%s: got NULL pointer", me);
406
    return 1;
407
  }
408
  splineP = (limnSpline **)ptr;
409
  if (!airStrlen(str)) {
410
    /* got an empty string, which for now we take as an okay way
411
       to ask for NO spline */
412
    *splineP = NULL;
413
    return 0;
414
  }
415
416
  if (!( *splineP = limnSplineParse(str) )) {
417
    err2 = biffGetDone(LIMN);
418
    sprintf(err, "%s: couldn't parse \"%s\":\n", me, str);
419
    strncat(err, err2, AIR_STRLEN_HUGE-1-strlen(err));
420
    free(err2); return 1;
421
  }
422
423
  return 0;
424
}
425
426
427
hestCB
428
_limnHestSpline = {
429
  sizeof(limnSpline *),
430
  "spline specification",
431
  _limnHestSplineParse,
432
  (airMopper)limnSplineNix
433
};
434
435
hestCB *
436
limnHestSpline = &_limnHestSpline;