1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimpmatrix.c
5  * Copyright (C) 1998 Jay Cox <jaycox@gimp.org>
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 3 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <glib-object.h>
25 
26 #include "gimpmath.h"
27 
28 
29 /**
30  * SECTION: gimpmatrix
31  * @title: GimpMatrix
32  * @short_description: Utilities to set up and manipulate 3x3
33  *                     transformation matrices.
34  * @see_also: #GimpVector2, #GimpVector3, #GimpVector4
35  *
36  * When doing image manipulation you will often need 3x3
37  * transformation matrices that define translation, rotation, scaling,
38  * shearing and arbitrary perspective transformations using a 3x3
39  * matrix. Here you'll find a set of utility functions to set up those
40  * matrices and to perform basic matrix manipulations and tests.
41  *
42  * Each matrix class has a 2 dimensional gdouble coeff member. The
43  * element for row r and column c of the matrix is coeff[r][c].
44  **/
45 
46 
47 #define EPSILON 1e-6
48 
49 
50 static GimpMatrix2 * matrix2_copy                  (const GimpMatrix2 *matrix);
51 
52 /**
53  * gimp_matrix2_get_type:
54  *
55  * Reveals the object type
56  *
57  * Returns: the #GType for Matrix2 objects
58  *
59  * Since: 2.4
60  **/
61 GType
gimp_matrix2_get_type(void)62 gimp_matrix2_get_type (void)
63 {
64   static GType matrix_type = 0;
65 
66   if (!matrix_type)
67     matrix_type = g_boxed_type_register_static ("GimpMatrix2",
68                                                (GBoxedCopyFunc) matrix2_copy,
69                                                (GBoxedFreeFunc) g_free);
70 
71   return matrix_type;
72 }
73 
74 
75 /*
76  * GIMP_TYPE_PARAM_MATRIX2
77  */
78 
79 #define GIMP_PARAM_SPEC_MATRIX2(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_MATRIX2, GimpParamSpecMatrix2))
80 
81 static void   gimp_param_matrix2_class_init  (GParamSpecClass *class);
82 static void   gimp_param_matrix2_init        (GParamSpec      *pspec);
83 static void   gimp_param_matrix2_set_default (GParamSpec      *pspec,
84                                               GValue          *value);
85 static gint   gimp_param_matrix2_values_cmp  (GParamSpec      *pspec,
86                                               const GValue    *value1,
87                                               const GValue    *value2);
88 
89 typedef struct _GimpParamSpecMatrix2 GimpParamSpecMatrix2;
90 
91 struct _GimpParamSpecMatrix2
92 {
93   GParamSpecBoxed      parent_instance;
94 
95   GimpMatrix2          default_value;
96 };
97 
98 /**
99  * gimp_param_matrix2_get_type:
100  *
101  * Reveals the object type
102  *
103  * Returns: the #GType for a GimpMatrix2 object
104  *
105  * Since: 2.4
106  **/
107 GType
gimp_param_matrix2_get_type(void)108 gimp_param_matrix2_get_type (void)
109 {
110   static GType spec_type = 0;
111 
112   if (!spec_type)
113     {
114       static const GTypeInfo type_info =
115       {
116         sizeof (GParamSpecClass),
117         NULL, NULL,
118         (GClassInitFunc) gimp_param_matrix2_class_init,
119         NULL, NULL,
120         sizeof (GimpParamSpecMatrix2),
121         0,
122         (GInstanceInitFunc) gimp_param_matrix2_init
123       };
124 
125       spec_type = g_type_register_static (G_TYPE_PARAM_BOXED,
126                                           "GimpParamMatrix2",
127                                           &type_info, 0);
128     }
129 
130   return spec_type;
131 }
132 
133 static void
gimp_param_matrix2_class_init(GParamSpecClass * class)134 gimp_param_matrix2_class_init (GParamSpecClass *class)
135 {
136   class->value_type        = GIMP_TYPE_MATRIX2;
137   class->value_set_default = gimp_param_matrix2_set_default;
138   class->values_cmp        = gimp_param_matrix2_values_cmp;
139 }
140 
141 static void
gimp_param_matrix2_init(GParamSpec * pspec)142 gimp_param_matrix2_init (GParamSpec *pspec)
143 {
144   GimpParamSpecMatrix2 *cspec = GIMP_PARAM_SPEC_MATRIX2 (pspec);
145 
146   gimp_matrix2_identity (&cspec->default_value);
147 }
148 
149 static void
gimp_param_matrix2_set_default(GParamSpec * pspec,GValue * value)150 gimp_param_matrix2_set_default (GParamSpec *pspec,
151                                 GValue     *value)
152 {
153   GimpParamSpecMatrix2 *cspec = GIMP_PARAM_SPEC_MATRIX2 (pspec);
154 
155   g_value_set_static_boxed (value, &cspec->default_value);
156 }
157 
158 static gint
gimp_param_matrix2_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)159 gimp_param_matrix2_values_cmp (GParamSpec   *pspec,
160                                const GValue *value1,
161                                const GValue *value2)
162 {
163   GimpMatrix2 *matrix1;
164   GimpMatrix2 *matrix2;
165   gint         i, j;
166 
167   matrix1 = value1->data[0].v_pointer;
168   matrix2 = value2->data[0].v_pointer;
169 
170   /*  try to return at least *something*, it's useless anyway...  */
171 
172   if (! matrix1)
173     return matrix2 != NULL ? -1 : 0;
174   else if (! matrix2)
175     return matrix1 != NULL;
176 
177   for (i = 0; i < 2; i++)
178     for (j = 0; j < 2; j++)
179       if (matrix1->coeff[i][j] != matrix2->coeff[i][j])
180         return 1;
181 
182   return 0;
183 }
184 
185 /**
186  * gimp_param_spec_matrix2:
187  * @name:          Canonical name of the param
188  * @nick:          Nickname of the param
189  * @blurb:         Brief description of param.
190  * @default_value: Value to use if none is assigned.
191  * @flags:         a combination of #GParamFlags
192  *
193  * Creates a param spec to hold a #GimpMatrix2 value.
194  * See g_param_spec_internal() for more information.
195  *
196  * Returns: a newly allocated #GParamSpec instance
197  *
198  * Since: 2.4
199  **/
200 GParamSpec *
gimp_param_spec_matrix2(const gchar * name,const gchar * nick,const gchar * blurb,const GimpMatrix2 * default_value,GParamFlags flags)201 gimp_param_spec_matrix2 (const gchar       *name,
202                          const gchar       *nick,
203                          const gchar       *blurb,
204                          const GimpMatrix2 *default_value,
205                          GParamFlags        flags)
206 {
207   GimpParamSpecMatrix2 *cspec;
208 
209   g_return_val_if_fail (default_value != NULL, NULL);
210 
211   cspec = g_param_spec_internal (GIMP_TYPE_PARAM_MATRIX2,
212                                  name, nick, blurb, flags);
213 
214   cspec->default_value = *default_value;
215 
216   return G_PARAM_SPEC (cspec);
217 }
218 
219 
220 static GimpMatrix2 *
matrix2_copy(const GimpMatrix2 * matrix)221 matrix2_copy (const GimpMatrix2 *matrix)
222 {
223   return (GimpMatrix2 *) g_memdup (matrix, sizeof (GimpMatrix2));
224 }
225 
226 
227 /**
228  * gimp_matrix2_identity:
229  * @matrix: A matrix.
230  *
231  * Sets the matrix to the identity matrix.
232  */
233 void
gimp_matrix2_identity(GimpMatrix2 * matrix)234 gimp_matrix2_identity (GimpMatrix2 *matrix)
235 {
236   static const GimpMatrix2 identity = { { { 1.0, 0.0 },
237                                           { 0.0, 1.0 } } };
238 
239   *matrix = identity;
240 }
241 
242 /**
243  * gimp_matrix2_mult:
244  * @matrix1: The first input matrix.
245  * @matrix2: The second input matrix which will be overwritten by the result.
246  *
247  * Multiplies two matrices and puts the result into the second one.
248  */
249 void
gimp_matrix2_mult(const GimpMatrix2 * matrix1,GimpMatrix2 * matrix2)250 gimp_matrix2_mult (const GimpMatrix2 *matrix1,
251                    GimpMatrix2       *matrix2)
252 {
253   GimpMatrix2  tmp;
254 
255   tmp.coeff[0][0] = (matrix1->coeff[0][0] * matrix2->coeff[0][0] +
256                      matrix1->coeff[0][1] * matrix2->coeff[1][0]);
257   tmp.coeff[0][1] = (matrix1->coeff[0][0] * matrix2->coeff[0][1] +
258                      matrix1->coeff[0][1] * matrix2->coeff[1][1]);
259   tmp.coeff[1][0] = (matrix1->coeff[1][0] * matrix2->coeff[0][0] +
260                      matrix1->coeff[1][1] * matrix2->coeff[1][0]);
261   tmp.coeff[1][1] = (matrix1->coeff[1][0] * matrix2->coeff[0][1] +
262                      matrix1->coeff[1][1] * matrix2->coeff[1][1]);
263 
264   *matrix2 = tmp;
265 }
266 
267 /**
268  * gimp_matrix2_determinant:
269  * @matrix: The input matrix.
270  *
271  * Calculates the determinant of the given matrix.
272  *
273  * Returns: The determinant.
274  *
275  * Since: 2.10.16
276  */
277 
278 gdouble
gimp_matrix2_determinant(const GimpMatrix2 * matrix)279 gimp_matrix2_determinant (const GimpMatrix2 *matrix)
280 {
281   return matrix->coeff[0][0] * matrix->coeff[1][1] -
282          matrix->coeff[0][1] * matrix->coeff[1][0];
283 }
284 
285 /**
286  * gimp_matrix2_invert:
287  * @matrix: The matrix that is to be inverted.
288  *
289  * Inverts the given matrix.
290  *
291  * Since: 2.10.16
292  */
293 void
gimp_matrix2_invert(GimpMatrix2 * matrix)294 gimp_matrix2_invert (GimpMatrix2 *matrix)
295 {
296   gdouble det = gimp_matrix2_determinant (matrix);
297   gdouble temp;
298 
299   if (fabs (det) <= EPSILON)
300     return;
301 
302   temp = matrix->coeff[0][0];
303 
304   matrix->coeff[0][0]  = matrix->coeff[1][1] / det;
305   matrix->coeff[0][1] /= -det;
306   matrix->coeff[1][0] /= -det;
307   matrix->coeff[1][1]  = temp / det;
308 }
309 
310 /**
311  * gimp_matrix2_transform_point:
312  * @matrix: The transformation matrix.
313  * @x: The source X coordinate.
314  * @y: The source Y coordinate.
315  * @newx: The transformed X coordinate.
316  * @newy: The transformed Y coordinate.
317  *
318  * Transforms a point in 2D as specified by the transformation matrix.
319  *
320  * Since: 2.10.16
321  */
322 void
gimp_matrix2_transform_point(const GimpMatrix2 * matrix,gdouble x,gdouble y,gdouble * newx,gdouble * newy)323 gimp_matrix2_transform_point (const GimpMatrix2 *matrix,
324                               gdouble            x,
325                               gdouble            y,
326                               gdouble           *newx,
327                               gdouble           *newy)
328 {
329   *newx = matrix->coeff[0][0] * x + matrix->coeff[0][1] * y;
330   *newy = matrix->coeff[1][0] * x + matrix->coeff[1][1] * y;
331 }
332 
333 
334 static GimpMatrix3 * matrix3_copy                  (const GimpMatrix3 *matrix);
335 
336 /**
337  * gimp_matrix3_get_type:
338  *
339  * Reveals the object type
340  *
341  * Returns: the #GType for Matrix3 objects
342  *
343  * Since: 2.8
344  **/
345 GType
gimp_matrix3_get_type(void)346 gimp_matrix3_get_type (void)
347 {
348   static GType matrix_type = 0;
349 
350   if (!matrix_type)
351     matrix_type = g_boxed_type_register_static ("GimpMatrix3",
352                                                (GBoxedCopyFunc) matrix3_copy,
353                                                (GBoxedFreeFunc) g_free);
354 
355   return matrix_type;
356 }
357 
358 
359 /*
360  * GIMP_TYPE_PARAM_MATRIX3
361  */
362 
363 #define GIMP_PARAM_SPEC_MATRIX3(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_MATRIX3, GimpParamSpecMatrix3))
364 
365 static void   gimp_param_matrix3_class_init  (GParamSpecClass *class);
366 static void   gimp_param_matrix3_init        (GParamSpec      *pspec);
367 static void   gimp_param_matrix3_set_default (GParamSpec      *pspec,
368                                               GValue          *value);
369 static gint   gimp_param_matrix3_values_cmp  (GParamSpec      *pspec,
370                                               const GValue    *value1,
371                                               const GValue    *value2);
372 
373 typedef struct _GimpParamSpecMatrix3 GimpParamSpecMatrix3;
374 
375 struct _GimpParamSpecMatrix3
376 {
377   GParamSpecBoxed      parent_instance;
378 
379   GimpMatrix3          default_value;
380 };
381 
382 /**
383  * gimp_param_matrix3_get_type:
384  *
385  * Reveals the object type
386  *
387  * Returns: the #GType for a GimpMatrix3 object
388  *
389  * Since: 2.8
390  **/
391 GType
gimp_param_matrix3_get_type(void)392 gimp_param_matrix3_get_type (void)
393 {
394   static GType spec_type = 0;
395 
396   if (!spec_type)
397     {
398       static const GTypeInfo type_info =
399       {
400         sizeof (GParamSpecClass),
401         NULL, NULL,
402         (GClassInitFunc) gimp_param_matrix3_class_init,
403         NULL, NULL,
404         sizeof (GimpParamSpecMatrix3),
405         0,
406         (GInstanceInitFunc) gimp_param_matrix3_init
407       };
408 
409       spec_type = g_type_register_static (G_TYPE_PARAM_BOXED,
410                                           "GimpParamMatrix3",
411                                           &type_info, 0);
412     }
413 
414   return spec_type;
415 }
416 
417 static void
gimp_param_matrix3_class_init(GParamSpecClass * class)418 gimp_param_matrix3_class_init (GParamSpecClass *class)
419 {
420   class->value_type        = GIMP_TYPE_MATRIX3;
421   class->value_set_default = gimp_param_matrix3_set_default;
422   class->values_cmp        = gimp_param_matrix3_values_cmp;
423 }
424 
425 static void
gimp_param_matrix3_init(GParamSpec * pspec)426 gimp_param_matrix3_init (GParamSpec *pspec)
427 {
428   GimpParamSpecMatrix3 *cspec = GIMP_PARAM_SPEC_MATRIX3 (pspec);
429 
430   gimp_matrix3_identity (&cspec->default_value);
431 }
432 
433 static void
gimp_param_matrix3_set_default(GParamSpec * pspec,GValue * value)434 gimp_param_matrix3_set_default (GParamSpec *pspec,
435                                 GValue     *value)
436 {
437   GimpParamSpecMatrix3 *cspec = GIMP_PARAM_SPEC_MATRIX3 (pspec);
438 
439   g_value_set_static_boxed (value, &cspec->default_value);
440 }
441 
442 static gint
gimp_param_matrix3_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)443 gimp_param_matrix3_values_cmp (GParamSpec   *pspec,
444                                const GValue *value1,
445                                const GValue *value2)
446 {
447   GimpMatrix3 *matrix1;
448   GimpMatrix3 *matrix2;
449   gint         i, j;
450 
451   matrix1 = value1->data[0].v_pointer;
452   matrix2 = value2->data[0].v_pointer;
453 
454   /*  try to return at least *something*, it's useless anyway...  */
455 
456   if (! matrix1)
457     return matrix2 != NULL ? -1 : 0;
458   else if (! matrix2)
459     return matrix1 != NULL;
460 
461   for (i = 0; i < 3; i++)
462     for (j = 0; j < 3; j++)
463       if (matrix1->coeff[i][j] != matrix2->coeff[i][j])
464         return 1;
465 
466   return 0;
467 }
468 
469 /**
470  * gimp_param_spec_matrix3:
471  * @name:          Canonical name of the param
472  * @nick:          Nickname of the param
473  * @blurb:         Brief description of param.
474  * @default_value: Value to use if none is assigned.
475  * @flags:         a combination of #GParamFlags
476  *
477  * Creates a param spec to hold a #GimpMatrix3 value.
478  * See g_param_spec_internal() for more information.
479  *
480  * Returns: a newly allocated #GParamSpec instance
481  *
482  * Since: 2.8
483  **/
484 GParamSpec *
gimp_param_spec_matrix3(const gchar * name,const gchar * nick,const gchar * blurb,const GimpMatrix3 * default_value,GParamFlags flags)485 gimp_param_spec_matrix3 (const gchar       *name,
486                          const gchar       *nick,
487                          const gchar       *blurb,
488                          const GimpMatrix3 *default_value,
489                          GParamFlags        flags)
490 {
491   GimpParamSpecMatrix3 *cspec;
492 
493   cspec = g_param_spec_internal (GIMP_TYPE_PARAM_MATRIX3,
494                                  name, nick, blurb, flags);
495 
496   if (default_value)
497     cspec->default_value = *default_value;
498 
499   return G_PARAM_SPEC (cspec);
500 }
501 
502 
503 static GimpMatrix3 *
matrix3_copy(const GimpMatrix3 * matrix)504 matrix3_copy (const GimpMatrix3 *matrix)
505 {
506   return (GimpMatrix3 *) g_memdup (matrix, sizeof (GimpMatrix3));
507 }
508 
509 
510 /**
511  * gimp_matrix3_identity:
512  * @matrix: A matrix.
513  *
514  * Sets the matrix to the identity matrix.
515  */
516 void
gimp_matrix3_identity(GimpMatrix3 * matrix)517 gimp_matrix3_identity (GimpMatrix3 *matrix)
518 {
519   static const GimpMatrix3 identity = { { { 1.0, 0.0, 0.0 },
520                                           { 0.0, 1.0, 0.0 },
521                                           { 0.0, 0.0, 1.0 } } };
522 
523   *matrix = identity;
524 }
525 
526 /**
527  * gimp_matrix3_transform_point:
528  * @matrix: The transformation matrix.
529  * @x: The source X coordinate.
530  * @y: The source Y coordinate.
531  * @newx: The transformed X coordinate.
532  * @newy: The transformed Y coordinate.
533  *
534  * Transforms a point in 2D as specified by the transformation matrix.
535  */
536 void
gimp_matrix3_transform_point(const GimpMatrix3 * matrix,gdouble x,gdouble y,gdouble * newx,gdouble * newy)537 gimp_matrix3_transform_point (const GimpMatrix3 *matrix,
538                               gdouble            x,
539                               gdouble            y,
540                               gdouble           *newx,
541                               gdouble           *newy)
542 {
543   gdouble  w;
544 
545   w = matrix->coeff[2][0] * x + matrix->coeff[2][1] * y + matrix->coeff[2][2];
546 
547   if (w == 0.0)
548     w = 1.0;
549   else
550     w = 1.0/w;
551 
552   *newx = (matrix->coeff[0][0] * x +
553            matrix->coeff[0][1] * y +
554            matrix->coeff[0][2]) * w;
555   *newy = (matrix->coeff[1][0] * x +
556            matrix->coeff[1][1] * y +
557            matrix->coeff[1][2]) * w;
558 }
559 
560 /**
561  * gimp_matrix3_mult:
562  * @matrix1: The first input matrix.
563  * @matrix2: The second input matrix which will be overwritten by the result.
564  *
565  * Multiplies two matrices and puts the result into the second one.
566  */
567 void
gimp_matrix3_mult(const GimpMatrix3 * matrix1,GimpMatrix3 * matrix2)568 gimp_matrix3_mult (const GimpMatrix3 *matrix1,
569                    GimpMatrix3       *matrix2)
570 {
571   gint         i, j;
572   GimpMatrix3  tmp;
573   gdouble      t1, t2, t3;
574 
575   for (i = 0; i < 3; i++)
576     {
577       t1 = matrix1->coeff[i][0];
578       t2 = matrix1->coeff[i][1];
579       t3 = matrix1->coeff[i][2];
580 
581       for (j = 0; j < 3; j++)
582         {
583           tmp.coeff[i][j]  = t1 * matrix2->coeff[0][j];
584           tmp.coeff[i][j] += t2 * matrix2->coeff[1][j];
585           tmp.coeff[i][j] += t3 * matrix2->coeff[2][j];
586         }
587     }
588 
589   *matrix2 = tmp;
590 }
591 
592 /**
593  * gimp_matrix3_translate:
594  * @matrix: The matrix that is to be translated.
595  * @x: Translation in X direction.
596  * @y: Translation in Y direction.
597  *
598  * Translates the matrix by x and y.
599  */
600 void
gimp_matrix3_translate(GimpMatrix3 * matrix,gdouble x,gdouble y)601 gimp_matrix3_translate (GimpMatrix3 *matrix,
602                         gdouble      x,
603                         gdouble      y)
604 {
605   gdouble g, h, i;
606 
607   g = matrix->coeff[2][0];
608   h = matrix->coeff[2][1];
609   i = matrix->coeff[2][2];
610 
611   matrix->coeff[0][0] += x * g;
612   matrix->coeff[0][1] += x * h;
613   matrix->coeff[0][2] += x * i;
614   matrix->coeff[1][0] += y * g;
615   matrix->coeff[1][1] += y * h;
616   matrix->coeff[1][2] += y * i;
617 }
618 
619 /**
620  * gimp_matrix3_scale:
621  * @matrix: The matrix that is to be scaled.
622  * @x: X scale factor.
623  * @y: Y scale factor.
624  *
625  * Scales the matrix by x and y
626  */
627 void
gimp_matrix3_scale(GimpMatrix3 * matrix,gdouble x,gdouble y)628 gimp_matrix3_scale (GimpMatrix3 *matrix,
629                     gdouble      x,
630                     gdouble      y)
631 {
632   matrix->coeff[0][0] *= x;
633   matrix->coeff[0][1] *= x;
634   matrix->coeff[0][2] *= x;
635 
636   matrix->coeff[1][0] *= y;
637   matrix->coeff[1][1] *= y;
638   matrix->coeff[1][2] *= y;
639 }
640 
641 /**
642  * gimp_matrix3_rotate:
643  * @matrix: The matrix that is to be rotated.
644  * @theta: The angle of rotation (in radians).
645  *
646  * Rotates the matrix by theta degrees.
647  */
648 void
gimp_matrix3_rotate(GimpMatrix3 * matrix,gdouble theta)649 gimp_matrix3_rotate (GimpMatrix3 *matrix,
650                      gdouble      theta)
651 {
652   gdouble t1, t2;
653   gdouble cost, sint;
654 
655   cost = cos (theta);
656   sint = sin (theta);
657 
658   t1 = matrix->coeff[0][0];
659   t2 = matrix->coeff[1][0];
660   matrix->coeff[0][0] = cost * t1 - sint * t2;
661   matrix->coeff[1][0] = sint * t1 + cost * t2;
662 
663   t1 = matrix->coeff[0][1];
664   t2 = matrix->coeff[1][1];
665   matrix->coeff[0][1] = cost * t1 - sint * t2;
666   matrix->coeff[1][1] = sint * t1 + cost * t2;
667 
668   t1 = matrix->coeff[0][2];
669   t2 = matrix->coeff[1][2];
670   matrix->coeff[0][2] = cost * t1 - sint * t2;
671   matrix->coeff[1][2] = sint * t1 + cost * t2;
672 }
673 
674 /**
675  * gimp_matrix3_xshear:
676  * @matrix: The matrix that is to be sheared.
677  * @amount: X shear amount.
678  *
679  * Shears the matrix in the X direction.
680  */
681 void
gimp_matrix3_xshear(GimpMatrix3 * matrix,gdouble amount)682 gimp_matrix3_xshear (GimpMatrix3 *matrix,
683                      gdouble      amount)
684 {
685   matrix->coeff[0][0] += amount * matrix->coeff[1][0];
686   matrix->coeff[0][1] += amount * matrix->coeff[1][1];
687   matrix->coeff[0][2] += amount * matrix->coeff[1][2];
688 }
689 
690 /**
691  * gimp_matrix3_yshear:
692  * @matrix: The matrix that is to be sheared.
693  * @amount: Y shear amount.
694  *
695  * Shears the matrix in the Y direction.
696  */
697 void
gimp_matrix3_yshear(GimpMatrix3 * matrix,gdouble amount)698 gimp_matrix3_yshear (GimpMatrix3 *matrix,
699                      gdouble      amount)
700 {
701   matrix->coeff[1][0] += amount * matrix->coeff[0][0];
702   matrix->coeff[1][1] += amount * matrix->coeff[0][1];
703   matrix->coeff[1][2] += amount * matrix->coeff[0][2];
704 }
705 
706 /**
707  * gimp_matrix3_affine:
708  * @matrix: The input matrix.
709  * @a: the 'a' coefficient
710  * @b: the 'b' coefficient
711  * @c: the 'c' coefficient
712  * @d: the 'd' coefficient
713  * @e: the 'e' coefficient
714  * @f: the 'f' coefficient
715  *
716  * Applies the affine transformation given by six values to @matrix.
717  * The six values form define an affine transformation matrix as
718  * illustrated below:
719  *
720  *  ( a c e )
721  *  ( b d f )
722  *  ( 0 0 1 )
723  **/
724 void
gimp_matrix3_affine(GimpMatrix3 * matrix,gdouble a,gdouble b,gdouble c,gdouble d,gdouble e,gdouble f)725 gimp_matrix3_affine (GimpMatrix3 *matrix,
726                      gdouble      a,
727                      gdouble      b,
728                      gdouble      c,
729                      gdouble      d,
730                      gdouble      e,
731                      gdouble      f)
732 {
733   GimpMatrix3 affine;
734 
735   affine.coeff[0][0] = a;
736   affine.coeff[1][0] = b;
737   affine.coeff[2][0] = 0.0;
738 
739   affine.coeff[0][1] = c;
740   affine.coeff[1][1] = d;
741   affine.coeff[2][1] = 0.0;
742 
743   affine.coeff[0][2] = e;
744   affine.coeff[1][2] = f;
745   affine.coeff[2][2] = 1.0;
746 
747   gimp_matrix3_mult (&affine, matrix);
748 }
749 
750 /**
751  * gimp_matrix3_determinant:
752  * @matrix: The input matrix.
753  *
754  * Calculates the determinant of the given matrix.
755  *
756  * Returns: The determinant.
757  */
758 gdouble
gimp_matrix3_determinant(const GimpMatrix3 * matrix)759 gimp_matrix3_determinant (const GimpMatrix3 *matrix)
760 {
761   gdouble determinant;
762 
763   determinant  = (matrix->coeff[0][0] *
764                   (matrix->coeff[1][1] * matrix->coeff[2][2] -
765                    matrix->coeff[1][2] * matrix->coeff[2][1]));
766   determinant -= (matrix->coeff[1][0] *
767                   (matrix->coeff[0][1] * matrix->coeff[2][2] -
768                    matrix->coeff[0][2] * matrix->coeff[2][1]));
769   determinant += (matrix->coeff[2][0] *
770                   (matrix->coeff[0][1] * matrix->coeff[1][2] -
771                    matrix->coeff[0][2] * matrix->coeff[1][1]));
772 
773   return determinant;
774 }
775 
776 /**
777  * gimp_matrix3_invert:
778  * @matrix: The matrix that is to be inverted.
779  *
780  * Inverts the given matrix.
781  */
782 void
gimp_matrix3_invert(GimpMatrix3 * matrix)783 gimp_matrix3_invert (GimpMatrix3 *matrix)
784 {
785   GimpMatrix3 inv;
786   gdouble     det;
787 
788   det = gimp_matrix3_determinant (matrix);
789 
790   if (det == 0.0)
791     return;
792 
793   det = 1.0 / det;
794 
795   inv.coeff[0][0] =   (matrix->coeff[1][1] * matrix->coeff[2][2] -
796                        matrix->coeff[1][2] * matrix->coeff[2][1]) * det;
797 
798   inv.coeff[1][0] = - (matrix->coeff[1][0] * matrix->coeff[2][2] -
799                        matrix->coeff[1][2] * matrix->coeff[2][0]) * det;
800 
801   inv.coeff[2][0] =   (matrix->coeff[1][0] * matrix->coeff[2][1] -
802                        matrix->coeff[1][1] * matrix->coeff[2][0]) * det;
803 
804   inv.coeff[0][1] = - (matrix->coeff[0][1] * matrix->coeff[2][2] -
805                        matrix->coeff[0][2] * matrix->coeff[2][1]) * det;
806 
807   inv.coeff[1][1] =   (matrix->coeff[0][0] * matrix->coeff[2][2] -
808                        matrix->coeff[0][2] * matrix->coeff[2][0]) * det;
809 
810   inv.coeff[2][1] = - (matrix->coeff[0][0] * matrix->coeff[2][1] -
811                        matrix->coeff[0][1] * matrix->coeff[2][0]) * det;
812 
813   inv.coeff[0][2] =   (matrix->coeff[0][1] * matrix->coeff[1][2] -
814                        matrix->coeff[0][2] * matrix->coeff[1][1]) * det;
815 
816   inv.coeff[1][2] = - (matrix->coeff[0][0] * matrix->coeff[1][2] -
817                        matrix->coeff[0][2] * matrix->coeff[1][0]) * det;
818 
819   inv.coeff[2][2] =   (matrix->coeff[0][0] * matrix->coeff[1][1] -
820                        matrix->coeff[0][1] * matrix->coeff[1][0]) * det;
821 
822   *matrix = inv;
823 }
824 
825 
826 /*  functions to test for matrix properties  */
827 
828 /**
829  * gimp_matrix3_is_identity:
830  * @matrix: The matrix that is to be tested.
831  *
832  * Checks if the given matrix is the identity matrix.
833  *
834  * Returns: %TRUE if the matrix is the identity matrix, %FALSE otherwise
835  */
836 gboolean
gimp_matrix3_is_identity(const GimpMatrix3 * matrix)837 gimp_matrix3_is_identity (const GimpMatrix3 *matrix)
838 {
839   gint i, j;
840 
841   for (i = 0; i < 3; i++)
842     {
843       for (j = 0; j < 3; j++)
844         {
845           if (i == j)
846             {
847               if (fabs (matrix->coeff[i][j] - 1.0) > EPSILON)
848                 return FALSE;
849             }
850           else
851             {
852               if (fabs (matrix->coeff[i][j]) > EPSILON)
853                 return FALSE;
854             }
855         }
856     }
857 
858   return TRUE;
859 }
860 
861 /**
862  * gimp_matrix3_is_diagonal:
863  * @matrix: The matrix that is to be tested.
864  *
865  * Checks if the given matrix is diagonal.
866  *
867  * Returns: %TRUE if the matrix is diagonal, %FALSE otherwise
868  */
869 gboolean
gimp_matrix3_is_diagonal(const GimpMatrix3 * matrix)870 gimp_matrix3_is_diagonal (const GimpMatrix3 *matrix)
871 {
872   gint i, j;
873 
874   for (i = 0; i < 3; i++)
875     {
876       for (j = 0; j < 3; j++)
877         {
878           if (i != j && fabs (matrix->coeff[i][j]) > EPSILON)
879             return FALSE;
880         }
881     }
882 
883   return TRUE;
884 }
885 
886 /**
887  * gimp_matrix3_is_affine:
888  * @matrix: The matrix that is to be tested.
889  *
890  * Checks if the given matrix defines an affine transformation.
891  *
892  * Returns: %TRUE if the matrix defines an affine transformation,
893  *          %FALSE otherwise
894  *
895  * Since: 2.4
896  */
897 gboolean
gimp_matrix3_is_affine(const GimpMatrix3 * matrix)898 gimp_matrix3_is_affine (const GimpMatrix3 *matrix)
899 {
900   return (fabs (matrix->coeff[2][0]) < EPSILON &&
901           fabs (matrix->coeff[2][1]) < EPSILON &&
902           fabs (matrix->coeff[2][2] - 1.0) < EPSILON);
903 }
904 
905 /**
906  * gimp_matrix3_is_simple:
907  * @matrix: The matrix that is to be tested.
908  *
909  * Checks if we'll need to interpolate when applying this matrix as
910  * a transformation.
911  *
912  * Returns: %TRUE if all entries of the upper left 2x2 matrix are
913  *          either 0 or 1, %FALSE otherwise
914  */
915 gboolean
gimp_matrix3_is_simple(const GimpMatrix3 * matrix)916 gimp_matrix3_is_simple (const GimpMatrix3 *matrix)
917 {
918   gdouble absm;
919   gint    i, j;
920 
921   for (i = 0; i < 2; i++)
922     {
923       for (j = 0; j < 2; j++)
924         {
925           absm = fabs (matrix->coeff[i][j]);
926           if (absm > EPSILON && fabs (absm - 1.0) > EPSILON)
927             return FALSE;
928         }
929     }
930 
931   return TRUE;
932 }
933 
934 /**
935  * gimp_matrix3_equal:
936  * @matrix1: The first matrix
937  * @matrix2: The second matrix
938  *
939  * Checks if two matrices are equal.
940  *
941  * Returns: %TRUE the matrices are equal, %FALSE otherwise
942  *
943  * Since: 2.10.16
944  */
945 gboolean
gimp_matrix3_equal(const GimpMatrix3 * matrix1,const GimpMatrix3 * matrix2)946 gimp_matrix3_equal (const GimpMatrix3 *matrix1,
947                     const GimpMatrix3 *matrix2)
948 {
949   gint i, j;
950 
951   for (i = 0; i < 3; i++)
952     {
953       for (j = 0; j < 3; j++)
954         {
955           if (fabs (matrix1->coeff[i][j] - matrix2->coeff[i][j]) > EPSILON)
956             return FALSE;
957         }
958     }
959 
960   return TRUE;
961 }
962 
963 /**
964  * gimp_matrix4_identity:
965  * @matrix: A matrix.
966  *
967  * Sets the matrix to the identity matrix.
968  *
969  * Since: 2.10.16
970  */
971 void
gimp_matrix4_identity(GimpMatrix4 * matrix)972 gimp_matrix4_identity (GimpMatrix4 *matrix)
973 {
974   gint i, j;
975 
976   for (i = 0; i < 4; i++)
977     {
978       for (j = 0; j < 4; j++)
979         matrix->coeff[i][j] = i == j;
980     }
981 }
982 
983 /**
984  * gimp_matrix4_mult:
985  * @matrix1: The first input matrix.
986  * @matrix2: The second input matrix which will be overwritten by the result.
987  *
988  * Multiplies two matrices and puts the result into the second one.
989  *
990  * Since: 2.10.16
991  */
992 void
gimp_matrix4_mult(const GimpMatrix4 * matrix1,GimpMatrix4 * matrix2)993 gimp_matrix4_mult (const GimpMatrix4 *matrix1,
994                    GimpMatrix4       *matrix2)
995 {
996   GimpMatrix4 result = {};
997   gint        i, j, k;
998 
999   for (i = 0; i < 4; i++)
1000     {
1001       for (j = 0; j < 4; j++)
1002         {
1003           for (k = 0; k < 4; k++)
1004             result.coeff[i][j] += matrix1->coeff[i][k] * matrix2->coeff[k][j];
1005         }
1006     }
1007 
1008   *matrix2 = result;
1009 }
1010 
1011 /**
1012  * gimp_matrix4_to_deg:
1013  * @matrix:
1014  * @a:
1015  * @b:
1016  * @c:
1017  *
1018  *
1019  **/
1020 void
gimp_matrix4_to_deg(const GimpMatrix4 * matrix,gdouble * a,gdouble * b,gdouble * c)1021 gimp_matrix4_to_deg (const GimpMatrix4 *matrix,
1022                      gdouble           *a,
1023                      gdouble           *b,
1024                      gdouble           *c)
1025 {
1026   *a = 180 * (asin (matrix->coeff[1][0]) / G_PI_2);
1027   *b = 180 * (asin (matrix->coeff[2][0]) / G_PI_2);
1028   *c = 180 * (asin (matrix->coeff[2][1]) / G_PI_2);
1029 }
1030 
1031 /**
1032  * gimp_matrix4_transform_point:
1033  * @matrix: The transformation matrix.
1034  * @x: The source X coordinate.
1035  * @y: The source Y coordinate.
1036  * @z: The source Z coordinate.
1037  * @newx: The transformed X coordinate.
1038  * @newy: The transformed Y coordinate.
1039  * @newz: The transformed Z coordinate.
1040  *
1041  * Transforms a point in 3D as specified by the transformation matrix.
1042  *
1043  * Returns: The transformed W coordinate.
1044  *
1045  * Since: 2.10.16
1046  */
1047 gdouble
gimp_matrix4_transform_point(const GimpMatrix4 * matrix,gdouble x,gdouble y,gdouble z,gdouble * newx,gdouble * newy,gdouble * newz)1048 gimp_matrix4_transform_point (const GimpMatrix4 *matrix,
1049                               gdouble            x,
1050                               gdouble            y,
1051                               gdouble            z,
1052                               gdouble           *newx,
1053                               gdouble           *newy,
1054                               gdouble           *newz)
1055 {
1056   gdouble neww;
1057 
1058   *newx = matrix->coeff[0][0] * x +
1059           matrix->coeff[0][1] * y +
1060           matrix->coeff[0][2] * z +
1061           matrix->coeff[0][3];
1062   *newy = matrix->coeff[1][0] * x +
1063           matrix->coeff[1][1] * y +
1064           matrix->coeff[1][2] * z +
1065           matrix->coeff[1][3];
1066   *newz = matrix->coeff[2][0] * x +
1067           matrix->coeff[2][1] * y +
1068           matrix->coeff[2][2] * z +
1069           matrix->coeff[2][3];
1070   neww  = matrix->coeff[3][0] * x +
1071           matrix->coeff[3][1] * y +
1072           matrix->coeff[3][2] * z +
1073           matrix->coeff[3][3];
1074 
1075   *newx /= neww;
1076   *newy /= neww;
1077   *newz /= neww;
1078 
1079   return neww;
1080 }
1081