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// Bilinear 2D transformations
17//
18//----------------------------------------------------------------------------
19#ifndef AGG_TRANS_BILINEAR_INCLUDED
20#define AGG_TRANS_BILINEAR_INCLUDED
21
22#include "agg_basics.h"
23#include "agg_simul_eq.h"
24
25namespace agg
26{
27
28    //==========================================================trans_bilinear
29    class trans_bilinear
30    {
31    public:
32        //--------------------------------------------------------------------
33        trans_bilinear() : m_valid(false) {}
34
35        //--------------------------------------------------------------------
36        // Arbitrary quadrangle transformations
37        trans_bilinear(const double* src, const double* dst)
38        {
39            quad_to_quad(src, dst);
40        }
41
42
43        //--------------------------------------------------------------------
44        // Direct transformations
45        trans_bilinear(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_bilinear(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            double left[4][4];
66            double right[4][2];
67
68            unsigned i;
69            for(i = 0; i < 4; i++)
70            {
71                unsigned ix = i * 2;
72                unsigned iy = ix + 1;
73                left[i][0] = 1.0;
74                left[i][1] = src[ix] * src[iy];
75                left[i][2] = src[ix];
76                left[i][3] = src[iy];
77
78                right[i][0] = dst[ix];
79                right[i][1] = dst[iy];
80            }
81            m_valid = simul_eq<4, 2>::solve(left, right, m_mtx);
82        }
83
84
85        //--------------------------------------------------------------------
86        // Set the direct transformations, i.e., rectangle -> quadrangle
87        void rect_to_quad(double x1, double y1, double x2, double y2,
88                          const double* quad)
89        {
90            double src[8];
91            src[0] = src[6] = x1;
92            src[2] = src[4] = x2;
93            src[1] = src[3] = y1;
94            src[5] = src[7] = y2;
95            quad_to_quad(src, quad);
96        }
97
98
99        //--------------------------------------------------------------------
100        // Set the reverse transformations, i.e., quadrangle -> rectangle
101        void quad_to_rect(const double* quad,
102                          double x1, double y1, double x2, double y2)
103        {
104            double dst[8];
105            dst[0] = dst[6] = x1;
106            dst[2] = dst[4] = x2;
107            dst[1] = dst[3] = y1;
108            dst[5] = dst[7] = y2;
109            quad_to_quad(quad, dst);
110        }
111
112        //--------------------------------------------------------------------
113        // Check if the equations were solved successfully
114        bool is_valid() const { return m_valid; }
115
116        //--------------------------------------------------------------------
117        // Transform a point (x, y)
118        void transform(double* x, double* y) const
119        {
120            double tx = *x;
121            double ty = *y;
122            double xy = tx * ty;
123            *x = m_mtx[0][0] + m_mtx[1][0] * xy + m_mtx[2][0] * tx + m_mtx[3][0] * ty;
124            *y = m_mtx[0][1] + m_mtx[1][1] * xy + m_mtx[2][1] * tx + m_mtx[3][1] * ty;
125        }
126
127
128        //--------------------------------------------------------------------
129        class iterator_x
130        {
131            double inc_x;
132            double inc_y;
133
134        public:
135            double x;
136            double y;
137
138            iterator_x() {}
139            iterator_x(double tx, double ty, double step, const double m[4][2]) :
140                inc_x(m[1][0] * step * ty + m[2][0] * step),
141                inc_y(m[1][1] * step * ty + m[2][1] * step),
142                x(m[0][0] + m[1][0] * tx * ty + m[2][0] * tx + m[3][0] * ty),
143                y(m[0][1] + m[1][1] * tx * ty + m[2][1] * tx + m[3][1] * ty)
144            {
145            }
146
147            void operator ++ ()
148            {
149                x += inc_x;
150                y += inc_y;
151            }
152        };
153
154        iterator_x begin(double x, double y, double step) const
155        {
156            return iterator_x(x, y, step, m_mtx);
157        }
158
159    private:
160        double m_mtx[4][2];
161        bool   m_valid;
162    };
163
164}
165
166#endif
167