agg_rust/
span_subdiv_adaptor.rs1use crate::basics::iround;
8use crate::span_interpolator_linear::{SpanInterpolatorLinear, Transformer, SUBPIXEL_SCALE};
9
10pub struct SpanSubdivAdaptor<T: Transformer> {
23 subdiv_shift: u32,
24 subdiv_size: u32,
25 subdiv_mask: u32,
26 interpolator: SpanInterpolatorLinear<T>,
27 src_x: i32,
28 src_y: f64,
29 pos: u32,
30 len: u32,
31}
32
33impl<T: Transformer> SpanSubdivAdaptor<T> {
34 pub fn new(interpolator: SpanInterpolatorLinear<T>) -> Self {
36 Self {
37 subdiv_shift: 4,
38 subdiv_size: 1 << 4,
39 subdiv_mask: (1 << 4) - 1,
40 interpolator,
41 src_x: 0,
42 src_y: 0.0,
43 pos: 0,
44 len: 0,
45 }
46 }
47
48 pub fn new_with_shift(interpolator: SpanInterpolatorLinear<T>, subdiv_shift: u32) -> Self {
50 Self {
51 subdiv_shift,
52 subdiv_size: 1 << subdiv_shift,
53 subdiv_mask: (1 << subdiv_shift) - 1,
54 interpolator,
55 src_x: 0,
56 src_y: 0.0,
57 pos: 0,
58 len: 0,
59 }
60 }
61
62 pub fn interpolator(&self) -> &SpanInterpolatorLinear<T> {
63 &self.interpolator
64 }
65
66 pub fn interpolator_mut(&mut self) -> &mut SpanInterpolatorLinear<T> {
67 &mut self.interpolator
68 }
69
70 pub fn transformer(&self) -> &T {
71 self.interpolator.transformer()
72 }
73
74 pub fn subdiv_shift(&self) -> u32 {
75 self.subdiv_shift
76 }
77
78 pub fn set_subdiv_shift(&mut self, shift: u32) {
79 self.subdiv_shift = shift;
80 self.subdiv_size = 1 << shift;
81 self.subdiv_mask = self.subdiv_size - 1;
82 }
83
84 pub fn begin(&mut self, x: f64, y: f64, len: u32) {
86 self.pos = 1;
87 self.src_x = iround(x * SUBPIXEL_SCALE as f64) + SUBPIXEL_SCALE;
88 self.src_y = y;
89 self.len = len;
90 let sub_len = if len > self.subdiv_size {
91 self.subdiv_size
92 } else {
93 len
94 };
95 self.interpolator.begin(x, y, sub_len);
96 }
97
98 #[inline]
100 pub fn next(&mut self) {
101 self.interpolator.next();
102 if self.pos >= self.subdiv_size {
103 let mut sub_len = self.len;
104 if sub_len > self.subdiv_size {
105 sub_len = self.subdiv_size;
106 }
107 self.interpolator.resynchronize(
108 self.src_x as f64 / SUBPIXEL_SCALE as f64 + sub_len as f64,
109 self.src_y,
110 sub_len,
111 );
112 self.pos = 0;
113 }
114 self.src_x += SUBPIXEL_SCALE;
115 self.pos += 1;
116 self.len -= 1;
117 }
118
119 #[inline]
121 pub fn coordinates(&self, x: &mut i32, y: &mut i32) {
122 self.interpolator.coordinates(x, y);
123 }
124}
125
126#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::trans_affine::TransAffine;
134
135 #[test]
136 fn test_identity_subdiv() {
137 let interp = SpanInterpolatorLinear::new(TransAffine::new());
138 let mut subdiv = SpanSubdivAdaptor::new(interp);
139 subdiv.begin(5.0, 10.0, 20);
140
141 let mut x = 0i32;
142 let mut y = 0i32;
143 subdiv.coordinates(&mut x, &mut y);
144 assert_eq!(x, 5 * 256);
145 assert_eq!(y, 10 * 256);
146 }
147
148 #[test]
149 fn test_next_advances() {
150 let interp = SpanInterpolatorLinear::new(TransAffine::new());
151 let mut subdiv = SpanSubdivAdaptor::new(interp);
152 subdiv.begin(0.0, 0.0, 10);
153
154 let mut x = 0i32;
155 let mut y = 0i32;
156 subdiv.coordinates(&mut x, &mut y);
157 assert_eq!(x, 0);
158
159 subdiv.next();
160 subdiv.coordinates(&mut x, &mut y);
161 assert_eq!(x, 256);
162 }
163
164 #[test]
165 fn test_subdiv_shift() {
166 let interp = SpanInterpolatorLinear::new(TransAffine::new());
167 let subdiv = SpanSubdivAdaptor::new_with_shift(interp, 3);
168 assert_eq!(subdiv.subdiv_shift(), 3);
169 }
170
171 #[test]
172 fn test_resynchronize_across_boundary() {
173 let interp = SpanInterpolatorLinear::new(TransAffine::new());
174 let mut subdiv = SpanSubdivAdaptor::new(interp);
175 subdiv.begin(0.0, 0.0, 32);
177
178 for _ in 0..16 {
179 subdiv.next();
180 }
181 let mut x = 0i32;
182 let mut y = 0i32;
183 subdiv.coordinates(&mut x, &mut y);
184 assert_eq!(x, 16 * 256);
186 }
187
188 #[test]
189 fn test_with_translation() {
190 let trans = TransAffine::new_translation(100.0, 200.0);
191 let interp = SpanInterpolatorLinear::new(trans);
192 let mut subdiv = SpanSubdivAdaptor::new(interp);
193 subdiv.begin(0.0, 0.0, 5);
194
195 let mut x = 0i32;
196 let mut y = 0i32;
197 subdiv.coordinates(&mut x, &mut y);
198 assert_eq!(x, 100 * 256);
199 assert_eq!(y, 200 * 256);
200 }
201
202 #[test]
203 fn test_set_subdiv_shift() {
204 let interp = SpanInterpolatorLinear::new(TransAffine::new());
205 let mut subdiv = SpanSubdivAdaptor::new(interp);
206 subdiv.set_subdiv_shift(6);
207 assert_eq!(subdiv.subdiv_shift(), 6);
208 }
209}