alpha2_geometry/
affine.rs1use kurbo::{Affine, Point, Vec2};
5
6#[must_use]
9pub fn rotation(degrees: f64) -> Affine {
10 let radians = degrees.to_radians();
11 let (sin, cos) = (libm::sin(radians), libm::cos(radians));
12 Affine::new([cos, sin, -sin, cos, 0.0, 0.0])
13}
14
15#[must_use]
17pub fn rotation_about(degrees: f64, center: Point) -> Affine {
18 Affine::translate(center.to_vec2()) * rotation(degrees) * Affine::translate(-center.to_vec2())
19}
20
21#[must_use]
24pub fn placement(position: Point, anchor: Point, scale: Vec2, degrees: f64) -> Affine {
25 Affine::translate(position.to_vec2())
26 * rotation(degrees)
27 * Affine::scale_non_uniform(scale.x, scale.y)
28 * Affine::translate(-anchor.to_vec2())
29}
30
31#[must_use]
33pub fn length(vector: Vec2) -> f64 {
34 (vector.x * vector.x + vector.y * vector.y).sqrt()
35}
36
37#[must_use]
39pub fn distance(a: Point, b: Point) -> f64 {
40 length(b - a)
41}
42
43#[must_use]
46pub fn max_scale(affine: Affine) -> f64 {
47 let [xx, yx, xy, yy, _, _] = affine.as_coeffs();
48 let first = xx * xx + yx * yx;
50 let second = xy * xy + yy * yy;
51 let cross = xx * xy + yx * yy;
52 let half_sum = f64::midpoint(first, second);
53 let half_difference = 0.5 * (first - second);
54 let root = (half_difference * half_difference + cross * cross).sqrt();
55 (half_sum + root).max(0.0).sqrt()
56}
57
58#[must_use]
60pub fn is_invertible(affine: Affine) -> bool {
61 let determinant = affine.determinant();
62 determinant.is_finite() && determinant.abs() > 1e-12
63}