1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.4
3// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15#ifndef AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED
16#define AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED
17
18#include "agg_trans_perspective.h"
19#include "agg_dda_line.h"
20
21namespace agg
22{
23
24
25
26    //===========================================span_interpolator_persp_exact
27    template<unsigned SubpixelShift = 8>
28    class span_interpolator_persp_exact
29    {
30    public:
31        typedef trans_perspective trans_type;
32        typedef trans_perspective::iterator_x iterator_type;
33        enum subpixel_scale_e
34        {
35            subpixel_shift = SubpixelShift,
36            subpixel_scale = 1 << subpixel_shift
37        };
38
39        //--------------------------------------------------------------------
40        span_interpolator_persp_exact() {}
41
42        //--------------------------------------------------------------------
43        // Arbitrary quadrangle transformations
44        span_interpolator_persp_exact(const double* src, const double* dst)
45        {
46            quad_to_quad(src, dst);
47        }
48
49        //--------------------------------------------------------------------
50        // Direct transformations
51        span_interpolator_persp_exact(double x1, double y1,
52                                      double x2, double y2,
53                                      const double* quad)
54        {
55            rect_to_quad(x1, y1, x2, y2, quad);
56        }
57
58        //--------------------------------------------------------------------
59        // Reverse transformations
60        span_interpolator_persp_exact(const double* quad,
61                                      double x1, double y1,
62                                      double x2, double y2)
63        {
64            quad_to_rect(quad, x1, y1, x2, y2);
65        }
66
67        //--------------------------------------------------------------------
68        // Set the transformations using two arbitrary quadrangles.
69        void quad_to_quad(const double* src, const double* dst)
70        {
71            m_trans_dir.quad_to_quad(src, dst);
72            m_trans_inv.quad_to_quad(dst, src);
73        }
74
75        //--------------------------------------------------------------------
76        // Set the direct transformations, i.e., rectangle -> quadrangle
77        void rect_to_quad(double x1, double y1, double x2, double y2,
78                          const double* quad)
79        {
80            double src[8];
81            src[0] = src[6] = x1;
82            src[2] = src[4] = x2;
83            src[1] = src[3] = y1;
84            src[5] = src[7] = y2;
85            quad_to_quad(src, quad);
86        }
87
88
89        //--------------------------------------------------------------------
90        // Set the reverse transformations, i.e., quadrangle -> rectangle
91        void quad_to_rect(const double* quad,
92                          double x1, double y1, double x2, double y2)
93        {
94            double dst[8];
95            dst[0] = dst[6] = x1;
96            dst[2] = dst[4] = x2;
97            dst[1] = dst[3] = y1;
98            dst[5] = dst[7] = y2;
99            quad_to_quad(quad, dst);
100        }
101
102        //--------------------------------------------------------------------
103        // Check if the equations were solved successfully
104        bool is_valid() const { return m_trans_dir.is_valid(); }
105
106        //----------------------------------------------------------------
107        void begin(double x, double y, unsigned len)
108        {
109            m_iterator = m_trans_dir.begin(x, y, 1.0);
110            double xt = m_iterator.x;
111            double yt = m_iterator.y;
112
113            double dx;
114            double dy;
115            const double delta = 1/double(subpixel_scale);
116            dx = xt + delta;
117            dy = yt;
118            m_trans_inv.transform(&dx, &dy);
119            dx -= x;
120            dy -= y;
121            int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
122            dx = xt;
123            dy = yt + delta;
124            m_trans_inv.transform(&dx, &dy);
125            dx -= x;
126            dy -= y;
127            int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
128
129            x += len;
130            xt = x;
131            yt = y;
132            m_trans_dir.transform(&xt, &yt);
133
134            dx = xt + delta;
135            dy = yt;
136            m_trans_inv.transform(&dx, &dy);
137            dx -= x;
138            dy -= y;
139            int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
140            dx = xt;
141            dy = yt + delta;
142            m_trans_inv.transform(&dx, &dy);
143            dx -= x;
144            dy -= y;
145            int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
146
147            m_scale_x = dda2_line_interpolator(sx1, sx2, len);
148            m_scale_y = dda2_line_interpolator(sy1, sy2, len);
149        }
150
151
152        //----------------------------------------------------------------
153        void resynchronize(double xe, double ye, unsigned len)
154        {
155            // Assume x1,y1 are equal to the ones at the previous end point
156            int sx1 = m_scale_x.y();
157            int sy1 = m_scale_y.y();
158
159            // Calculate transformed coordinates at x2,y2
160            double xt = xe;
161            double yt = ye;
162            m_trans_dir.transform(&xt, &yt);
163
164            const double delta = 1/double(subpixel_scale);
165            double dx;
166            double dy;
167
168            // Calculate scale by X at x2,y2
169            dx = xt + delta;
170            dy = yt;
171            m_trans_inv.transform(&dx, &dy);
172            dx -= xe;
173            dy -= ye;
174            int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
175
176            // Calculate scale by Y at x2,y2
177            dx = xt;
178            dy = yt + delta;
179            m_trans_inv.transform(&dx, &dy);
180            dx -= xe;
181            dy -= ye;
182            int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
183
184            // Initialize the interpolators
185            m_scale_x = dda2_line_interpolator(sx1, sx2, len);
186            m_scale_y = dda2_line_interpolator(sy1, sy2, len);
187        }
188
189
190
191        //----------------------------------------------------------------
192        void operator++()
193        {
194            ++m_iterator;
195            ++m_scale_x;
196            ++m_scale_y;
197        }
198
199        //----------------------------------------------------------------
200        void coordinates(int* x, int* y) const
201        {
202            *x = iround(m_iterator.x * subpixel_scale);
203            *y = iround(m_iterator.y * subpixel_scale);
204        }
205
206        //----------------------------------------------------------------
207        void local_scale(int* x, int* y)
208        {
209            *x = m_scale_x.y();
210            *y = m_scale_y.y();
211        }
212
213        //----------------------------------------------------------------
214        void transform(double* x, double* y) const
215        {
216            m_trans_dir.transform(x, y);
217        }
218
219    private:
220        trans_type             m_trans_dir;
221        trans_type             m_trans_inv;
222        iterator_type          m_iterator;
223        dda2_line_interpolator m_scale_x;
224        dda2_line_interpolator m_scale_y;
225    };
226
227
228
229
230
231
232
233
234
235
236
237    //============================================span_interpolator_persp_lerp
238    template<unsigned SubpixelShift = 8>
239    class span_interpolator_persp_lerp
240    {
241    public:
242        typedef trans_perspective trans_type;
243        enum subpixel_scale_e
244        {
245            subpixel_shift = SubpixelShift,
246            subpixel_scale = 1 << subpixel_shift
247        };
248
249        //--------------------------------------------------------------------
250        span_interpolator_persp_lerp() {}
251
252        //--------------------------------------------------------------------
253        // Arbitrary quadrangle transformations
254        span_interpolator_persp_lerp(const double* src, const double* dst)
255        {
256            quad_to_quad(src, dst);
257        }
258
259        //--------------------------------------------------------------------
260        // Direct transformations
261        span_interpolator_persp_lerp(double x1, double y1,
262                                     double x2, double y2,
263                                     const double* quad)
264        {
265            rect_to_quad(x1, y1, x2, y2, quad);
266        }
267
268        //--------------------------------------------------------------------
269        // Reverse transformations
270        span_interpolator_persp_lerp(const double* quad,
271                                     double x1, double y1,
272                                     double x2, double y2)
273        {
274            quad_to_rect(quad, x1, y1, x2, y2);
275        }
276
277        //--------------------------------------------------------------------
278        // Set the transformations using two arbitrary quadrangles.
279        void quad_to_quad(const double* src, const double* dst)
280        {
281            m_trans_dir.quad_to_quad(src, dst);
282            m_trans_inv.quad_to_quad(dst, src);
283        }
284
285        //--------------------------------------------------------------------
286        // Set the direct transformations, i.e., rectangle -> quadrangle
287        void rect_to_quad(double x1, double y1, double x2, double y2,
288                          const double* quad)
289        {
290            double src[8];
291            src[0] = src[6] = x1;
292            src[2] = src[4] = x2;
293            src[1] = src[3] = y1;
294            src[5] = src[7] = y2;
295            quad_to_quad(src, quad);
296        }
297
298
299        //--------------------------------------------------------------------
300        // Set the reverse transformations, i.e., quadrangle -> rectangle
301        void quad_to_rect(const double* quad,
302                          double x1, double y1, double x2, double y2)
303        {
304            double dst[8];
305            dst[0] = dst[6] = x1;
306            dst[2] = dst[4] = x2;
307            dst[1] = dst[3] = y1;
308            dst[5] = dst[7] = y2;
309            quad_to_quad(quad, dst);
310        }
311
312        //--------------------------------------------------------------------
313        // Check if the equations were solved successfully
314        bool is_valid() const { return m_trans_dir.is_valid(); }
315
316        //----------------------------------------------------------------
317        void begin(double x, double y, unsigned len)
318        {
319            // Calculate transformed coordinates at x1,y1
320            double xt = x;
321            double yt = y;
322            m_trans_dir.transform(&xt, &yt);
323            int x1 = iround(xt * subpixel_scale);
324            int y1 = iround(yt * subpixel_scale);
325
326            double dx;
327            double dy;
328            const double delta = 1/double(subpixel_scale);
329
330            // Calculate scale by X at x1,y1
331            dx = xt + delta;
332            dy = yt;
333            m_trans_inv.transform(&dx, &dy);
334            dx -= x;
335            dy -= y;
336            int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
337
338            // Calculate scale by Y at x1,y1
339            dx = xt;
340            dy = yt + delta;
341            m_trans_inv.transform(&dx, &dy);
342            dx -= x;
343            dy -= y;
344            int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
345
346            // Calculate transformed coordinates at x2,y2
347            x += len;
348            xt = x;
349            yt = y;
350            m_trans_dir.transform(&xt, &yt);
351            int x2 = iround(xt * subpixel_scale);
352            int y2 = iround(yt * subpixel_scale);
353
354            // Calculate scale by X at x2,y2
355            dx = xt + delta;
356            dy = yt;
357            m_trans_inv.transform(&dx, &dy);
358            dx -= x;
359            dy -= y;
360            int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
361
362            // Calculate scale by Y at x2,y2
363            dx = xt;
364            dy = yt + delta;
365            m_trans_inv.transform(&dx, &dy);
366            dx -= x;
367            dy -= y;
368            int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
369
370            // Initialize the interpolators
371            m_coord_x = dda2_line_interpolator(x1,  x2,  len);
372            m_coord_y = dda2_line_interpolator(y1,  y2,  len);
373            m_scale_x = dda2_line_interpolator(sx1, sx2, len);
374            m_scale_y = dda2_line_interpolator(sy1, sy2, len);
375        }
376
377
378        //----------------------------------------------------------------
379        void resynchronize(double xe, double ye, unsigned len)
380        {
381            // Assume x1,y1 are equal to the ones at the previous end point
382            int x1  = m_coord_x.y();
383            int y1  = m_coord_y.y();
384            int sx1 = m_scale_x.y();
385            int sy1 = m_scale_y.y();
386
387            // Calculate transformed coordinates at x2,y2
388            double xt = xe;
389            double yt = ye;
390            m_trans_dir.transform(&xt, &yt);
391            int x2 = iround(xt * subpixel_scale);
392            int y2 = iround(yt * subpixel_scale);
393
394            const double delta = 1/double(subpixel_scale);
395            double dx;
396            double dy;
397
398            // Calculate scale by X at x2,y2
399            dx = xt + delta;
400            dy = yt;
401            m_trans_inv.transform(&dx, &dy);
402            dx -= xe;
403            dy -= ye;
404            int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
405
406            // Calculate scale by Y at x2,y2
407            dx = xt;
408            dy = yt + delta;
409            m_trans_inv.transform(&dx, &dy);
410            dx -= xe;
411            dy -= ye;
412            int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
413
414            // Initialize the interpolators
415            m_coord_x = dda2_line_interpolator(x1,  x2,  len);
416            m_coord_y = dda2_line_interpolator(y1,  y2,  len);
417            m_scale_x = dda2_line_interpolator(sx1, sx2, len);
418            m_scale_y = dda2_line_interpolator(sy1, sy2, len);
419        }
420
421
422        //----------------------------------------------------------------
423        void operator++()
424        {
425            ++m_coord_x;
426            ++m_coord_y;
427            ++m_scale_x;
428            ++m_scale_y;
429        }
430
431        //----------------------------------------------------------------
432        void coordinates(int* x, int* y) const
433        {
434            *x = m_coord_x.y();
435            *y = m_coord_y.y();
436        }
437
438        //----------------------------------------------------------------
439        void local_scale(int* x, int* y)
440        {
441            *x = m_scale_x.y();
442            *y = m_scale_y.y();
443        }
444
445        //----------------------------------------------------------------
446        void transform(double* x, double* y) const
447        {
448            m_trans_dir.transform(x, y);
449        }
450
451    private:
452        trans_type             m_trans_dir;
453        trans_type             m_trans_inv;
454        dda2_line_interpolator m_coord_x;
455        dda2_line_interpolator m_coord_y;
456        dda2_line_interpolator m_scale_x;
457        dda2_line_interpolator m_scale_y;
458    };
459
460}
461
462#endif
463