Skip to main content

apple_cf/cg/
affine.rs

1//! `CGAffineTransform` and `CGVector` value types.
2//!
3//! `CGAffineTransform` is the 2-D transformation matrix used throughout
4//! Core Graphics / Core Animation / Core Image:
5//!
6//! ```text
7//!     [ a   b   0 ]
8//!     [ c   d   0 ]
9//!     [ tx  ty  1 ]
10//! ```
11//!
12//! Wraps Apple's `CGAffineTransformMake*` / `CGAffineTransformConcat`
13//! helpers. Layout-compatible with the C struct so it crosses the FFI
14//! boundary by value.
15
16/// A 2-D vector — `(dx, dy)` in screen coordinates.
17#[derive(Debug, Clone, Copy, Default, PartialEq)]
18#[repr(C)]
19pub struct CGVector {
20    pub dx: f64,
21    pub dy: f64,
22}
23
24impl CGVector {
25    /// Creates a Core Graphics vector with the supplied components.
26    #[must_use]
27    pub const fn new(dx: f64, dy: f64) -> Self {
28        Self { dx, dy }
29    }
30}
31
32/// Affine transformation matrix.
33#[derive(Debug, Clone, Copy, PartialEq)]
34#[repr(C)]
35pub struct CGAffineTransform {
36    pub a: f64,
37    pub b: f64,
38    pub c: f64,
39    pub d: f64,
40    pub tx: f64,
41    pub ty: f64,
42}
43
44impl Default for CGAffineTransform {
45    fn default() -> Self {
46        Self::IDENTITY
47    }
48}
49
50impl CGAffineTransform {
51    /// The identity transform — no scale, rotation, or translation.
52    pub const IDENTITY: Self = Self {
53        a: 1.0,
54        b: 0.0,
55        c: 0.0,
56        d: 1.0,
57        tx: 0.0,
58        ty: 0.0,
59    };
60
61    /// Raw constructor; component values match Apple's
62    /// `CGAffineTransformMake(a, b, c, d, tx, ty)`.
63    #[must_use]
64    pub const fn new(a: f64, b: f64, c: f64, d: f64, tx: f64, ty: f64) -> Self {
65        Self { a, b, c, d, tx, ty }
66    }
67
68    /// Translation-only transform — wraps `CGAffineTransformMakeTranslation`.
69    #[must_use]
70    pub fn translation(tx: f64, ty: f64) -> Self {
71        unsafe { CGAffineTransformMakeTranslation(tx, ty) }
72    }
73
74    /// Scale-only transform — wraps `CGAffineTransformMakeScale`.
75    #[must_use]
76    pub fn scale(sx: f64, sy: f64) -> Self {
77        unsafe { CGAffineTransformMakeScale(sx, sy) }
78    }
79
80    /// Rotation-only transform (radians) — wraps `CGAffineTransformMakeRotation`.
81    #[must_use]
82    pub fn rotation(radians: f64) -> Self {
83        unsafe { CGAffineTransformMakeRotation(radians) }
84    }
85
86    /// `self` then `other` (Apple's matrix-multiply order). Wraps
87    /// `CGAffineTransformConcat`.
88    #[must_use]
89    pub fn concat(self, other: Self) -> Self {
90        unsafe { CGAffineTransformConcat(self, other) }
91    }
92
93    /// Inverse transform. Wraps `CGAffineTransformInvert`. Returns
94    /// the identity if `self` is non-invertible.
95    #[must_use]
96    pub fn invert(self) -> Self {
97        unsafe { CGAffineTransformInvert(self) }
98    }
99
100    /// True if this is the identity transform. Wraps
101    /// `CGAffineTransformIsIdentity`.
102    #[must_use]
103    pub fn is_identity(self) -> bool {
104        unsafe { CGAffineTransformIsIdentity(self) }
105    }
106}
107
108#[link(name = "ApplicationServices", kind = "framework")]
109extern "C" {
110    fn CGAffineTransformMakeTranslation(tx: f64, ty: f64) -> CGAffineTransform;
111    fn CGAffineTransformMakeScale(sx: f64, sy: f64) -> CGAffineTransform;
112    fn CGAffineTransformMakeRotation(radians: f64) -> CGAffineTransform;
113    fn CGAffineTransformConcat(a: CGAffineTransform, b: CGAffineTransform) -> CGAffineTransform;
114    fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform;
115    fn CGAffineTransformIsIdentity(t: CGAffineTransform) -> bool;
116}