xref: /PHP-7.4/ext/gd/libgd/gd_matrix.c (revision 2c586051)
1 #include "gd.h"
2 #include <math.h>
3 
4 #ifndef M_PI
5 # define M_PI 3.14159265358979323846
6 #endif
7 
8 /**
9  * Title: Matrix
10  * Group: Affine Matrix
11  */
12 
13 /**
14  * Function: gdAffineApplyToPointF
15  *  Applies an affine transformation to a point (floating point
16  *  gdPointF)
17  *
18  *
19  * Parameters:
20  * 	dst - Where to store the resulting point
21  *  affine - Source Point
22  *  flip_horz - affine matrix
23  *
24  * Returns:
25  *  GD_TRUE if the affine is rectilinear or GD_FALSE
26  */
gdAffineApplyToPointF(gdPointFPtr dst,const gdPointFPtr src,const double affine[6])27 int gdAffineApplyToPointF (gdPointFPtr dst, const gdPointFPtr src,
28 		  const double affine[6])
29 {
30 	double x = src->x;
31 	double y = src->y;
32 	x = src->x;
33 	y = src->y;
34 	dst->x = x * affine[0] + y * affine[2] + affine[4];
35 	dst->y = x * affine[1] + y * affine[3] + affine[5];
36 	return GD_TRUE;
37 }
38 
39 /**
40  * Function: gdAffineInvert
41  *  Find the inverse of an affine transformation.
42  *
43  * All non-degenerate affine transforms are invertible. Applying the
44  * inverted matrix will restore the original values. Multiplying <src>
45  * by <dst> (commutative) will return the identity affine (rounding
46  * error possible).
47  *
48  * Parameters:
49  * 	dst - Where to store the resulting affine transform
50  *  src_affine - Original affine matrix
51  *  flip_horz - Whether or not to flip horizontally
52  *  flip_vert - Whether or not to flip vertically
53  *
54  * See also:
55  *  <gdAffineIdentity>
56  *
57  * Returns:
58  *  GD_TRUE on success or GD_FALSE on failure
59  */
gdAffineInvert(double dst[6],const double src[6])60 int gdAffineInvert (double dst[6], const double src[6])
61 {
62 	double r_det = (src[0] * src[3] - src[1] * src[2]);
63 
64 	if (r_det <= 0.0) {
65 		return GD_FALSE;
66 	}
67 
68 	r_det = 1.0 / r_det;
69 	dst[0] = src[3] * r_det;
70 	dst[1] = -src[1] * r_det;
71 	dst[2] = -src[2] * r_det;
72 	dst[3] = src[0] * r_det;
73 	dst[4] = -src[4] * dst[0] - src[5] * dst[2];
74 	dst[5] = -src[4] * dst[1] - src[5] * dst[3];
75 	return GD_TRUE;
76 }
77 
78 /**
79  * Function: gdAffineFlip
80  *  Flip an affine transformation horizontally or vertically.
81  *
82  * Flips the affine transform, giving GD_FALSE for <flip_horz> and
83  * <flip_vert> will clone the affine matrix. GD_TRUE for both will
84  * copy a 180° rotation.
85  *
86  * Parameters:
87  * 	dst - Where to store the resulting affine transform
88  *  src_affine - Original affine matrix
89  *  flip_h - Whether or not to flip horizontally
90  *  flip_v - Whether or not to flip vertically
91  *
92  * Returns:
93  *  GD_SUCCESS on success or GD_FAILURE
94  */
gdAffineFlip(double dst[6],const double src[6],const int flip_h,const int flip_v)95 int gdAffineFlip (double dst[6], const double src[6], const int flip_h, const int flip_v)
96 {
97 	dst[0] = flip_h ? - src[0] : src[0];
98 	dst[1] = flip_h ? - src[1] : src[1];
99 	dst[2] = flip_v ? - src[2] : src[2];
100 	dst[3] = flip_v ? - src[3] : src[3];
101 	dst[4] = flip_h ? - src[4] : src[4];
102 	dst[5] = flip_v ? - src[5] : src[5];
103 	return GD_TRUE;
104 }
105 
106 /**
107  * Function: gdAffineConcat
108  * Concat (Multiply) two affine transformation matrices.
109  *
110  * Concats two affine transforms together, i.e. the result
111  * will be the equivalent of doing first the transformation m1 and then
112  * m2. All parameters can be the same matrix (safe to call using
113  * the same array for all three arguments).
114  *
115  * Parameters:
116  * 	dst - Where to store the resulting affine transform
117  *  m1 - First affine matrix
118  *  m2 - Second affine matrix
119  *
120  * Returns:
121  *  GD_SUCCESS on success or GD_FAILURE
122  */
gdAffineConcat(double dst[6],const double m1[6],const double m2[6])123 int gdAffineConcat (double dst[6], const double m1[6], const double m2[6])
124 {
125 	double dst0, dst1, dst2, dst3, dst4, dst5;
126 
127 	dst0 = m1[0] * m2[0] + m1[1] * m2[2];
128 	dst1 = m1[0] * m2[1] + m1[1] * m2[3];
129 	dst2 = m1[2] * m2[0] + m1[3] * m2[2];
130 	dst3 = m1[2] * m2[1] + m1[3] * m2[3];
131 	dst4 = m1[4] * m2[0] + m1[5] * m2[2] + m2[4];
132 	dst5 = m1[4] * m2[1] + m1[5] * m2[3] + m2[5];
133 	dst[0] = dst0;
134 	dst[1] = dst1;
135 	dst[2] = dst2;
136 	dst[3] = dst3;
137 	dst[4] = dst4;
138 	dst[5] = dst5;
139 	return GD_TRUE;
140 }
141 
142 /**
143  * Function: gdAffineIdentity
144  * Set up the identity matrix.
145  *
146  * Parameters:
147  * 	dst - Where to store the resulting affine transform
148  *
149  * Returns:
150  *  GD_SUCCESS on success or GD_FAILURE
151  */
gdAffineIdentity(double dst[6])152 int gdAffineIdentity (double dst[6])
153 {
154 	dst[0] = 1;
155 	dst[1] = 0;
156 	dst[2] = 0;
157 	dst[3] = 1;
158 	dst[4] = 0;
159 	dst[5] = 0;
160 	return GD_TRUE;
161 }
162 
163 /**
164  * Function: gdAffineScale
165  * Set up a scaling matrix.
166  *
167  * Parameters:
168  * 	scale_x - X scale factor
169  * 	scale_y - Y scale factor
170  *
171  * Returns:
172  *  GD_SUCCESS on success or GD_FAILURE
173  */
gdAffineScale(double dst[6],const double scale_x,const double scale_y)174 int gdAffineScale (double dst[6], const double scale_x, const double scale_y)
175 {
176 	dst[0] = scale_x;
177 	dst[1] = 0;
178 	dst[2] = 0;
179 	dst[3] = scale_y;
180 	dst[4] = 0;
181 	dst[5] = 0;
182 	return GD_TRUE;
183 }
184 
185 /**
186  * Function: gdAffineRotate
187  * Set up a rotation affine transform.
188  *
189  * Like the other angle in libGD, in which increasing y moves
190  * downward, this is a counterclockwise rotation.
191  *
192  * Parameters:
193  * 	dst - Where to store the resulting affine transform
194  * 	angle - Rotation angle in degrees
195  *
196  * Returns:
197  *  GD_SUCCESS on success or GD_FAILURE
198  */
gdAffineRotate(double dst[6],const double angle)199 int gdAffineRotate (double dst[6], const double angle)
200 {
201 	const double sin_t = sin (angle * M_PI / 180.0);
202 	const double cos_t = cos (angle * M_PI / 180.0);
203 
204 	dst[0] = cos_t;
205 	dst[1] = sin_t;
206 	dst[2] = -sin_t;
207 	dst[3] = cos_t;
208 	dst[4] = 0;
209 	dst[5] = 0;
210 	return GD_TRUE;
211 }
212 
213 /**
214  * Function: gdAffineShearHorizontal
215  * Set up a horizontal shearing matrix || becomes \\.
216  *
217  * Parameters:
218  * 	dst - Where to store the resulting affine transform
219  * 	angle - Shear angle in degrees
220  *
221  * Returns:
222  *  GD_SUCCESS on success or GD_FAILURE
223  */
gdAffineShearHorizontal(double dst[6],const double angle)224 int gdAffineShearHorizontal(double dst[6], const double angle)
225 {
226 	dst[0] = 1;
227 	dst[1] = 0;
228 	dst[2] = tan(angle * M_PI / 180.0);
229 	dst[3] = 1;
230 	dst[4] = 0;
231 	dst[5] = 0;
232   	return GD_TRUE;
233 }
234 
235 /**
236  * Function: gdAffineShearVertical
237  * Set up a vertical shearing matrix, columns are untouched.
238  *
239  * Parameters:
240  * 	dst - Where to store the resulting affine transform
241  * 	angle - Shear angle in degrees
242  *
243  * Returns:
244  *  GD_SUCCESS on success or GD_FAILURE
245  */
gdAffineShearVertical(double dst[6],const double angle)246 int gdAffineShearVertical(double dst[6], const double angle)
247 {
248 	dst[0] = 1;
249 	dst[1] = tan(angle * M_PI / 180.0);
250 	dst[2] = 0;
251 	dst[3] = 1;
252 	dst[4] = 0;
253 	dst[5] = 0;
254   	return GD_TRUE;
255 }
256 
257 /**
258  * Function: gdAffineTranslate
259  * Set up a translation matrix.
260  *
261  * Parameters:
262  * 	dst - Where to store the resulting affine transform
263  * 	offset_x - Horizontal translation amount
264  * 	offset_y - Vertical translation amount
265  *
266  * Returns:
267  *  GD_SUCCESS on success or GD_FAILURE
268  */
gdAffineTranslate(double dst[6],const double offset_x,const double offset_y)269 int gdAffineTranslate (double dst[6], const double offset_x, const double offset_y)
270 {
271 	dst[0] = 1;
272 	dst[1] = 0;
273 	dst[2] = 0;
274 	dst[3] = 1;
275 	dst[4] = offset_x;
276 	dst[5] = offset_y;
277     return GD_TRUE;
278 }
279 
280 /**
281  * gdAffineexpansion: Find the affine's expansion factor.
282  * @src: The affine transformation.
283  *
284  * Finds the expansion factor, i.e. the square root of the factor
285  * by which the affine transform affects area. In an affine transform
286  * composed of scaling, rotation, shearing, and translation, returns
287  * the amount of scaling.
288  *
289  *  GD_SUCCESS on success or GD_FAILURE
290  **/
gdAffineExpansion(const double src[6])291 double gdAffineExpansion (const double src[6])
292 {
293   return sqrt (fabs (src[0] * src[3] - src[1] * src[2]));
294 }
295 
296 /**
297  * Function: gdAffineRectilinear
298  * Determines whether the affine transformation is axis aligned. A
299  * tolerance has been implemented using GD_EPSILON.
300  *
301  * Parameters:
302  * 	m - The affine transformation
303  *
304  * Returns:
305  *  GD_TRUE if the affine is rectilinear or GD_FALSE
306  */
gdAffineRectilinear(const double m[6])307 int gdAffineRectilinear (const double m[6])
308 {
309   return ((fabs (m[1]) < GD_EPSILON && fabs (m[2]) < GD_EPSILON) ||
310 	  (fabs (m[0]) < GD_EPSILON && fabs (m[3]) < GD_EPSILON));
311 }
312 
313 /**
314  * Function: gdAffineEqual
315  * Determines whether two affine transformations are equal. A tolerance
316  * has been implemented using GD_EPSILON.
317  *
318  * Parameters:
319  * 	m1 - The first affine transformation
320  * 	m2 - The first affine transformation
321  *
322  * Returns:
323  * 	GD_SUCCESS on success or GD_FAILURE
324  */
gdAffineEqual(const double m1[6],const double m2[6])325 int gdAffineEqual (const double m1[6], const double m2[6])
326 {
327   return (fabs (m1[0] - m2[0]) < GD_EPSILON &&
328 	  fabs (m1[1] - m2[1]) < GD_EPSILON &&
329 	  fabs (m1[2] - m2[2]) < GD_EPSILON &&
330 	  fabs (m1[3] - m2[3]) < GD_EPSILON &&
331 	  fabs (m1[4] - m2[4]) < GD_EPSILON &&
332 	  fabs (m1[5] - m2[5]) < GD_EPSILON);
333 }
334