use crate::header::Header;
#[derive(Debug, Clone)]
pub struct Group {
parameters: Vec<f64>,
names: Vec<String>,
data: Vec<f64>,
}
impl Group {
pub(crate) fn new(parameters: Vec<f64>, names: Vec<String>, data: Vec<f64>) -> Self {
Self {
parameters,
names,
data,
}
}
pub fn parameters(&self) -> &[f64] {
&self.parameters
}
pub fn parameter(&self, name: &str) -> Option<f64> {
let mut total = None;
for (index, parameter_name) in self.names.iter().enumerate() {
if parameter_name == name {
total = Some(total.unwrap_or(0.0) + self.parameters.get(index).copied()?);
}
}
total
}
pub fn parameter_names(&self) -> &[String] {
&self.names
}
pub fn data(&self) -> &[f64] {
&self.data
}
}
pub(crate) fn decode_group(header: &Header, bytes: &[u8]) -> Option<Group> {
let bitpix = header.bitpix()?;
let width = bitpix.byte_size();
let count = header.pcount().unwrap_or(0).max(0) as usize;
let zero = header.bzero_or_default();
let scale = header.bscale_or_default();
let mut parameters = Vec::with_capacity(count);
let mut names = Vec::with_capacity(count);
for index in 0..count {
let raw = bitpix.read_be(bytes.get(index * width..)?)?;
let parameter_scale = header.parameter_scaling_factor(index).unwrap_or(1.0);
let parameter_zero = header.parameter_scaling_zero_point(index).unwrap_or(0.0);
parameters.push(parameter_zero + parameter_scale * raw);
names.push(header.parameter_type(index).unwrap_or_default().to_string());
}
let array = bytes.get(count * width..)?;
let data = array
.chunks_exact(width)
.filter_map(|raw| bitpix.read_be(raw))
.map(|raw| zero + scale * raw)
.collect();
Some(Group::new(parameters, names, data))
}