1#![allow(clippy::excessive_precision)]
4
5use core::marker::PhantomData;
6
7use crate::BackingStore;
8use crate::observer::{Cie1931, StandardObserver};
9
10pub trait SpectralKind: 'static {}
23
24#[derive(Debug, Clone, Copy)]
29pub struct IsRadiance;
30
31#[derive(Debug, Clone, Copy)]
37pub struct IsReflectance;
38
39#[derive(Debug, Clone, Copy)]
45pub struct IsTransmittance;
46
47#[derive(Debug, Clone, Copy)]
62pub struct IsBispectral;
63
64impl SpectralKind for IsRadiance {}
65impl SpectralKind for IsReflectance {}
66impl SpectralKind for IsTransmittance {}
67impl SpectralKind for IsBispectral {}
68
69pub trait SpectralSpace: 'static {
74 type Kind: SpectralKind;
76}
77
78pub trait Radiance: SpectralSpace<Kind = IsRadiance> {}
80impl<M: SpectralSpace<Kind = IsRadiance>> Radiance for M {}
81
82pub trait Reflectance: SpectralSpace<Kind = IsReflectance> {}
84impl<M: SpectralSpace<Kind = IsReflectance>> Reflectance for M {}
85
86pub trait Transmittance: SpectralSpace<Kind = IsTransmittance> {}
88impl<M: SpectralSpace<Kind = IsTransmittance>> Transmittance for M {}
89
90pub trait Bispectral: SpectralSpace<Kind = IsBispectral> {}
92impl<M: SpectralSpace<Kind = IsBispectral>> Bispectral for M {}
93
94pub trait WavelengthGrid<const BANDS: usize>: 'static {
115 const START_NM: f32;
117 const STEP_NM: f32;
119}
120
121pub trait ColorMatchingFunctions<const BANDS: usize, O: StandardObserver>:
123 WavelengthGrid<BANDS>
124{
125 const CMF_X: &'static [f32; BANDS];
127 const CMF_Y: &'static [f32; BANDS];
129 const CMF_Z: &'static [f32; BANDS];
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
143pub struct Spectral<const BANDS: usize, G, K>(PhantomData<(G, K)>);
144
145impl<const BANDS: usize, G, K> SpectralSpace for Spectral<BANDS, G, K>
146where
147 G: WavelengthGrid<BANDS>,
148 K: SpectralKind,
149{
150 type Kind = K;
151}
152
153impl<const BANDS: usize, G> BackingStore<[f32; BANDS]> for Spectral<BANDS, G, IsRadiance> where
154 G: WavelengthGrid<BANDS>
155{
156}
157
158impl<const BANDS: usize, G> BackingStore<[f32; BANDS]> for Spectral<BANDS, G, IsReflectance> where
159 G: WavelengthGrid<BANDS>
160{
161}
162
163impl<const BANDS: usize, G> BackingStore<[f32; BANDS]> for Spectral<BANDS, G, IsTransmittance> where
164 G: WavelengthGrid<BANDS>
165{
166}
167
168#[derive(Debug, Clone, Copy)]
174pub struct Grid380_780_10nm;
175
176impl WavelengthGrid<41> for Grid380_780_10nm {
177 const START_NM: f32 = 380.0;
178 const STEP_NM: f32 = 10.0;
179}
180
181impl ColorMatchingFunctions<41, Cie1931> for Grid380_780_10nm {
182 #[rustfmt::skip]
183 const CMF_X: &'static [f32; 41] = &[
184 0.001368, 0.004243, 0.014310, 0.043510, 0.134380,
185 0.283900, 0.348280, 0.336200, 0.290800, 0.195360,
186 0.095640, 0.032010, 0.004900, 0.009300, 0.063270,
187 0.165500, 0.290400, 0.433450, 0.594500, 0.762100,
188 0.916300, 1.026300, 1.062200, 1.002600, 0.854450,
189 0.642400, 0.447900, 0.283500, 0.164900, 0.087400,
190 0.046770, 0.022700, 0.011359, 0.005790, 0.002899,
191 0.001440, 0.000690, 0.000332, 0.000166, 0.000083,
192 0.000042,
193 ];
194 #[rustfmt::skip]
195 const CMF_Y: &'static [f32; 41] = &[
196 0.000039, 0.000120, 0.000396, 0.001210, 0.004000,
197 0.011600, 0.023000, 0.038000, 0.060000, 0.090980,
198 0.139020, 0.208020, 0.323000, 0.503000, 0.710000,
199 0.862000, 0.954000, 0.994950, 0.995000, 0.952000,
200 0.870000, 0.757000, 0.631000, 0.503000, 0.381000,
201 0.265000, 0.175000, 0.107000, 0.061000, 0.032000,
202 0.017000, 0.008210, 0.004102, 0.002091, 0.001047,
203 0.000520, 0.000249, 0.000120, 0.000060, 0.000030,
204 0.000015,
205 ];
206 #[rustfmt::skip]
207 const CMF_Z: &'static[f32; 41] = &[
208 0.006450, 0.020050, 0.067850, 0.207400, 0.645600,
209 1.385600, 1.747060, 1.772110, 1.669200, 1.287640,
210 0.812950, 0.465180, 0.272000, 0.158200, 0.078250,
211 0.042160, 0.020300, 0.008750, 0.003900, 0.002100,
212 0.001650, 0.001100, 0.000800, 0.000340, 0.000190,
213 0.000050, 0.000020, 0.000000, 0.000000, 0.000000,
214 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
215 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
216 0.000000,
217 ];
218}
219
220#[derive(Debug, Clone, Copy)]
226pub struct Grid380_730_10nm;
227
228impl WavelengthGrid<36> for Grid380_730_10nm {
229 const START_NM: f32 = 380.0;
230 const STEP_NM: f32 = 10.0;
231}
232
233impl ColorMatchingFunctions<36, Cie1931> for Grid380_730_10nm {
234 #[rustfmt::skip]
235 const CMF_X: &'static[f32; 36] = &[
236 0.001368, 0.004243, 0.014310, 0.043510, 0.134380,
237 0.283900, 0.348280, 0.336200, 0.290800, 0.195360,
238 0.095640, 0.032010, 0.004900, 0.009300, 0.063270,
239 0.165500, 0.290400, 0.433450, 0.594500, 0.762100,
240 0.916300, 1.026300, 1.062200, 1.002600, 0.854450,
241 0.642400, 0.447900, 0.283500, 0.164900, 0.087400,
242 0.046770, 0.022700, 0.011359, 0.005790, 0.002899,
243 0.001440,
244 ];
245 #[rustfmt::skip]
246 const CMF_Y: &'static [f32; 36] = &[
247 0.000039, 0.000120, 0.000396, 0.001210, 0.004000,
248 0.011600, 0.023000, 0.038000, 0.060000, 0.090980,
249 0.139020, 0.208020, 0.323000, 0.503000, 0.710000,
250 0.862000, 0.954000, 0.994950, 0.995000, 0.952000,
251 0.870000, 0.757000, 0.631000, 0.503000, 0.381000,
252 0.265000, 0.175000, 0.107000, 0.061000, 0.032000,
253 0.017000, 0.008210, 0.004102, 0.002091, 0.001047,
254 0.000520,
255 ];
256 #[rustfmt::skip]
257 const CMF_Z: &'static [f32; 36] = &[
258 0.006450, 0.020050, 0.067850, 0.207400, 0.645600,
259 1.385600, 1.747060, 1.772110, 1.669200, 1.287640,
260 0.812950, 0.465180, 0.272000, 0.158200, 0.078250,
261 0.042160, 0.020300, 0.008750, 0.003900, 0.002100,
262 0.001650, 0.001100, 0.000800, 0.000340, 0.000190,
263 0.000050, 0.000020, 0.000000, 0.000000, 0.000000,
264 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
265 0.000000,
266 ];
267}
268
269#[derive(Debug, Clone, Copy)]
274pub struct Grid400_700_10nm;
275
276impl WavelengthGrid<31> for Grid400_700_10nm {
277 const START_NM: f32 = 400.0;
278 const STEP_NM: f32 = 10.0;
279}
280
281impl ColorMatchingFunctions<31, Cie1931> for Grid400_700_10nm {
282 #[rustfmt::skip]
283 const CMF_X: &'static [f32; 31] = &[
284 0.014310, 0.043510, 0.134380,
285 0.283900, 0.348280, 0.336200, 0.290800, 0.195360,
286 0.095640, 0.032010, 0.004900, 0.009300, 0.063270,
287 0.165500, 0.290400, 0.433450, 0.594500, 0.762100,
288 0.916300, 1.026300, 1.062200, 1.002600, 0.854450,
289 0.642400, 0.447900, 0.283500, 0.164900, 0.087400,
290 0.046770, 0.022700, 0.011359,
291 ];
292 #[rustfmt::skip]
293 const CMF_Y: &'static [f32; 31] = &[
294 0.000396, 0.001210, 0.004000,
295 0.011600, 0.023000, 0.038000, 0.060000, 0.090980,
296 0.139020, 0.208020, 0.323000, 0.503000, 0.710000,
297 0.862000, 0.954000, 0.994950, 0.995000, 0.952000,
298 0.870000, 0.757000, 0.631000, 0.503000, 0.381000,
299 0.265000, 0.175000, 0.107000, 0.061000, 0.032000,
300 0.017000, 0.008210, 0.004102,
301 ];
302 #[rustfmt::skip]
303 const CMF_Z: &'static [f32; 31] = &[
304 0.067850, 0.207400, 0.645600,
305 1.385600, 1.747060, 1.772110, 1.669200, 1.287640,
306 0.812950, 0.465180, 0.272000, 0.158200, 0.078250,
307 0.042160, 0.020300, 0.008750, 0.003900, 0.002100,
308 0.001650, 0.001100, 0.000800, 0.000340, 0.000190,
309 0.000050, 0.000020, 0.000000, 0.000000, 0.000000,
310 0.000000, 0.000000, 0.000000,
311 ];
312}
313
314#[derive(Debug, Clone, Copy)]
320pub struct Grid380_780_5nm;
321
322impl WavelengthGrid<81> for Grid380_780_5nm {
323 const START_NM: f32 = 380.0;
324 const STEP_NM: f32 = 5.0;
325}
326
327impl ColorMatchingFunctions<81, Cie1931> for Grid380_780_5nm {
328 #[rustfmt::skip]
329 const CMF_X: &'static [f32; 81] = &[
330 0.001368, 0.002236, 0.004243, 0.007650, 0.014310,
331 0.023190, 0.043510, 0.077630, 0.134380, 0.214770,
332 0.283900, 0.328500, 0.348280, 0.348060, 0.336200,
333 0.318700, 0.290800, 0.251100, 0.195360, 0.142100,
334 0.095640, 0.057950, 0.032010, 0.014700, 0.004900,
335 0.002400, 0.009300, 0.029100, 0.063270, 0.109600,
336 0.165500, 0.225750, 0.290400, 0.359700, 0.433450,
337 0.512050, 0.594500, 0.678400, 0.762100, 0.842500,
338 0.916300, 0.978600, 1.026300, 1.056700, 1.062200,
339 1.045600, 1.002600, 0.938400, 0.854450, 0.751400,
340 0.642400, 0.541900, 0.447900, 0.360800, 0.283500,
341 0.218700, 0.164900, 0.121200, 0.087400, 0.063600,
342 0.046770, 0.032900, 0.022700, 0.015840, 0.011359,
343 0.008111, 0.005790, 0.004109, 0.002899, 0.002049,
344 0.001440, 0.001000, 0.000690, 0.000476, 0.000332,
345 0.000235, 0.000166, 0.000117, 0.000083, 0.000059,
346 0.000042,
347 ];
348 #[rustfmt::skip]
349 const CMF_Y: &'static [f32; 81] = &[
350 0.000039, 0.000064, 0.000120, 0.000217, 0.000396,
351 0.000640, 0.001210, 0.002180, 0.004000, 0.007300,
352 0.011600, 0.016840, 0.023000, 0.029800, 0.038000,
353 0.048000, 0.060000, 0.073900, 0.090980, 0.112600,
354 0.139020, 0.169300, 0.208020, 0.258600, 0.323000,
355 0.407300, 0.503000, 0.608200, 0.710000, 0.793200,
356 0.862000, 0.914850, 0.954000, 0.980300, 0.994950,
357 1.000000, 0.995000, 0.978600, 0.952000, 0.915400,
358 0.870000, 0.816300, 0.757000, 0.694900, 0.631000,
359 0.566800, 0.503000, 0.441200, 0.381000, 0.321000,
360 0.265000, 0.217000, 0.175000, 0.138200, 0.107000,
361 0.081600, 0.061000, 0.044580, 0.032000, 0.023200,
362 0.017000, 0.011920, 0.008210, 0.005723, 0.004102,
363 0.002929, 0.002091, 0.001484, 0.001047, 0.000740,
364 0.000520, 0.000361, 0.000249, 0.000172, 0.000120,
365 0.000085, 0.000060, 0.000042, 0.000030, 0.000021,
366 0.000015,
367 ];
368 #[rustfmt::skip]
369 const CMF_Z: &'static [f32; 81] = &[
370 0.006450, 0.010550, 0.020050, 0.036210, 0.067850,
371 0.110200, 0.207400, 0.371300, 0.645600, 1.039050,
372 1.385600, 1.622960, 1.747060, 1.782600, 1.772110,
373 1.744100, 1.669200, 1.528100, 1.287640, 1.041900,
374 0.812950, 0.616200, 0.465180, 0.353300, 0.272000,
375 0.212300, 0.158200, 0.111700, 0.078250, 0.057250,
376 0.042160, 0.029840, 0.020300, 0.013400, 0.008750,
377 0.005750, 0.003900, 0.002750, 0.002100, 0.001800,
378 0.001650, 0.001400, 0.001100, 0.001000, 0.000800,
379 0.000600, 0.000340, 0.000240, 0.000190, 0.000100,
380 0.000050, 0.000030, 0.000020, 0.000010, 0.000000,
381 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
382 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
383 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
384 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
385 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
386 0.000000,
387 ];
388}
389
390pub type Spectral31Radiance = Spectral<31, Grid400_700_10nm, IsRadiance>;
392pub type Spectral31Reflectance = Spectral<31, Grid400_700_10nm, IsReflectance>;
394pub type Spectral31Transmittance = Spectral<31, Grid400_700_10nm, IsTransmittance>;
396pub type Spectral36Radiance = Spectral<36, Grid380_730_10nm, IsRadiance>;
398pub type Spectral36Reflectance = Spectral<36, Grid380_730_10nm, IsReflectance>;
400pub type Spectral36Transmittance = Spectral<36, Grid380_730_10nm, IsTransmittance>;
402pub type Spectral41Radiance = Spectral<41, Grid380_780_10nm, IsRadiance>;
404pub type Spectral41Reflectance = Spectral<41, Grid380_780_10nm, IsReflectance>;
406pub type Spectral41Transmittance = Spectral<41, Grid380_780_10nm, IsTransmittance>;
408pub type Spectral81Radiance = Spectral<81, Grid380_780_5nm, IsRadiance>;
410pub type Spectral81Reflectance = Spectral<81, Grid380_780_5nm, IsReflectance>;
412pub type Spectral81Transmittance = Spectral<81, Grid380_780_5nm, IsTransmittance>;