transform: Implement gsk_transform_invert()

And use it.

And test it.
This commit is contained in:
Benjamin Otte 2019-03-03 17:57:11 +01:00
parent 70b341139b
commit 3545abc7a1
5 changed files with 176 additions and 5 deletions

View File

@ -163,6 +163,7 @@ gsk_transform_to_affine
gsk_transform_to_translate
<SUBSECTION>
gsk_transform_transform
gsk_transform_invert
gsk_transform_matrix
gsk_transform_translate
gsk_transform_translate_3d

View File

@ -75,6 +75,8 @@ struct _GskTransformClass
GString *string);
GskTransform * (* apply) (GskTransform *transform,
GskTransform *apply_to);
GskTransform * (* invert) (GskTransform *transform,
GskTransform *next);
/* both matrices have the same type */
gboolean (* equal) (GskTransform *first_transform,
GskTransform *second_transform);
@ -178,7 +180,26 @@ static GskTransform *
gsk_identity_transform_apply (GskTransform *transform,
GskTransform *apply_to)
{
return apply_to;
/* We do the following to make sure inverting a non-NULL transform
* will return a non-NULL transform.
*/
if (apply_to)
return apply_to;
else
return gsk_transform_new ();
}
static GskTransform *
gsk_identity_transform_invert (GskTransform *transform,
GskTransform *next)
{
/* We do the following to make sure inverting a non-NULL transform
* will return a non-NULL transform.
*/
if (next)
return next;
else
return gsk_transform_new ();
}
static gboolean
@ -200,6 +221,7 @@ static const GskTransformClass GSK_IDENTITY_TRANSFORM_CLASS =
gsk_identity_transform_apply_translate,
gsk_identity_transform_print,
gsk_identity_transform_apply,
gsk_identity_transform_invert,
gsk_identity_transform_equal,
};
@ -372,6 +394,24 @@ gsk_matrix_transform_apply (GskTransform *transform,
self->category);
}
static GskTransform *
gsk_matrix_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskMatrixTransform *self = (GskMatrixTransform *) transform;
graphene_matrix_t inverse;
if (!graphene_matrix_inverse (&self->matrix, &inverse))
{
gsk_transform_unref (next);
return NULL;
}
return gsk_transform_matrix_with_category (next,
&inverse,
self->category);
}
static gboolean
gsk_matrix_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
@ -395,6 +435,7 @@ static const GskTransformClass GSK_TRANSFORM_TRANSFORM_CLASS =
gsk_matrix_transform_apply_translate,
gsk_matrix_transform_print,
gsk_matrix_transform_apply,
gsk_matrix_transform_invert,
gsk_matrix_transform_equal,
};
@ -526,6 +567,15 @@ gsk_translate_transform_apply (GskTransform *transform,
return gsk_transform_translate_3d (apply_to, &self->point);
}
static GskTransform *
gsk_translate_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskTranslateTransform *self = (GskTranslateTransform *) transform;
return gsk_transform_translate_3d (next, &GRAPHENE_POINT3D_INIT (-self->point.x, -self->point.y, -self->point.z));
}
static gboolean
gsk_translate_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
@ -570,6 +620,7 @@ static const GskTransformClass GSK_TRANSLATE_TRANSFORM_CLASS =
gsk_translate_transform_apply_translate,
gsk_translate_transform_print,
gsk_translate_transform_apply,
gsk_translate_transform_invert,
gsk_translate_transform_equal,
};
@ -710,6 +761,15 @@ gsk_rotate_transform_apply (GskTransform *transform,
return gsk_transform_rotate (apply_to, self->angle);
}
static GskTransform *
gsk_rotate_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskRotateTransform *self = (GskRotateTransform *) transform;
return gsk_transform_rotate (next, - self->angle);
}
static gboolean
gsk_rotate_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
@ -743,6 +803,7 @@ static const GskTransformClass GSK_ROTATE_TRANSFORM_CLASS =
gsk_rotate_transform_apply_translate,
gsk_rotate_transform_print,
gsk_rotate_transform_apply,
gsk_rotate_transform_invert,
gsk_rotate_transform_equal,
};
@ -837,6 +898,15 @@ gsk_rotate3d_transform_apply (GskTransform *transform,
return gsk_transform_rotate_3d (apply_to, self->angle, &self->axis);
}
static GskTransform *
gsk_rotate3d_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskRotate3dTransform *self = (GskRotate3dTransform *) transform;
return gsk_transform_rotate_3d (next, - self->angle, &self->axis);
}
static gboolean
gsk_rotate3d_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
@ -879,6 +949,7 @@ static const GskTransformClass GSK_ROTATE3D_TRANSFORM_CLASS =
gsk_rotate3d_transform_apply_translate,
gsk_rotate3d_transform_print,
gsk_rotate3d_transform_apply,
gsk_rotate3d_transform_invert,
gsk_rotate3d_transform_equal,
};
@ -1007,6 +1078,18 @@ gsk_scale_transform_apply (GskTransform *transform,
return gsk_transform_scale_3d (apply_to, self->factor_x, self->factor_y, self->factor_z);
}
static GskTransform *
gsk_scale_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskScaleTransform *self = (GskScaleTransform *) transform;
return gsk_transform_scale_3d (next,
1.f / self->factor_x,
1.f / self->factor_y,
1.f / self->factor_z);
}
static gboolean
gsk_scale_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
@ -1060,6 +1143,7 @@ static const GskTransformClass GSK_SCALE_TRANSFORM_CLASS =
gsk_scale_transform_apply_translate,
gsk_scale_transform_print,
gsk_scale_transform_apply,
gsk_scale_transform_invert,
gsk_scale_transform_equal,
};
@ -1394,6 +1478,39 @@ gsk_transform_transform (GskTransform *next,
return other->transform_class->apply (other, next);
}
/**
* gsk_transform_invert:
* @self: (allow-none) (transfer full): Transform to invert
*
* Inverts the given transform.
*
* If @self is not invertible, %NULL is returned.
* Note that inverting %NULL also returns %NULL, which is
* the correct inverse of %NULL. If you need to differentiate
* between those cases, you should check @self is not %NULL
* before calling this function.
*
* Returns: The inverted transform or %NULL if the transform
* cannot be inverted.
**/
GskTransform *
gsk_transform_invert (GskTransform *self)
{
GskTransform *result = NULL;
GskTransform *cur;
for (cur = self; cur; cur = cur->next)
{
result = cur->transform_class->invert (cur, result);
if (result == NULL)
break;
}
gsk_transform_unref (self);
return result;
}
/**
* gsk_transform_equal:
* @first: the first matrix

View File

@ -79,6 +79,8 @@ GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_transform (GskTransform *next,
GskTransform *other);
GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_invert (GskTransform *self);
GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_matrix (GskTransform *next,
const graphene_matrix_t *matrix);
GDK_AVAILABLE_IN_ALL

View File

@ -820,13 +820,23 @@ gtk_widget_real_pick (GtkWidget *widget,
child = _gtk_widget_get_prev_sibling (child))
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child);
GskTransform *transform;
graphene_matrix_t inv;
GtkWidget *picked;
graphene_point3d_t p0, p1, res;
gsk_transform_to_matrix (priv->transform, &inv);
if (!graphene_matrix_inverse (&inv, &inv))
continue;
if (priv->transform)
{
transform = gsk_transform_invert (gsk_transform_ref (priv->transform));
if (transform == NULL)
continue;
}
else
{
transform = NULL;
}
gsk_transform_to_matrix (transform, &inv);
gsk_transform_unref (transform);
graphene_point3d_init (&p0, x, y, 0);
graphene_point3d_init (&p1, x, y, 1);
graphene_matrix_transform_point3d (&inv, &p0, &p0);

View File

@ -21,7 +21,7 @@
#include <gtk/gtk.h>
#define EPSILON (1.f / 1024 / 1024)
#define EPSILON (1.f / 1024 / 32) /* 2^-15 */
/* macros stolen from graphene testsuite, so they get to keep their names */
@ -66,6 +66,14 @@
} \
} G_STMT_END
#define graphene_assert_fuzzy_transform_equal(t1,t2,epsilon) \
G_STMT_START { \
graphene_matrix_t __mat1, __mat2; \
gsk_transform_to_matrix ((t1), &__mat1); \
gsk_transform_to_matrix ((t2), &__mat2); \
graphene_assert_fuzzy_matrix_equal (&__mat1, &__mat2, (epsilon)); \
} G_STMT_END
static struct {
GskTransformCategory category;
} test_transforms[] = {
@ -235,6 +243,38 @@ test_conversions_transformed (void)
}
}
static void
test_invert (void)
{
GskTransform *transform, *inverse, *identity;
guint i, j, k;
for (i = 0; i < G_N_ELEMENTS (test_transforms); i++)
{
for (j = 0; j < G_N_ELEMENTS (test_transforms); j++)
{
for (k = 0; k < G_N_ELEMENTS (test_transforms); k++)
{
transform = apply_test_transform (NULL, i);
transform = apply_test_transform (transform, j);
transform = apply_test_transform (transform, k);
inverse = gsk_transform_invert (gsk_transform_ref (transform));
g_assert (inverse != NULL || transform == NULL);
identity = gsk_transform_transform (gsk_transform_ref (transform), inverse);
graphene_assert_fuzzy_transform_equal (identity, NULL, EPSILON);
gsk_transform_unref (identity);
inverse = gsk_transform_invert (inverse);
graphene_assert_fuzzy_transform_equal (transform, inverse, EPSILON);
gsk_transform_unref (transform);
gsk_transform_unref (inverse);
}
}
}
}
int
main (int argc,
char *argv[])
@ -243,6 +283,7 @@ main (int argc,
g_test_add_func ("/transform/conversions/simple", test_conversions_simple);
g_test_add_func ("/transform/conversions/transformed", test_conversions_transformed);
g_test_add_func ("/transform/invert", test_invert);
return g_test_run ();
}