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