xref: /haiku/headers/libs/agg/agg_trans_affine.h (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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 
25 namespace 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 = 0.707106781 * m0 + 0.707106781 * m2;
308         double y = 0.707106781 * m1 + 0.707106781 * 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