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 if the affine is rectilinear or GD_FALSE
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
335