use std::marker::PhantomData;
use crate::{Conic, Error, Gmt, Quaternion, Vector, M1, M2};
#[derive(Debug, Clone)]
pub struct Segment<M: Gmt> {
id: i32,
height: f64,
beta: Option<f64>,
distance: Option<f64>,
cloking: Option<i32>,
conic: Conic,
mirror: PhantomData<M>,
}
pub trait SegmentTrait {
fn new(o: i32) -> Result<Self, Error>
where
Self: Sized;
fn rotation(&self) -> Option<Quaternion>;
}
impl<M: Gmt> Segment<M> {
pub fn translation(&self) -> Vector {
if self.id < 7 {
let o = self.cloking.unwrap() as f64;
let d = self.distance.unwrap();
let z = self.conic.height(d);
let (s, c) = (90. + o).to_radians().sin_cos();
Vector::from([d * c, d * s, self.height + z])
} else {
Vector::from([0., 0., self.height])
}
}
}
impl SegmentTrait for Segment<M1> {
fn new(id: i32) -> Result<Self, Error> {
match id {
7 => Ok(Self {
id: 7,
height: 3.9,
beta: None,
distance: None,
cloking: None,
conic: Conic::m1(),
mirror: PhantomData,
}),
id @ 1..=6 => Ok(Self {
id,
height: 3.9,
beta: Some(13.601685f64),
distance: Some(8.71),
cloking: Some(-60i32 * (id - 1)),
conic: Conic::m1(),
mirror: PhantomData,
}),
_ => Err(Error::SegmentId(id)),
}
}
fn rotation(&self) -> Option<Quaternion> {
if self.id < 7 {
let o = self.cloking.unwrap() as f64;
Some(
Quaternion::unit(o.to_radians(), Vector::k())
* Quaternion::unit(self.beta.unwrap().to_radians(), Vector::i()),
)
} else {
None
}
}
}
impl SegmentTrait for Segment<M2> {
fn new(id: i32) -> Result<Self, Error> {
match id {
7 => Ok(Self {
id: 7,
height: 3.9 + 20.26247614,
beta: None,
distance: None,
cloking: None,
conic: Conic::m2(),
mirror: PhantomData,
}),
id @ 1..=6 => Ok(Self {
id,
height: 3.9 + 20.26247614,
beta: Some(14.777498),
distance: Some(1.08774),
cloking: Some(180i32 - 60i32 * (id - 1)),
conic: Conic::m2(),
mirror: PhantomData,
}),
_ => Err(Error::SegmentId(id)),
}
}
fn rotation(&self) -> Option<Quaternion> {
if self.id < 7 {
let o = self.cloking.unwrap() as f64;
Some(
Quaternion::unit(o.to_radians(), Vector::k())
* Quaternion::unit(std::f64::consts::PI, Vector::j())
* Quaternion::unit(self.beta.unwrap().to_radians(), Vector::i()),
)
} else {
Some(
Quaternion::unit(180f64.to_radians(), Vector::k())
* Quaternion::unit(std::f64::consts::PI, Vector::j()),
)
}
}
}