devela/media/color/spectral/
refed.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// devela::media::color::spectral::refed

use crate::{ColorBase, Interval, Ordering};
#[cfg(feature = "alloc")]
use crate::{ToOwned, Vec};

/// A borrowed chromatic representation based on sampled spectral data.
///
/// Represents a color as intensity values over sampled wavelengths, with an
/// optional range for the spectral domain.
///
/// # Type Parameters
/// - `C`: The type of the spectral intensity components (e.g., `f32`, `f64`).
#[derive(Clone, Default)]
pub struct SpectralColorRef<'a, C> {
    /// Intensity values for each sampled wavelength.
    pub wavelengths: &'a [C],

    /// The range of the sampled wavelengths.
    ///
    /// If specified, the interval defines the lower and upper bounds of the
    /// sampled spectral range (e.g., 380–780 nm for visible light).
    pub range: Option<Interval<C>>,
}

// TODO
// impl<'a, C> ColorBase for SpectralColorRef<'a, C> {
//     ///
//     #[cfg(feature = "alloc")]
//     pub fn into_owned(self) -> SpectralColor {
//     }
// }

impl<C: Copy> ColorBase for SpectralColorRef<'_, C> {
    type Component = C;

    fn color_component_count(&self) -> usize {
        self.wavelengths.len()
    }

    fn color_components_write(&self, buffer: &mut [Self::Component]) {
        assert!(buffer.len() >= self.color_component_count(), "Buffer too small!");
        buffer[..self.wavelengths.len()].copy_from_slice(self.wavelengths);
    }
    #[cfg(feature = "alloc")]
    fn color_components_vec(&self) -> Vec<Self::Component> {
        self.wavelengths.to_owned()
    }
}

impl<'a, C: Copy + PartialOrd> SpectralColorRef<'a, C> {
    /// Creates a new `SpectralColor` with the given sampled intensities and optional range.
    ///
    /// # Parameters
    /// - `wavelengths`: A vector of intensity values for sampled wavelengths.
    /// - `range`: An optional interval defining the spectral range.
    ///
    /// # Panics
    /// Panics if the provided vector is empty.
    pub fn new(wavelengths: &'a [C], range: Option<Interval<C>>) -> Self {
        assert!(!wavelengths.is_empty(), "SpectralColor must have at least one sample.");
        Self { wavelengths, range }
    }

    /// Returns the number of sampled wavelengths.
    #[inline]
    pub fn sample_count(&self) -> usize {
        self.wavelengths.len()
    }

    /// Returns the intensity at the given sample index.
    ///
    /// # Parameters
    /// - `index`: The index of the sample to retrieve.
    ///
    /// # Panics
    /// Panics if the index is out of bounds.
    pub fn intensity_at(&self, index: usize) -> C {
        self.wavelengths[index]
    }

    /// Returns the maximum intensity value across all sampled wavelengths.
    #[inline]
    pub fn max_intensity(&self) -> C {
        *self
            .wavelengths
            .iter()
            .max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
            .unwrap()
    }
}