polarization/jones/
identity.rs

1//! An element that has no effect.
2//!
3//! An identity element simply passes the incident beam straight through. In real life
4//! this could simply be the beam traveling through a transparent medium. This element
5//! is mostly useful for testing and other internal uses in `polarization`, but may
6//! prove handy for other uses as well.
7
8use num::complex::Complex;
9
10use super::common::{rotate_matrix, Angle, ComplexMatrix, JonesMatrix};
11#[cfg(test)]
12use proptest::prelude::*;
13
14/// An optical element that simply passes a beam through untouched.
15#[derive(Debug, Copy, Clone)]
16pub struct IdentityElement {
17    mat: ComplexMatrix,
18}
19
20impl IdentityElement {
21    /// Constructs a new `IdentityElement`.
22    ///
23    /// There are no parameters because this element doesn't really do anything.
24    pub fn new() -> Self {
25        let zero = Complex::new(0_f64, 0_f64);
26        let one = Complex::new(1_f64, 0_f64);
27        let mat = ComplexMatrix::new(one, zero, zero, one);
28        IdentityElement { mat }
29    }
30}
31
32impl JonesMatrix for IdentityElement {
33    /// Returns an `IdentityElement` that has been rotated counter-clockwise by
34    /// `angle`.
35    ///
36    /// Note that the identity element only passes the original beam through when the
37    /// element and the beam are in the same coordinate system. For example, if you
38    /// start with a given beam and pass it through an identity element that has
39    /// been rotated, in general you will not get back the same beam. However, if you
40    /// start with a given beam, rotate both the beam and the element by the same angle,
41    /// then rotate the beam back to its original orientation, you will recover the beam
42    /// that you started with.
43    fn rotated(&self, angle: Angle) -> Self {
44        let mat = rotate_matrix(&self.matrix(), &angle);
45        IdentityElement { mat }
46    }
47
48    /// Replaces this element with one that has been rotated counter-clockwise by
49    /// `angle`.
50    ///
51    /// See above for notes on the semantics of rotating an `IdentityElement`.
52    fn rotate(&mut self, angle: Angle) {
53        self.mat = rotate_matrix(&self.matrix(), &angle);
54    }
55
56    /// Returns the 2x2 Jones matrix of the element.
57    fn matrix(&self) -> ComplexMatrix {
58        self.mat
59    }
60}
61
62#[cfg(test)]
63impl Arbitrary for IdentityElement {
64    type Parameters = ();
65    type Strategy = BoxedStrategy<Self>;
66
67    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
68        Just(IdentityElement::new()).boxed()
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use super::*;
75    use jones::common::{are_rel_eq, float_angle, Beam, JonesVector};
76
77    proptest! {
78        #[test]
79        fn test_identity_element_returns_same_beam(beam: Beam) {
80            let ident = IdentityElement::new();
81            let beam_after = beam.apply_element(ident);
82            prop_assert_beam_approx_eq!(beam_after, beam);
83        }
84
85        #[test]
86        fn test_multiple_identity_elements_preserves_beam(beam: Beam, elems: Vec<IdentityElement>) {
87            let mut beam_after = beam.clone();
88            for elem in elems {
89                beam_after = beam_after.apply_element(elem);
90            }
91            prop_assert_beam_approx_eq!(beam_after, beam);
92        }
93
94        #[test]
95        fn test_identity_preserved_under_rotation(theta in float_angle()) {
96            let beam = Beam::linear(Angle::Degrees(theta));
97            let ident = IdentityElement::new().rotated(Angle::Degrees(theta));
98            let beam_after = beam.apply_element(ident);
99            prop_assert_beam_approx_eq!(beam_after, beam);
100        }
101
102    }
103}