Skip to main content

agg_rust/
span_interpolator_trans.rs

1//! Per-pixel transform span interpolator.
2//!
3//! Port of `agg_span_interpolator_trans.h` — transforms every pixel individually
4//! through an arbitrary transformer. Unlike the linear interpolator which transforms
5//! only endpoints and interpolates, this calls `transform()` for each pixel.
6
7use crate::basics::iround;
8use crate::span_interpolator_linear::{SpanInterpolator, Transformer};
9
10/// Subpixel precision constants (matching span_interpolator_linear).
11const SUBPIXEL_SHIFT: u32 = 8;
12const SUBPIXEL_SCALE: i32 = 1 << SUBPIXEL_SHIFT;
13
14// ============================================================================
15// SpanInterpolatorTrans
16// ============================================================================
17
18/// Per-pixel transform span interpolator.
19///
20/// Transforms every single pixel through the given transformer. This is more
21/// accurate than linear interpolation but significantly slower since `transform()`
22/// is called for every pixel rather than just the span endpoints.
23///
24/// Port of C++ `span_interpolator_trans<Transformer, SubpixelShift>`.
25pub struct SpanInterpolatorTrans<T: Transformer> {
26    trans: T,
27    x: f64,
28    y: f64,
29    ix: i32,
30    iy: i32,
31}
32
33impl<T: Transformer> SpanInterpolatorTrans<T> {
34    pub fn new(trans: T) -> Self {
35        Self {
36            trans,
37            x: 0.0,
38            y: 0.0,
39            ix: 0,
40            iy: 0,
41        }
42    }
43
44    pub fn new_begin(trans: T, x: f64, y: f64, len: u32) -> Self {
45        let mut s = Self::new(trans);
46        s.begin(x, y, len);
47        s
48    }
49
50    pub fn transformer(&self) -> &T {
51        &self.trans
52    }
53
54    pub fn set_transformer(&mut self, trans: T) {
55        self.trans = trans;
56    }
57
58    /// Initialize interpolation for a span starting at (x, y).
59    pub fn begin(&mut self, x: f64, y: f64, _len: u32) {
60        self.x = x;
61        self.y = y;
62        let mut tx = x;
63        let mut ty = y;
64        self.trans.transform(&mut tx, &mut ty);
65        self.ix = iround(tx * SUBPIXEL_SCALE as f64);
66        self.iy = iround(ty * SUBPIXEL_SCALE as f64);
67    }
68
69    /// Advance to the next pixel.
70    #[inline]
71    pub fn next(&mut self) {
72        self.x += 1.0;
73        let mut tx = self.x;
74        let mut ty = self.y;
75        self.trans.transform(&mut tx, &mut ty);
76        self.ix = iround(tx * SUBPIXEL_SCALE as f64);
77        self.iy = iround(ty * SUBPIXEL_SCALE as f64);
78    }
79
80    /// Get the current transformed coordinates (in subpixel units).
81    #[inline]
82    pub fn coordinates(&self, x: &mut i32, y: &mut i32) {
83        *x = self.ix;
84        *y = self.iy;
85    }
86}
87
88impl<T: Transformer> SpanInterpolator for SpanInterpolatorTrans<T> {
89    fn begin(&mut self, x: f64, y: f64, len: u32) {
90        self.begin(x, y, len);
91    }
92    fn next(&mut self) {
93        self.next();
94    }
95    fn coordinates(&self, x: &mut i32, y: &mut i32) {
96        self.coordinates(x, y);
97    }
98}
99
100// ============================================================================
101// Tests
102// ============================================================================
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::trans_affine::TransAffine;
108
109    #[test]
110    fn test_identity_transform() {
111        let trans = TransAffine::new();
112        let mut interp = SpanInterpolatorTrans::new(trans);
113        interp.begin(10.0, 20.0, 5);
114
115        let mut x = 0i32;
116        let mut y = 0i32;
117        interp.coordinates(&mut x, &mut y);
118        // Identity: (10, 20) → (10*256, 20*256) = (2560, 5120)
119        assert_eq!(x, 2560);
120        assert_eq!(y, 5120);
121    }
122
123    #[test]
124    fn test_next_increments_x() {
125        let trans = TransAffine::new();
126        let mut interp = SpanInterpolatorTrans::new(trans);
127        interp.begin(5.0, 3.0, 10);
128
129        let mut x = 0i32;
130        let mut y = 0i32;
131        interp.coordinates(&mut x, &mut y);
132        assert_eq!(x, 5 * 256);
133        assert_eq!(y, 3 * 256);
134
135        interp.next();
136        interp.coordinates(&mut x, &mut y);
137        assert_eq!(x, 6 * 256);
138        assert_eq!(y, 3 * 256);
139    }
140
141    #[test]
142    fn test_with_translation() {
143        let trans = TransAffine::new_translation(10.0, 20.0);
144        let mut interp = SpanInterpolatorTrans::new(trans);
145        interp.begin(0.0, 0.0, 1);
146
147        let mut x = 0i32;
148        let mut y = 0i32;
149        interp.coordinates(&mut x, &mut y);
150        assert_eq!(x, 10 * 256);
151        assert_eq!(y, 20 * 256);
152    }
153
154    #[test]
155    fn test_with_scaling() {
156        let trans = TransAffine::new_scaling(2.0, 3.0);
157        let mut interp = SpanInterpolatorTrans::new(trans);
158        interp.begin(5.0, 4.0, 1);
159
160        let mut x = 0i32;
161        let mut y = 0i32;
162        interp.coordinates(&mut x, &mut y);
163        assert_eq!(x, 10 * 256);
164        assert_eq!(y, 12 * 256);
165    }
166
167    #[test]
168    fn test_new_begin() {
169        let trans = TransAffine::new();
170        let interp = SpanInterpolatorTrans::new_begin(trans, 1.0, 2.0, 5);
171        let mut x = 0i32;
172        let mut y = 0i32;
173        interp.coordinates(&mut x, &mut y);
174        assert_eq!(x, 256);
175        assert_eq!(y, 512);
176    }
177}