1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
16 // Affine transformation classes.
18 //----------------------------------------------------------------------------
19 #ifndef AGG_TRANS_AFFINE_INCLUDED
20 #define AGG_TRANS_AFFINE_INCLUDED
23 #include "agg_basics.h"
27 const double affine_epsilon
= 1e-14; // About of precision of doubles
29 //============================================================trans_affine
31 // See Implementation agg_trans_affine.cpp
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.
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:
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,
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:
59 // m *= rotate_matrix(30);
60 // m *= scaleX_matrix(2.0);
61 // m *= scaleY_matrix(1.5);
62 // m *= move_matrix(100,100);
64 // m.transform_my_point_at_last(x, y);
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.
70 // So, how to use it? Very easy - literally as it's shown above. Not quite,
71 // let us write a correct example:
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);
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):
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 //----------------------------------------------------------------------
90 //------------------------------------------ Construction
91 // Construct an identity matrix - it does not transform anything
93 m0(1.0), m1(0.0), m2(0.0), m3(1.0), m4(0.0), m5(0.0)
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
)
101 // Construct a matrix to transform a parallelogram to another one.
102 trans_affine(const double* rect
, const double* parl
)
104 parl_to_parl(rect
, parl
);
107 // Construct a matrix to transform a rectangle to a parallelogram.
108 trans_affine(double x1
, double y1
, double x2
, double y2
,
111 rect_to_parl(x1
, y1
, x2
, y2
, parl
);
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
)
118 parl_to_rect(parl
, x1
, y1
, x2
, y2
);
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
,
132 const trans_affine
& rect_to_parl(double x1
, double y1
,
133 double x2
, double y2
,
136 const trans_affine
& parl_to_rect(const double* parl
,
137 double x1
, double y1
,
138 double x2
, double y2
);
141 //------------------------------------------ Operations
142 // Reset - actually load an identity matrix
143 const trans_affine
& reset();
145 // Multiply matrix to another one
146 const trans_affine
& multiply(const trans_affine
& m
);
148 // Multiply "m" to "this" and assign the result to "this"
149 const trans_affine
& premultiply(const trans_affine
& m
);
151 // Invert matrix. Do not try to invert degenerate matrices,
152 // there's no check for validity. If you set scale to 0 and
153 // then try to invert matrix, expect unpredictable result.
154 const trans_affine
& invert();
156 // Mirroring around X
157 const trans_affine
& flip_x();
159 // Mirroring around Y
160 const trans_affine
& flip_y();
162 //------------------------------------------- Load/Store
163 // Store matrix to an array [6] of double
164 void store_to(double* m
) const
166 *m
++ = m0
; *m
++ = m1
; *m
++ = m2
; *m
++ = m3
; *m
++ = m4
; *m
++ = m5
;
169 // Load matrix from an array [6] of double
170 const trans_affine
& load_from(const double* m
)
172 m0
= *m
++; m1
= *m
++; m2
= *m
++; m3
= *m
++; m4
= *m
++; m5
= *m
++;
176 //------------------------------------------- Operators
178 // Multiply current matrix to another one
179 const trans_affine
& operator *= (const trans_affine
& m
)
184 // Multiply current matrix to another one and return
185 // the result in a separete matrix.
186 trans_affine
operator * (const trans_affine
& m
)
188 return trans_affine(*this).multiply(m
);
191 // Calculate and return the inverse matrix
192 trans_affine
operator ~ () const
194 trans_affine ret
= *this;
198 // Equal operator with default epsilon
199 bool operator == (const trans_affine
& m
) const
201 return is_equal(m
, affine_epsilon
);
204 // Not Equal operator with default epsilon
205 bool operator != (const trans_affine
& m
) const
207 return !is_equal(m
, affine_epsilon
);
210 //-------------------------------------------- Transformations
211 // Direct transformation x and y
212 void transform(double* x
, double* y
) const;
214 // Inverse transformation x and y. It works slower than the
215 // direct transformation, so if the performance is critical
216 // it's better to invert() the matrix and then use transform()
217 void inverse_transform(double* x
, double* y
) const;
219 //-------------------------------------------- Auxiliary
220 // Calculate the determinant of matrix
221 double determinant() const
223 return 1.0 / (m0
* m3
- m1
* m2
);
226 // Get the average scale (by X and Y).
227 // Basically used to calculate the approximation_scale when
228 // decomposinting curves into line segments.
229 double scale() const;
231 // Check to see if it's an identity matrix
232 bool is_identity(double epsilon
= affine_epsilon
) const;
234 // Check to see if two matrices are equal
235 bool is_equal(const trans_affine
& m
, double epsilon
= affine_epsilon
) const;
237 // Determine the major parameters. Use carefully considering degenerate matrices
238 double rotation() const;
239 void translation(double* dx
, double* dy
) const;
240 void scaling(double* sx
, double* sy
) const;
241 void scaling_abs(double* sx
, double* sy
) const
243 *sx
= sqrt(m0
*m0
+ m2
*m2
);
244 *sy
= sqrt(m1
*m1
+ m3
*m3
);
256 //------------------------------------------------------------------------
257 inline void trans_affine::transform(double* x
, double* y
) const
259 register double tx
= *x
;
260 *x
= tx
* m0
+ *y
* m2
+ m4
;
261 *y
= tx
* m1
+ *y
* m3
+ m5
;
264 //------------------------------------------------------------------------
265 inline void trans_affine::inverse_transform(double* x
, double* y
) const
267 register double d
= determinant();
268 register double a
= (*x
- m4
) * d
;
269 register double b
= (*y
- m5
) * d
;
270 *x
= a
* m3
- b
* m2
;
271 *y
= b
* m0
- a
* m1
;
274 //------------------------------------------------------------------------
275 inline double trans_affine::scale() const
277 double x
= 0.707106781 * m0
+ 0.707106781 * m2
;
278 double y
= 0.707106781 * m1
+ 0.707106781 * m3
;
279 return sqrt(x
*x
+ y
*y
);
283 //------------------------------------------------------------------------
284 inline const trans_affine
& trans_affine::premultiply(const trans_affine
& m
)
287 return *this = t
.multiply(*this);
291 //====================================================trans_affine_rotation
292 // Rotation matrix. sin() and cos() are calculated twice for the same angle.
293 // There's no harm because the performance of sin()/cos() is very good on all
294 // modern processors. Besides, this operation is not going to be invoked too
296 class trans_affine_rotation
: public trans_affine
299 trans_affine_rotation(double a
) :
300 trans_affine(cos(a
), sin(a
), -sin(a
), cos(a
), 0.0, 0.0)
304 //====================================================trans_affine_scaling
305 // Scaling matrix. sx, sy - scale coefficients by X and Y respectively
306 class trans_affine_scaling
: public trans_affine
309 trans_affine_scaling(double sx
, double sy
) :
310 trans_affine(sx
, 0.0, 0.0, sy
, 0.0, 0.0)
313 trans_affine_scaling(double s
) :
314 trans_affine(s
, 0.0, 0.0, s
, 0.0, 0.0)
318 //================================================trans_affine_translation
319 // Translation matrix
320 class trans_affine_translation
: public trans_affine
323 trans_affine_translation(double tx
, double ty
) :
324 trans_affine(1.0, 0.0, 0.0, 1.0, tx
, ty
)
328 //====================================================trans_affine_skewing
329 // Sckewing (shear) matrix
330 class trans_affine_skewing
: public trans_affine
333 trans_affine_skewing(double sx
, double sy
) :
334 trans_affine(1.0, tan(sy
), tan(sx
), 1.0, 0.0, 0.0)