1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! # Helixiser's equivalent of an image
use ndarray::Array2;
use num::complex::Complex64;
use num::traits::Pow;
use crate::utilities::luminance_to_rgba;


pub struct Wavefront {
    /// A wavefront is a 2D array of complex value where each point corresponds to a coordinate in
    /// 2D space. The array indices correspond to a point in space.
    pub values: Array2<Complex64>,
    width: usize,
    height: usize,
}

impl Wavefront {
    /// Instantiate a new Wavefront struct
    pub fn new(values: Array2<Complex64>) -> Self {
        Wavefront {
            width: values.nrows(),
            height: values.ncols(),
            values,
        }
    }

    /// rescale the (complex) values of the wavefront by a (real) scalar value.
    ///
    /// # Examples
    /// ```
    /// use assert_approx_eq::assert_approx_eq;
    /// use helixiser::wavefront::Wavefront;
    /// use num::traits::Pow;
    /// use ndarray::arr2;
    /// use num::complex::Complex64;
    /// let mut my_wavefront = Wavefront::new( arr2(&[[Complex64::new(5., 1.),
    ///                                           Complex64::new(0., 0.)],
    ///                                          [Complex64::new(0., 0.),
    ///                                           Complex64::new(4., 2.)]]));
    /// // Rescale the wavefront
    /// my_wavefront.rescale(10.5);
    ///
    /// assert_eq!(my_wavefront.values, arr2(&[[Complex64::new(52.5, 10.5),
    ///                                         Complex64::new(0., 0.)],
    ///                                        [Complex64::new(0., 0.),
    ///                                         Complex64::new(42., 21.)]]))
    ///
    /// ```
    pub fn rescale(&mut self, factor:f64) {
        self.values = &self.values * factor;
    }

    /// Convert the complex valued wavefront into (real valued) intensities.
    ///
    /// Real values are obtained by squaring the norm of the complex values.
    pub fn intensities(&self) -> Array2<f64>{
        self.values.mapv(
            |comval| (comval).norm().pow(2)
        )
    }

    /// Save wavefront intensities as image using the image crate
    ///
    /// # Panics
    /// This function uses the `image::save_buffer` function which can panic
    pub fn save_image(&self, path: &str) -> () {
        let intensities = Self::intensities(&self);
        let rgba = luminance_to_rgba(intensities.into_raw_vec());
        let img: Vec<u8> = rgba.iter().map(|val| *val as u8).collect();
        image::save_buffer(path, &img, self.width as u32, self.height as u32, image::ColorType::Rgba8).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use assert_approx_eq::assert_approx_eq;
    use crate::wavefront::Wavefront;
    use num::traits::Pow;
    use ndarray::arr2;
    use num::complex::Complex64;

    #[test]
    fn complex_to_intensities() {
        let my_wavefront = Wavefront::new( arr2(&[[Complex64::new(5., 1.),
                                                                      Complex64::new(0., 0.)],
                                                                     [Complex64::new(0., 0.),
                                                                      Complex64::new(4., 2.)]]));

        let analytic_answers = vec![5f64.pow(2) + 1f64.pow(2), 0., 0.,
                                    4f64.pow(2) + 2f64.pow(2)];

        for (i, intensity) in my_wavefront.intensities().iter().enumerate() {
            assert_approx_eq!(intensity, analytic_answers[i])
        }
    }
}