use std::path::PathBuf;
use super::{utils::slice_view1, Base, ChannelAxis, Error, Numeric, NumericAxis};
use crate::{
array_cache::{ArrayCache, UriResolvable},
schema::{
array_uri_reference::{AbsoluteUri, ArrayUriReference},
PolynomialTransform,
},
strided_array_file::{ArrayProxy, Statistics, StridedArrayFile},
};
use ndarray::{Array1, Ix1, SliceInfoElem};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CoordinateAxis {
pub name: String,
pub units: Option<String>,
pub bounds: [f64; 2],
pub size: usize,
pub transform: Option<PolynomialTransform>,
pub uri: ArrayUriReference,
}
impl CoordinateAxis {
pub fn copy_to(&self, uri: &ArrayUriReference) -> Result<Self, Error> {
let coordinates = self.coordinates()?;
let proxy = ArrayProxy::from_view(coordinates.view().into_dyn())?;
let path: PathBuf = uri.try_into()?;
StridedArrayFile::write(&path, &[proxy])
.map_err(|e| format!("Failed to write axis coordinates: {e}"))?;
let mut copy = self.clone();
copy.uri = uri.clone();
Ok(copy)
}
}
impl UriResolvable for CoordinateAxis {
fn set_base_for_relative_uris(&mut self, base: &AbsoluteUri) {
self.uri = self.uri.with_base_if_relative(base);
}
}
impl Base for CoordinateAxis {
fn size(&self) -> Result<usize, Error> {
Ok(self.size)
}
fn slice(&self, slice_info: &SliceInfoElem) -> Result<ChannelAxis, Error> {
if matches!(slice_info, SliceInfoElem::NewAxis) {
return Err("SliceInfoElem::NewAxis variant is not supported".into());
}
let coordinates = self.coordinates()?;
let slice = slice_view1(coordinates.view(), slice_info)?;
let proxy = ArrayProxy::F64(slice.into_dyn());
let uri = ArrayCache::insert(proxy.clone())?;
Ok(Self {
name: self.name.clone(),
units: self.units.clone(),
bounds: [
proxy.calc_stats(Statistics::Min)?,
proxy.calc_stats(Statistics::Max)?,
],
size: proxy.shape()[0],
transform: self.transform.clone(),
uri,
}
.into())
}
}
impl Numeric for CoordinateAxis {
fn name(&self) -> &str {
&self.name
}
fn units(&self) -> &Option<String> {
&self.units
}
fn coordinates(&self) -> Result<Array1<f64>, Error> {
if self.transform.is_some() {
return Err("CoordinateAxis.transform is not yet supported".into());
}
ArrayCache::get(&self.uri)?
.try_as::<f64>()?
.to_owned()
.into_dimensionality::<Ix1>()
.map_err(|e| format!("Coordinates are not 1D: {e}"))
}
fn make_monotonic(&self) -> Result<Vec<NumericAxis>, Error> {
todo!()
}
}