use std::path::Path;
use image::{ImageResult, Rgb, RgbImage};
use indicatif::{ProgressBar, ProgressStyle};
use super::{Builder, Field, FieldBuilder, Observing, SeeingLimited};
use crate::{AdaptiveOptics, Observer, SaveOptions, SeeingBuilder};
pub struct SeeingLimitedField<T: Observer> {
field_builder: FieldBuilder<T>,
seeing_builders: Vec<SeeingBuilder>,
}
impl<T: Observer> Builder<SeeingLimitedField<T>> for (FieldBuilder<T>, Vec<SeeingBuilder>) {
fn build(self) -> SeeingLimitedField<T> {
SeeingLimitedField {
field_builder: self.0,
seeing_builders: self.1,
}
}
}
impl<T: Observer> Builder<SeeingLimitedField<T>> for (FieldBuilder<T>, SeeingBuilder) {
fn build(self) -> SeeingLimitedField<T> {
<(FieldBuilder<T>, Vec<SeeingBuilder>) as Builder<SeeingLimitedField<T>>>::build((
self.0,
vec![self.1],
))
}
}
impl<T> SeeingLimitedField<T>
where
T: Observer + Sync + Send,
{
pub fn len(&self) -> usize {
self.seeing_builders.len()
}
pub fn save<P: AsRef<Path>>(&mut self, path: P, save_options: SaveOptions) -> ImageResult<()> {
let mut intensities = vec![];
for seeing_builder in self.seeing_builders.iter() {
let FieldBuilder {
pixel_scale,
field_of_view,
photometry,
objects,
exposure,
poisson_noise,
observer,
seeing: _,
flux,
} = self.field_builder.clone();
let bar = save_options
.mbar
.as_ref()
.map(|mbar| mbar.add(ProgressBar::new(objects.len() as u64)));
bar.as_ref().map(|bar| {
bar.set_style(
ProgressStyle::with_template(&format!(
"{}",
"[{eta:>4}] {bar:40.cyan/blue} {pos:>5}/{len:5}"
))
.unwrap(),
)
});
let mut intensity = if seeing_builder.adaptive_optics.is_none() {
let mut field: Field<T, SeeingLimited> = Field {
pixel_scale,
field_of_view,
photometry: photometry[0],
objects,
exposure,
poisson_noise,
observer,
observing_mode: Observing::seeing_limited(Some(
seeing_builder.clone().wavelength(photometry[0]),
)),
flux,
intensity_sampling: None,
};
field.intensity(bar)
} else {
let mut field: Field<T, AdaptiveOptics> = Field {
pixel_scale,
field_of_view,
photometry: photometry[0],
objects,
exposure,
poisson_noise,
observer,
observing_mode: Observing::seeing_limited(Some(
seeing_builder.clone().wavelength(photometry[0]),
)),
flux,
intensity_sampling: None,
};
field.intensity(bar)
};
if let Some(lufn) = save_options.lufn {
intensity.iter_mut().for_each(|i| *i = lufn(*i));
}
intensities.push(intensity);
}
let threshold = save_options
.saturation
.threshold(intensities.iter().flatten());
intensities
.iter_mut()
.for_each(|intensity| intensity.iter_mut().for_each(|i| *i /= threshold));
let lut = colorous::CUBEHELIX;
let n_px = (intensities[0].len() as f64).sqrt() as usize;
let mut img = RgbImage::new((n_px * self.len()) as u32, n_px as u32);
for mut px_row in img.rows_mut() {
for intensity in intensities.iter_mut() {
intensity.drain(..n_px).for_each(|i| {
**(px_row.next().as_mut().unwrap()) = Rgb(lut.eval_continuous(i).into_array());
})
}
}
img.save(path)
}
}