polyscope_structures/floating/
scalar_image.rs1use polyscope_core::quantity::{Quantity, QuantityKind};
4
5use super::ImageOrigin;
6
7pub struct FloatingScalarImage {
11 name: String,
12 width: u32,
13 height: u32,
14 values: Vec<f32>,
15 origin: ImageOrigin,
16 enabled: bool,
17 colormap_name: String,
18 data_min: f32,
19 data_max: f32,
20}
21
22impl FloatingScalarImage {
23 pub fn new(name: impl Into<String>, width: u32, height: u32, values: Vec<f32>) -> Self {
25 let min = values.iter().copied().fold(f32::INFINITY, f32::min);
26 let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
27
28 Self {
29 name: name.into(),
30 width,
31 height,
32 values,
33 origin: ImageOrigin::default(),
34 enabled: true,
35 colormap_name: "viridis".to_string(),
36 data_min: min,
37 data_max: max,
38 }
39 }
40
41 #[must_use]
43 pub fn width(&self) -> u32 {
44 self.width
45 }
46
47 #[must_use]
49 pub fn height(&self) -> u32 {
50 self.height
51 }
52
53 #[must_use]
55 pub fn values(&self) -> &[f32] {
56 &self.values
57 }
58
59 #[must_use]
61 pub fn origin(&self) -> ImageOrigin {
62 self.origin
63 }
64
65 pub fn set_origin(&mut self, origin: ImageOrigin) -> &mut Self {
67 self.origin = origin;
68 self
69 }
70
71 #[must_use]
73 pub fn colormap_name(&self) -> &str {
74 &self.colormap_name
75 }
76
77 pub fn set_colormap(&mut self, name: impl Into<String>) -> &mut Self {
79 self.colormap_name = name.into();
80 self
81 }
82
83 #[must_use]
85 pub fn data_min(&self) -> f32 {
86 self.data_min
87 }
88
89 #[must_use]
91 pub fn data_max(&self) -> f32 {
92 self.data_max
93 }
94
95 pub fn set_data_range(&mut self, min: f32, max: f32) -> &mut Self {
97 self.data_min = min;
98 self.data_max = max;
99 self
100 }
101
102 #[must_use]
104 pub fn pixel(&self, x: u32, y: u32) -> f32 {
105 let row = match self.origin {
106 ImageOrigin::UpperLeft => y,
107 ImageOrigin::LowerLeft => self.height - 1 - y,
108 };
109 self.values[(row * self.width + x) as usize]
110 }
111}
112
113impl Quantity for FloatingScalarImage {
114 fn as_any(&self) -> &dyn std::any::Any {
115 self
116 }
117 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
118 self
119 }
120 fn name(&self) -> &str {
121 &self.name
122 }
123 #[allow(clippy::unnecessary_literal_bound)]
124 fn structure_name(&self) -> &str {
125 "" }
127 fn kind(&self) -> QuantityKind {
128 QuantityKind::Other
129 }
130 fn is_enabled(&self) -> bool {
131 self.enabled
132 }
133 fn set_enabled(&mut self, enabled: bool) {
134 self.enabled = enabled;
135 }
136 fn build_ui(&mut self, _ui: &dyn std::any::Any) {}
137 fn refresh(&mut self) {}
138 fn data_size(&self) -> usize {
139 self.values.len()
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_scalar_image_creation() {
149 let values = vec![0.0, 0.5, 1.0, 1.5];
150 let img = FloatingScalarImage::new("test", 2, 2, values);
151
152 assert_eq!(img.name(), "test");
153 assert_eq!(img.width(), 2);
154 assert_eq!(img.height(), 2);
155 assert_eq!(img.data_size(), 4);
156 assert_eq!(img.data_min(), 0.0);
157 assert_eq!(img.data_max(), 1.5);
158 assert_eq!(img.kind(), QuantityKind::Other);
159 assert!(img.is_enabled());
160 }
161
162 #[test]
163 fn test_scalar_image_pixel_access() {
164 let values = vec![0.0, 1.0, 2.0, 3.0];
166 let img = FloatingScalarImage::new("test", 2, 2, values);
167
168 assert_eq!(img.pixel(0, 0), 0.0); assert_eq!(img.pixel(1, 0), 1.0); assert_eq!(img.pixel(0, 1), 2.0); assert_eq!(img.pixel(1, 1), 3.0); }
174
175 #[test]
176 fn test_scalar_image_lower_left_origin() {
177 let values = vec![0.0, 1.0, 2.0, 3.0];
178 let mut img = FloatingScalarImage::new("test", 2, 2, values);
179 img.set_origin(ImageOrigin::LowerLeft);
180
181 assert_eq!(img.pixel(0, 0), 2.0); assert_eq!(img.pixel(1, 0), 3.0);
184 assert_eq!(img.pixel(0, 1), 0.0); assert_eq!(img.pixel(1, 1), 1.0);
186 }
187
188 #[test]
189 fn test_scalar_image_setters() {
190 let mut img = FloatingScalarImage::new("test", 2, 2, vec![0.0; 4]);
191
192 img.set_colormap("blues");
193 assert_eq!(img.colormap_name(), "blues");
194
195 img.set_data_range(-1.0, 1.0);
196 assert_eq!(img.data_min(), -1.0);
197 assert_eq!(img.data_max(), 1.0);
198 }
199}