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()
}
}