use std::{fmt::Display, ops::Deref};
use num_complex::Complex;
use crate::Observer;
#[derive(Debug, Clone, serde::Serialize)]
pub struct Hexagon {
origin: (f64, f64),
flat_to_flat: f64,
}
impl Hexagon {
pub fn new(origin: (f64, f64), flat_to_flat: f64) -> Self {
Self {
origin,
flat_to_flat,
}
}
}
impl Observer for Hexagon {
fn diameter(&self) -> f64 {
let (cx, cy) = self.origin;
2. * (cx.hypot(cy) + 0.5 * self.flat_to_flat / 30f64.to_radians().cos())
}
fn inside_pupil(&self, x: f64, y: f64) -> bool {
let (cx, cy) = self.origin;
let d = self.flat_to_flat * 0.5;
for o in [-30f64.to_radians(), 30f64.to_radians()] {
let (so, co) = o.sin_cos();
let xp = (x - cx) * co + (y - cy) * so;
if xp.abs() > d {
return false;
}
}
if (y - cy).abs() > d {
return false;
}
true
}
}
#[derive(Debug, Clone)]
pub struct Jwst(Vec<Hexagon>);
impl Deref for Jwst {
type Target = Vec<Hexagon>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Jwst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"JWST: {}m diameter, {:.3}m^2 collection area",
self.diameter(),
self.area()
)
}
}
impl Jwst {
pub fn new() -> Self {
let f2f = 1.32;
Self(
(0..6)
.map(|i| {
let o = (30. + i as f64 * 60.).to_radians();
let z = Complex::from_polar(f2f, o);
Hexagon::new((z.re, z.im), f2f)
})
.chain((0..6).map(|i| {
let o = (i as f64 * 60.).to_radians();
let z = Complex::from_polar(3. * f2f / 3f64.sqrt(), o);
Hexagon::new((z.re, z.im), f2f)
}))
.chain((0..6).map(|i| {
let o = (30. + i as f64 * 60.).to_radians();
let z = Complex::from_polar(2. * f2f, o);
Hexagon::new((z.re, z.im), f2f)
}))
.collect(),
)
}
}
impl Observer for Jwst {
fn diameter(&self) -> f64 {
6.6
}
fn inside_pupil(&self, x: f64, y: f64) -> bool {
for hex in self.iter() {
if hex.inside_pupil(x, y) {
return true;
}
}
false
}
}
use serde::ser::{Serialize, Serializer};
impl Serialize for Jwst {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
"JWST".serialize(serializer)
}
}