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