agg_trans_affine.h revision d1f885b4
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// Affine transformation classes.
17//
18//----------------------------------------------------------------------------
19#ifndef AGG_TRANS_AFFINE_INCLUDED
20#define AGG_TRANS_AFFINE_INCLUDED
21
22#include <math.h>
23#include "agg_basics.h"
24
25namespace agg
26{
27    const double affine_epsilon = 1e-14; // About of precision of doubles
28
29    //============================================================trans_affine
30    //
31    // See Implementation agg_trans_affine.cpp
32    //
33    // Affine transformation are linear transformations in Cartesian coordinates
34    // (strictly speaking not only in Cartesian, but for the beginning we will
35    // think so). They are rotation, scaling, translation and skewing.
36    // After any affine transformation a line segment remains a line segment
37    // and it will never become a curve.
38    //
39    // There will be no math about matrix calculations, since it has been
40    // described many times. Ask yourself a very simple question:
41    // "why do we need to understand and use some matrix stuff instead of just
42    // rotating, scaling and so on". The answers are:
43    //
44    // 1. Any combination of transformations can be done by only 4 multiplications
45    //    and 4 additions in floating point.
46    // 2. One matrix transformation is equivalent to the number of consecutive
47    //    discrete transformations, i.e. the matrix "accumulates" all transformations
48    //    in the order of their settings. Suppose we have 4 transformations:
49    //       * rotate by 30 degrees,
50    //       * scale X to 2.0,
51    //       * scale Y to 1.5,
52    //       * move to (100, 100).
53    //    The result will depend on the order of these transformations,
54    //    and the advantage of matrix is that the sequence of discret calls:
55    //    rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
56    //    will have exactly the same result as the following matrix transformations:
57    //
58    //    affine_matrix m;
59    //    m *= rotate_matrix(30);
60    //    m *= scaleX_matrix(2.0);
61    //    m *= scaleY_matrix(1.5);
62    //    m *= move_matrix(100,100);
63    //
64    //    m.transform_my_point_at_last(x, y);
65    //
66    // What is the good of it? In real life we will set-up the matrix only once
67    // and then transform many points, let alone the convenience to set any
68    // combination of transformations.
69    //
70    // So, how to use it? Very easy - literally as it's shown above. Not quite,
71    // let us write a correct example:
72    //
73    // agg::trans_affine m;
74    // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);
75    // m *= agg::trans_affine_scaling(2.0, 1.5);
76    // m *= agg::trans_affine_translation(100.0, 100.0);
77    // m.transform(&x, &y);
78    //
79    // The affine matrix is all you need to perform any linear transformation,
80    // but all transformations have origin point (0,0). It means that we need to
81    // use 2 translations if we want to rotate someting around (100,100):
82    //
83    // m *= agg::trans_affine_translation(-100.0, -100.0);         // move to (0,0)
84    // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);  // rotate
85    // m *= agg::trans_affine_translation(100.0, 100.0);           // move back to (100,100)
86    //----------------------------------------------------------------------
87    class trans_affine
88    {
89    public:
90        //------------------------------------------ Construction
91        // Construct an identity matrix - it does not transform anything
92        trans_affine() :
93            m0(1.0), m1(0.0), m2(0.0), m3(1.0), m4(0.0), m5(0.0)
94        {}
95
96        // Construct a custom matrix. Usually used in derived classes
97        trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) :
98            m0(v0), m1(v1), m2(v2), m3(v3), m4(v4), m5(v5)
99        {}
100
101        // Construct a matrix to transform a parallelogram to another one.
102        trans_affine(const double* rect, const double* parl)
103        {
104            parl_to_parl(rect, parl);
105        }
106
107        // Construct a matrix to transform a rectangle to a parallelogram.
108        trans_affine(double x1, double y1, double x2, double y2,
109                     const double* parl)
110        {
111            rect_to_parl(x1, y1, x2, y2, parl);
112        }
113
114        // Construct a matrix to transform a parallelogram to a rectangle.
115        trans_affine(const double* parl,
116                     double x1, double y1, double x2, double y2)
117        {
118            parl_to_rect(parl, x1, y1, x2, y2);
119        }
120
121
122        //---------------------------------- Parellelogram transformations
123        // Calculate a matrix to transform a parallelogram to another one.
124        // src and dst are pointers to arrays of three points
125        // (double[6], x,y,...) that identify three corners of the
126        // parallelograms assuming implicit fourth points.
127        // There are also transformations rectangtle to parallelogram and
128        // parellelogram to rectangle
129        const trans_affine& parl_to_parl(const double* src,
130                                         const double* dst);
131
132        const trans_affine& rect_to_parl(double x1, double y1,
133                                         double x2, double y2,
134                                         const double* parl);
135
136        const trans_affine& parl_to_rect(const double* parl,
137                                         double x1, double y1,
138                                         double x2, double y2);
139
140
141        //------------------------------------------ Operations
142        // Reset - actually load an identity matrix
143        const trans_affine& reset();
144
145        // Multiply matrix to another one
146        const trans_affine& multiply(const trans_affine& m);
147
148        // Multiply "m" to "this" and assign the result to "this"
149        const trans_affine& premultiply(const trans_affine& m);
150
151        // Multiply matrix to inverse of another one
152        const trans_affine& multiply_inv(const trans_affine& m);
153
154        // Multiply inverse of "m" to "this" and assign the result to "this"
155        const trans_affine& premultiply_inv(const trans_affine& m);
156
157        // Invert matrix. Do not try to invert degenerate matrices,
158        // there's no check for validity. If you set scale to 0 and
159        // then try to invert matrix, expect unpredictable result.
160        const trans_affine& invert();
161
162        // Mirroring around X
163        const trans_affine& flip_x();
164
165        // Mirroring around Y
166        const trans_affine& flip_y();
167
168        //------------------------------------------- Load/Store
169        // Store matrix to an array [6] of double
170        void store_to(double* m) const
171        {
172            *m++ = m0; *m++ = m1; *m++ = m2; *m++ = m3; *m++ = m4; *m++ = m5;
173        }
174
175        // Load matrix from an array [6] of double
176        const trans_affine& load_from(const double* m)
177        {
178            m0 = *m++; m1 = *m++; m2 = *m++; m3 = *m++; m4 = *m++;  m5 = *m++;
179            return *this;
180        }
181
182        //------------------------------------------- Operators
183
184        // Multiply current matrix to another one
185        const trans_affine& operator *= (const trans_affine& m)
186        {
187            return multiply(m);
188        }
189
190        // Multiply current matrix to inverse of another one
191        const trans_affine& operator /= (const trans_affine& m)
192        {
193            return multiply_inv(m);
194        }
195
196        // Multiply current matrix to another one and return
197        // the result in a separete matrix.
198        trans_affine operator * (const trans_affine& m) const
199        {
200            return trans_affine(*this).multiply(m);
201        }
202
203        // Multiply current matrix to inverse of another one
204        // and return the result in a separete matrix.
205        trans_affine operator / (const trans_affine& m) const
206        {
207            return trans_affine(*this).multiply_inv(m);
208        }
209
210        // Calculate and return the inverse matrix
211        trans_affine operator ~ () const
212        {
213            trans_affine ret = *this;
214            return ret.invert();
215        }
216
217        // Equal operator with default epsilon
218        bool operator == (const trans_affine& m) const
219        {
220            return is_equal(m, affine_epsilon);
221        }
222
223        // Not Equal operator with default epsilon
224        bool operator != (const trans_affine& m) const
225        {
226            return !is_equal(m, affine_epsilon);
227        }
228
229        //-------------------------------------------- Transformations
230        // Direct transformation x and y
231        void transform(double* x, double* y) const;
232
233        // Direct transformation x and y, 2x2 matrix only, no translation
234        void transform_2x2(double* x, double* y) const;
235
236        // Inverse transformation x and y. It works slower than the
237        // direct transformation, so if the performance is critical
238        // it's better to invert() the matrix and then use transform()
239        void inverse_transform(double* x, double* y) const;
240
241        //-------------------------------------------- Auxiliary
242        // Calculate the determinant of matrix
243        double determinant() const
244        {
245            return 1.0 / (m0 * m3 - m1 * m2);
246        }
247
248        // Get the average scale (by X and Y).
249        // Basically used to calculate the approximation_scale when
250        // decomposinting curves into line segments.
251        double scale() const;
252
253        // Check to see if it's an identity matrix
254        bool is_identity(double epsilon = affine_epsilon) const;
255
256        // Check to see if two matrices are equal
257        bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
258
259        // Determine the major parameters. Use carefully considering degenerate matrices
260        double rotation() const;
261        void   translation(double* dx, double* dy) const;
262        void   scaling(double* sx, double* sy) const;
263        void   scaling_abs(double* sx, double* sy) const
264        {
265            *sx = sqrt(m0*m0 + m2*m2);
266            *sy = sqrt(m1*m1 + m3*m3);
267        }
268
269    private:
270        double m0;
271        double m1;
272        double m2;
273        double m3;
274        double m4;
275        double m5;
276    };
277
278    //------------------------------------------------------------------------
279    inline void trans_affine::transform(double* x, double* y) const
280    {
281        register double tx = *x;
282        *x = tx * m0 + *y * m2 + m4;
283        *y = tx * m1 + *y * m3 + m5;
284    }
285
286    //------------------------------------------------------------------------
287    inline void trans_affine::transform_2x2(double* x, double* y) const
288    {
289        register double tx = *x;
290        *x = tx * m0 + *y * m2;
291        *y = tx * m1 + *y * m3;
292    }
293
294    //------------------------------------------------------------------------
295    inline void trans_affine::inverse_transform(double* x, double* y) const
296    {
297        register double d = determinant();
298        register double a = (*x - m4) * d;
299        register double b = (*y - m5) * d;
300        *x = a * m3 - b * m2;
301        *y = b * m0 - a * m1;
302    }
303
304    //------------------------------------------------------------------------
305    inline double trans_affine::scale() const
306    {
307        double x = M_SQRT1_2 * m0 + M_SQRT1_2 * m2;
308        double y = M_SQRT1_2 * m1 + M_SQRT1_2 * m3;
309        return sqrt(x*x + y*y);
310    }
311
312    //------------------------------------------------------------------------
313    inline const trans_affine& trans_affine::premultiply(const trans_affine& m)
314    {
315        trans_affine t = m;
316        return *this = t.multiply(*this);
317    }
318
319    //------------------------------------------------------------------------
320    inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m)
321    {
322        trans_affine t = m;
323        t.invert();
324        multiply(t);
325        return *this;
326    }
327
328    //------------------------------------------------------------------------
329    inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m)
330    {
331        trans_affine t = m;
332        t.invert();
333        return *this = t.multiply(*this);
334    }
335
336    //====================================================trans_affine_rotation
337    // Rotation matrix. sin() and cos() are calculated twice for the same angle.
338    // There's no harm because the performance of sin()/cos() is very good on all
339    // modern processors. Besides, this operation is not going to be invoked too
340    // often.
341    class trans_affine_rotation : public trans_affine
342    {
343    public:
344        trans_affine_rotation(double a) :
345          trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
346        {}
347    };
348
349    //====================================================trans_affine_scaling
350    // Scaling matrix. sx, sy - scale coefficients by X and Y respectively
351    class trans_affine_scaling : public trans_affine
352    {
353    public:
354        trans_affine_scaling(double sx, double sy) :
355          trans_affine(sx, 0.0, 0.0, sy, 0.0, 0.0)
356        {}
357
358        trans_affine_scaling(double s) :
359          trans_affine(s, 0.0, 0.0, s, 0.0, 0.0)
360        {}
361    };
362
363    //================================================trans_affine_translation
364    // Translation matrix
365    class trans_affine_translation : public trans_affine
366    {
367    public:
368        trans_affine_translation(double tx, double ty) :
369          trans_affine(1.0, 0.0, 0.0, 1.0, tx, ty)
370        {}
371    };
372
373    //====================================================trans_affine_skewing
374    // Sckewing (shear) matrix
375    class trans_affine_skewing : public trans_affine
376    {
377    public:
378        trans_affine_skewing(double sx, double sy) :
379          trans_affine(1.0, tan(sy), tan(sx), 1.0, 0.0, 0.0)
380        {}
381    };
382
383
384    //===============================================trans_affine_line_segment
385    // Rotate, Scale and Translate, associating 0...dist with line segment
386    // x1,y1,x2,y2
387    class trans_affine_line_segment : public trans_affine
388    {
389    public:
390        trans_affine_line_segment(double x1, double y1, double x2, double y2,
391                                  double dist)
392        {
393            double dx = x2 - x1;
394            double dy = y2 - y1;
395            if(dist > 0.0)
396            {
397                multiply(trans_affine_scaling(sqrt(dx * dx + dy * dy) / dist));
398            }
399            multiply(trans_affine_rotation(atan2(dy, dx)));
400            multiply(trans_affine_translation(x1, y1));
401        }
402    };
403
404
405}
406
407
408#endif
409
410