1#![deny(missing_docs)]
2
3extern crate float;
6
7use float::{Float, FromPrimitive};
8
9#[derive(Debug, Copy, Clone, PartialEq)]
11pub struct Viewport {
12 pub rect: [i32; 4],
15 pub draw_size: [u32; 2],
17 pub window_size: [f64; 2],
19}
20
21impl Viewport {
22 #[must_use]
34 pub fn abs_transform<T: Float>(&self) -> [[T; 3]; 2] {
35 let (dw, dh) = (f64::from(self.draw_size[0]), f64::from(self.draw_size[1]));
36 let sx = 2.0 * (dw / self.window_size[0]) / f64::from(self.rect[2]);
37 let sy = -2.0 * (dh / self.window_size[1]) / f64::from(self.rect[3]);
38 let f = |x| FromPrimitive::from_f64(x);
39 [
40 [f(sx), f(0.0), f(-1.0)],
41 [f(0.0), f(sy), f(1.0)]
42 ]
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn abs() {
52 let transform = |mat: [[f64; 3]; 2], (px, py)| -> (f64, f64) {
53 (mat[0][0] * px + mat[0][1] * py + mat[0][2],
54 mat[1][0] * px + mat[1][1] * py + mat[1][2])
55 };
56
57 let viewport = Viewport {
58 rect: [0, 0, 100, 200],
59 draw_size: [100, 200],
60 window_size: [100.0, 200.0],
61 };
62 let abs = viewport.abs_transform();
63 assert_eq!(abs, [
64 [0.02, 0.0, -1.0],
65 [0.0, -0.01, 1.0]
66 ]);
67 assert_eq!(transform(abs, (0.0, 0.0)), (-1.0, 1.0));
68 assert_eq!(transform(abs, (50.0, 100.0)), (0.0, 0.0));
69 assert_eq!(transform(abs, (100.0, 200.0)), (1.0, -1.0));
70
71 let viewport = Viewport {
72 rect: [10, 10, 80, 80],
73 draw_size: [100, 100],
74 window_size: [50.0, 50.0],
75 };
76 let abs = viewport.abs_transform();
77 assert_eq!(abs, [
78 [0.05, 0.0, -1.0],
79 [0.0, -0.05, 1.0]
80 ]);
81 assert_eq!(transform(abs, (0.0, 0.0)), (-1.0, 1.0));
82 assert_eq!(transform(abs, (20.0, 20.0)), (0.0, 0.0));
84 assert_eq!(transform(abs, (40.0, 40.0)), (1.0, -1.0));
85 }
86}