mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-09 18:30:08 +00:00
transform: Implement gsk_transform_invert()
And use it. And test it.
This commit is contained in:
parent
70b341139b
commit
3545abc7a1
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user