use super::common::{rotate_matrix, Angle, ComplexMatrix, JonesMatrix};
use na::Matrix2;
use num::complex::Complex;
#[cfg(test)]
use proptest::prelude::*;
#[derive(Debug, Copy, Clone)]
pub struct PolarizationRotator {
mat: ComplexMatrix,
}
impl PolarizationRotator {
pub fn new(angle: Angle) -> Self {
let rad = match angle {
Angle::Degrees(ang) => ang.to_radians(),
Angle::Radians(ang) => ang,
};
let sin = Complex::new(rad.sin(), 0_f64);
let cos = Complex::new(rad.cos(), 0_f64);
let mat = Matrix2::new(cos, -sin, sin, cos);
PolarizationRotator { mat }
}
}
impl JonesMatrix for PolarizationRotator {
fn rotated(&self, angle: Angle) -> Self {
PolarizationRotator {
mat: rotate_matrix(&self.matrix(), &angle),
}
}
fn rotate(&mut self, angle: Angle) {
self.mat = rotate_matrix(&self.mat, &angle);
}
fn matrix(&self) -> ComplexMatrix {
self.mat
}
}
#[cfg(test)]
impl Arbitrary for PolarizationRotator {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<Angle>()
.prop_map(|angle| PolarizationRotator::new(angle))
.boxed()
}
}
#[cfg(test)]
mod tests {
use super::*;
use jones::common::{are_rel_eq, Beam, JonesVector};
proptest! {
#[test]
fn test_polarization_rotator_rotates(theta in 0_f64..360_f64) {
let beam = Beam::linear(Angle::Degrees(0.0));
let expected_beam = Beam::linear(Angle::Degrees(theta));
let rotator = PolarizationRotator::new(Angle::Degrees(theta));
let beam_after = beam.apply_element(rotator);
prop_assert_beam_approx_eq!(beam_after, expected_beam);
}
#[test]
fn test_polarization_rotator_preserves_beam_with_0_degree_rotation(beam: Beam) {
let rotator = PolarizationRotator::new(Angle::Degrees(0.0));
let beam_after = beam.apply_element(rotator);
prop_assert_beam_approx_eq!(beam_after, beam);
}
#[test]
fn test_polarization_rotator_preserves_beam_with_360_degree_rotation(beam: Beam) {
let rotator = PolarizationRotator::new(Angle::Degrees(360.0));
let beam_after = beam.apply_element(rotator);
prop_assert_beam_approx_eq!(beam_after, beam);
}
}
}