use glam::{Vec3, Vec4};
use polyscope_core::quantity::{Quantity, QuantityKind};
use super::ImageOrigin;
pub struct FloatingColorImage {
name: String,
width: u32,
height: u32,
colors: Vec<Vec4>, origin: ImageOrigin,
enabled: bool,
}
impl FloatingColorImage {
pub fn new(name: impl Into<String>, width: u32, height: u32, colors: Vec<Vec3>) -> Self {
let colors = colors.into_iter().map(|c| c.extend(1.0)).collect();
Self {
name: name.into(),
width,
height,
colors,
origin: ImageOrigin::default(),
enabled: true,
}
}
#[must_use]
pub fn width(&self) -> u32 {
self.width
}
#[must_use]
pub fn height(&self) -> u32 {
self.height
}
#[must_use]
pub fn colors(&self) -> &[Vec4] {
&self.colors
}
#[must_use]
pub fn origin(&self) -> ImageOrigin {
self.origin
}
pub fn set_origin(&mut self, origin: ImageOrigin) -> &mut Self {
self.origin = origin;
self
}
#[must_use]
pub fn pixel(&self, x: u32, y: u32) -> Vec4 {
let row = match self.origin {
ImageOrigin::UpperLeft => y,
ImageOrigin::LowerLeft => self.height - 1 - y,
};
self.colors[(row * self.width + x) as usize]
}
}
impl Quantity for FloatingColorImage {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn name(&self) -> &str {
&self.name
}
#[allow(clippy::unnecessary_literal_bound)]
fn structure_name(&self) -> &str {
"" }
fn kind(&self) -> QuantityKind {
QuantityKind::Color
}
fn is_enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn build_ui(&mut self, _ui: &dyn std::any::Any) {}
fn refresh(&mut self) {}
fn data_size(&self) -> usize {
self.colors.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_color_image_creation() {
let colors = vec![
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(1.0, 1.0, 1.0),
];
let img = FloatingColorImage::new("test", 2, 2, colors);
assert_eq!(img.name(), "test");
assert_eq!(img.width(), 2);
assert_eq!(img.height(), 2);
assert_eq!(img.data_size(), 4);
assert_eq!(img.kind(), QuantityKind::Color);
}
#[test]
fn test_color_image_pixel_access() {
let colors = vec![
Vec3::new(1.0, 0.0, 0.0), Vec3::new(0.0, 1.0, 0.0), Vec3::new(0.0, 0.0, 1.0), Vec3::new(1.0, 1.0, 1.0), ];
let img = FloatingColorImage::new("test", 2, 2, colors);
assert_eq!(img.pixel(0, 0), Vec4::new(1.0, 0.0, 0.0, 1.0));
assert_eq!(img.pixel(1, 0), Vec4::new(0.0, 1.0, 0.0, 1.0));
assert_eq!(img.pixel(0, 1), Vec4::new(0.0, 0.0, 1.0, 1.0));
assert_eq!(img.pixel(1, 1), Vec4::new(1.0, 1.0, 1.0, 1.0));
}
#[test]
fn test_color_image_lower_left_origin() {
let colors = vec![
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(1.0, 1.0, 1.0),
];
let mut img = FloatingColorImage::new("test", 2, 2, colors);
img.set_origin(ImageOrigin::LowerLeft);
assert_eq!(img.pixel(0, 0), Vec4::new(0.0, 0.0, 1.0, 1.0));
assert_eq!(img.pixel(1, 0), Vec4::new(1.0, 1.0, 1.0, 1.0));
assert_eq!(img.pixel(0, 1), Vec4::new(1.0, 0.0, 0.0, 1.0));
assert_eq!(img.pixel(1, 1), Vec4::new(0.0, 1.0, 0.0, 1.0));
}
}