PageRenderTime 30ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/brlcad/tags/rel-7-0-4/src/tab/tabinterp.c

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