diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-09-18 02:06:00 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-09-18 02:06:51 -0400 |
commit | 41b810da7f36366ca7bbda7630453faed54fa016 (patch) | |
tree | 15a6a5715af1263cc0257b499be332eef676d284 /gsk/gsktransform.c | |
parent | 5742483422a75aa69b7bbeda5e737159baaf1b12 (diff) | |
download | gtk+-41b810da7f36366ca7bbda7630453faed54fa016.tar.gz |
Add gsk_transform_to_2d_components
This function decomposes a general 2D transform
into skew, scale, rotation and translation.
Tests included.
Diffstat (limited to 'gsk/gsktransform.c')
-rw-r--r-- | gsk/gsktransform.c | 118 |
1 files changed, 105 insertions, 13 deletions
diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index cc30f567d9..9eeab2d66a 100644 --- a/gsk/gsktransform.c +++ b/gsk/gsktransform.c @@ -121,6 +121,14 @@ gsk_transform_alloc (const GskTransformClass *transform_class, return self; } +static void +gsk_transform_finalize (GskTransform *self) +{ + self->transform_class->finalize (self); + + gsk_transform_unref (self->next); +} + /* }}} */ /* {{{ IDENTITY */ @@ -1022,6 +1030,9 @@ gsk_skew_transform_finalize (GskTransform *self) { } +#define DEG_TO_RAD(x) ((x) / 180.f * G_PI) +#define RAD_TO_DEG(x) ((x) * 180.f / G_PI) + static void gsk_skew_transform_to_matrix (GskTransform *transform, graphene_matrix_t *out_matrix) @@ -1029,8 +1040,8 @@ gsk_skew_transform_to_matrix (GskTransform *transform, GskSkewTransform *self = (GskSkewTransform *) transform; graphene_matrix_init_skew (out_matrix, - self->skew_x / 180.0 * G_PI, - self->skew_y / 180.0 * G_PI); + DEG_TO_RAD (self->skew_x), + DEG_TO_RAD (self->skew_y)); } static void @@ -1104,8 +1115,8 @@ gsk_skew_transform_invert (GskTransform *transform, float tx, ty; graphene_matrix_t matrix; - tx = tanf (self->skew_x / 180.0 * G_PI); - ty = tanf (self->skew_y / 180.0 * G_PI); + tx = tanf (DEG_TO_RAD (self->skew_x)); + ty = tanf (DEG_TO_RAD (self->skew_y)); graphene_matrix_init_from_2d (&matrix, 1 / (1 - tx * ty), @@ -1506,14 +1517,6 @@ gsk_transform_perspective (GskTransform *next, /* }}} */ /* {{{ PUBLIC API */ -static void -gsk_transform_finalize (GskTransform *self) -{ - self->transform_class->finalize (self); - - gsk_transform_unref (self->next); -} - /** * gsk_transform_ref: * @self: (nullable): a `GskTransform` @@ -1698,6 +1701,95 @@ gsk_transform_to_2d (GskTransform *self, } /** + * gsk_transform_to_2d_components: + * @self: a `GskTransform` + * @out_skew_x: (out): return location for the skew factor + * in the x direction + * @out_skew_y: (out): return location for the skew factor + * in the y direction + * @out_scale_x: (out): return location for the scale + * factor in the x direction + * @out_scale_y: (out): return location for the scale + * factor in the y direction + * @out_angle: (out): return location for the rotation angle + * @out_dx: (out): return location for the translation + * in the x direction + * @out_dy: (out): return location for the translation + * in the y direction + * + * Converts a `GskTransform` to 2D transformation factors. + * + * To recreate an equivalent transform from the factors returned + * by this function, use + * + * gsk_transform_skew ( + * gsk_transform_scale ( + * gsk_transform_rotate ( + * gsk_transform_translate (NULL, &GRAPHENE_POINT_T (dx, dy)), + * angle), + * scale_x, scale_y), + * skew_x, skew_y) + * + * @self must be a 2D transformation. If you are not sure, use + * + * gsk_transform_get_category() >= %GSK_TRANSFORM_CATEGORY_2D + * + * to check. + * + * Since: 4.6 + */ +void +gsk_transform_to_2d_components (GskTransform *self, + float *out_skew_x, + float *out_skew_y, + float *out_scale_x, + float *out_scale_y, + float *out_angle, + float *out_dx, + float *out_dy) +{ + float a, b, c, d, e, f; + + gsk_transform_to_2d (self, &a, &b, &c, &d, &e, &f); + + *out_dx = e; + *out_dy = f; + +#define sign(f) ((f) < 0 ? -1 : 1) + + if (a != 0 || b != 0) + { + float det = a * d - b * c; + float r = sqrtf (a*a + b*b); + + *out_angle = RAD_TO_DEG (sign (b) * acosf (a / r)); + *out_scale_x = r; + *out_scale_y = det / r; + *out_skew_x = RAD_TO_DEG (atanf ((a*c + b*d) / (r*r))); + *out_skew_y = 0; + } + else if (c != 0 || d != 0) + { + float det = a * d - b * c; + float s = sqrtf (c*c + d*d); + + *out_angle = RAD_TO_DEG (G_PI/2 - sign (d) * acosf (-c / s)); + *out_scale_x = det / s; + *out_scale_y = s; + *out_skew_x = 0; + *out_skew_y = RAD_TO_DEG (atanf ((a*c + b*d) / (s*s))); + } + else + { + *out_angle = 0; + *out_scale_x = 0; + *out_scale_y = 0; + *out_skew_x = 0; + *out_skew_y = 0; + } +} + +/** * gsk_transform_to_affine: * @self: a `GskTransform` * @out_scale_x: (out): return location for the scale @@ -1718,7 +1810,7 @@ gsk_transform_to_2d (GskTransform *self, * &GRAPHENE_POINT_T (dx, dy)), * sx, sy) * - * @self must be a 2D transformation. If you are not + * @self must be a 2D affine transformation. If you are not * sure, use * * gsk_transform_get_category() >= %GSK_TRANSFORM_CATEGORY_2D_AFFINE |