1use crate::basics::{iround, uround};
9use crate::dda_line::Dda2LineInterpolator;
10use crate::span_interpolator_linear::SpanInterpolator;
11use crate::trans_perspective::{PerspectiveIteratorX, TransPerspective};
12
13const SUBPIXEL_SHIFT: u32 = 8;
15const SUBPIXEL_SCALE: i32 = 1 << SUBPIXEL_SHIFT;
16
17fn calc_scale(
20 xt: f64,
21 yt: f64,
22 x_src: f64,
23 y_src: f64,
24 trans_inv: &TransPerspective,
25 dx_offset: f64,
26 dy_offset: f64,
27) -> i32 {
28 let mut dx = xt + dx_offset;
29 let mut dy = yt + dy_offset;
30 trans_inv.transform(&mut dx, &mut dy);
31 dx -= x_src;
32 dy -= y_src;
33 (uround(SUBPIXEL_SCALE as f64 / (dx * dx + dy * dy).sqrt()) >> SUBPIXEL_SHIFT) as i32
34}
35
36pub struct SpanInterpolatorPerspExact {
46 trans_dir: TransPerspective,
47 trans_inv: TransPerspective,
48 iterator: PerspectiveIteratorX,
49 scale_x: Dda2LineInterpolator,
50 scale_y: Dda2LineInterpolator,
51}
52
53impl SpanInterpolatorPerspExact {
54 pub fn new() -> Self {
55 Self {
56 trans_dir: TransPerspective::new(),
57 trans_inv: TransPerspective::new(),
58 iterator: PerspectiveIteratorX::default_new(),
59 scale_x: Dda2LineInterpolator::new_forward(0, 0, 1),
60 scale_y: Dda2LineInterpolator::new_forward(0, 0, 1),
61 }
62 }
63
64 pub fn new_quad_to_quad(src: &[f64; 8], dst: &[f64; 8]) -> Self {
65 let mut s = Self::new();
66 s.quad_to_quad(src, dst);
67 s
68 }
69
70 pub fn new_rect_to_quad(x1: f64, y1: f64, x2: f64, y2: f64, quad: &[f64; 8]) -> Self {
71 let mut s = Self::new();
72 s.rect_to_quad(x1, y1, x2, y2, quad);
73 s
74 }
75
76 pub fn new_quad_to_rect(quad: &[f64; 8], x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
77 let mut s = Self::new();
78 s.quad_to_rect(quad, x1, y1, x2, y2);
79 s
80 }
81
82 pub fn quad_to_quad(&mut self, src: &[f64; 8], dst: &[f64; 8]) {
83 self.trans_dir.quad_to_quad(src, dst);
84 self.trans_inv.quad_to_quad(dst, src);
85 }
86
87 pub fn rect_to_quad(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, quad: &[f64; 8]) {
88 let src = [x1, y1, x2, y1, x2, y2, x1, y2];
89 self.quad_to_quad(&src, quad);
90 }
91
92 pub fn quad_to_rect(&mut self, quad: &[f64; 8], x1: f64, y1: f64, x2: f64, y2: f64) {
93 let dst = [x1, y1, x2, y1, x2, y2, x1, y2];
94 self.quad_to_quad(quad, &dst);
95 }
96
97 pub fn is_valid(&self) -> bool {
98 self.trans_dir.is_valid()
99 }
100
101 pub fn local_scale(&self, x: &mut i32, y: &mut i32) {
102 *x = self.scale_x.y();
103 *y = self.scale_y.y();
104 }
105
106 pub fn transform(&self, x: &mut f64, y: &mut f64) {
107 self.trans_dir.transform(x, y);
108 }
109
110 pub fn trans_dir(&self) -> &TransPerspective {
111 &self.trans_dir
112 }
113
114 pub fn trans_inv(&self) -> &TransPerspective {
115 &self.trans_inv
116 }
117}
118
119impl SpanInterpolator for SpanInterpolatorPerspExact {
120 fn begin(&mut self, x: f64, y: f64, len: u32) {
121 self.iterator = self.trans_dir.begin(x, y, 1.0);
122 let xt = self.iterator.x;
123 let yt = self.iterator.y;
124
125 let delta = 1.0 / SUBPIXEL_SCALE as f64;
126
127 let sx1 = calc_scale(xt, yt, x, y, &self.trans_inv, delta, 0.0);
128 let sy1 = calc_scale(xt, yt, x, y, &self.trans_inv, 0.0, delta);
129
130 let x2 = x + len as f64;
131 let mut xt2 = x2;
132 let mut yt2 = y;
133 self.trans_dir.transform(&mut xt2, &mut yt2);
134
135 let sx2 = calc_scale(xt2, yt2, x2, y, &self.trans_inv, delta, 0.0);
136 let sy2 = calc_scale(xt2, yt2, x2, y, &self.trans_inv, 0.0, delta);
137
138 self.scale_x = Dda2LineInterpolator::new_forward(sx1, sx2, len as i32);
139 self.scale_y = Dda2LineInterpolator::new_forward(sy1, sy2, len as i32);
140 }
141
142 fn next(&mut self) {
143 self.iterator.next();
144 self.scale_x.inc();
145 self.scale_y.inc();
146 }
147
148 fn coordinates(&self, x: &mut i32, y: &mut i32) {
149 *x = iround(self.iterator.x * SUBPIXEL_SCALE as f64);
150 *y = iround(self.iterator.y * SUBPIXEL_SCALE as f64);
151 }
152}
153
154pub struct SpanInterpolatorPerspLerp {
164 trans_dir: TransPerspective,
165 trans_inv: TransPerspective,
166 coord_x: Dda2LineInterpolator,
167 coord_y: Dda2LineInterpolator,
168 scale_x: Dda2LineInterpolator,
169 scale_y: Dda2LineInterpolator,
170}
171
172impl SpanInterpolatorPerspLerp {
173 pub fn new() -> Self {
174 Self {
175 trans_dir: TransPerspective::new(),
176 trans_inv: TransPerspective::new(),
177 coord_x: Dda2LineInterpolator::new_forward(0, 0, 1),
178 coord_y: Dda2LineInterpolator::new_forward(0, 0, 1),
179 scale_x: Dda2LineInterpolator::new_forward(0, 0, 1),
180 scale_y: Dda2LineInterpolator::new_forward(0, 0, 1),
181 }
182 }
183
184 pub fn new_quad_to_quad(src: &[f64; 8], dst: &[f64; 8]) -> Self {
185 let mut s = Self::new();
186 s.quad_to_quad(src, dst);
187 s
188 }
189
190 pub fn new_rect_to_quad(x1: f64, y1: f64, x2: f64, y2: f64, quad: &[f64; 8]) -> Self {
191 let mut s = Self::new();
192 s.rect_to_quad(x1, y1, x2, y2, quad);
193 s
194 }
195
196 pub fn new_quad_to_rect(quad: &[f64; 8], x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
197 let mut s = Self::new();
198 s.quad_to_rect(quad, x1, y1, x2, y2);
199 s
200 }
201
202 pub fn quad_to_quad(&mut self, src: &[f64; 8], dst: &[f64; 8]) {
203 self.trans_dir.quad_to_quad(src, dst);
204 self.trans_inv.quad_to_quad(dst, src);
205 }
206
207 pub fn rect_to_quad(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, quad: &[f64; 8]) {
208 let src = [x1, y1, x2, y1, x2, y2, x1, y2];
209 self.quad_to_quad(&src, quad);
210 }
211
212 pub fn quad_to_rect(&mut self, quad: &[f64; 8], x1: f64, y1: f64, x2: f64, y2: f64) {
213 let dst = [x1, y1, x2, y1, x2, y2, x1, y2];
214 self.quad_to_quad(quad, &dst);
215 }
216
217 pub fn is_valid(&self) -> bool {
218 self.trans_dir.is_valid()
219 }
220
221 pub fn local_scale(&self, x: &mut i32, y: &mut i32) {
222 *x = self.scale_x.y();
223 *y = self.scale_y.y();
224 }
225
226 pub fn transform(&self, x: &mut f64, y: &mut f64) {
227 self.trans_dir.transform(x, y);
228 }
229
230 pub fn trans_dir(&self) -> &TransPerspective {
231 &self.trans_dir
232 }
233
234 pub fn trans_inv(&self) -> &TransPerspective {
235 &self.trans_inv
236 }
237}
238
239impl SpanInterpolator for SpanInterpolatorPerspLerp {
240 fn begin(&mut self, x: f64, y: f64, len: u32) {
241 let mut xt = x;
243 let mut yt = y;
244 self.trans_dir.transform(&mut xt, &mut yt);
245 let x1 = iround(xt * SUBPIXEL_SCALE as f64);
246 let y1 = iround(yt * SUBPIXEL_SCALE as f64);
247
248 let delta = 1.0 / SUBPIXEL_SCALE as f64;
249
250 let sx1 = calc_scale(xt, yt, x, y, &self.trans_inv, delta, 0.0);
251 let sy1 = calc_scale(xt, yt, x, y, &self.trans_inv, 0.0, delta);
252
253 let x_end = x + len as f64;
255 let mut xt2 = x_end;
256 let mut yt2 = y;
257 self.trans_dir.transform(&mut xt2, &mut yt2);
258 let x2 = iround(xt2 * SUBPIXEL_SCALE as f64);
259 let y2 = iround(yt2 * SUBPIXEL_SCALE as f64);
260
261 let sx2 = calc_scale(xt2, yt2, x_end, y, &self.trans_inv, delta, 0.0);
262 let sy2 = calc_scale(xt2, yt2, x_end, y, &self.trans_inv, 0.0, delta);
263
264 self.coord_x = Dda2LineInterpolator::new_forward(x1, x2, len as i32);
265 self.coord_y = Dda2LineInterpolator::new_forward(y1, y2, len as i32);
266 self.scale_x = Dda2LineInterpolator::new_forward(sx1, sx2, len as i32);
267 self.scale_y = Dda2LineInterpolator::new_forward(sy1, sy2, len as i32);
268 }
269
270 fn next(&mut self) {
271 self.coord_x.inc();
272 self.coord_y.inc();
273 self.scale_x.inc();
274 self.scale_y.inc();
275 }
276
277 fn coordinates(&self, x: &mut i32, y: &mut i32) {
278 *x = self.coord_x.y();
279 *y = self.coord_y.y();
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_exact_identity() {
289 let src = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
290 let dst = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
291 let mut interp = SpanInterpolatorPerspExact::new_quad_to_quad(&src, &dst);
292 assert!(interp.is_valid());
293
294 interp.begin(50.0, 50.0, 10);
295 let (mut x, mut y) = (0, 0);
296 interp.coordinates(&mut x, &mut y);
297 assert!((x - 12800).abs() < 5, "x={x}");
299 assert!((y - 12800).abs() < 5, "y={y}");
300 }
301
302 #[test]
303 fn test_exact_next_advances() {
304 let src = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
305 let dst = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
306 let mut interp = SpanInterpolatorPerspExact::new_quad_to_quad(&src, &dst);
307
308 interp.begin(0.0, 50.0, 10);
309 let (mut x1, mut y1) = (0, 0);
310 interp.coordinates(&mut x1, &mut y1);
311
312 interp.next();
313 let (mut x2, mut y2) = (0, 0);
314 interp.coordinates(&mut x2, &mut y2);
315
316 assert!(x2 > x1, "x2={x2} should be > x1={x1}");
318 assert!((x2 - x1 - 256).abs() < 5, "step={}", x2 - x1);
319 }
320
321 #[test]
322 fn test_lerp_identity() {
323 let src = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
324 let dst = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
325 let mut interp = SpanInterpolatorPerspLerp::new_quad_to_quad(&src, &dst);
326 assert!(interp.is_valid());
327
328 interp.begin(50.0, 50.0, 10);
329 let (mut x, mut y) = (0, 0);
330 interp.coordinates(&mut x, &mut y);
331 assert!((x - 12800).abs() < 5, "x={x}");
332 assert!((y - 12800).abs() < 5, "y={y}");
333 }
334
335 #[test]
336 fn test_lerp_next_advances() {
337 let src = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
338 let dst = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 0.0, 100.0];
339 let mut interp = SpanInterpolatorPerspLerp::new_quad_to_quad(&src, &dst);
340
341 interp.begin(0.0, 50.0, 10);
342 let (mut x1, mut y1) = (0, 0);
343 interp.coordinates(&mut x1, &mut y1);
344
345 interp.next();
346 let (mut x2, mut y2) = (0, 0);
347 interp.coordinates(&mut x2, &mut y2);
348
349 assert!(x2 > x1, "x2={x2} should be > x1={x1}");
350 assert!((x2 - x1 - 256).abs() < 5, "step={}", x2 - x1);
351 }
352
353 #[test]
354 fn test_exact_rect_to_quad() {
355 let quad = [10.0, 10.0, 110.0, 10.0, 110.0, 110.0, 10.0, 110.0];
356 let mut interp = SpanInterpolatorPerspExact::new_rect_to_quad(0.0, 0.0, 100.0, 100.0, &quad);
357 assert!(interp.is_valid());
358
359 interp.begin(0.0, 0.0, 1);
361 let (mut x, mut y) = (0, 0);
362 interp.coordinates(&mut x, &mut y);
363 assert!((x - 10 * 256).abs() < 5, "x={x}");
364 assert!((y - 10 * 256).abs() < 5, "y={y}");
365 }
366
367 #[test]
368 fn test_lerp_rect_to_quad() {
369 let quad = [10.0, 10.0, 110.0, 10.0, 110.0, 110.0, 10.0, 110.0];
370 let mut interp = SpanInterpolatorPerspLerp::new_rect_to_quad(0.0, 0.0, 100.0, 100.0, &quad);
371 assert!(interp.is_valid());
372
373 interp.begin(0.0, 0.0, 1);
374 let (mut x, mut y) = (0, 0);
375 interp.coordinates(&mut x, &mut y);
376 assert!((x - 10 * 256).abs() < 5, "x={x}");
377 assert!((y - 10 * 256).abs() < 5, "y={y}");
378 }
379
380 #[test]
381 fn test_exact_and_lerp_agree_on_identity() {
382 let src = [0.0, 0.0, 200.0, 0.0, 200.0, 200.0, 0.0, 200.0];
383 let dst = src;
384
385 let mut exact = SpanInterpolatorPerspExact::new_quad_to_quad(&src, &dst);
386 let mut lerp = SpanInterpolatorPerspLerp::new_quad_to_quad(&src, &dst);
387
388 exact.begin(10.0, 10.0, 5);
389 lerp.begin(10.0, 10.0, 5);
390
391 for _ in 0..5 {
392 let (mut ex, mut ey) = (0, 0);
393 let (mut lx, mut ly) = (0, 0);
394 exact.coordinates(&mut ex, &mut ey);
395 lerp.coordinates(&mut lx, &mut ly);
396 assert!((ex - lx).abs() < 3, "ex={ex} lx={lx}");
397 assert!((ey - ly).abs() < 3, "ey={ey} ly={ly}");
398
399 exact.next();
400 lerp.next();
401 }
402 }
403}