1use super::{Volume, VolumeInfo};
4use glam::{DMat3, DVec3, UVec3};
5
6#[derive(Debug, Clone)]
14#[non_exhaustive]
15pub enum DynVolume {
16 U8(Volume<u8>),
18 I8(Volume<i8>),
20 U16(Volume<u16>),
22 I16(Volume<i16>),
24 U32(Volume<u32>),
26 I32(Volume<i32>),
28 F32(Volume<f32>),
30 F64(Volume<f64>),
32}
33
34impl DynVolume {
35 #[must_use]
37 pub fn as_bytes(&self) -> &[u8] {
38 match self {
39 Self::U8(v) => v.as_bytes(),
40 Self::I8(v) => v.as_bytes(),
41 Self::U16(v) => v.as_bytes(),
42 Self::I16(v) => v.as_bytes(),
43 Self::U32(v) => v.as_bytes(),
44 Self::I32(v) => v.as_bytes(),
45 Self::F32(v) => v.as_bytes(),
46 Self::F64(v) => v.as_bytes(),
47 }
48 }
49
50 #[must_use]
52 pub fn scalar_range(&self) -> (f64, f64) {
53 match self {
54 Self::U8(v) => v.scalar_range(),
55 Self::I8(v) => v.scalar_range(),
56 Self::U16(v) => v.scalar_range(),
57 Self::I16(v) => v.scalar_range(),
58 Self::U32(v) => v.scalar_range(),
59 Self::I32(v) => v.scalar_range(),
60 Self::F32(v) => v.scalar_range(),
61 Self::F64(v) => v.scalar_range(),
62 }
63 }
64
65 #[must_use]
67 pub fn sample_linear(&self, ijk: DVec3) -> Option<f64> {
68 match self {
69 Self::U8(v) => v.sample_linear(ijk),
70 Self::I8(v) => v.sample_linear(ijk),
71 Self::U16(v) => v.sample_linear(ijk),
72 Self::I16(v) => v.sample_linear(ijk),
73 Self::U32(v) => v.sample_linear(ijk),
74 Self::I32(v) => v.sample_linear(ijk),
75 Self::F32(v) => v.sample_linear(ijk),
76 Self::F64(v) => v.sample_linear(ijk),
77 }
78 }
79
80 #[must_use]
82 pub fn bytes_per_component(&self) -> usize {
83 match self {
84 Self::U8(_) | Self::I8(_) => 1,
85 Self::U16(_) | Self::I16(_) => 2,
86 Self::U32(_) | Self::I32(_) | Self::F32(_) => 4,
87 Self::F64(_) => 8,
88 }
89 }
90}
91
92impl VolumeInfo for DynVolume {
93 fn dimensions(&self) -> UVec3 {
94 match self {
95 Self::U8(v) => v.dimensions(),
96 Self::I8(v) => v.dimensions(),
97 Self::U16(v) => v.dimensions(),
98 Self::I16(v) => v.dimensions(),
99 Self::U32(v) => v.dimensions(),
100 Self::I32(v) => v.dimensions(),
101 Self::F32(v) => v.dimensions(),
102 Self::F64(v) => v.dimensions(),
103 }
104 }
105 fn spacing(&self) -> DVec3 {
106 match self {
107 Self::U8(v) => v.spacing(),
108 Self::I8(v) => v.spacing(),
109 Self::U16(v) => v.spacing(),
110 Self::I16(v) => v.spacing(),
111 Self::U32(v) => v.spacing(),
112 Self::I32(v) => v.spacing(),
113 Self::F32(v) => v.spacing(),
114 Self::F64(v) => v.spacing(),
115 }
116 }
117 fn origin(&self) -> DVec3 {
118 match self {
119 Self::U8(v) => v.origin(),
120 Self::I8(v) => v.origin(),
121 Self::U16(v) => v.origin(),
122 Self::I16(v) => v.origin(),
123 Self::U32(v) => v.origin(),
124 Self::I32(v) => v.origin(),
125 Self::F32(v) => v.origin(),
126 Self::F64(v) => v.origin(),
127 }
128 }
129 fn direction(&self) -> DMat3 {
130 match self {
131 Self::U8(v) => v.direction(),
132 Self::I8(v) => v.direction(),
133 Self::U16(v) => v.direction(),
134 Self::I16(v) => v.direction(),
135 Self::U32(v) => v.direction(),
136 Self::I32(v) => v.direction(),
137 Self::F32(v) => v.direction(),
138 Self::F64(v) => v.direction(),
139 }
140 }
141 fn components(&self) -> u32 {
142 match self {
143 Self::U8(v) => v.components(),
144 Self::I8(v) => v.components(),
145 Self::U16(v) => v.components(),
146 Self::I16(v) => v.components(),
147 Self::U32(v) => v.components(),
148 Self::I32(v) => v.components(),
149 Self::F32(v) => v.components(),
150 Self::F64(v) => v.components(),
151 }
152 }
153}
154
155macro_rules! impl_from_volume {
157 ($T:ty, $Variant:ident) => {
158 impl From<Volume<$T>> for DynVolume {
159 fn from(v: Volume<$T>) -> Self {
160 Self::$Variant(v)
161 }
162 }
163 };
164}
165
166impl_from_volume!(u8, U8);
167impl_from_volume!(i8, I8);
168impl_from_volume!(u16, U16);
169impl_from_volume!(i16, I16);
170impl_from_volume!(u32, U32);
171impl_from_volume!(i32, I32);
172impl_from_volume!(f32, F32);
173impl_from_volume!(f64, F64);
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use glam::{DMat3, DVec3, UVec3};
179
180 fn make_i16_volume() -> DynVolume {
181 let data: Vec<i16> = (-4i16..4i16).collect();
182 let vol = Volume::from_data(
183 data,
184 UVec3::new(2, 2, 2),
185 DVec3::ONE,
186 DVec3::ZERO,
187 DMat3::IDENTITY,
188 1,
189 )
190 .unwrap();
191 DynVolume::I16(vol)
192 }
193
194 #[test]
195 fn dyn_scalar_range() {
196 let dv = make_i16_volume();
197 let (lo, hi) = dv.scalar_range();
198 approx::assert_abs_diff_eq!(lo, -4.0, epsilon = 1e-10);
199 approx::assert_abs_diff_eq!(hi, 3.0, epsilon = 1e-10);
200 }
201
202 #[test]
203 fn dyn_dimensions() {
204 let dv = make_i16_volume();
205 assert_eq!(dv.dimensions(), UVec3::new(2, 2, 2));
206 }
207
208 #[test]
209 fn dyn_bytes_per_component() {
210 assert_eq!(make_i16_volume().bytes_per_component(), 2);
211 }
212
213 #[test]
214 fn from_volume_u8() {
215 let v = Volume::<u8>::from_data(
216 vec![0u8; 8],
217 UVec3::new(2, 2, 2),
218 DVec3::ONE,
219 DVec3::ZERO,
220 DMat3::IDENTITY,
221 1,
222 )
223 .unwrap();
224 let dv: DynVolume = v.into();
225 assert!(matches!(dv, DynVolume::U8(_)));
226 }
227}