PageRenderTime 31ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/brlcad/tags/rel-7-14-6/src/tab/tabinterp.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 1238 lines | 890 code | 136 blank | 212 comment | 181 complexity | 57d20329e4822067f09198e3c1e2b33b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, Apache-2.0, AGPL-3.0, LGPL-3.0, GPL-3.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, 0BSD, BSD-3-Clause
  1. /* T A B I N T E R P . C
  2. * BRL-CAD
  3. *
  4. * Copyright (c) 1988-2009 United States Government as represented by
  5. * the U.S. Army Research Laboratory.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public License
  9. * version 2.1 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this file; see the file named COPYING for more
  18. * information.
  19. */
  20. /** @file tabinterp.c
  21. *
  22. * This program is the crucial middle step in the key-frame animation
  23. * software.
  24. *
  25. * First, one or more files, on different time scales, are read into
  26. * internal "channels", with FILE and RATE commands.
  27. *
  28. * Next, the TIMES command is given.
  29. *
  30. * Next, a section of those times is interpolated, and multi-channel
  31. * output is produced, on uniform time samples.
  32. *
  33. * This multi-channel output is fed to the next stage to generate
  34. * control scripts, etc.
  35. *
  36. */
  37. #include "common.h"
  38. #include <stdlib.h>
  39. #include <math.h>
  40. #include <string.h>
  41. #include "bio.h"
  42. #include "bu.h"
  43. #include "vmath.h"
  44. #include "bn.h"
  45. #include "raytrace.h"
  46. struct chan {
  47. /* INPUTS */
  48. int c_ilen; /* length of input array */
  49. char *c_itag; /* description of input source */
  50. fastf_t *c_itime; /* input time array */
  51. fastf_t *c_ival; /* input value array */
  52. /* OUTPUTS */
  53. fastf_t *c_oval; /* output value array */
  54. /* FLAGS */
  55. int c_interp; /* linear or spline? */
  56. #define INTERP_STEP 1
  57. #define INTERP_LINEAR 2
  58. #define INTERP_SPLINE 3
  59. #define INTERP_RATE 4
  60. #define INTERP_ACCEL 5
  61. #define INTERP_QUAT 6 /* first chan of 4 that define a quaternion */
  62. #define INTERP_QUAT2 7 /* an additional quaterion chan (2, 3, 4) */
  63. #define INTERP_NEXT 8 /* method to look forward/backward in time */
  64. int c_periodic; /* cyclic end conditions? */
  65. int c_sourcechan; /* index of source chan (QUAT, NEXT) */
  66. int c_offset; /* source offset (NEXT) */
  67. };
  68. extern int bu_optind;
  69. extern char *bu_optarg;
  70. int verbose = 1;
  71. int o_len; /* length of all output arrays */
  72. fastf_t *o_time; /* pointer to output time array */
  73. int fps; /* frames/sec of output */
  74. int nchans; /* number of chan[] elements in use */
  75. int max_chans; /* current size of chan[] array */
  76. struct chan *chan; /* ptr to array of chan structs */
  77. extern int cm_file();
  78. extern int cm_times();
  79. extern int cm_interp();
  80. extern int cm_idump();
  81. extern int cm_rate();
  82. extern int cm_accel();
  83. extern int cm_next();
  84. extern int cm_help();
  85. void linear_interpolate();
  86. void rate_interpolate();
  87. void accel_interpolate();
  88. void go();
  89. void output();
  90. void pr_ichan();
  91. void next_interpolate();
  92. void step_interpolate();
  93. void quat_interpolate();
  94. int get_args(int argc, char **argv);
  95. int create_chan( char *num, int len, char *itag );
  96. int chan_not_loaded_or_specified( int ch );
  97. int spline( struct chan *chp, fastf_t *times );
  98. struct command_tab cmdtab[] = {
  99. {"file", "filename chan_num(s)", "load channels from file",
  100. cm_file, 3, 999},
  101. {"times", "start stop fps", "specify time range and fps rate",
  102. cm_times, 4, 4},
  103. {"interp", "{step|linear|spline|cspline|quat} chan_num(s)", "set interpolation type",
  104. cm_interp, 3, 999},
  105. {"next", "dest_chan src_chan [+/- #nsamp]", "lookahead in time",
  106. cm_next, 3, 4},
  107. {"idump", "[chan_num(s)]", "dump input channel values",
  108. cm_idump, 1, 999},
  109. {"rate", "chan_num init_value incr_per_sec [comment]", "create rate based channel",
  110. cm_rate, 4, 5},
  111. {"accel", "chan_num init_value mult_per_sec [comment]", "create acceleration based channel",
  112. cm_accel, 4, 5},
  113. {"help", "", "print help message",
  114. cm_help, 1, 999},
  115. {(char *)0, (char *)0, (char *)0,
  116. 0, 0, 0} /* END */
  117. };
  118. /*
  119. * M A I N
  120. */
  121. int
  122. main( int argc, char **argv )
  123. {
  124. register char *buf;
  125. register int ret;
  126. get_args(argc, argv);
  127. /*
  128. * All the work happens in the functions
  129. * called by rt_do_cmd().
  130. * NOTE that the value of MAXWORDS in rt_do_cmd() limits
  131. * the maximum number of columns that a 'file' command can list.
  132. */
  133. while ( (buf = rt_read_cmd( stdin )) != (char *)0 ) {
  134. if (verbose) bu_log("cmd: %s\n", buf );
  135. ret = rt_do_cmd( 0, buf, cmdtab );
  136. bu_free( buf, "cmd buf" );
  137. if ( ret < 0 ) {
  138. if (verbose) bu_log("aborting\n");
  139. bu_exit(1, NULL);
  140. }
  141. }
  142. if (verbose) bu_log("performing interpolations\n");
  143. go();
  144. if (verbose) bu_log("writing output\n");
  145. output();
  146. bu_exit(0, NULL);
  147. }
  148. /*
  149. * XXX this really should go in librt/cmd.c as rt_help_cmd().
  150. */
  151. int
  152. cm_help( int argc, char **argv )
  153. {
  154. register struct command_tab *ctp;
  155. if ( argc <= 1 )
  156. {
  157. bu_log("The following commands are available:\n\n");
  158. for ( ctp = cmdtab; ctp->ct_cmd != (char *)0; ctp++ ) {
  159. bu_log("%s %s\n\t%s\n",
  160. ctp->ct_cmd, ctp->ct_parms,
  161. ctp->ct_comment );
  162. }
  163. return 0;
  164. }
  165. bu_log("Detailed help is not yet available.\n");
  166. return -1;
  167. }
  168. /*
  169. * C M _ F I L E
  170. */
  171. int
  172. cm_file( int argc, char **argv )
  173. {
  174. FILE *fp;
  175. char *file;
  176. char lbuf[512]; /* temporary label buffer */
  177. int *cnum;
  178. int i;
  179. int line;
  180. char **iwords;
  181. int nlines; /* number of lines in input file */
  182. int nwords; /* number of words on each input line */
  183. fastf_t *times;
  184. auto double d;
  185. int errors = 0;
  186. struct bu_vls buf; /* unlimited size input line buffer */
  187. file = argv[1];
  188. if ( (fp = fopen( file, "r" )) == NULL ) {
  189. perror( file );
  190. return(0);
  191. }
  192. /* First step, count number of lines in file */
  193. nlines = 0;
  194. {
  195. register int c;
  196. while ( (c = fgetc(fp)) != EOF ) {
  197. if ( c == '\n' )
  198. nlines++;
  199. }
  200. }
  201. rewind(fp);
  202. /* Intermediate dynamic memory */
  203. cnum = (int *)bu_malloc( argc * sizeof(int), "cnum[]");
  204. nwords = argc - 1;
  205. iwords = (char **)bu_malloc( (nwords+1) * sizeof(char *), "iwords[]" );
  206. bu_vls_init(&buf);
  207. /* Retained dynamic memory */
  208. times = (fastf_t *)bu_malloc( nlines * sizeof(fastf_t), "times");
  209. /* Now, create & allocate memory for each chan */
  210. for ( i = 1; i < nwords; i++ ) {
  211. /* See if this column is not wanted */
  212. if ( argv[i+1][0] == '-' ) {
  213. cnum[i] = -1;
  214. continue;
  215. }
  216. snprintf( lbuf, 512, "File '%s', Column %d", file, i );
  217. if ( (cnum[i] = create_chan( argv[i+1], nlines, lbuf )) < 0 ) {
  218. errors = 1;
  219. goto out;
  220. }
  221. /* Share array of times */
  222. chan[cnum[i]].c_itime = times;
  223. }
  224. for ( line=0; line < nlines; line++ ) {
  225. register char *bp;
  226. bu_vls_trunc( &buf, 0 );
  227. if ( bu_vls_gets( &buf, fp ) == -1 ) break;
  228. bp = bu_vls_addr(&buf);
  229. if ( bp[0] == '#' ) {
  230. line--;
  231. nlines--;
  232. for ( i = 1; i < nwords; i++ ) {
  233. if ( cnum[i] < 0 ) continue;
  234. chan[cnum[i]].c_ilen--;
  235. }
  236. continue;
  237. }
  238. i = bu_argv_from_string( iwords, nwords, bp );
  239. if ( i != nwords ) {
  240. bu_log("File '%s', Line %d: expected %d columns, got %d\n",
  241. file, line, nwords, i );
  242. while ( i < nwords ) {
  243. iwords[i++] = "0.123456789";
  244. errors++;
  245. }
  246. }
  247. /* Obtain the time from the first column */
  248. sscanf( iwords[0], "%lf", &d );
  249. times[line] = d;
  250. if ( line > 0 && times[line-1] > times[line] ) {
  251. bu_log("File '%s', Line %d: time sequence error %g > %g\n",
  252. file, line, times[line-1], times[line] );
  253. errors++;
  254. }
  255. /* Obtain the desired values from the remaining columns,
  256. * and assign them to the channels indicated in cnum[]
  257. */
  258. for ( i=1; i < nwords; i++ ) {
  259. if ( cnum[i] < 0 ) continue;
  260. if ( sscanf( iwords[i], "%lf", &d ) != 1 ) {
  261. bu_log("File '%s', Line %d: scanf failure on '%s'\n",
  262. file, line, iwords[i] );
  263. d = 0.0;
  264. errors++;
  265. }
  266. chan[cnum[i]].c_ival[line] = d;
  267. }
  268. }
  269. fclose(fp);
  270. /* Free intermediate dynamic memory */
  271. out:
  272. bu_free( (char *)cnum, "cnum[]");
  273. bu_free( (char *)iwords, "iwords[]");
  274. bu_vls_free(&buf);
  275. if (errors)
  276. return(-1); /* abort */
  277. return(0);
  278. }
  279. /*
  280. * C R E A T E _ C H A N
  281. */
  282. int
  283. create_chan( char *num, int len, char *itag )
  284. {
  285. int n;
  286. n = atoi(num);
  287. if ( n < 0 ) return(-1);
  288. if ( n >= max_chans ) {
  289. int prev = max_chans;
  290. if ( max_chans <= 0 ) {
  291. max_chans = 32;
  292. chan = (struct chan *)bu_calloc( 1,
  293. max_chans * sizeof(struct chan),
  294. "chan[]" );
  295. } else {
  296. while ( n >= max_chans )
  297. max_chans *= 2;
  298. if (verbose) bu_log("reallocating from %d to %d chans\n",
  299. prev, max_chans);
  300. chan = (struct chan *)bu_realloc( (char *)chan,
  301. max_chans * sizeof(struct chan),
  302. "chan[]" );
  303. memset((char *)(&chan[prev]), 0, (max_chans-prev)*sizeof(struct chan));
  304. }
  305. }
  306. /* Allocate and clear channels */
  307. while ( nchans <= n ) {
  308. if ( chan[nchans].c_ilen > 0 ) {
  309. bu_log("create_chan: internal error\n");
  310. return -1;
  311. } else {
  312. memset((char *)&chan[nchans++], 0, sizeof(struct chan));
  313. }
  314. }
  315. if (verbose) bu_log("chan %d: %s\n", n, itag );
  316. chan[n].c_ilen = len;
  317. chan[n].c_itag = bu_strdup( itag );
  318. chan[n].c_ival = (fastf_t *)bu_malloc( len * sizeof(fastf_t), "c_ival");
  319. return(n);
  320. }
  321. /*
  322. * C M _ I D U M P
  323. *
  324. * Dump the indicated input channels, or all, if none specified.
  325. */
  326. int
  327. cm_idump( int argc, char **argv )
  328. {
  329. register int ch;
  330. register int i;
  331. if ( argc <= 1 ) {
  332. for ( ch=0; ch < nchans; ch++ ) {
  333. pr_ichan( ch );
  334. }
  335. } else {
  336. for ( i = 1; i < argc; i++ ) {
  337. pr_ichan( atoi( argv[i] ) );
  338. }
  339. }
  340. return(0);
  341. }
  342. /*
  343. * P R _ I C H A N S
  344. *
  345. * Print input channel values.
  346. */
  347. void
  348. pr_ichan( int ch )
  349. {
  350. register struct chan *cp;
  351. register int i;
  352. if ( ch < 0 || ch >= nchans ) {
  353. bu_log("pr_ichan(%d) out of range\n", ch );
  354. return;
  355. }
  356. cp = &chan[ch];
  357. if ( cp->c_itag == (char *)0 ) cp->c_itag = "_no_file_";
  358. bu_log("--- Channel %d, ilen=%d (%s):\n",
  359. ch, cp->c_ilen, cp->c_itag );
  360. for ( i=0; i < cp->c_ilen; i++ ) {
  361. bu_log(" %g\t%g\n", cp->c_itime[i], cp->c_ival[i]);
  362. }
  363. }
  364. /*
  365. * O U T P U T
  366. */
  367. void
  368. output()
  369. {
  370. register int ch;
  371. register struct chan *cp;
  372. register int t;
  373. if ( !o_time ) {
  374. bu_log("times command not given, aborting\n");
  375. return;
  376. }
  377. for ( t=0; t < o_len; t++ ) {
  378. printf("%g", o_time[t]);
  379. for ( ch=0; ch < nchans; ch++ ) {
  380. cp = &chan[ch];
  381. if ( cp->c_ilen <= 0 ) {
  382. printf("\t.");
  383. continue;
  384. }
  385. printf("\t%g", cp->c_oval[t] );
  386. }
  387. printf("\n");
  388. }
  389. }
  390. /*
  391. * C M _ T I M E S
  392. */
  393. int
  394. cm_times( int argc, char **argv )
  395. {
  396. double a, b;
  397. register int i;
  398. a = atof(argv[1]);
  399. b = atof(argv[2]);
  400. fps = atoi(argv[3]);
  401. if ( a >= b ) {
  402. bu_log("times: %g >= %g\n", a, b );
  403. return(0);
  404. }
  405. if ( o_len > 0 ) {
  406. bu_log("times: already specified\n");
  407. return(0); /* ignore */
  408. }
  409. o_len = ((b-a) * fps) + 0.999;
  410. o_len++; /* one final step to reach endpoint */
  411. o_time = (fastf_t *)bu_malloc( o_len * sizeof(fastf_t), "o_time[]");
  412. /*
  413. * Don't use an incremental algorithm, to avoid acrueing error
  414. */
  415. for ( i=0; i<o_len; i++ )
  416. o_time[i] = a + ((double)i)/fps;
  417. return(0);
  418. }
  419. /*
  420. * C M _ I N T E R P
  421. */
  422. int
  423. cm_interp( int argc, char **argv )
  424. {
  425. int interp = 0;
  426. int periodic = 0;
  427. int i;
  428. int ch;
  429. struct chan *chp;
  430. if ( strcmp( argv[1], "step" ) == 0 ) {
  431. interp = INTERP_STEP;
  432. periodic = 0;
  433. } else if ( strcmp( argv[1], "cstep" ) == 0 ) {
  434. interp = INTERP_STEP;
  435. periodic = 1;
  436. } else if ( strcmp( argv[1], "linear" ) == 0 ) {
  437. interp = INTERP_LINEAR;
  438. periodic = 0;
  439. } else if ( strcmp( argv[1], "clinear" ) == 0 ) {
  440. interp = INTERP_LINEAR;
  441. periodic = 1;
  442. } else if ( strcmp( argv[1], "spline" ) == 0 ) {
  443. interp = INTERP_SPLINE;
  444. periodic = 0;
  445. } else if ( strcmp( argv[1], "cspline" ) == 0 ) {
  446. interp = INTERP_SPLINE;
  447. periodic = 1;
  448. } else if ( strcmp( argv[1], "quat" ) == 0 ) {
  449. interp = INTERP_QUAT;
  450. periodic = 0;
  451. } else {
  452. bu_log("interpolation type '%s' unknown\n", argv[1] );
  453. interp = INTERP_LINEAR;
  454. }
  455. for ( i = 2; i < argc; i++ ) {
  456. ch = atoi( argv[i] );
  457. chp = &chan[ch];
  458. if ( chan_not_loaded_or_specified(ch) ) continue;
  459. chp->c_interp = interp;
  460. chp->c_periodic = periodic;
  461. if ( interp == INTERP_QUAT ) {
  462. int j;
  463. for ( j = 1; j < 4; j++ ) {
  464. chp = &chan[ch+j];
  465. if ( chan_not_loaded_or_specified(ch+j) ) continue;
  466. chp->c_interp = INTERP_QUAT2;
  467. chp->c_periodic = periodic;
  468. chp->c_sourcechan = ch;
  469. }
  470. }
  471. }
  472. return(0);
  473. }
  474. /*
  475. * G O
  476. *
  477. * Perform the requested interpolation on each channel
  478. */
  479. void
  480. go()
  481. {
  482. int ch;
  483. struct chan *chp;
  484. fastf_t *times;
  485. register int t;
  486. if ( !o_time ) {
  487. bu_log("times command not given\n");
  488. return;
  489. }
  490. times = (fastf_t *)bu_malloc( o_len*sizeof(fastf_t), "periodic times");
  491. /* First, get memory for all output channels */
  492. for ( ch=0; ch < nchans; ch++ ) {
  493. chp = &chan[ch];
  494. if ( chp->c_ilen <= 0 )
  495. continue;
  496. /* Allocate memory for all the output values */
  497. chan[ch].c_oval = (fastf_t *)bu_malloc(
  498. o_len * sizeof(fastf_t), "c_oval[]");
  499. }
  500. /* Interpolate values for all "interp" channels */
  501. for ( ch=0; ch < nchans; ch++ ) {
  502. chp = &chan[ch];
  503. if ( chp->c_ilen <= 0 )
  504. continue;
  505. if ( chp->c_interp == INTERP_NEXT ) continue;
  506. /* As a service to interpolators, if this is a periodic
  507. * interpolation, build the mapped time array.
  508. */
  509. if ( chp->c_periodic ) {
  510. for ( t=0; t < o_len; t++ ) {
  511. register double cur_t;
  512. cur_t = o_time[t];
  513. while ( cur_t > chp->c_itime[chp->c_ilen-1] ) {
  514. cur_t -= (chp->c_itime[chp->c_ilen-1] -
  515. chp->c_itime[0] );
  516. }
  517. while ( cur_t < chp->c_itime[0] ) {
  518. cur_t += (chp->c_itime[chp->c_ilen-1] -
  519. chp->c_itime[0] );
  520. }
  521. times[t] = cur_t;
  522. }
  523. } else {
  524. for ( t=0; t < o_len; t++ ) {
  525. times[t] = o_time[t];
  526. }
  527. }
  528. again:
  529. switch ( chp->c_interp ) {
  530. default:
  531. bu_log("channel %d: unknown interpolation type %d\n", ch, chp->c_interp);
  532. break;
  533. case INTERP_LINEAR:
  534. linear_interpolate( chp, times );
  535. break;
  536. case INTERP_STEP:
  537. step_interpolate( chp, times );
  538. break;
  539. case INTERP_SPLINE:
  540. if ( spline( chp, times ) <= 0 ) {
  541. bu_log("spline failure, switching to linear\n");
  542. chp->c_interp = INTERP_LINEAR;
  543. goto again;
  544. }
  545. break;
  546. case INTERP_RATE:
  547. rate_interpolate( chp, times );
  548. break;
  549. case INTERP_ACCEL:
  550. accel_interpolate( chp, times );
  551. break;
  552. case INTERP_QUAT:
  553. quat_interpolate( chp, &chan[ch+1], &chan[ch+2], &chan[ch+3], times );
  554. break;
  555. case INTERP_QUAT2:
  556. /* Don't touch these here, handled above */
  557. continue;
  558. }
  559. }
  560. /* Copy out values for all "next" channels */
  561. for ( ch=0; ch < nchans; ch++ ) {
  562. chp = &chan[ch];
  563. if ( chp->c_ilen <= 0 )
  564. continue;
  565. if ( chp->c_interp != INTERP_NEXT ) continue;
  566. next_interpolate( chp );
  567. }
  568. bu_free( (char *)times, "loc times");
  569. }
  570. /*
  571. * N E X T _ I N T E R P O L A T E
  572. */
  573. void
  574. next_interpolate( struct chan *chp )
  575. {
  576. register int t; /* output time index */
  577. register int i; /* input time index */
  578. register struct chan *ip;
  579. ip = &chan[chp->c_sourcechan];
  580. for ( t=0; t<o_len; t++ ) {
  581. i = t + chp->c_offset;
  582. if ( i <= 0 ) {
  583. chp->c_oval[t] = ip->c_oval[0];
  584. continue;
  585. }
  586. if ( i >= o_len ) {
  587. chp->c_oval[t] = ip->c_oval[o_len-1];
  588. continue;
  589. }
  590. chp->c_oval[t] = ip->c_oval[i];
  591. }
  592. }
  593. /*
  594. * S T E P _ I N T E R P O L A T E
  595. *
  596. * Simply select the value at the beinning of the interval.
  597. * This allows parameters to take instantaneous jumps in value
  598. * at specified times.
  599. *
  600. * This routine takes advantage of (and depends on) the fact that
  601. * the input and output is sorted in increasing time values.
  602. */
  603. void
  604. step_interpolate( struct chan *chp, fastf_t *times )
  605. {
  606. register int t; /* output time index */
  607. register int i; /* input time index */
  608. i = 0;
  609. for ( t=0; t<o_len; t++ ) {
  610. /* Check for below initial time */
  611. if ( times[t] < chp->c_itime[0] ) {
  612. chp->c_oval[t] = chp->c_ival[0];
  613. continue;
  614. }
  615. /* Find time range in input data. */
  616. while ( i < chp->c_ilen-1 ) {
  617. if ( times[t] >= chp->c_itime[i] &&
  618. times[t] < chp->c_itime[i+1] )
  619. break;
  620. i++;
  621. }
  622. /* Check for above final time */
  623. if ( i >= chp->c_ilen-1 ) {
  624. chp->c_oval[t] = chp->c_ival[chp->c_ilen-1];
  625. continue;
  626. }
  627. /* Select value at beginning of interval */
  628. chp->c_oval[t] = chp->c_ival[i];
  629. }
  630. }
  631. /*
  632. * L I N E A R _ I N T E R P O L A T E
  633. *
  634. * This routine takes advantage of (and depends on) the fact that
  635. * the input and output arrays are sorted in increasing time values.
  636. */
  637. void
  638. linear_interpolate( struct chan *chp, fastf_t *times )
  639. {
  640. register int t; /* output time index */
  641. register int i; /* input time index */
  642. if ( chp->c_ilen < 2 ) {
  643. bu_log("lienar_interpolate: need at least 2 points\n");
  644. return;
  645. }
  646. i = 0;
  647. for ( t=0; t<o_len; t++ ) {
  648. /* Check for below initial time */
  649. if ( times[t] < chp->c_itime[0] ) {
  650. chp->c_oval[t] = chp->c_ival[0];
  651. continue;
  652. }
  653. /* Find time range in input data. */
  654. while ( i < chp->c_ilen-1 ) {
  655. if ( times[t] >= chp->c_itime[i] &&
  656. times[t] < chp->c_itime[i+1] )
  657. break;
  658. i++;
  659. }
  660. /* Check for above final time */
  661. if ( i >= chp->c_ilen-1 ) {
  662. chp->c_oval[t] = chp->c_ival[chp->c_ilen-1];
  663. continue;
  664. }
  665. /* Perform actual interpolation */
  666. chp->c_oval[t] = chp->c_ival[i] +
  667. (times[t] - chp->c_itime[i]) *
  668. (chp->c_ival[i+1] - chp->c_ival[i]) /
  669. (chp->c_itime[i+1] - chp->c_itime[i]);
  670. }
  671. }
  672. /*
  673. * R A T E _ I N T E R P O L A T E
  674. *
  675. * The one (and only) input value is interpreted as rate, in
  676. * unspecified units per second.
  677. * This is really just a hack to allow multiplying the time by a constant.
  678. */
  679. void
  680. rate_interpolate( struct chan *chp, fastf_t *times )
  681. {
  682. register int t; /* output time index */
  683. register double ival;
  684. register double rate;
  685. if ( chp->c_ilen != 2 ) {
  686. bu_log("rate_interpolate: only 2 points (ival & rate) may be specified\n");
  687. return;
  688. }
  689. ival = chp->c_ival[0];
  690. rate = chp->c_ival[1];
  691. for ( t=0; t < o_len; t++ ) {
  692. chp->c_oval[t] = ival + rate * times[t];
  693. }
  694. }
  695. /*
  696. * A C C E L _ I N T E R P O L A T E
  697. *
  698. */
  699. void
  700. accel_interpolate( struct chan *chp, fastf_t *times )
  701. {
  702. register int t; /* output time index */
  703. double ival;
  704. double mul;
  705. register double scale;
  706. if ( chp->c_ilen != 2 ) {
  707. bu_log("accel_interpolate: only 2 points (ival & mul) may be specified\n");
  708. return;
  709. }
  710. ival = chp->c_ival[0];
  711. mul = chp->c_ival[1];
  712. /* scale ^ fps = mul */
  713. scale = exp( log(mul) / fps );
  714. chp->c_oval[0] = ival;
  715. for ( t=1; t < o_len; t++ ) {
  716. chp->c_oval[t] = chp->c_oval[t-1] * scale;
  717. }
  718. }
  719. /*
  720. * S P L I N E
  721. *
  722. * Fit an interpolating spline to the data points given.
  723. * Time in the independent (x) variable, and the single channel
  724. * of data values is the dependent (y) variable.
  725. *
  726. * Returns -
  727. * 0 bad
  728. * 1 OK
  729. */
  730. int
  731. spline( register struct chan *chp, fastf_t *times )
  732. {
  733. double d, s;
  734. double u = 0;
  735. double v = 0;
  736. double hi; /* horiz interval i-1 to i */
  737. double hi1; /* horiz interval i to i+1 */
  738. double D2yi; /* D2 of y[i] */
  739. double D2yi1; /* D2 of y[i+1] */
  740. double D2yn1; /* D2 of y[n-1] (last point) */
  741. double a;
  742. int end;
  743. double corr;
  744. double konst = 0.0; /* derriv. at endpts, non-periodic */
  745. double *diag = (double *)0;
  746. double *rrr = (double *)0;
  747. register int i;
  748. register int t;
  749. if (chp->c_ilen<3) {
  750. bu_log("spline(%s): need at least 3 points\n", chp->c_itag);
  751. goto bad;
  752. }
  753. /* First, as a quick hack, do linear interpolation to fill in
  754. * values off the endpoints, in non-periodic case
  755. */
  756. if ( chp->c_periodic == 0 )
  757. linear_interpolate( chp, times );
  758. if ( chp->c_periodic && chp->c_ival[0] != chp->c_ival[chp->c_ilen-1] ) {
  759. bu_log("spline(%s): endpoints don't match, replacing final data value\n", chp->c_itag);
  760. chp->c_ival[chp->c_ilen-1] = chp->c_ival[0];
  761. }
  762. i = (chp->c_ilen+1)*sizeof(double);
  763. diag = (double *)bu_malloc((unsigned)i, "diag");
  764. rrr = (double *)bu_malloc((unsigned)i, "rrr");
  765. if ( !rrr || !diag ) {
  766. bu_log("spline: malloc failure\n");
  767. goto bad;
  768. }
  769. if (chp->c_periodic) konst = 0;
  770. d = 1;
  771. rrr[0] = 0;
  772. s = chp->c_periodic?-1:0;
  773. /* triangularize */
  774. for ( i=0; ++i < chp->c_ilen - !chp->c_periodic; ) {
  775. double rhs;
  776. hi = chp->c_itime[i]-chp->c_itime[i-1];
  777. hi1 = (i==chp->c_ilen-1) ?
  778. chp->c_itime[1] - chp->c_itime[0] :
  779. chp->c_itime[i+1] - chp->c_itime[i];
  780. if (hi1*hi<=0) {
  781. bu_log(
  782. "spline: Horiz. interval changed sign at i=%d, time=%g\n",
  783. i, chp->c_itime[i]);
  784. goto bad;
  785. }
  786. if ( i <= 1 ) {
  787. u = v = 0.0; /* First time through */
  788. } else {
  789. u = u - s * s / d;
  790. v = v - s * rrr[i-1] / d;
  791. }
  792. rhs = (i==chp->c_ilen-1) ?
  793. (chp->c_ival[1] - chp->c_ival[0]) /
  794. (chp->c_itime[1] - chp->c_itime[0]) :
  795. (chp->c_ival[i+1] - chp->c_ival[i]) /
  796. (chp->c_itime[i+1] - chp->c_itime[i]);
  797. rhs = 6 * ( rhs -
  798. ( (chp->c_ival[i] - chp->c_ival[i-1]) /
  799. (chp->c_itime[i] - chp->c_itime[i-1]) ) );
  800. rrr[i] = rhs - hi * rrr[i-1] / d;
  801. s = -hi*s/d;
  802. a = 2*(hi+hi1);
  803. if (i==1) a += konst*hi;
  804. if (i==chp->c_ilen-2) a += konst*hi1;
  805. diag[i] = d = i==1? a:
  806. a - hi*hi/d;
  807. }
  808. D2yi = D2yn1 = 0;
  809. /* back substitute */
  810. for ( i = chp->c_ilen - !chp->c_periodic; --i >= 0; ) {
  811. end = i==chp->c_ilen-1;
  812. /* hi1 is range of time covered in this interval */
  813. hi1 = end ? chp->c_itime[1] - chp->c_itime[0]:
  814. chp->c_itime[i+1] - chp->c_itime[i];
  815. D2yi1 = D2yi;
  816. if (i>0) {
  817. hi = chp->c_itime[i]-chp->c_itime[i-1];
  818. corr = end ? 2*s+u : 0.0;
  819. D2yi = (end*v+rrr[i]-hi1*D2yi1-s*D2yn1)/
  820. (diag[i]+corr);
  821. if (end) D2yn1 = D2yi;
  822. if (i>1) {
  823. a = 2*(hi+hi1);
  824. if (i==1) a += konst*hi;
  825. if (i==chp->c_ilen-2) a += konst*hi1;
  826. d = diag[i-1];
  827. s = -s*d/hi;
  828. }
  829. }
  830. else D2yi = D2yn1;
  831. if (!chp->c_periodic) {
  832. if (i==0) D2yi = konst*D2yi1;
  833. if (i==chp->c_ilen-2) D2yi1 = konst*D2yi;
  834. }
  835. if (end) continue;
  836. /* Sweep downward in times[], looking for times in this span */
  837. for ( t=o_len-1; t>=0; t-- ) {
  838. register double x0; /* fraction from [i+0] */
  839. register double x1; /* fraction from [i+1] */
  840. register double yy;
  841. register double cur_t;
  842. cur_t = times[t];
  843. if ( cur_t > chp->c_itime[i+1] )
  844. continue;
  845. if ( cur_t < chp->c_itime[i] )
  846. continue;
  847. x1 = (cur_t - chp->c_itime[i]) /
  848. (chp->c_itime[i+1] - chp->c_itime[i]);
  849. x0 = 1 - x1;
  850. /* Linear interpolation, with correction */
  851. yy = D2yi * (x0 - x0*x0*x0) + D2yi1 * (x1 - x1*x1*x1);
  852. yy = chp->c_ival[i] * x0 + chp->c_ival[i+1] * x1 -
  853. hi1 * hi1 * yy / 6;
  854. chp->c_oval[t] = yy;
  855. }
  856. }
  857. bu_free( (char *)diag, "diag");
  858. bu_free( (char *)rrr, "rrr" );
  859. return(1);
  860. bad:
  861. if (diag) bu_free( (char *)diag, "diag");
  862. if (rrr) bu_free( (char *)rrr, "rrr" );
  863. return(0);
  864. }
  865. /*
  866. * C M _ R A T E
  867. *
  868. * Just to communiate with the "interpolator", use two input values.
  869. * First is initial value, second is change PER SECOND
  870. * Input time values are meaningless.
  871. */
  872. int
  873. cm_rate( int argc, char **argv )
  874. {
  875. register struct chan *chp;
  876. int ch;
  877. int nvals = 2;
  878. ch = create_chan( argv[1], nvals, argc>4?argv[4]:"rate chan" );
  879. chp = &chan[ch];
  880. chp->c_interp = INTERP_RATE;
  881. chp->c_periodic = 0;
  882. chp->c_itime = (fastf_t *)bu_malloc( nvals * sizeof(fastf_t), "rate times");
  883. chp->c_itime[0] = chp->c_itime[1] = 0;
  884. chp->c_ival[0] = atof(argv[2]);
  885. chp->c_ival[1] = atof(argv[3]);
  886. return(0);
  887. }
  888. /*
  889. * C M _ A C C E L
  890. *
  891. * Just to communiate with the "interpolator", use two input values.
  892. * First is initial value, second is change PER SECOND
  893. * Input time values are meaningless.
  894. */
  895. int
  896. cm_accel( int argc, char **argv )
  897. {
  898. register struct chan *chp;
  899. int ch;
  900. int nvals = 2;
  901. ch = create_chan( argv[1], nvals, argc>4?argv[4]:"accel chan" );
  902. chp = &chan[ch];
  903. chp->c_interp = INTERP_ACCEL;
  904. chp->c_periodic = 0;
  905. chp->c_itime = (fastf_t *)bu_malloc( nvals * sizeof(fastf_t), "accel times");
  906. chp->c_itime[0] = chp->c_itime[1] = 0;
  907. chp->c_ival[0] = atof(argv[2]);
  908. chp->c_ival[1] = atof(argv[3]);
  909. return(0);
  910. }
  911. /*
  912. * Q U A T _ I N T E R P O L A T E
  913. *
  914. * Do linear interpolation for first and last span.
  915. * Use Bezier interpolation for all the rest.
  916. *
  917. * This routine depends on the four input channels having identical
  918. * time stamps, because only the "x" input times are used.
  919. */
  920. void
  921. quat_interpolate( struct chan *x, struct chan *y, struct chan *z, struct chan *w, fastf_t *times )
  922. {
  923. register int t; /* output time index */
  924. register int i; /* input time index */
  925. #define QIGET(_q, _it) QSET( (_q), x->c_ival[(_it)], y->c_ival[(_it)], z->c_ival[(_it)], w->c_ival[(_it)] );
  926. #define QPUT(_q) { x->c_oval[t] = (_q)[X]; y->c_oval[t] = (_q)[Y]; \
  927. z->c_oval[t] = (_q)[Z]; w->c_oval[t] = (_q)[W]; }
  928. i = 0;
  929. for ( t=0; t<o_len; t++ ) {
  930. register fastf_t now = times[t];
  931. /* Check for below initial time */
  932. if ( now <= x->c_itime[0] ) {
  933. quat_t q1;
  934. QIGET( q1, 0 );
  935. QUNITIZE( q1 );
  936. QPUT( q1 );
  937. continue;
  938. }
  939. /* Find time range in input data. */
  940. while ( i < x->c_ilen-1 ) {
  941. if ( now >= x->c_itime[i] &&
  942. now < x->c_itime[i+1] )
  943. break;
  944. i++;
  945. }
  946. /* Check for above final time */
  947. if ( i >= x->c_ilen-1 ) {
  948. quat_t q1;
  949. i = x->c_ilen-1;
  950. QIGET( q1, i );
  951. QUNITIZE( q1 );
  952. QPUT( q1 );
  953. continue;
  954. }
  955. /* Check for being in first or last time span */
  956. if ( i == 0 || i >= x->c_ilen-2 )
  957. {
  958. fastf_t f;
  959. quat_t qout, q1, q2, q3, qtemp1, qtemp2, qtemp3;
  960. f = (now - x->c_itime[i]) /
  961. (x->c_itime[i+1] - x->c_itime[i]);
  962. if (i==0)
  963. {
  964. QIGET( q1, i );
  965. QIGET( q2, i+1 );
  966. QIGET( q3, i+2);
  967. QUNITIZE( q1 );
  968. QUNITIZE( q2 );
  969. QUNITIZE( q3 );
  970. quat_make_nearest( q2, q1 );
  971. quat_make_nearest( q3, q2 );
  972. }
  973. else
  974. {
  975. QIGET( q1, i+1 );
  976. QIGET( q2, i );
  977. QIGET( q3, i-1 );
  978. f = 1.0 - f;
  979. QUNITIZE( q1 );
  980. QUNITIZE( q2 );
  981. QUNITIZE( q3 );
  982. quat_make_nearest( q2, q3 );
  983. quat_make_nearest( q1, q2 );
  984. }
  985. /* find middle control point */
  986. quat_slerp( qtemp1, q3, q2, 2.0 );
  987. quat_slerp( qtemp2, qtemp1, q1, 0.5 );
  988. quat_slerp( qtemp3, q2, qtemp2, 0.33333 );
  989. /* do 3-point bezier interpolation */
  990. quat_slerp( qtemp1, q1, qtemp3, f );
  991. quat_slerp( qtemp2, qtemp3, q2, f );
  992. quat_slerp( qout, qtemp1, qtemp2, f );
  993. QPUT( qout );
  994. continue;
  995. }
  996. /* In an intermediate time span */
  997. {
  998. fastf_t f;
  999. quat_t qout, q1, q2, q3, q4, qa, qb, qtemp1, qtemp2;
  1000. f = (now - x->c_itime[i]) /
  1001. (x->c_itime[i+1] - x->c_itime[i]);
  1002. QIGET( q1, i-1 );
  1003. QIGET( q2, i );
  1004. QIGET( q3, i+1 );
  1005. QIGET( q4, i+2 );
  1006. QUNITIZE( q1 );
  1007. QUNITIZE( q2 );
  1008. QUNITIZE( q3 );
  1009. QUNITIZE( q4 );
  1010. quat_make_nearest( q2, q1 );
  1011. quat_make_nearest( q3, q2 );
  1012. quat_make_nearest( q4, q3 );
  1013. /* find two middle control points */
  1014. quat_slerp( qtemp1, q1, q2, 2.0 );
  1015. quat_slerp( qtemp2, qtemp1, q3, 0.5 );
  1016. quat_slerp( qa, q2, qtemp2, 0.333333 );
  1017. quat_slerp( qtemp1, q4, q3, 2.0 );
  1018. quat_slerp( qtemp2, qtemp1, q2, 0.5 );
  1019. quat_slerp( qb, q3, qtemp2, 0.333333 );
  1020. quat_sberp( qout, q2, qa, qb, q3, f );
  1021. QPUT( qout );
  1022. }
  1023. }
  1024. }
  1025. int
  1026. cm_next( int argc, char **argv )
  1027. {
  1028. int ochan, ichan;
  1029. int offset = 1;
  1030. char buf[128];
  1031. ochan = atoi(argv[1]);
  1032. ichan = atoi(argv[2]);
  1033. if ( argc > 3 ) offset = atoi(argv[3]);
  1034. /* If input channel not loaded, or not interpolated, error */
  1035. if ( chan[ichan].c_ilen <= 0 || chan[ichan].c_interp <= 0 ) {
  1036. bu_log("ERROR next: ichan %d not loaded yet\n");
  1037. return 0;
  1038. }
  1039. /* If output channel is loaded, error */
  1040. if ( chan[ochan].c_ilen > 0 ) {
  1041. bu_log("ERROR next: ochan %d previous loaded\n");
  1042. return 0;
  1043. }
  1044. sprintf(buf, "next: value of chan %d [%d]", ichan, offset);
  1045. if ( create_chan( argv[1], chan[ichan].c_ilen, buf ) < 0 ) {
  1046. bu_log("ERROR next: uanble to create output channel\n");
  1047. return 0;
  1048. }
  1049. /* c_ilen, c_itag, c_ival are now initialized */
  1050. chan[ochan].c_interp = INTERP_NEXT;
  1051. chan[ochan].c_sourcechan = ichan;
  1052. chan[ochan].c_offset = offset;
  1053. chan[ochan].c_periodic = 0;
  1054. chan[ochan].c_itime = chan[ichan].c_itime; /* share time array */
  1055. /* c_ival[] will not be loaded with anything */
  1056. return 0;
  1057. }
  1058. /*
  1059. * Returns -
  1060. * -1 on error
  1061. * 0 if data loaded, and interpolator not yet set.
  1062. * 1 if no data, or interpolator already set (message printed)
  1063. */
  1064. int
  1065. chan_not_loaded_or_specified( int ch )
  1066. {
  1067. if ( ch < 0 || ch >= nchans ) return -1;
  1068. if ( chan[ch].c_ilen <= 0 ) {
  1069. bu_log("error: attempt to set interpolation type on unallocated channel %d\n", ch);
  1070. return 1;
  1071. }
  1072. if ( chan[ch].c_interp > 0 ) {
  1073. bu_log("error: attempt to modify channel %d which already has interpolation type set\n", ch);
  1074. return 1;
  1075. }
  1076. return 0;
  1077. }
  1078. #define OPT_STR "q"
  1079. int get_args(int argc, char **argv)
  1080. {
  1081. int c;
  1082. while ( (c=bu_getopt(argc, argv, OPT_STR)) != EOF) {
  1083. switch (c) {
  1084. case 'q':
  1085. verbose = 0;
  1086. break;
  1087. default:
  1088. fprintf(stderr, "Unknown option: -%c\n", c);
  1089. return(0);
  1090. }
  1091. }
  1092. return(1);
  1093. }
  1094. /*
  1095. * Local Variables:
  1096. * mode: C
  1097. * tab-width: 8
  1098. * indent-tabs-mode: t
  1099. * c-file-style: "stroustrup"
  1100. * End:
  1101. * ex: shiftwidth=4 tabstop=8
  1102. */