tabdata.c

Go to the documentation of this file.
00001 /*                       T A B D A T A . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup anim */
00023 /*@{*/
00024 /** @file tabdata.c
00025  * @brief
00026  *  Routines for processing tables (curves) of data with one independent
00027  *  parameter which is common to many sets of dependent data values.
00028  *
00029  *  Operates on bn_table (independent var) and
00030  *  bn_tabdata (dependent variable) structures.
00031  *
00032  *  One application is for storing spectral curves, see spectrum.c
00033  *
00034  *  @author
00035  *      Michael John Muuss
00036  *
00037  *  @par Source
00038  *      The U. S. Army Research Laboratory
00039  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00040  *
00041  *
00042  *  @par Inspired by -
00043  *      Roy Hall and his book "Illumination and Color in Computer
00044  *@n    Generated Imagery", Springer Verlag, New York, 1989.
00045  *@n    ISBN 0-387-96774-5
00046  *
00047  *  With thanks to Russ Moulton Jr, EOSoft Inc. for his "rad.c" module.
00048  */
00049 /*@}*/
00050 
00051 #ifndef lint
00052 static const char RCStabdata[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/tabdata.c,v 14.11 2006/09/05 04:19:55 lbutler Exp $ (ARL)";
00053 #endif
00054 
00055 #include "common.h"
00056 
00057 
00058 #include <stdio.h>
00059 #if HAVE_UNISTD_H
00060 #include <unistd.h>
00061 #endif
00062 #include <math.h>
00063 #include <fcntl.h>
00064 #ifdef HAVE_STRING_H
00065 #include <string.h>
00066 #else
00067 #include <strings.h>
00068 #endif
00069 
00070 #include "machine.h"
00071 #include "vmath.h"
00072 #include "bu.h"
00073 #include "bn.h"
00074 
00075 /*
00076  *                      B N _ T A B L E _ F R E E
00077  */
00078 void
00079 bn_table_free(struct bn_table *tabp)
00080 {
00081         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_free(x%x)\n", tabp);
00082         BN_CK_TABLE(tabp);
00083 
00084         tabp->nx = 0;                   /* sanity */
00085         bu_free( tabp, "struct bn_table");
00086 }
00087 
00088 /*
00089  *                      B N _ T A B D A T A _ F R E E
00090  */
00091 void
00092 bn_tabdata_free(struct bn_tabdata *data)
00093 {
00094         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_free(x%x)\n", data);
00095 
00096         BN_CK_TABDATA(data);
00097         BN_CK_TABLE(data->table);
00098 
00099         data->ny = 0;                   /* sanity */
00100         data->table = NULL;             /* sanity */
00101         bu_free( data, "struct bn_tabdata" );
00102 }
00103 
00104 /*
00105  *                      B N _ C K _ T A B L E
00106  */
00107 void
00108 bn_ck_table(const struct bn_table *tabp)
00109 {
00110         register int    i;
00111 
00112         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_ck_table(x%x)\n", tabp);
00113 
00114         BN_CK_TABLE(tabp);
00115 
00116         if( tabp->nx < 2 ) bu_bomb("bn_ck_table() less than 2 wavelengths\n");
00117 
00118         for( i=0; i < tabp->nx; i++ )  {
00119                 if( tabp->x[i] >= tabp->x[i+1] )
00120                         bu_bomb("bn_ck_table() wavelengths not in strictly ascending order\n");
00121         }
00122 }
00123 
00124 /*
00125  *                      B N _ T A B L E _ M A K E _ U N I F O R M
00126  *@brief
00127  *  Set up an independent "table margin" from 'first' to 'last',
00128  *  inclusive, using 'num' uniformly spaced samples.  Num >= 1.
00129  */
00130 struct bn_table *
00131 bn_table_make_uniform(int num, double first, double last)
00132 {
00133         struct bn_table *tabp;
00134         fastf_t                 *fp;
00135         fastf_t                 delta;
00136         int                     j;
00137 
00138         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_make_uniform( num=%d, %g, %g )\n", num, first, last );
00139 
00140         if( first >= last )  bu_bomb("bn_table_make_uniform() first >= last\n");
00141 
00142         BN_GET_TABLE( tabp, num );
00143 
00144         delta = (last - first) / (double)num;
00145 
00146         fp = &tabp->x[0];
00147         for( j = num; j > 0; j-- )  {
00148                 *fp++ = first;
00149                 first += delta;
00150         }
00151         tabp->x[num] = last;
00152 
00153         return( tabp );
00154 }
00155 
00156 /*
00157  *                      B N _ T A B D A T A _ A D D
00158  *@brief
00159  *  Sum the values from two data tables.
00160  */
00161 void
00162 bn_tabdata_add(struct bn_tabdata *out, const struct bn_tabdata *in1, const struct bn_tabdata *in2)
00163 {
00164         register int            j;
00165         register fastf_t        *op;
00166         register const fastf_t  *i1, *i2;
00167 
00168         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_add(x%x, x%x, x%x)\n", out, in1, in2);
00169 
00170         BN_CK_TABDATA( out );
00171         BN_CK_TABDATA( in1 );
00172         BN_CK_TABDATA( in2 );
00173 
00174         if( in1->table != in2->table || in1->table != out->table )
00175                 bu_bomb("bn_tabdata_add(): samples drawn from different tables\n");
00176         if( in1->ny != in2->ny || in1->ny != out->ny )
00177                 bu_bomb("bn_tabdata_add(): different tabdata lengths?\n");
00178 
00179         op = out->y;
00180         i1 = in1->y;
00181         i2 = in2->y;
00182         for( j = in1->ny; j > 0; j-- )
00183                 *op++ = *i1++ + *i2++;
00184         /* VADD2N( out->y, i1->y, i2->y, in1->ny ); */
00185 }
00186 
00187 /*
00188  *                      B N _ T A B D A T A _ M U L
00189  *@brief
00190  *  Element-by-element multiply the values from two data tables.
00191  */
00192 void
00193 bn_tabdata_mul(struct bn_tabdata *out, const struct bn_tabdata *in1, const struct bn_tabdata *in2)
00194 {
00195         register int            j;
00196         register fastf_t        *op;
00197         register const fastf_t  *i1, *i2;
00198 
00199         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_mul(x%x, x%x, x%x)\n", out, in1, in2);
00200 
00201         BN_CK_TABDATA( out );
00202         BN_CK_TABDATA( in1 );
00203         BN_CK_TABDATA( in2 );
00204 
00205         if( in1->table != in2->table || in1->table != out->table )
00206                 bu_bomb("bn_tabdata_mul(): samples drawn from different tables\n");
00207         if( in1->ny != in2->ny || in1->ny != out->ny )
00208                 bu_bomb("bn_tabdata_mul(): different tabdata lengths?\n");
00209 
00210         op = out->y;
00211         i1 = in1->y;
00212         i2 = in2->y;
00213         for( j = in1->ny; j > 0; j-- )
00214                 *op++ = *i1++ * *i2++;
00215         /* VELMUL2N( out->y, i1->y, i2->y, in1->ny ); */
00216 }
00217 
00218 /*
00219  *                      B N _ T A B D A T A _ M U L 3
00220  *@brief
00221  *  Element-by-element multiply the values from three data tables.
00222  */
00223 void
00224 bn_tabdata_mul3(struct bn_tabdata *out, const struct bn_tabdata *in1, const struct bn_tabdata *in2, const struct bn_tabdata *in3)
00225 {
00226         register int            j;
00227         register fastf_t        *op;
00228         register const fastf_t  *i1, *i2, *i3;
00229 
00230         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_mul3(x%x, x%x, x%x, x%x)\n", out, in1, in2, in3);
00231 
00232         BN_CK_TABDATA( out );
00233         BN_CK_TABDATA( in1 );
00234         BN_CK_TABDATA( in2 );
00235         BN_CK_TABDATA( in3 );
00236 
00237         if( in1->table != in2->table || in1->table != out->table || in1->table != in2->table )
00238                 bu_bomb("bn_tabdata_mul(): samples drawn from different tables\n");
00239         if( in1->ny != in2->ny || in1->ny != out->ny )
00240                 bu_bomb("bn_tabdata_mul(): different tabdata lengths?\n");
00241 
00242         op = out->y;
00243         i1 = in1->y;
00244         i2 = in2->y;
00245         i3 = in3->y;
00246         for( j = in1->ny; j > 0; j-- )
00247                 *op++ = *i1++ * *i2++ * *i3++;
00248         /* VELMUL3N( out->y, i1->y, i2->y, i3->y, in1->ny ); */
00249 }
00250 
00251 /*
00252  *                      B N _ T A B D A T A _ I N C R _ M U L 3 _ S C A L E
00253  *@brief
00254  *  Element-by-element multiply the values from three data tables and a scalor.
00255  *
00256  *      out += in1 * in2 * in3 * scale
00257  */
00258 void
00259 bn_tabdata_incr_mul3_scale(struct bn_tabdata *out, const struct bn_tabdata *in1, const struct bn_tabdata *in2, const struct bn_tabdata *in3, register double scale)
00260 {
00261         register int            j;
00262         register fastf_t        *op;
00263         register const fastf_t  *i1, *i2, *i3;
00264 
00265         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_incr_mul3_scale(x%x, x%x, x%x, x%x, %g)\n", out, in1, in2, in3, scale);
00266 
00267         BN_CK_TABDATA( out );
00268         BN_CK_TABDATA( in1 );
00269         BN_CK_TABDATA( in2 );
00270         BN_CK_TABDATA( in3 );
00271 
00272         if( in1->table != in2->table || in1->table != out->table || in1->table != in3->table )
00273                 bu_bomb("bn_tabdata_mul(): samples drawn from different tables\n");
00274         if( in1->ny != in2->ny || in1->ny != out->ny )
00275                 bu_bomb("bn_tabdata_mul(): different tabdata lengths?\n");
00276 
00277         op = out->y;
00278         i1 = in1->y;
00279         i2 = in2->y;
00280         i3 = in3->y;
00281         for( j = in1->ny; j > 0; j-- )
00282                 *op++ += *i1++ * *i2++ * *i3++ * scale;
00283 }
00284 
00285 /*
00286  *                      B N _ T A B D A T A _ I N C R _ M U L 2 _ S C A L E
00287  *@brief
00288  *  Element-by-element multiply the values from two data tables and a scalor.
00289  *
00290  *      out += in1 * in2 * scale
00291  */
00292 void
00293 bn_tabdata_incr_mul2_scale(struct bn_tabdata *out, const struct bn_tabdata *in1, const struct bn_tabdata *in2, register double scale)
00294 {
00295         register int            j;
00296         register fastf_t        *op;
00297         register const fastf_t  *i1, *i2;
00298 
00299         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_incr_mul2_scale(x%x, x%x, x%x, %g)\n", out, in1, in2, scale);
00300 
00301         BN_CK_TABDATA( out );
00302         BN_CK_TABDATA( in1 );
00303         BN_CK_TABDATA( in2 );
00304 
00305         if( in1->table != in2->table || in1->table != out->table )
00306                 bu_bomb("bn_tabdata_mul(): samples drawn from different tables\n");
00307         if( in1->ny != in2->ny || in1->ny != out->ny )
00308                 bu_bomb("bn_tabdata_mul(): different tabdata lengths?\n");
00309 
00310         op = out->y;
00311         i1 = in1->y;
00312         i2 = in2->y;
00313         for( j = in1->ny; j > 0; j-- )
00314                 *op++ += *i1++ * *i2++ * scale;
00315 }
00316 
00317 /*
00318  *                      B N _ T A B D A T A _ S C A L E
00319  *@brief
00320  *  Multiply every element in a data table by a scalar value 'scale'.
00321  */
00322 void
00323 bn_tabdata_scale(struct bn_tabdata *out, const struct bn_tabdata *in1, register double scale)
00324 {
00325         register int            j;
00326         register fastf_t        *op;
00327         register const fastf_t  *i1;
00328 
00329         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_scale(x%x, x%x, %g)\n", out, in1, scale);
00330 
00331         BN_CK_TABDATA( out );
00332         BN_CK_TABDATA( in1 );
00333 
00334         if( in1->table != out->table )
00335                 bu_bomb("bn_tabdata_scale(): samples drawn from different tables\n");
00336         if( in1->ny != out->ny )
00337                 bu_bomb("bn_tabdata_scale(): different tabdata lengths?\n");
00338 
00339         op = out->y;
00340         i1 = in1->y;
00341         for( j = in1->ny; j > 0; j-- )
00342                 *op++ = *i1++ * scale;
00343         /* VSCALEN( out->y, in->y, scale ); */
00344 }
00345 
00346 /*
00347  *                      B N _ T A B L E _ S C A L E
00348  *@brief
00349  *  Scale the indepentent axis of a table by 'scale'.
00350  */
00351 void
00352 bn_table_scale(struct bn_table *tabp, register double scale)
00353 {
00354         register int            j;
00355         register fastf_t        *op;
00356 
00357         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_scale(x%x, %g)\n", tabp, scale );
00358 
00359         BN_CK_TABLE( tabp );
00360 
00361         op = tabp->x;
00362         for( j = tabp->nx+1; j > 0; j-- )
00363                 *op++ *= scale;
00364         /* VSCALEN( tabp->x, tabp->x, scale, tabp->nx+1 ); */
00365 }
00366 
00367 /*
00368  *                      B N _ T A B D A T A _ J O I N 1
00369  *@brief
00370  *  Multiply every element in data table in2 by a scalar value 'scale',
00371  *  add it to the element in in1, and store in 'out'.
00372  *  'out' may overlap in1 or in2.
00373  */
00374 void
00375 bn_tabdata_join1(struct bn_tabdata *out, const struct bn_tabdata *in1, register double scale, const struct bn_tabdata *in2)
00376 {
00377         register int            j;
00378         register fastf_t        *op;
00379         register const fastf_t  *i1, *i2;
00380 
00381         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_join1(x%x, x%x, %g, x%x)\n", out, in1, scale, in2 );
00382 
00383         BN_CK_TABDATA( out );
00384         BN_CK_TABDATA( in1 );
00385         BN_CK_TABDATA( in2 );
00386 
00387         if( in1->table != out->table )
00388                 bu_bomb("bn_tabdata_join1(): samples drawn from different tables\n");
00389         if( in1->table != in2->table )
00390                 bu_bomb("bn_tabdata_join1(): samples drawn from different tables\n");
00391         if( in1->ny != out->ny )
00392                 bu_bomb("bn_tabdata_join1(): different tabdata lengths?\n");
00393 
00394         op = out->y;
00395         i1 = in1->y;
00396         i2 = in2->y;
00397         for( j = in1->ny; j > 0; j-- )
00398                 *op++ = *i1++ + scale * *i2++;
00399         /* VJOIN1N( out->y, in1->y, scale, in2->y ); */
00400 }
00401 
00402 /*
00403  *                      B N _ T A B D A T A _ J O I N 2
00404  *@brief
00405  *  Multiply every element in data table in2 by a scalar value 'scale2',
00406  *  plus in3 * scale3, and
00407  *  add it to the element in in1, and store in 'out'.
00408  *  'out' may overlap in1 or in2.
00409  */
00410 void
00411 bn_tabdata_join2(struct bn_tabdata *out, const struct bn_tabdata *in1, register double scale2, const struct bn_tabdata *in2, register double scale3, const struct bn_tabdata *in3)
00412 {
00413         register int            j;
00414         register fastf_t        *op;
00415         register const fastf_t  *i1, *i2, *i3;
00416 
00417         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_join2(x%x, x%x, %g, x%x, %g, x%x)\n", out, in1, scale2, in2, scale3, in3 );
00418 
00419         BN_CK_TABDATA( out );
00420         BN_CK_TABDATA( in1 );
00421         BN_CK_TABDATA( in2 );
00422 
00423         if( in1->table != out->table )
00424                 bu_bomb("bn_tabdata_join1(): samples drawn from different tables\n");
00425         if( in1->table != in2->table )
00426                 bu_bomb("bn_tabdata_join1(): samples drawn from different tables\n");
00427         if( in1->table != in3->table )
00428                 bu_bomb("bn_tabdata_join1(): samples drawn from different tables\n");
00429         if( in1->ny != out->ny )
00430                 bu_bomb("bn_tabdata_join1(): different tabdata lengths?\n");
00431 
00432         op = out->y;
00433         i1 = in1->y;
00434         i2 = in2->y;
00435         i3 = in3->y;
00436         for( j = in1->ny; j > 0; j-- )
00437                 *op++ = *i1++ + scale2 * *i2++ + scale3 * *i3++;
00438         /* VJOIN2N( out->y, in1->y, scale2, in2->y, scale3, in3->y ); */
00439 }
00440 
00441 /*
00442  *                      B N _ T A B D A T A _ B L E N D 2
00443  */
00444 void
00445 bn_tabdata_blend2(struct bn_tabdata *out, register double scale1, const struct bn_tabdata *in1, register double scale2, const struct bn_tabdata *in2)
00446 {
00447         register int            j;
00448         register fastf_t        *op;
00449         register const fastf_t  *i1, *i2;
00450 
00451         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_blend2(x%x, %g, x%x, %g, x%x)\n", out, scale1, in1, scale2, in2 );
00452 
00453         BN_CK_TABDATA( out );
00454         BN_CK_TABDATA( in1 );
00455         BN_CK_TABDATA( in2 );
00456 
00457         if( in1->table != out->table )
00458                 bu_bomb("bn_tabdata_blend2(): samples drawn from different tables\n");
00459         if( in1->table != in2->table )
00460                 bu_bomb("bn_tabdata_blend2(): samples drawn from different tables\n");
00461         if( in1->ny != out->ny )
00462                 bu_bomb("bn_tabdata_blend2(): different tabdata lengths?\n");
00463 
00464         op = out->y;
00465         i1 = in1->y;
00466         i2 = in2->y;
00467         for( j = in1->ny; j > 0; j-- )
00468                 *op++ = scale1 * *i1++ + scale2 * *i2++;
00469         /* VBLEND2N( out->y, scale1, in1->y, scale2, in2->y ); */
00470 }
00471 
00472 /*
00473  *                      B N _ T A B D A T A _ B L E N D 3
00474  */
00475 void
00476 bn_tabdata_blend3(struct bn_tabdata *out, register double scale1, const struct bn_tabdata *in1, register double scale2, const struct bn_tabdata *in2, register double scale3, const struct bn_tabdata *in3)
00477 {
00478         register int            j;
00479         register fastf_t        *op;
00480         register const fastf_t  *i1, *i2, *i3;
00481 
00482         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_blend3(x%x, %g, x%x, %g, x%x, %g, x%x)\n", out, scale1, in1, scale2, in2, scale3, in3 );
00483 
00484         BN_CK_TABDATA( out );
00485         BN_CK_TABDATA( in1 );
00486         BN_CK_TABDATA( in2 );
00487         BN_CK_TABDATA( in3 );
00488 
00489         if( in1->table != out->table )
00490                 bu_bomb("bn_tabdata_blend3(): samples drawn from different tables\n");
00491         if( in1->table != in2->table )
00492                 bu_bomb("bn_tabdata_blend3(): samples drawn from different tables\n");
00493         if( in1->table != in3->table )
00494                 bu_bomb("bn_tabdata_blend3(): samples drawn from different tables\n");
00495         if( in1->ny != out->ny )
00496                 bu_bomb("bn_tabdata_blend3(): different tabdata lengths?\n");
00497 
00498         op = out->y;
00499         i1 = in1->y;
00500         i2 = in2->y;
00501         i3 = in3->y;
00502         for( j = in1->ny; j > 0; j-- )
00503                 *op++ = scale1 * *i1++ + scale2 * *i2++ + scale3 * *i3++;
00504         /* VBLEND3N( out->y, scale1, in1->y, scale2, in2->y, scale3, in3->y ); */
00505 }
00506 
00507 /*
00508  *                      B N _ T A B D A T A _ A R E A 1
00509  *@brief
00510  *  Following interpretation #1, where y[j] stores the total (integral
00511  *  or area) value within the interval, return the area under the whole curve.
00512  *  This is simply totaling up the areas from each of the intervals.
00513  */
00514 double
00515 bn_tabdata_area1(const struct bn_tabdata *in)
00516 {
00517         FAST fastf_t            area;
00518         register const fastf_t  *ip;
00519         register int            j;
00520 
00521         BN_CK_TABDATA(in);
00522 
00523         area = 0;
00524         ip = in->y;
00525         for( j = in->ny; j > 0; j-- )
00526                 area += *ip++;
00527 
00528         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_area(x%x) = %g\n", in, area);
00529 
00530         return area;
00531 }
00532 
00533 /*
00534  *                      B N _ T A B D A T A _ A R E A 2
00535  *@brief
00536  *  Following interpretation #2, where y[j] stores the average
00537  *  value for the interval, return the area under
00538  *  the whole curve.  Since the iterval spacing need not be uniform,
00539  *  sum the areas of the rectangles.
00540  */
00541 double
00542 bn_tabdata_area2(const struct bn_tabdata *in)
00543 {
00544         const struct bn_table   *tabp;
00545         FAST fastf_t            area;
00546         fastf_t                 width;
00547         register int            j;
00548 
00549         BN_CK_TABDATA(in);
00550         tabp = in->table;
00551         BN_CK_TABLE(tabp);
00552 
00553         area = 0;
00554         for( j = in->ny-1; j >= 0; j-- )  {
00555                 width = tabp->x[j+1] - tabp->x[j];
00556                 area += in->y[j] * width;
00557         }
00558 
00559         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_area2(x%x) = %g\n", in, area);
00560         return area;
00561 }
00562 
00563 /*
00564  *                      B N _ T A B D A T A _ M U L _ A R E A 1
00565  *@brief
00566  *  Following interpretation #1, where y[j] stores the total (integral
00567  *  or area) value within the interval, return the area under the whole curve.
00568  *  This is simply totaling up the areas from each of the intervals.
00569  *  The curve value is found by multiplying corresponding entries from
00570  *  in1 and in2.
00571  */
00572 double
00573 bn_tabdata_mul_area1(const struct bn_tabdata *in1, const struct bn_tabdata *in2)
00574 {
00575         FAST fastf_t            area;
00576         register const fastf_t  *i1, *i2;
00577         register int            j;
00578 
00579         BN_CK_TABDATA(in1);
00580         BN_CK_TABDATA(in2);
00581 
00582         area = 0;
00583         i1 = in1->y;
00584         i2 = in2->y;
00585         for( j = in1->ny; j > 0; j-- )
00586                 area += *i1++ * *i2++;
00587 
00588         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_mul_area1(x%x, x%x) = %g\n", in1, in2, area);
00589         return area;
00590 }
00591 
00592 /*
00593  *                      B N _ T A B D A T A _ M U L _ A R E A 2
00594  *@brief
00595  *  Following interpretation #2,
00596  *  return the area under the whole curve.
00597  *  The curve value is found by multiplying corresponding entries from
00598  *  in1 and in2.
00599  */
00600 double
00601 bn_tabdata_mul_area2(const struct bn_tabdata *in1, const struct bn_tabdata *in2)
00602 {
00603         const struct bn_table   *tabp;
00604         FAST fastf_t            area;
00605         fastf_t                 width;
00606         register int            j;
00607 
00608         BN_CK_TABDATA(in1);
00609         BN_CK_TABDATA(in2);
00610         tabp = in1->table;
00611         BN_CK_TABLE(tabp);
00612 
00613         area = 0;
00614         for( j = in1->ny-1; j >= 0; j-- )  {
00615                 width = tabp->x[j+1] - tabp->x[j];
00616                 area += in1->y[j] * in2->y[j] * width;
00617         }
00618 
00619         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_mul_area2(x%x, x%x) = %g\n", in1, in2, area);
00620         return area;
00621 }
00622 
00623 /*
00624  *                      B N _ T A B L E _ F I N D _ X
00625  *@brief
00626  *  Return the index in the table's x[] array of the interval which
00627  *  contains 'xval'.
00628  *
00629  *
00630  * @return      -1      if less than start value
00631  * @return      -2      if greater than end value.
00632  * @return      0..nx-1 otherwise.
00633  *              Never returns a value of nx.
00634  *
00635  *  A binary search would be more efficient, as the wavelengths (x values)
00636  *  are known to be sorted in ascending order.
00637  */
00638 int
00639 bn_table_find_x(const struct bn_table *tabp, double xval)
00640 {
00641         register int    i;
00642 
00643         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_find_x(x%x, %g)\n", tabp, xval );
00644         BN_CK_TABLE(tabp);
00645 
00646         if( xval > tabp->x[tabp->nx] )  return -2;
00647         if( xval >= tabp->x[tabp->nx-1] )  return tabp->nx-1;
00648 
00649         /* Search for proper interval in input spectrum */
00650         for( i = tabp->nx-2; i >=0; i-- )  {
00651                 if( xval >= tabp->x[i] )  return i;
00652         }
00653         /* if( xval < tabp->x[0] )  return -1; */
00654         return -1;
00655 }
00656 
00657 /*
00658  *                      B N _ T A B L E _ L I N _ I N T E R P
00659  *@brief
00660  *  Return the value of the curve at independent parameter value 'wl'.
00661  *  Linearly interpolate between values in the input table.
00662  *  Zero is returned for values outside the sampled range.
00663  */
00664 fastf_t
00665 bn_table_lin_interp(const struct bn_tabdata *samp, register double wl)
00666 {
00667         const struct bn_table   *tabp;
00668         register int            i;
00669         register fastf_t        fract;
00670         register fastf_t        ret;
00671 
00672         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_lin_interp(x%x, %g)\n", samp, wl);
00673 
00674         BN_CK_TABDATA(samp);
00675         tabp = samp->table;
00676         BN_CK_TABLE(tabp);
00677 
00678         if( (i = bn_table_find_x( tabp, wl )) < 0 )  {
00679                 if(bu_debug&BU_DEBUG_TABDATA)bu_log("bn_table_lin_interp(%g) out of range %g to %g\n", wl, tabp->x[0], tabp->x[tabp->nx] );
00680                 return 0;
00681         }
00682 
00683         if( wl < tabp->x[i] || wl >= tabp->x[i+1] )  {
00684                 bu_log("bn_table_lin_interp(%g) assertion1 failed at %g\n", wl, tabp->x[i] );
00685                 bu_bomb("bn_table_lin_interp() assertion1 failed\n");
00686         }
00687 
00688         if( i >= tabp->nx-2 )  {
00689                 /* Assume value is constant in final interval. */
00690                 if(bu_debug&BU_DEBUG_TABDATA)bu_log("bn_table_lin_interp(%g)=%g off end of range %g to %g\n", wl, samp->y[tabp->nx-1], tabp->x[0], tabp->x[tabp->nx] );
00691                 return samp->y[tabp->nx-1];
00692         }
00693 
00694         /* The interval has been found */
00695         fract = (wl - tabp->x[i]) / (tabp->x[i+1] - tabp->x[i]);
00696         if( fract < 0 || fract > 1 )  bu_bomb("bn_table_lin_interp() assertion2 failed\n");
00697         ret = (1-fract) * samp->y[i] + fract * samp->y[i+1];
00698         if(bu_debug&BU_DEBUG_TABDATA)bu_log("bn_table_lin_interp(%g)=%g in range %g to %g\n",
00699                 wl, ret, tabp->x[i], tabp->x[i+1] );
00700         return ret;
00701 }
00702 
00703 /*
00704  *                      B N _ T A B D A T A _ R E S A M P L E _ M A X
00705  *@brief
00706  *  Given a set of sampled data 'olddata', resample it for different
00707  *  spacing, by linearly interpolating the values when an output span
00708  *  is entirely contained within an input span, and by taking the
00709  *  maximum when an output span covers more than one input span.
00710  *
00711  *  This assumes interpretation (2) of the data, i.e. that the values
00712  *  are the average value across the interval.
00713  */
00714 struct bn_tabdata *
00715 bn_tabdata_resample_max(const struct bn_table *newtable, const struct bn_tabdata *olddata)
00716 {
00717         const struct bn_table   *oldtable;
00718         struct bn_tabdata       *newsamp;
00719         int                     i;
00720         int                     j, k;
00721 
00722         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_resample_max(x%x, x%x)\n", newtable, olddata);
00723 
00724         BN_CK_TABLE(newtable);
00725         BN_CK_TABDATA(olddata);
00726         oldtable = olddata->table;
00727         BN_CK_TABLE(oldtable);
00728 
00729         if( oldtable == newtable )  bu_log("bn_tabdata_resample_max() NOTICE old and new bn_table structs are the same\n");
00730 
00731         BN_GET_TABDATA( newsamp, newtable );
00732 
00733         for( i = 0; i < newtable->nx; i++ )  {
00734                 /*
00735                  *  Find good value(s) in olddata to represent the span from
00736                  *  newtable->x[i] to newtable->x[i+1].
00737                  */
00738                 j = bn_table_find_x( oldtable, newtable->x[i] );
00739                 k = bn_table_find_x( oldtable, newtable->x[i+1] );
00740                 if( k == -1 )  {
00741                         /* whole new span is off left side of old table */
00742                         newsamp->y[i] = 0;
00743                         continue;
00744                 }
00745                 if( j == -2 )  {
00746                         /* whole new span is off right side of old table */
00747                         newsamp->y[i] = 0;
00748                         continue;
00749                 }
00750 
00751                 if( j == k && j > 0 )  {
00752                         register fastf_t tmp;
00753                         /*
00754                          *  Simple case, ends of output span are completely
00755                          *  contained within one input span.
00756                          *  Interpolate for both ends, take max.
00757                          *  XXX this could be more efficiently written inline here.
00758                          */
00759                         newsamp->y[i] = bn_table_lin_interp( olddata, newtable->x[i] );
00760                         tmp = bn_table_lin_interp( olddata, newtable->x[i+1] );
00761                         if( tmp > newsamp->y[i] )  newsamp->y[i] = tmp;
00762                 } else {
00763                         register fastf_t tmp, n;
00764                         register int    s;
00765                         /*
00766                          *  Complex case: find good representative value.
00767                          *  Interpolate both ends, and consider all
00768                          *  intermediate old samples in span.  Take max.
00769                          *  One (but not both) new ends may be off old table.
00770                          */
00771                         n = bn_table_lin_interp( olddata, newtable->x[i] );
00772                         tmp = bn_table_lin_interp( olddata, newtable->x[i+1] );
00773                         if( tmp > n )  n = tmp;
00774                         for( s = j+1; s <= k; s++ )  {
00775                                 if( (tmp = olddata->y[s]) > n )
00776                                         n = tmp;
00777                         }
00778                         newsamp->y[i] = n;
00779                 }
00780         }
00781         return newsamp;
00782 }
00783 
00784 /*
00785  *                      B N _ T A B D A T A _ R E S A M P L E _ A V G
00786  *@brief
00787  *  Given a set of sampled data 'olddata', resample it for different
00788  *  spacing, by linearly interpolating the values when an output span
00789  *  is entirely contained within an input span, and by taking the
00790  *  average when an output span covers more than one input span.
00791  *
00792  *  This assumes interpretation (2) of the data, i.e. that the values
00793  *  are the average value across the interval.
00794  */
00795 struct bn_tabdata *
00796 bn_tabdata_resample_avg(const struct bn_table *newtable, const struct bn_tabdata *olddata)
00797 {
00798         const struct bn_table   *oldtable;
00799         struct bn_tabdata       *newsamp;
00800         int                     i;
00801         int                     j, k;
00802 
00803         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_resample_avg(x%x, x%x)\n", newtable, olddata);
00804 
00805         BN_CK_TABLE(newtable);
00806         BN_CK_TABDATA(olddata);
00807         oldtable = olddata->table;
00808         BN_CK_TABLE(oldtable);
00809 
00810         if( oldtable == newtable )  bu_log("bn_tabdata_resample_avg() NOTICE old and new bn_table structs are the same\n");
00811 
00812         BN_GET_TABDATA( newsamp, newtable );
00813 
00814         for( i = 0; i < newtable->nx; i++ )  {
00815                 /*
00816                  *  Find good value(s) in olddata to represent the span from
00817                  *  newtable->x[i] to newtable->x[i+1].
00818                  */
00819                 j = bn_table_find_x( oldtable, newtable->x[i] );
00820                 k = bn_table_find_x( oldtable, newtable->x[i+1] );
00821 
00822                 if( j < 0 || k < 0 || j == k )  {
00823                         /*
00824                          *  Simple case, ends of output span are completely
00825                          *  contained within one input span.
00826                          *  Interpolate for both ends, take average.
00827                          *  XXX this could be more efficiently written inline here.
00828                          */
00829                         newsamp->y[i] = 0.5 * (
00830                             bn_table_lin_interp( olddata, newtable->x[i] ) +
00831                             bn_table_lin_interp( olddata, newtable->x[i+1] ) );
00832                 } else {
00833                         /*
00834                          *  Complex case: find average value.
00835                          *  Interpolate both end, and consider all
00836                          *  intermediate old spans.
00837                          *  There are three parts to sum:
00838                          *      Partial interval from newx[i] to j+1
00839                          *      Full intervals from j+1 to k
00840                          *      Partial interval from k to newx[i+1]
00841                          */
00842                         fastf_t wsum;           /* weighted sum */
00843                         fastf_t a,b;            /* values being averaged */
00844                         int     s;
00845 
00846                         /* Partial interval from newx[i] to j+1 */
00847                         a = bn_table_lin_interp( olddata, newtable->x[i] );     /* in "j" bin */
00848                         b = olddata->y[j+1];
00849                         wsum = 0.5 * (a+b) * (oldtable->x[j+1] - newtable->x[i] );
00850 
00851                         /* Full intervals from j+1 to k */
00852                         for( s = j+1; s < k; s++ )  {
00853                                 a = olddata->y[s];
00854                                 b = olddata->y[s+1];
00855                                 wsum += 0.5 * (a+b) * (oldtable->x[s+1] - oldtable->x[s] );
00856                         }
00857 
00858                         /* Partial interval from k to newx[i+1] */
00859                         a = olddata->y[k];
00860                         b = bn_table_lin_interp( olddata, newtable->x[i+1] );   /* in "k" bin */
00861                         wsum += 0.5 * (a+b) * (newtable->x[i+1] - oldtable->x[k] );
00862 
00863                         /* Adjust the weighted sum by the total width */
00864                         newsamp->y[i] =
00865                                 wsum / (newtable->x[i+1] - newtable->x[i]);
00866                 }
00867         }
00868         return newsamp;
00869 }
00870 
00871 /*
00872  *                      B N _ T A B L E _ W R I T E
00873  *@brief
00874  *  Write out the table structure in an ASCII file,
00875  *  giving the number of values (minus 1), and the
00876  *  actual values.
00877  */
00878 int
00879 bn_table_write(const char *filename, const struct bn_table *tabp)
00880 {
00881         FILE    *fp;
00882         int     j;
00883 
00884         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_write(%s, x%x)\n", filename, tabp);
00885 
00886         BN_CK_TABLE(tabp);
00887 
00888         bu_semaphore_acquire( BU_SEM_SYSCALL );
00889         fp = fopen( filename, "w" );
00890         bu_semaphore_release( BU_SEM_SYSCALL );
00891 
00892         if( fp == NULL )  {
00893                 perror(filename);
00894                 bu_log("bn_table_write(%s, x%x) FAILED\n", filename, tabp);
00895                 return -1;
00896         }
00897 
00898         bu_semaphore_acquire( BU_SEM_SYSCALL );
00899         fprintf(fp, "  %d sample starts, and one end.\n", tabp->nx );
00900         for( j=0; j <= tabp->nx; j++ )  {
00901                 fprintf( fp, "%g\n", tabp->x[j] );
00902         }
00903         fclose(fp);
00904         bu_semaphore_release( BU_SEM_SYSCALL );
00905         return 0;
00906 }
00907 
00908 /*
00909  *                      B N _ T A B L E _ R E A D
00910  *@brief
00911  *  Allocate and read in the independent variable values from an ASCII file,
00912  *  giving the number of samples (minus 1), and the
00913  *  actual values.
00914  */
00915 struct bn_table *
00916 bn_table_read(const char *filename)
00917 {
00918         struct bn_table *tabp;
00919         struct bu_vls           line;
00920         FILE    *fp;
00921         int     nw;
00922         int     j;
00923 
00924         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_read(%s)\n", filename);
00925 
00926         bu_semaphore_acquire( BU_SEM_SYSCALL );
00927         fp = fopen( filename, "r" );
00928         bu_semaphore_release( BU_SEM_SYSCALL );
00929 
00930         if( fp == NULL )  {
00931                 perror(filename);
00932                 bu_log("bn_table_read(%s) FAILED\n", filename);
00933                 return NULL;
00934         }
00935 
00936         bu_vls_init(&line);
00937         bu_vls_gets( &line, fp );
00938         nw = 0;
00939         sscanf( bu_vls_addr(&line), "%d", &nw );
00940         bu_vls_free(&line);
00941 
00942         if( nw <= 0 ) bu_bomb("bn_table_read() bad nw value\n");
00943 
00944         BN_GET_TABLE( tabp, nw );
00945 
00946         bu_semaphore_acquire( BU_SEM_SYSCALL );
00947         for( j=0; j <= tabp->nx; j++ )  {
00948                 /* XXX assumes fastf_t == double */
00949                 fscanf( fp, "%lf", &tabp->x[j] );
00950         }
00951         fclose(fp);
00952         bu_semaphore_release( BU_SEM_SYSCALL );
00953 
00954         bn_ck_table( tabp );
00955 
00956         return tabp;
00957 }
00958 
00959 /*
00960  *                      B N _ P R _ T A B L E
00961  */
00962 void
00963 bn_pr_table(const char *title, const struct bn_table *tabp)
00964 {
00965         int     j;
00966 
00967         bu_log("%s\n", title);
00968         BN_CK_TABLE(tabp);
00969 
00970         for( j=0; j <= tabp->nx; j++ )  {
00971                 bu_log("%3d: %g\n", j, tabp->x[j] );
00972         }
00973 }
00974 
00975 /*
00976  *                      B N _ P R _ T A B D A T A
00977  */
00978 void
00979 bn_pr_tabdata(const char *title, const struct bn_tabdata *data)
00980 {
00981         int     j;
00982 
00983         bu_log("%s: ", title);
00984         BN_CK_TABDATA(data);
00985 
00986         for( j=0; j < data->ny; j++ )  {
00987                 bu_log("%g, ", data->y[j] );
00988         }
00989         bu_log("\n");
00990 }
00991 
00992 /*
00993  *                      B N _ P R I N T _ T A B L E _ A N D _ T A B D A T A
00994  *@brief
00995  *  Write out a given data table into an ASCII file,
00996  *  suitable for input to GNUPLOT.
00997  *
00998  *      (set term postscript)
00999  *      (set output "|print-postscript")
01000  *      (plot "filename" with lines)
01001  */
01002 int
01003 bn_print_table_and_tabdata(const char *filename, const struct bn_tabdata *data)
01004 {
01005         FILE    *fp;
01006         const struct bn_table   *tabp;
01007         int     j;
01008 
01009         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_print_table_and_tabdata(%s, x%x)\n", filename, data);
01010 
01011         BN_CK_TABDATA(data);
01012         tabp = data->table;
01013         BN_CK_TABLE(tabp);
01014 
01015         bu_semaphore_acquire( BU_SEM_SYSCALL );
01016         fp = fopen( filename, "w" );
01017         bu_semaphore_release( BU_SEM_SYSCALL );
01018 
01019         if( fp == NULL )  {
01020                 perror(filename);
01021                 bu_log("bn_print_table_and_tabdata(%s, x%x) FAILED\n", filename, data );
01022                 return -1;
01023         }
01024 
01025         bu_semaphore_acquire( BU_SEM_SYSCALL );
01026         for( j=0; j < tabp->nx; j++ )  {
01027                 fprintf( fp, "%g %g\n", tabp->x[j], data->y[j] );
01028         }
01029         fprintf( fp, "%g (novalue)\n", tabp->x[tabp->nx] );
01030         fclose(fp);
01031         bu_semaphore_release( BU_SEM_SYSCALL );
01032         return 0;
01033 }
01034 
01035 /*
01036  *                      B N _ R E A D _ T A B L E _ A N D _ T A B D A T A
01037  *@brief
01038  *  Read in a file which contains two columns of numbers, the first
01039  *  column being the waveength, the second column being the sample value
01040  *  at that wavelength.
01041  *
01042  *  A new bn_table structure and one bn_tabdata structure
01043  *  are created, a pointer to the bn_tabdata structure is returned.
01044  *  The final wavelength is guessed at.
01045  */
01046 struct bn_tabdata *
01047 bn_read_table_and_tabdata(const char *filename)
01048 {
01049         struct bn_table *tabp;
01050         struct bn_tabdata       *data;
01051         FILE    *fp;
01052         char    buf[128];
01053         int     count = 0;
01054         int     i;
01055 
01056         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_read_table_and_tabdata(%s)\n", filename);
01057 
01058         bu_semaphore_acquire( BU_SEM_SYSCALL );
01059         fp = fopen( filename, "r" );
01060         bu_semaphore_release( BU_SEM_SYSCALL );
01061 
01062         if( fp == NULL )  {
01063                 perror(filename);
01064                 bu_log("bn_read_table_and_tabdata(%s) FAILED\n", filename);
01065                 return NULL;
01066         }
01067 
01068         /* First pass:  Count number of lines */
01069         bu_semaphore_acquire( BU_SEM_SYSCALL );
01070         for(;;)  {
01071                 if( fgets( buf, sizeof(buf), fp ) == NULL )  break;
01072                 count++;
01073         }
01074         fclose(fp);
01075         bu_semaphore_release( BU_SEM_SYSCALL );
01076 
01077         /* Allocate storage */
01078         BN_GET_TABLE( tabp, count );
01079         BN_GET_TABDATA( data, tabp );
01080 
01081         /* Second pass:  Read only as much data as storage was allocated for */
01082         bu_semaphore_acquire( BU_SEM_SYSCALL );
01083         fp = fopen( filename, "r" );
01084         for( i=0; i < count; i++ )  {
01085                 buf[0] = '\0';
01086                 if( fgets( buf, sizeof(buf), fp ) == NULL )  {
01087                         bu_log("bn_read_table_and_tabdata(%s) unexpected EOF on line %d\n", filename, i);
01088                         break;
01089                 }
01090                 sscanf( buf, "%lf %lf", &tabp->x[i], &data->y[i] );
01091         }
01092         fclose(fp);
01093         bu_semaphore_release( BU_SEM_SYSCALL );
01094 
01095         /* Complete final interval */
01096         tabp->x[count] = 2 * tabp->x[count-1] - tabp->x[count-2];
01097 
01098         bn_ck_table( tabp );
01099 
01100         return data;
01101 }
01102 
01103 /*
01104  *                      B N _ T A B D A T A _ B I N A R Y _ R E A D
01105  */
01106 struct bn_tabdata *
01107 bn_tabdata_binary_read(const char *filename, int num, const struct bn_table *tabp)
01108 {
01109         struct bn_tabdata       *data;
01110         char    *cp;
01111         int     nbytes;
01112         int     len;
01113         int     got;
01114         int     fd;
01115         int     i;
01116 
01117         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_binary_read(%s, num=%d, x%x)\n", filename, num, tabp);
01118 
01119         BN_CK_TABLE(tabp);
01120 
01121         nbytes = BN_SIZEOF_TABDATA(tabp);
01122         len = num * nbytes;
01123 
01124         bu_semaphore_acquire( BU_SEM_SYSCALL );
01125         fd = open(filename, 0);
01126         bu_semaphore_release( BU_SEM_SYSCALL );
01127         if( fd <= 0 )  {
01128             perror(filename);
01129             bu_log("bn_tabdata_binary_read open failed on \"%s\"\n", filename);
01130             bu_semaphore_acquire( BU_SEM_SYSCALL );
01131             close(fd);
01132             bu_semaphore_release( BU_SEM_SYSCALL );
01133             return (struct bn_tabdata *)NULL;
01134         }
01135 
01136         /* Get a big array of structures for reading all at once */
01137         data = (struct bn_tabdata *)bu_malloc( len+8, "bn_tabdata[]" );
01138 
01139         bu_semaphore_acquire( BU_SEM_SYSCALL );
01140         got = read( fd, (char *)data, len );
01141         bu_semaphore_release( BU_SEM_SYSCALL );
01142         if( got != len )  {
01143             if (got < 0) {
01144                 perror(filename);               
01145                 bu_log("bn_tabdata_binary_read read error on \"%s\"\n", filename);
01146             } else {
01147                 bu_log("bn_tabdata_binary_read(%s) expected %d got %d\n", filename, len, got);
01148             }
01149             bu_free( data, "bn_tabdata[]" );
01150             bu_semaphore_acquire( BU_SEM_SYSCALL );
01151             close(fd);
01152             bu_semaphore_release( BU_SEM_SYSCALL );
01153             return (struct bn_tabdata *)NULL;
01154         }
01155         bu_semaphore_acquire( BU_SEM_SYSCALL );
01156         close(fd);
01157         bu_semaphore_release( BU_SEM_SYSCALL );
01158 
01159         /* Connect data[i].table pointer to tabp */
01160         cp = (char *)data;
01161         for( i = num-1; i >= 0; i--, cp += nbytes )  {
01162             register struct bn_tabdata *sp;
01163             sp = (struct bn_tabdata *)cp;
01164             BN_CK_TABDATA(sp);
01165             sp->table = tabp;
01166         }
01167 
01168         return data;
01169 }
01170 
01171 /*
01172  *                      B N _ T A B D A T A _ M A L L O C _ A R R A Y
01173  *@brief
01174  *  Allocate storage for, and initialize, an array of 'num' data table
01175  *  structures.
01176  *  This subroutine is provided because the bn_tabdata structures
01177  *  are variable length.
01178  */
01179 struct bn_tabdata *
01180 bn_tabdata_malloc_array(const struct bn_table *tabp, int num)
01181 {
01182         struct bn_tabdata       *data;
01183         char    *cp;
01184         int     i;
01185         int     nw;
01186         int     nbytes;
01187 
01188         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_malloc_array(x%x, num=%d)\n", tabp, num);
01189 
01190         BN_CK_TABLE(tabp);
01191         nw = tabp->nx;
01192         nbytes = BN_SIZEOF_TABDATA(tabp);
01193 
01194         data = (struct bn_tabdata *)bu_calloc( num,
01195                 nbytes, "struct bn_tabdata[]" );
01196 
01197         cp = (char *)data;
01198         for( i = 0; i < num; i++ ) {
01199                 register struct bn_tabdata      *sp;
01200 
01201                 sp = (struct bn_tabdata *)cp;
01202                 sp->magic = BN_TABDATA_MAGIC;
01203                 sp->ny = nw;
01204                 sp->table = tabp;
01205                 cp += nbytes;
01206         }
01207         return data;
01208 }
01209 
01210 /*
01211  *                      B N _ T A B D A T A _ C O P Y
01212  */
01213 void
01214 bn_tabdata_copy(struct bn_tabdata *out, const struct bn_tabdata *in)
01215 {
01216         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_copy(x%x, x%x)\n", out, in);
01217 
01218         BN_CK_TABDATA( out );
01219         BN_CK_TABDATA( in );
01220 
01221         if( in->table != out->table )
01222                 bu_bomb("bn_tabdata_copy(): samples drawn from different tables\n");
01223         if( in->ny != out->ny )
01224                 bu_bomb("bn_tabdata_copy(): different tabdata lengths?\n");
01225 
01226         bcopy( (const char *)in->y, (char *)out->y, BN_SIZEOF_TABDATA_Y(in) );
01227 }
01228 
01229 /*
01230  *                      B N _ T A B D A T A _ D U P
01231  */
01232 struct bn_tabdata *
01233 bn_tabdata_dup(const struct bn_tabdata *in)
01234 {
01235         struct bn_tabdata *data;
01236 
01237         BN_CK_TABDATA( in );
01238         BN_GET_TABDATA( data, in->table );
01239 
01240         bcopy( (const char *)in->y, (char *)data->y, BN_SIZEOF_TABDATA_Y(in) );
01241 
01242         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_dup(x%x) = x%x\n", in, data);
01243         return data;
01244 }
01245 
01246 /*
01247  *                      B N _ T A B D A T A _ G E T _ C O N S T V A L
01248  *@brief
01249  *  For a given table, allocate and return a tabdata structure
01250  *  with all elements initialized to 'val'.
01251  */
01252 struct bn_tabdata *
01253 bn_tabdata_get_constval(double val, const struct bn_table *tabp)
01254 {
01255         struct bn_tabdata       *data;
01256         int                     todo;
01257         register fastf_t        *op;
01258 
01259         BN_CK_TABLE(tabp);
01260         BN_GET_TABDATA( data, tabp );
01261 
01262         op = data->y;
01263         for( todo = data->ny-1; todo >= 0; todo-- )
01264                 *op++ = val;
01265 
01266         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_get_constval(val=%g, x%x)=x%x\n", val, tabp, data);
01267 
01268         return data;
01269 }
01270 
01271 /*
01272  *                      B N _ T A B D A T A _ C O N S T V A L
01273  *@brief
01274  *  Set all the tabdata elements to 'val'
01275  */
01276 void
01277 bn_tabdata_constval(struct bn_tabdata *data, double val)
01278 {
01279         int                     todo;
01280         register fastf_t        *op;
01281 
01282         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_constval(x%x, val=%g)\n", data, val);
01283 
01284         BN_CK_TABDATA(data);
01285 
01286         op = data->y;
01287         for( todo = data->ny-1; todo >= 0; todo-- )
01288                 *op++ = val;
01289 }
01290 
01291 /*
01292  *                      B N _ T A B D A T A _ T O _ T C L
01293  *@brief
01294  *  Convert an bn_tabdata/bn_table pair into a Tcl compatible string
01295  *  appended to a VLS.  It will have form:
01296  *      x {...} y {...} nx # ymin # ymax #
01297  */
01298 void
01299 bn_tabdata_to_tcl(struct bu_vls *vp, const struct bn_tabdata *data)
01300 {
01301         const struct bn_table   *tabp;
01302         register int i;
01303         FAST fastf_t    minval = MAX_FASTF, maxval = -MAX_FASTF;
01304 
01305         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_to_tcl(x%x, x%x)\n", vp, data);
01306 
01307         BU_CK_VLS(vp);
01308         BN_CK_TABDATA(data);
01309         tabp = data->table;
01310         BN_CK_TABLE(tabp);
01311 
01312         bu_vls_strcat(vp, "x {");
01313         for( i=0; i < tabp->nx; i++ )  {
01314                 bu_vls_printf( vp, "%g ", tabp->x[i] );
01315         }
01316         bu_vls_strcat(vp, "} y {");
01317         for( i=0; i < data->ny; i++ )  {
01318                 register fastf_t val = data->y[i];
01319                 bu_vls_printf( vp, "%g ", val );
01320                 if( val < minval )  minval = val;
01321                 if( val > maxval )  maxval = val;
01322         }
01323         bu_vls_printf( vp, "} nx %d ymin %g ymax %g",
01324                 tabp->nx, minval, maxval );
01325 }
01326 
01327 /*
01328  *                      B N _ T A B D A T A _ F R O M _ A R R A Y
01329  *@brief
01330  *  Given an array of (x,y) pairs, build the relevant bn_table and
01331  *  bn_tabdata structures.
01332  *
01333  *  The table is terminated by an x value <= 0.
01334  *  Consistent with the interpretation of the spans,
01335  *  invent a final span ending x value.
01336  */
01337 struct bn_tabdata *
01338 bn_tabdata_from_array(const double *array)
01339 {
01340         register const double   *dp;
01341         int                     len = 0;
01342         struct bn_table         *tabp;
01343         struct bn_tabdata       *data;
01344         register int            i;
01345 
01346         /* First, find len */
01347         for( dp = array; *dp > 0; dp += 2 )     /* NIL */ ;
01348         len = (dp - array) >> 1;
01349 
01350         /* Second, build bn_table */
01351         BN_GET_TABLE( tabp, len );
01352         for( i = 0; i < len; i++ )  {
01353                 tabp->x[i] = array[i<<1];
01354         }
01355         tabp->x[len] = tabp->x[len-1] + 1;      /* invent span end */
01356 
01357         /* Third, build bn_tabdata (last input "y" is ignored) */
01358         BN_GET_TABDATA( data, tabp );
01359         for( i = 0; i < len-1; i++ )  {
01360                 data->y[i] = array[(i<<1)+1];
01361         }
01362 
01363         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_from_array(x%x) = x%x\n", array, data);
01364         return data;
01365 }
01366 
01367 /*
01368  *                      B N _ T A B D A T A _ F R E Q _ S H I F T
01369  *@brief
01370  *  Shift the data by a constant offset in the independent variable
01371  *  (often frequency), interpolating new sample values.
01372  */
01373 void
01374 bn_tabdata_freq_shift(struct bn_tabdata *out, const struct bn_tabdata *in, double offset)
01375 {
01376         const struct bn_table   *tabp;
01377         register int            i;
01378 
01379         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_freq_shift(x%x, x%x, offset=%g)\n", out, in, offset);
01380 
01381         BN_CK_TABDATA( out );
01382         BN_CK_TABDATA( in );
01383         tabp = in->table;
01384 
01385         if( tabp != out->table )
01386                 bu_bomb("bn_tabdata_freq_shift(): samples drawn from different tables\n");
01387         if( in->ny != out->ny )
01388                 bu_bomb("bn_tabdata_freq_shift(): different tabdata lengths?\n");
01389 
01390         for( i=0; i < out->ny; i++ ) {
01391                 out->y[i] = bn_table_lin_interp( in, tabp->x[i]+offset );
01392         }
01393 }
01394 
01395 /*
01396  *                      B N _ T A B L E _ I N T E R V A L _ N U M _ S A M P L E S
01397  *@brief
01398  *  Returns number of sample points between 'low' and 'hi', inclusive.
01399  */
01400 int
01401 bn_table_interval_num_samples(const struct bn_table *tabp, double low, double hi)
01402 {
01403         register int    i;
01404         register int    count = 0;
01405 
01406         BN_CK_TABLE(tabp);
01407 
01408         for( i=0; i < tabp->nx-1; i++ )  {
01409                 if( tabp->x[i] >= low && tabp->x[i] <= hi )  count++;
01410         }
01411 
01412         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_interval_num_samples(x%x, low=%g, hi=%g) = %d\n", tabp, low, hi, count);
01413         return count;
01414 }
01415 
01416 /*
01417  *                      B N _ T A B L E _ D E L E T E _ S A M P L E _ P T S
01418  *@brief
01419  *  Remove all sampling points between subscripts i and j, inclusive.
01420  *  Don't bother freeing the tiny bit of storage at the end of the array.
01421  *  Returns number of points removed.
01422  */
01423 int
01424 bn_table_delete_sample_pts(struct bn_table *tabp, int i, int j)
01425 {
01426         int     tokill;
01427         int     k;
01428 
01429         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_delete_samples(x%x, %d, %d)\n", tabp, i, j);
01430 
01431         BN_CK_TABLE(tabp);
01432 
01433         if( i < 0 || j < 0 )  bu_bomb("bn_table_delete_sample_pts() negative indices\n");
01434         if( i >= tabp->nx || j >= tabp->nx )  bu_bomb("bn_table_delete_sample_pts() index out of range\n");
01435 
01436         tokill = j - i + 1;
01437         if( tokill < 1 )  bu_bomb("bn_table_delete_sample_pts(): nothing to delete\n");
01438         if( tokill >= tabp->nx ) bu_bomb("bn_table_delete_sample_pts(): you can't kill 'em all!\n");
01439 
01440         tabp->nx -= tokill;
01441 
01442         for( k = i; k < tabp->nx; k++ )  {
01443                 tabp->x[k] = tabp->x[k+tokill];
01444         }
01445         return tokill;
01446 }
01447 
01448 /*
01449  *                      B N _ T A B L E _ M E R G E 2
01450  *@brief
01451  *  A new table is returned which has sample points at places from
01452  *  each of the input tables.
01453  */
01454 struct bn_table *
01455 bn_table_merge2(const struct bn_table *a, const struct bn_table *b)
01456 {
01457         struct bn_table *new;
01458         register int i, j, k;
01459 
01460         BN_CK_TABLE(a);
01461         BN_CK_TABLE(b);
01462 
01463         BN_GET_TABLE(new, a->nx + b->nx + 2 );
01464 
01465         i = j = 0;              /* input subscripts */
01466         k = 0;                  /* output subscript */
01467         while( i <= a->nx || j <= b->nx )  {
01468                 if( i > a->nx )  {
01469                         while( j <= b->nx )
01470                                 new->x[k++] = b->x[j++];
01471                         break;
01472                 }
01473                 if( j > b->nx )  {
01474                         while( i <= a->nx )
01475                                 new->x[k++] = a->x[i++];
01476                         break;
01477                 }
01478                 /* Both have remaining elements, take lower one */
01479                 if( a->x[i] == b->x[j] )  {
01480                         new->x[k++] = a->x[i++];
01481                         j++;            /* compress out duplicate */
01482                         continue;
01483                 }
01484                 if( a->x[i] <= b->x[j] )  {
01485                         new->x[k++] = a->x[i++];
01486                 } else {
01487                         new->x[k++] = b->x[j++];
01488                 }
01489         }
01490         if( k > new->nx )  bu_bomb("bn_table_merge2() assertion failed, k>nx?\n");
01491         new->nx = k-1;
01492 
01493         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_table_merge2(x%x, x%x) = x%x\n", a, b, new);
01494         return new;
01495 }
01496 
01497 /*
01498  *              B N _ T A B D A T A _ M K _ L I N E A R _ F I L T E R
01499  *@brief
01500  *  Create a filter to accept power in a given band.
01501  *  The first and last filter values will be in the range 0..1,
01502  *  while all the internal filter values will be 1.0,
01503  *  and all samples outside the given band will be 0.0.
01504  *
01505  *
01506  *  @return     NULL    if given band does not overlap input spectrum
01507  *  @return     tabdata*
01508  */
01509 struct bn_tabdata *
01510 bn_tabdata_mk_linear_filter(const struct bn_table *spectrum, double lower_wavelen, double upper_wavelen)
01511 {
01512         struct bn_tabdata *filt;
01513         int     first;
01514         int     last;
01515         fastf_t filt_range;
01516         fastf_t cell_range;
01517         fastf_t frac;
01518         int     i;
01519 
01520         BN_CK_TABLE(spectrum);
01521 
01522         if(bu_debug&BU_DEBUG_TABDATA) bu_log("bn_tabdata_mk_linear_filter(x%x, low=%g, up=%g)\n", spectrum, lower_wavelen, upper_wavelen);
01523 
01524         if( lower_wavelen < spectrum->x[0] )
01525         if( upper_wavelen > spectrum->x[spectrum->nx] )
01526                 bu_log("bn_tabdata_mk_linear_filter() warning, upper_wavelen %g > hightest sampled wavelen %g\n",
01527                         upper_wavelen, spectrum->x[spectrum->nx] );
01528 
01529         /* First, find first (possibly partial) sample */
01530         first = bn_table_find_x( spectrum, lower_wavelen );
01531         if( first == -1 )  {
01532                 first = 0;
01533                 bu_log("bn_tabdata_mk_linear_filter() warning, lower_wavelen %g < lowest sampled wavelen %g\n",
01534                         lower_wavelen, spectrum->x[0] );
01535         } else if( first <= -2 )  {
01536                 bu_log("bn_tabdata_mk_linear_filter() ERROR, lower_wavelen %g > highest sampled wavelen %g\n",
01537                         lower_wavelen, spectrum->x[spectrum->nx] );
01538                 return NULL;
01539         }
01540 
01541         /* Second, find last (possibly partial) sample */
01542         last = bn_table_find_x( spectrum, upper_wavelen );
01543         if( last == -1 )  {
01544                 bu_log("bn_tabdata_mk_linear_filter() ERROR, upper_wavelen %g < lowest sampled wavelen %g\n",
01545                         upper_wavelen, spectrum->x[0] );
01546                 return NULL;
01547         } else if( last <= -2 )  {
01548                 last = spectrum->nx-1;
01549                 bu_log("bn_tabdata_mk_linear_filter() warning, upper_wavelen %g > highest sampled wavelen %g\n",
01550                         upper_wavelen, spectrum->x[spectrum->nx] );
01551         }
01552 
01553         /* 'filt' is filled with zeros by default */
01554         BN_GET_TABDATA( filt, spectrum );
01555 
01556         /* Special case:  first and last are in same sample cell */
01557         if( first == last )  {
01558                 filt_range = upper_wavelen - lower_wavelen;
01559                 cell_range = spectrum->x[first+1] - spectrum->x[first];
01560                 frac = filt_range / cell_range;
01561 
01562                 /* Could use a BU_ASSERT_RANGE_FLOAT */
01563                 BU_ASSERT( (frac >= 0.0) && (frac <= 1.0) );
01564 
01565                 filt->y[first] = frac;
01566                 return filt;
01567         }
01568 
01569         /* Calculate fraction 0..1.0 for first and last samples */
01570         filt_range = spectrum->x[first+1] - lower_wavelen;
01571         cell_range = spectrum->x[first+1] - spectrum->x[first];
01572         frac = filt_range / cell_range;
01573         if( frac > 1 )  frac = 1;
01574         BU_ASSERT( (frac >= 0.0) && (frac <= 1.0) );
01575         filt->y[first] = frac;
01576 
01577         filt_range = upper_wavelen - spectrum->x[last];
01578         cell_range = spectrum->x[last+1] - spectrum->x[last];
01579         frac = filt_range / cell_range;
01580         if( frac > 1 )  frac = 1;
01581         BU_ASSERT( (frac >= 0.0) && (frac <= 1.0) );
01582         filt->y[last] = frac;
01583 
01584         /* Fill in range between with 1.0 values */
01585         for( i = first+1; i < last; i++ )
01586                 filt->y[i] = 1.0;
01587 
01588         return filt;
01589 }
01590 /*@}*/
01591 /*
01592  * Local Variables:
01593  * mode: C
01594  * tab-width: 8
01595  * c-basic-offset: 4
01596  * indent-tabs-mode: t
01597  * End:
01598  * ex: shiftwidth=4 tabstop=8
01599  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6