00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #ifndef lint
00047 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/spectrum.c,v 14.10 2006/09/16 02:04:26 lbutler Exp $ (ARL)";
00048 #endif
00049
00050 #include "common.h"
00051
00052 #include <stdio.h>
00053 #include <math.h>
00054 #include "machine.h"
00055 #include "vmath.h"
00056 #include "raytrace.h"
00057 #include "spectrum.h"
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 const double rt_CIE_XYZ[81][4] = {
00068 {380, 0.0014, 0.0000, 0.0065}, {385, 0.0022, 0.0001, 0.0105},
00069 {390, 0.0042, 0.0001, 0.0201}, {395, 0.0076, 0.0002, 0.0362},
00070 {400, 0.0143, 0.0004, 0.0679}, {405, 0.0232, 0.0006, 0.1102},
00071 {410, 0.0435, 0.0012, 0.2074}, {415, 0.0776, 0.0022, 0.3713},
00072 {420, 0.1344, 0.0040, 0.6456}, {425, 0.2148, 0.0073, 1.0391},
00073 {430, 0.2839, 0.0116, 1.3856}, {435, 0.3285, 0.0168, 1.6230},
00074 {440, 0.3483, 0.0230, 1.7471}, {445, 0.3481, 0.0298, 1.7826},
00075 {450, 0.3362, 0.0380, 1.7721}, {455, 0.3187, 0.0480, 1.7441},
00076 {460, 0.2908, 0.0600, 1.6692}, {465, 0.2511, 0.0739, 1.5281},
00077 {470, 0.1954, 0.0910, 1.2876}, {475, 0.1421, 0.1126, 1.0419},
00078 {480, 0.0956, 0.1390, 0.8130}, {485, 0.0580, 0.1693, 0.6162},
00079 {490, 0.0320, 0.2080, 0.4652}, {495, 0.0147, 0.2586, 0.3533},
00080 {500, 0.0049, 0.3230, 0.2720}, {505, 0.0024, 0.4073, 0.2123},
00081 {510, 0.0093, 0.5030, 0.1582}, {515, 0.0291, 0.6082, 0.1117},
00082 {520, 0.0633, 0.7100, 0.0782}, {525, 0.1096, 0.7932, 0.0573},
00083 {530, 0.1655, 0.8620, 0.0422}, {535, 0.2257, 0.9149, 0.0298},
00084 {540, 0.2904, 0.9540, 0.0203}, {545, 0.3597, 0.9803, 0.0134},
00085 {550, 0.4334, 0.9950, 0.0087}, {555, 0.5121, 1.0000, 0.0057},
00086 {560, 0.5945, 0.9950, 0.0039}, {565, 0.6784, 0.9786, 0.0027},
00087 {570, 0.7621, 0.9520, 0.0021}, {575, 0.8425, 0.9154, 0.0018},
00088 {580, 0.9163, 0.8700, 0.0017}, {585, 0.9786, 0.8163, 0.0014},
00089 {590, 1.0263, 0.7570, 0.0011}, {595, 1.0567, 0.6949, 0.0010},
00090 {600, 1.0622, 0.6310, 0.0008}, {605, 1.0456, 0.5668, 0.0006},
00091 {610, 1.0026, 0.5030, 0.0003}, {615, 0.9384, 0.4412, 0.0002},
00092 {620, 0.8544, 0.3810, 0.0002}, {625, 0.7514, 0.3210, 0.0001},
00093 {630, 0.6424, 0.2650, 0.0000}, {635, 0.5419, 0.2170, 0.0000},
00094 {640, 0.4479, 0.1750, 0.0000}, {645, 0.3608, 0.1382, 0.0000},
00095 {650, 0.2835, 0.1070, 0.0000}, {655, 0.2187, 0.0816, 0.0000},
00096 {660, 0.1649, 0.0610, 0.0000}, {665, 0.1212, 0.0446, 0.0000},
00097 {670, 0.0874, 0.0320, 0.0000}, {675, 0.0636, 0.0232, 0.0000},
00098 {680, 0.0468, 0.0170, 0.0000}, {685, 0.0329, 0.0119, 0.0000},
00099 {690, 0.0227, 0.0082, 0.0000}, {695, 0.0158, 0.0057, 0.0000},
00100 {700, 0.0114, 0.0041, 0.0000}, {705, 0.0081, 0.0029, 0.0000},
00101 {710, 0.0058, 0.0021, 0.0000}, {715, 0.0041, 0.0015, 0.0000},
00102 {720, 0.0029, 0.0010, 0.0000}, {725, 0.0020, 0.0007, 0.0000},
00103 {730, 0.0014, 0.0005, 0.0000}, {735, 0.0010, 0.0004, 0.0000},
00104 {740, 0.0007, 0.0002, 0.0000}, {745, 0.0005, 0.0002, 0.0000},
00105 {750, 0.0003, 0.0001, 0.0000}, {755, 0.0002, 0.0001, 0.0000},
00106 {760, 0.0002, 0.0001, 0.0000}, {765, 0.0001, 0.0000, 0.0000},
00107 {770, 0.0001, 0.0000, 0.0000}, {775, 0.0001, 0.0000, 0.0000},
00108 {780, 0.0000, 0.0000, 0.0000}
00109 };
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 void
00126 rt_spect_make_CIE_XYZ(struct bn_tabdata **x, struct bn_tabdata **y, struct bn_tabdata **z, const struct bn_table *tabp)
00127 {
00128 struct bn_tabdata *a, *b, *c;
00129 fastf_t xyz_scale;
00130 int i;
00131 int j;
00132
00133 BN_CK_TABLE(tabp);
00134
00135 i = bn_table_interval_num_samples( tabp, 430., 650. );
00136 if( i <= 4 ) bu_log("rt_spect_make_CIE_XYZ: insufficient samples (%d) in visible band\n", i);
00137
00138 BN_GET_TABDATA( a, tabp );
00139 BN_GET_TABDATA( b, tabp );
00140 BN_GET_TABDATA( c, tabp );
00141 *x = a;
00142 *y = b;
00143 *z = c;
00144
00145
00146 for( j=0; tabp->x[j] < 380 && j < tabp->nx; j++ ) {
00147 a->y[j] = b->y[j] = c->y[j] = 0;
00148 }
00149
00150
00151
00152
00153 for( i = 0; i < 81-1; i++ ) {
00154 FAST fastf_t fract;
00155
00156 again:
00157 if( j >= tabp->nx ) break;
00158 if( tabp->x[j] < rt_CIE_XYZ[i][0] ) rt_bomb("rt_spect_make_CIE_XYZ assertion1 failed\n");
00159 if( tabp->x[j] >= rt_CIE_XYZ[i+1][0] ) continue;
00160
00161 fract = (tabp->x[j] - rt_CIE_XYZ[i][0] ) / 5;
00162 if( fract < 0 || fract > 1 ) rt_bomb("rt_spect_make_CIE_XYZ assertion2 failed\n");
00163 a->y[j] = (1-fract) * rt_CIE_XYZ[i][1] + fract * rt_CIE_XYZ[i+1][1];
00164 b->y[j] = (1-fract) * rt_CIE_XYZ[i][2] + fract * rt_CIE_XYZ[i+1][2];
00165 c->y[j] = (1-fract) * rt_CIE_XYZ[i][3] + fract * rt_CIE_XYZ[i+1][3];
00166 j++;
00167 goto again;
00168 }
00169
00170
00171 for( ; j < tabp->nx; j++ ) {
00172 a->y[j] = b->y[j] = c->y[j] = 0;
00173 }
00174
00175
00176 xyz_scale = bn_tabdata_area2( b );
00177 if( fabs(xyz_scale) < VDIVIDE_TOL ) {
00178 rt_log("rt_spect_make_CIE_XYZ(): Area = 0 (no luminance) in this part of the spectrum, skipping normalization step\n");
00179 return;
00180 }
00181 xyz_scale = 1 / xyz_scale;
00182 bn_tabdata_scale( a, a, xyz_scale );
00183 bn_tabdata_scale( b, b, xyz_scale );
00184 bn_tabdata_scale( c, c, xyz_scale );
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 void
00206 rt_spect_reflectance_rgb(struct bn_tabdata *curve, const float *rgb)
00207 {
00208 register int i;
00209 register const struct bn_table *tabp;
00210
00211 BN_CK_TABDATA(curve);
00212 tabp = curve->table;
00213 BN_CK_TABLE(tabp);
00214
00215
00216 for( i=0; i < tabp->nx; i++ ) {
00217 if( tabp->x[i] >= 492 ) break;
00218 curve->y[i] = rgb[2];
00219 }
00220
00221
00222 for( ; i < tabp->nx; i++ ) {
00223 if( tabp->x[i] >= 572 ) break;
00224 curve->y[i] = rgb[1];
00225 }
00226
00227
00228 for( ; i < tabp->nx; i++ ) {
00229 curve->y[i] = rgb[0];
00230 }
00231 }
00232
00233 #define PLANCK_C1 37415
00234 #define PLANCK_C2 14387.86
00235
00236
00237
00238
00239
00240 #define PLANCK(_w,_tempK) \
00241 (PLANCK_C1/(_w*_w*_w*_w*_w*(exp(PLANCK_C2/(_w*_tempK))-1)))
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 void
00254 rt_spect_black_body(struct bn_tabdata *data, double temp, unsigned int n)
00255
00256
00257
00258 {
00259 const struct bn_table *tabp;
00260 int j;
00261
00262 BN_CK_TABDATA(data);
00263 tabp = data->table;
00264 BN_CK_TABLE(tabp);
00265
00266 if(bu_debug&BU_DEBUG_TABDATA) {
00267 bu_log("rt_spect_black_body( x%x, %g degK ) %g um to %g um\n",
00268 data, temp,
00269 tabp->x[0] * 0.001,
00270 tabp->x[tabp->nx] * 0.001
00271 );
00272 }
00273
00274 if( n < 3 ) n = 3;
00275
00276 for( j = 0; j < tabp->nx; j++ ) {
00277 double ax;
00278 double bx;
00279 double dx;
00280 double w_sum;
00281 double wavlen;
00282 unsigned long i;
00283
00284 ax = tabp->x[j] * 0.001;
00285 bx = tabp->x[j+1] * 0.001;
00286 dx = (bx - ax) / (double)n;
00287
00288 w_sum = 0;
00289 wavlen = ax;
00290 for (i=0; i<n; i++) {
00291 w_sum += PLANCK(wavlen, temp);
00292 wavlen += dx;
00293 }
00294 w_sum *= dx;
00295
00296 data->y[j] = w_sum;
00297 }
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 void
00313 rt_spect_black_body_fast(struct bn_tabdata *data, double temp)
00314
00315
00316 {
00317 const struct bn_table *tabp;
00318 int j;
00319
00320 BN_CK_TABDATA(data);
00321 tabp = data->table;
00322 BN_CK_TABLE(tabp);
00323
00324 if(bu_debug&BU_DEBUG_TABDATA) {
00325 bu_log("rt_spect_black_body_fast( x%x, %g degK )\n",
00326 data, temp );
00327 }
00328
00329 for( j = 0; j < tabp->nx; j++ ) {
00330 data->y[j] = PLANCK( (tabp->x[j]*0.001), temp ) *
00331 (tabp->x[j+1] - tabp->x[j]) * 0.001;
00332 }
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342 void
00343 rt_spect_black_body_points(struct bn_tabdata *data, double temp)
00344
00345
00346 {
00347 const struct bn_table *tabp;
00348 int j;
00349
00350 BN_CK_TABDATA(data);
00351 tabp = data->table;
00352 BN_CK_TABLE(tabp);
00353
00354 if(bu_debug&BU_DEBUG_TABDATA) {
00355 bu_log("rt_spect_black_body_points( x%x, %g degK )\n",
00356 data, temp );
00357 }
00358
00359 for( j = 0; j < tabp->nx; j++ ) {
00360 data->y[j] = PLANCK( (tabp->x[j]*0.001), temp );
00361 }
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372