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//
16// Perspective 2D transformations
17//
18//----------------------------------------------------------------------------
19#ifndef AGG_TRANS_PERSPECTIVE_INCLUDED
20#define AGG_TRANS_PERSPECTIVE_INCLUDED
21
22#include "agg_basics.h"
23#include "agg_simul_eq.h"
24
25namespace agg
26{
27    //=======================================================trans_perspective
28    class trans_perspective
29    {
30    public:
31        //--------------------------------------------------------------------
32        trans_perspective() : m_valid(false) {}
33
34
35        //--------------------------------------------------------------------
36        // Arbitrary quadrangle transformations
37        trans_perspective(const double* src, const double* dst)
38        {
39            quad_to_quad(src, dst);
40        }
41
42
43        //--------------------------------------------------------------------
44        // Direct transformations
45        trans_perspective(double x1, double y1, double x2, double y2,
46                          const double* quad)
47        {
48            rect_to_quad(x1, y1, x2, y2, quad);
49        }
50
51
52        //--------------------------------------------------------------------
53        // Reverse transformations
54        trans_perspective(const double* quad,
55                          double x1, double y1, double x2, double y2)
56        {
57            quad_to_rect(quad, x1, y1, x2, y2);
58        }
59
60
61        //--------------------------------------------------------------------
62        // Set the transformations using two arbitrary quadrangles.
63        void quad_to_quad(const double* src, const double* dst)
64        {
65
66            double left[8][8];
67            double right[8][1];
68
69            unsigned i;
70            for (i = 0; i < 4; i++)
71            {
72                unsigned ix = i * 2;
73                unsigned iy = ix + 1;
74
75                left[ix][0]  =  1.0;
76                left[ix][1]  =  src[ix];
77                left[ix][2]  =  src[iy];
78                left[ix][3]  =  0.0;
79                left[ix][4]  =  0.0;
80                left[ix][5]  =  0.0;
81                left[ix][6]  = -src[ix] * dst[ix];
82                left[ix][7]  = -src[iy] * dst[ix];
83                right[ix][0] =  dst[ix];
84
85                left[iy][0]  =  0.0;
86                left[iy][1]  =  0.0;
87                left[iy][2]  =  0.0;
88                left[iy][3]  =  1.0;
89                left[iy][4]  =  src[ix];
90                left[iy][5]  =  src[iy];
91                left[iy][6]  = -src[ix] * dst[iy];
92                left[iy][7]  = -src[iy] * dst[iy];
93                right[iy][0] =  dst[iy];
94            }
95            m_valid = simul_eq<8, 1>::solve(left, right, m_mtx);
96        }
97
98
99        //--------------------------------------------------------------------
100        // Set the direct transformations, i.e., rectangle -> quadrangle
101        void rect_to_quad(double x1, double y1, double x2, double y2,
102                          const double* quad)
103        {
104            double src[8];
105            src[0] = src[6] = x1;
106            src[2] = src[4] = x2;
107            src[1] = src[3] = y1;
108            src[5] = src[7] = y2;
109            quad_to_quad(src, quad);
110        }
111
112
113        //--------------------------------------------------------------------
114        // Set the reverse transformations, i.e., quadrangle -> rectangle
115        void quad_to_rect(const double* quad,
116                          double x1, double y1, double x2, double y2)
117        {
118            double dst[8];
119            dst[0] = dst[6] = x1;
120            dst[2] = dst[4] = x2;
121            dst[1] = dst[3] = y1;
122            dst[5] = dst[7] = y2;
123            quad_to_quad(quad, dst);
124        }
125
126        //--------------------------------------------------------------------
127        // Check if the equations were solved successfully
128        bool is_valid() const { return m_valid; }
129
130        //--------------------------------------------------------------------
131        // Transform a point (x, y)
132        void transform(double* x, double* y) const
133        {
134            double tx = *x;
135            double ty = *y;
136            double d = 1.0 / (m_mtx[6][0] * tx + m_mtx[7][0] * ty + 1.0);
137            *x = (m_mtx[0][0] + m_mtx[1][0] * tx + m_mtx[2][0] * ty) * d;
138            *y = (m_mtx[3][0] + m_mtx[4][0] * tx + m_mtx[5][0] * ty) * d;
139        }
140
141        //--------------------------------------------------------------------
142        class iterator_x
143        {
144            double den;
145            double den_step;
146            double nom_x;
147            double nom_x_step;
148            double nom_y;
149            double nom_y_step;
150
151        public:
152            double x;
153            double y;
154
155            iterator_x() {}
156            iterator_x(double tx, double ty, double step, const double m[8][1]) :
157                den(m[6][0] * tx + m[7][0] * ty + 1.0),
158                den_step(m[6][0] * step),
159                nom_x(m[0][0] + m[1][0] * tx + m[2][0] * ty),
160                nom_x_step(m[1][0] * step),
161                nom_y(m[3][0] + m[4][0] * tx + m[5][0] * ty),
162                nom_y_step(m[4][0] * step),
163                x(nom_x / den),
164                y(nom_y / den)
165            {
166            }
167
168            void operator ++ ()
169            {
170                den   += den_step;
171                nom_x += nom_x_step;
172                nom_y += nom_y_step;
173                double d = 1.0 / den;
174                x = nom_x * d;
175                y = nom_y * d;
176            }
177        };
178
179        //--------------------------------------------------------------------
180        iterator_x begin(double x, double y, double step) const
181        {
182            return iterator_x(x, y, step, m_mtx);
183        }
184
185    private:
186        double m_mtx[8][1];
187        bool   m_valid;
188    };
189
190}
191
192#endif
193