gate/renderer/
geom.rs

1// Copyright 2017-2019 Matthew D. Michelotti
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::ops::{Add, Mul};
16
17// 2D Cartesian vector
18#[derive(Copy, Clone)]
19pub struct Vec2 { pub x: f64, pub y: f64 }
20
21impl Vec2 {
22    pub fn new(x: f64, y: f64) -> Vec2 { Vec2 { x, y } }
23    pub fn zero() -> Vec2 { Vec2::new(0.0, 0.0) }
24    pub fn len(&self) -> f64 { (self.x * self.x + self.y * self.y).sqrt() }
25}
26
27impl Add<Vec2> for Vec2 {
28    type Output = Vec2;
29    fn add(self, rhs: Vec2) -> Vec2 { Vec2::new(self.x + rhs.x, self.y + rhs.y) }
30}
31
32// Diagonal 2D matrix
33#[derive(Copy, Clone)]
34struct Diag2 { x: f64, y: f64 }
35
36impl Diag2 {
37    fn new(x: f64, y: f64) -> Diag2 { Diag2 { x, y } }
38}
39
40impl Mul<Vec2> for Diag2 {
41    type Output = Vec2;
42    fn mul(self, rhs: Vec2) -> Vec2 { Vec2::new(self.x*rhs.x, self.y*rhs.y) }
43}
44
45impl Mul<Vec2> for f64 {
46    type Output = Vec2;
47    fn mul(self, rhs: Vec2) -> Vec2 { Vec2::new(self * rhs.x, self * rhs.y) }
48}
49
50// General 2D matrix
51#[derive(Copy, Clone)]
52pub struct Mat2 { a: f64, b: f64, c: f64, d: f64 }
53
54impl Mat2 {
55    fn id() -> Mat2 { Mat2 { a: 1.0, b: 0.0, c: 0.0, d: 1.0 } }
56
57    fn rotation(angle: f64) -> Mat2 {
58        let (sin, cos) = (angle.sin(), angle.cos());
59        let (sin, cos) = if sin.abs() < 1e-7 || cos.abs() < 1e-7 {
60            (sin.round(), cos.round())
61        } else {
62            (sin, cos)
63        };
64        Mat2 { a: cos, b: -sin, c: sin, d: cos }
65    }
66
67    pub fn col_0(&self) -> Vec2 { Vec2::new(self.a, self.c) }
68    pub fn col_1(&self) -> Vec2 { Vec2::new(self.b, self.d) }
69}
70
71impl Mul<Vec2> for Mat2 {
72    type Output = Vec2;
73    fn mul(self, rhs: Vec2) -> Vec2 {
74        Vec2::new(self.a * rhs.x + self.b * rhs.y, self.c * rhs.x + self.d * rhs.y)
75    }
76}
77
78impl Mul<Mat2> for Mat2 {
79    type Output = Mat2;
80    fn mul(self, rhs: Mat2) -> Mat2 {
81        Mat2 {
82            a: self.a * rhs.a + self.b * rhs.c,
83            b: self.a * rhs.b + self.b * rhs.d,
84            c: self.c * rhs.a + self.d * rhs.c,
85            d: self.c * rhs.b + self.d * rhs.d,
86        }
87    }
88}
89
90impl Mul<Diag2> for Mat2 {
91    type Output = Mat2;
92    fn mul(self, rhs: Diag2) -> Mat2 {
93        Mat2 { a: self.a * rhs.x, b: self.b * rhs.y, c: self.c * rhs.x, d: self.d * rhs.y }
94    }
95}
96
97impl Mul<Mat2> for Diag2 {
98    type Output = Mat2;
99    fn mul(self, rhs: Mat2) -> Mat2 {
100        Mat2 { a: self.x * rhs.a, b: self.x * rhs.b, c: self.y * rhs.c, d: self.y * rhs.d }
101    }
102}
103
104impl Mul<Mat2> for f64 {
105    type Output = Mat2;
106    fn mul(self, rhs: Mat2) -> Mat2 {
107        Mat2 { a: self * rhs.a, b: self * rhs.b, c: self * rhs.c, d: self * rhs.d }
108    }
109}
110
111/// Represents an affine transformation in 2D space.
112#[derive(Copy, Clone)]
113pub struct Affine { mat: Mat2, offset: Vec2 }
114
115impl Affine {
116    /// Identity transformation.
117    #[inline]
118    pub fn id() -> Affine { Affine { mat: Mat2::id(), offset: Vec2::zero() } }
119
120    /// Returns a translation transformation.
121    pub fn translate(x_offset: f64, y_offset: f64) -> Affine {
122        Affine { mat: Mat2::id(), offset: Vec2::new(x_offset, y_offset) }
123    }
124
125    /// Returns a rotation transformation, rotating counter-clockwise by `angle` radians.
126    pub fn rotate(angle: f64) -> Affine {
127        Affine { mat: Mat2::rotation(angle), offset: Vec2::zero() }
128    }
129
130    /// Returns a scaling transformation, scaling x and y axes separately.
131    pub fn scale_axes(scale_x: f64, scale_y: f64) -> Affine {
132        Affine { mat: Mat2 { a: scale_x, b: 0., c: 0., d: scale_y }, offset: Vec2::zero() }
133    }
134
135    /// Returns a scaling transformation, scaling x and y axes identically.
136    pub fn scale(scale: f64) -> Affine {
137        Affine::scale_axes(scale, scale)
138    }
139
140    /// Returns a transformation that is functionally equivalent to `self` composed with `rhs`.
141    ///
142    /// This means that the `rhs` transformation is invoked first, and then the `self`
143    /// transformation is invoked on the output of that.
144    /// This is usually the desired ordering with graphics transformations.
145    pub fn pre_transform(&self, rhs: &Affine) -> Affine {
146        Affine {
147            mat: self.mat * rhs.mat,
148            offset: self.offset + self.mat * rhs.offset,
149        }
150    }
151
152    /// Logically equivalent to `self.pre_transform(&Affine::scale_axes(scale_x, scale_y))`.
153    pub fn pre_scale_axes(&self, scale_x: f64, scale_y: f64) -> Affine {
154        Affine {
155            mat: self.mat * Diag2::new(scale_x, scale_y),
156            offset: self.offset,
157        }
158    }
159
160    /// Logically equivalent to `self.pre_transform(&Affine::scale(scale))`.
161    pub fn pre_scale(&self, scale: f64) -> Affine {
162        Affine {
163            mat: scale * self.mat,
164            offset: self.offset,
165        }
166    }
167
168    /// Logically equivalent to `self.pre_transform(&Affine::rotate(angle))`.
169    pub fn pre_rotate(&self, angle: f64) -> Affine {
170        Affine {
171            mat: self.mat * Mat2::rotation(angle),
172            offset: self.offset,
173        }
174    }
175
176    /// Logically equivalent to `self.pre_transform(&Affine::translate(x_offset, y_offset))`.
177    pub fn pre_translate(&self, x_offset: f64, y_offset: f64) -> Affine {
178        Affine {
179            mat: self.mat,
180            offset: self.offset + self.mat * Vec2::new(x_offset, y_offset),
181        }
182    }
183
184    /// Logically equivalent to `Affine::scale_axes(scale_x, scale_y).pre_transform(self)`.
185    pub fn post_scale_axes(&self, scale_x: f64, scale_y: f64) -> Affine {
186        let scale = Diag2::new(scale_x, scale_y);
187        Affine {
188            mat: scale * self.mat,
189            offset: scale * self.offset,
190        }
191    }
192
193    /// Logically equivalent to `Affine::scale(scale).pre_transform(self)`.
194    pub fn post_scale(&self, scale: f64) -> Affine {
195        Affine {
196            mat: scale * self.mat,
197            offset: scale * self.offset,
198        }
199    }
200
201    /// Logically equivalent to `Affine::rotate(angle).pre_transform(self)`.
202    pub fn post_rotate(&self, angle: f64) -> Affine {
203        let rotation = Mat2::rotation(angle);
204        Affine {
205            mat: rotation * self.mat,
206            offset: rotation * self.offset,
207        }
208    }
209
210    /// Logically equivalent to `Affine::translate(x_offset, y_offset).pre_transform(self)`.
211    pub fn post_translate(&self, x_offset: f64, y_offset: f64) -> Affine {
212        Affine {
213            mat: self.mat,
214            offset: self.offset + Vec2::new(x_offset, y_offset),
215        }
216    }
217
218    pub(crate) fn apply(&self, input: Vec2) -> Vec2 { self.mat * input + self.offset }
219
220    pub(crate) fn apply_f32(&self, input: (f32, f32)) -> (f32, f32) {
221        let input = Vec2::new(input.0 as f64, input.1 as f64);
222        let result = self.apply(input);
223        (result.x as f32, result.y as f32)
224    }
225
226    pub(crate) fn mat(&self) -> &Mat2 { &self.mat }
227}