/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 . 1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*
* Authors : Benjamin Otte < otte @ gnome . org >
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gsk/gsktransformprivate.h"
#define EPSILON (1 .f / 1024 / 32 ) /* 2^-15 */
/* macros stolen from graphene testsuite, so they get to keep their names */
#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))
/* Use typeof on GCC */
# define graphene_fuzzy_equals(n1,n2,epsilon) \
G_GNUC_EXTENSION({ \
__auto_type _n1 = (n1); \
__auto_type _n2 = (n2); \
__auto_type _epsilon = (epsilon); \
((_n1 > _n2 ? (_n1 - _n2 ) : (_n2 - _n1)) <= _epsilon); \
})
#else
/* fallback for Visual Studio, typeof not supported */
# define graphene_fuzzy_equals(n1,n2,epsilon) \
(((n1) > (n2) ? ((n1) - (n2)) : ((n2) - (n1))) <= (epsilon))
#endif /* __GNUC__ */
#define graphene_assert_fuzzy_matrix_cell_equal(row,col,n1,n2,epsilon) \
G_STMT_START { \
if (graphene_fuzzy_equals (n1, n2, epsilon)) ; else { \
char *s = g_strdup_printf ("[%d][%d]: " #n1 " == " #n2 " (+/- " #epsilon "): (%.7g == %.7g)" , \
row, col, n1, n2); \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \
g_free (s); \
} \
} G_STMT_END
#define graphene_assert_fuzzy_matrix_equal(m1,m2,epsilon) \
G_STMT_START { \
unsigned int __i, __j; \
float __m1[16 ], __m2[16 ]; \
graphene_matrix_to_float ((m1), __m1); \
graphene_matrix_to_float ((m2), __m2); \
for (__i = 0 ; __i < 4 ; __i++) { \
for (__j = 0 ; __j < 4 ; __j++) { \
unsigned int __idx = __i * 4 + __j; \
graphene_assert_fuzzy_matrix_cell_equal (__i, __j, __m1[__idx], __m2[__idx], epsilon); \
} \
} \
} 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[] = {
{ GSK_TRANSFORM_CATEGORY_IDENTITY },
{ GSK_TRANSFORM_CATEGORY_IDENTITY },
{ GSK_TRANSFORM_CATEGORY_2D_TRANSLATE },
{ GSK_TRANSFORM_CATEGORY_3D },
{ GSK_TRANSFORM_CATEGORY_2D },
{ GSK_TRANSFORM_CATEGORY_3D },
{ GSK_TRANSFORM_CATEGORY_2D_AFFINE },
{ GSK_TRANSFORM_CATEGORY_3D },
{ GSK_TRANSFORM_CATEGORY_ANY },
};
static GskTransform *
apply_test_transform (GskTransform *transform,
guint i)
{
switch (i)
{
case 0 :
return transform ? transform : gsk_transform_new ();
case 1 :
return gsk_transform_transform (transform, NULL);
case 2 :
return gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (3 , 5 ));
case 3 :
return gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (3 , 5 , 7 ));
case 4 :
return gsk_transform_rotate (transform, 90 );
case 5 :
return gsk_transform_rotate_3d (transform, 90 , graphene_vec3_y_axis ());
case 6 :
return gsk_transform_scale (transform, 2 , 3 );
case 7 :
return gsk_transform_scale_3d (transform, 2 , 3 , 5 );
case 8 :
return gsk_transform_perspective (transform, 5 );
default :
g_assert_not_reached ();
return NULL;
}
}
static GskTransformCategory
categorize_matrix (const graphene_matrix_t *matrix)
{
if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0 , 3 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1 , 3 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2 , 3 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3 , 3 ), 1 , EPSILON))
return GSK_TRANSFORM_CATEGORY_ANY;
if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0 , 2 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1 , 2 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2 , 2 ), 1 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3 , 2 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2 , 0 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2 , 1 ), 0 , EPSILON))
return GSK_TRANSFORM_CATEGORY_3D;
if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0 , 1 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1 , 0 ), 0 , EPSILON))
return GSK_TRANSFORM_CATEGORY_2D;
if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0 , 0 ), 1 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1 , 1 ), 1 , EPSILON))
return GSK_TRANSFORM_CATEGORY_2D_AFFINE;
if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3 , 0 ), 0 , EPSILON) ||
!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3 , 1 ), 0 , EPSILON))
return GSK_TRANSFORM_CATEGORY_2D_TRANSLATE;
return GSK_TRANSFORM_CATEGORY_IDENTITY;
}
static void
check_conversions (GskTransform *transform,
GskTransformCategory expected_category)
{
graphene_matrix_t matrix, test;
float f[16 ] = { 1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 };
g_assert_cmpint (gsk_transform_get_category (transform), ==, expected_category);
gsk_transform_to_matrix (transform, &matrix);
/* we don't insist on getting simplifications right.
* The matrix " scale ( 2 ) scale ( 0 . 5 ) " would be categorized as identity ,
* but the transform might not do that .
*/
g_assert_cmpint (gsk_transform_get_category (transform), <=, categorize_matrix (&matrix));
switch (expected_category)
{
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
break ;
case GSK_TRANSFORM_CATEGORY_IDENTITY:
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
gsk_transform_to_translate (transform,
&f[4 * 3 + 0 ], &f[4 * 3 + 1 ]);
graphene_matrix_init_from_float (&test, f);
graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
G_GNUC_FALLTHROUGH;
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
gsk_transform_to_affine (transform,
&f[4 * 0 + 0 ], &f[4 * 1 + 1 ],
&f[4 * 3 + 0 ], &f[4 * 3 + 1 ]);
graphene_matrix_init_from_float (&test, f);
graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
G_GNUC_FALLTHROUGH;
case GSK_TRANSFORM_CATEGORY_2D:
gsk_transform_to_2d (transform,
&f[4 * 0 + 0 ], &f[4 * 0 + 1 ],
&f[4 * 1 + 0 ], &f[4 * 1 + 1 ],
&f[4 * 3 + 0 ], &f[4 * 3 + 1 ]);
graphene_matrix_init_from_float (&test, f);
graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
break ;
default :
g_assert_not_reached ();
}
}
static void
test_conversions_simple (void )
{
GskTransform *transform;
guint i;
for (i = 0 ; i < G_N_ELEMENTS (test_transforms); i++)
{
transform = apply_test_transform (NULL, i);
check_conversions (transform, test_transforms[i].category);
gsk_transform_unref (transform);
}
}
static void
test_conversions_transformed (void )
{
GskTransform *transform;
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);
check_conversions (transform, MIN (test_transforms[i].category, MIN (test_transforms[j].category, test_transforms[k].category)));
gsk_transform_unref (transform);
}
}
}
}
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_true (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);
}
}
}
}
/* some trivialities around identity transforms */
static void
test_identity (void )
{
GskTransform *s, *t, *u, *v, *w, *x;
char *string;
float a, b, c, d, tx, ty;
gboolean res;
s = gsk_transform_new ();
t = gsk_transform_new ();
u = gsk_transform_transform (gsk_transform_ref (s), NULL);
g_assert_cmpint (gsk_transform_get_category (s), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
g_assert_cmpint (gsk_transform_get_category (t), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
g_assert_cmpint (gsk_transform_get_category (u), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
g_assert_true (gsk_transform_equal (s, t));
g_assert_true (gsk_transform_equal (t, u));
g_assert_true (gsk_transform_equal (s, u));
v = gsk_transform_transform (gsk_transform_ref (s), t);
g_assert_cmpint (gsk_transform_get_category (v), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
w = gsk_transform_invert (gsk_transform_ref (v));
g_assert_cmpint (gsk_transform_get_category (w), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
string = gsk_transform_to_string (s);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_cmpint (gsk_transform_get_category (x), ==, GSK_TRANSFORM_CATEGORY_IDENTITY);
gsk_transform_to_2d (s, &a, &b, &c, &d, &tx, &ty);
g_assert_cmpfloat (a, ==, 1 .0 f);
g_assert_cmpfloat (b, ==, 0 .0 f);
g_assert_cmpfloat (c, ==, 0 .0 f);
g_assert_cmpfloat (d, ==, 1 .0 f);
g_assert_cmpfloat (tx, ==, 0 .0 f);
g_assert_cmpfloat (ty, ==, 0 .f);
gsk_transform_unref (s);
gsk_transform_unref (t);
gsk_transform_unref (u);
gsk_transform_unref (v);
gsk_transform_unref (w);
gsk_transform_unref (x);
g_free (string);
}
static void
test_identity_equal (void )
{
GskTransform *id = gsk_transform_new ();
GskTransform *t;
g_assert_true (gsk_transform_equal (NULL, NULL));
g_assert_true (gsk_transform_equal (id, NULL));
g_assert_true (gsk_transform_equal (NULL, id));
g_assert_true (gsk_transform_equal (id, id));
t = gsk_transform_transform (NULL, NULL);
g_assert_true (gsk_transform_equal (t, NULL));
gsk_transform_unref (t);
t = gsk_transform_transform (gsk_transform_new (), NULL);
g_assert_true (gsk_transform_equal (t, NULL));
gsk_transform_unref (t);
t = gsk_transform_transform (NULL, id);
g_assert_true (gsk_transform_equal (t, NULL));
gsk_transform_unref (t);
t = gsk_transform_transform (gsk_transform_new (), id);
g_assert_true (gsk_transform_equal (t, NULL));
gsk_transform_unref (t);
t = gsk_transform_new ();
t = gsk_transform_transform (t, t);
g_assert_true (gsk_transform_equal (t, NULL));
gsk_transform_unref (t);
gsk_transform_unref (id);
}
static void
test_print_parse (void )
{
GskTransform *transform, *parsed;
guint i, j, k;
char *str1, *str2;
gboolean ret;
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);
str1 = gsk_transform_to_string (transform);
g_assert_nonnull (str1);
g_assert_true (strlen (str1) > 0 );
str2 = gsk_transform_to_string (transform);
g_assert_cmpstr (str1, ==, str2);
g_free (str2);
ret = gsk_transform_parse (str1, &parsed);
g_assert_true (ret);
graphene_assert_fuzzy_transform_equal (parsed, transform, EPSILON);
str2 = gsk_transform_to_string (parsed);
g_assert_cmpstr (str1, ==, str2);
g_free (str2);
g_free (str1);
gsk_transform_unref (parsed);
gsk_transform_unref (transform);
}
}
}
ret = gsk_transform_parse ("rotate(45);" , &parsed);
g_assert_false (ret);
g_assert_null (parsed);
}
/* This is an auxiliary function used in the GL renderer to
* determine if transforming an axis - aligned rectangle produces
* axis - aligned output , to decide whether to use linear
* interpolation or not .
*/
static gboolean
result_is_axis_aligned (GskTransform *transform,
const graphene_rect_t *bounds)
{
graphene_matrix_t m;
graphene_quad_t q;
graphene_rect_t b;
graphene_point_t b1, b2;
const graphene_point_t *p;
int i;
gsk_transform_to_matrix (transform, &m);
gsk_matrix_transform_rect (&m, bounds, &q);
graphene_quad_bounds (&q, &b);
graphene_rect_get_top_left (&b, &b1);
graphene_rect_get_bottom_right (&b, &b2);
for (i = 0 ; i < 4 ; i++)
{
p = graphene_quad_get_point (&q, i);
if (fabs (p->x - b1.x) > FLT_EPSILON && fabs (p->x - b2.x) > FLT_EPSILON)
return FALSE ;
if (fabs (p->y - b1.y) > FLT_EPSILON && fabs (p->y - b2.y) > FLT_EPSILON)
return FALSE ;
}
return TRUE ;
}
static void
test_axis_aligned (void )
{
graphene_rect_t r = GRAPHENE_RECT_INIT (0 , 0 , 10 , 10 );
GskTransform *transform = NULL;
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 , 10 ));
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
transform = gsk_transform_translate_3d (NULL, &GRAPHENE_POINT3D_INIT(0 , 10 , 10 ));
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
transform = gsk_transform_rotate (NULL, 90 );
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
transform = gsk_transform_scale (NULL, 2 , 3 );
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
/* rotating around the y axis does not affect axis alignedness,
* as long as we don ' t involve perspective
*/
transform = gsk_transform_rotate_3d (NULL, 45 , graphene_vec3_y_axis ());
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
/* rotating by 45 around the z axis, not axis aligned */
transform = gsk_transform_rotate (NULL, 45 );
g_assert_false (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
/* perspective is harmless as long as we stay in the z=0 plane */
transform = gsk_transform_perspective (NULL, 100 );
g_assert_true (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
/* a complex transform that makes things look '3d' */
transform = gsk_transform_translate_3d (NULL, &GRAPHENE_POINT3D_INIT (0 , 0 , 50 ));
transform = gsk_transform_perspective (transform, 170 );
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (50 , 0 , 50 ));
transform = gsk_transform_rotate (transform, 20 );
transform = gsk_transform_rotate_3d (transform, 20 , graphene_vec3_y_axis ());
g_assert_false (result_is_axis_aligned (transform, &r));
gsk_transform_unref (transform);
}
static void
test_to_affine (void )
{
GskTransform *transform;
float sx, sy, dx, dy;
transform = gsk_transform_scale (NULL, 10 .0 , 5 .0 );
gsk_transform_to_affine (transform, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (sx, ==, 10 .0 );
g_assert_cmpfloat (sy, ==, 5 .0 );
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 ));
gsk_transform_to_affine (transform, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (sx, ==, 1 .0 );
g_assert_cmpfloat (sy, ==, 1 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
transform = gsk_transform_translate (gsk_transform_scale (NULL, 2 .0 , 3 .0 ), &GRAPHENE_POINT_INIT (10 .0 , 5 .0 ));
gsk_transform_to_affine (transform, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 2 .0 * 10 .0 );
g_assert_cmpfloat (dy, ==, 3 .0 * 5 .0 );
transform = gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), 2 .0 , 3 .0 );
gsk_transform_to_affine (transform, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
}
static void
test_transform_bounds (void )
{
GskTransform *t = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (50 , 50 ));
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0 , 0 , 100 , 100 );
graphene_rect_t out;
gsk_transform_transform_bounds (t, &bounds, &out);
g_assert_true (graphene_rect_equal (&out, &GRAPHENE_RECT_INIT(50 , 50 , 100 , 100 )));
t = gsk_transform_rotate (t, 180 );
gsk_transform_transform_bounds (t, &bounds, &out);
g_assert_true (graphene_rect_equal (&out, &GRAPHENE_RECT_INIT(-50 , -50 , 100 , 100 )));
t = gsk_transform_translate (t, &GRAPHENE_POINT_INIT (-50 , -50 ));
gsk_transform_transform_bounds (t, &bounds, &out);
g_assert_true (graphene_rect_equal (&out, &GRAPHENE_RECT_INIT(0 , 0 , 100 , 100 )));
t = gsk_transform_scale (NULL, -1 , 1 );
gsk_transform_transform_bounds (t, &bounds, &out);
g_assert_true (graphene_rect_equal (&out, &GRAPHENE_RECT_INIT(-100 , 0 , 100 , 100 )));
t = gsk_transform_scale (NULL, -1 , -2 );
gsk_transform_transform_bounds (t, &bounds, &out);
g_assert_true (graphene_rect_equal (&out, &GRAPHENE_RECT_INIT(-100 , -200 , 100 , 200 )));
}
#define DEG_TO_RAD(x) ((x) / 180 .0 * G_PI)
static void
test_to_2d (void )
{
GskTransform *transform;
float xx, yx, xy, yy, dx, dy;
float s, c;
float tx,ty;
transform = gsk_transform_scale (NULL, 10 .0 , 5 .0 );
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (xx, ==, 10 .0 );
g_assert_cmpfloat (yx, ==, 0 .0 );
g_assert_cmpfloat (xy, ==, 0 .0 );
g_assert_cmpfloat (yy, ==, 5 .0 );
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 ));
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (xx, ==, 1 .0 );
g_assert_cmpfloat (yx, ==, 0 .0 );
g_assert_cmpfloat (xy, ==, 0 .0 );
g_assert_cmpfloat (yy, ==, 1 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
transform = gsk_transform_rotate (NULL, 33 .0 );
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
c = cosf (DEG_TO_RAD (33 .0 ));
s = sinf (DEG_TO_RAD (33 .0 ));
g_assert_cmpfloat (xx, ==, c);
g_assert_cmpfloat (yx, ==, s);
g_assert_cmpfloat (xy, ==, -s);
g_assert_cmpfloat (yy, ==, c);
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_skew (NULL, 33 .0 , 0 );
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
tx = tanf (DEG_TO_RAD (33 .0 ));
g_assert_cmpfloat (xx, ==, 1 );
g_assert_cmpfloat (yx, ==, 0 );
g_assert_cmpfloat (xy, ==, tx);
g_assert_cmpfloat (yy, ==, 1 );
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_skew (NULL, 0 , 66 .0 );
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
ty = tanf (DEG_TO_RAD (66 .0 ));
g_assert_cmpfloat (xx, ==, 1 );
g_assert_cmpfloat (yx, ==, ty);
g_assert_cmpfloat (xy, ==, 0 );
g_assert_cmpfloat (yy, ==, 1 );
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 ));
transform = gsk_transform_rotate (transform, 33 .0 );
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (xx, ==, 0 .838670552 f);
g_assert_cmpfloat (yx, ==, 0 .544639051 f);
g_assert_cmpfloat (xy, ==, -0 .544639051 f);
g_assert_cmpfloat (yy, ==, 0 .838670552 f);
g_assert_cmpfloat (dx, ==, 10 .f);
g_assert_cmpfloat (dy, ==, 5 .f);
}
static void
test_to_2d_components (void )
{
GskTransform *transform, *transform2;
float skew_x, skew_y, scale_x, scale_y, angle, dx, dy;
graphene_matrix_t m, m2;
transform = gsk_transform_scale (
gsk_transform_rotate (
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 , 20 )),
22 ),
3 , 3 );
gsk_transform_to_2d_components (transform,
&skew_x, &skew_y,
&scale_x, &scale_y,
&angle,
&dx, &dy);
g_assert_cmpfloat_with_epsilon (skew_x, 0 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (skew_y, 0 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (scale_x, 3 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (scale_y, 3 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (angle, 22 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (dx, 10 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (dy, 20 , 0 .0001 );
gsk_transform_unref (transform);
transform = gsk_transform_skew (
gsk_transform_scale (
gsk_transform_rotate (
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 , 20 )),
22 ),
3 , 6 ),
33 , 0 );
g_assert_true (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D);
gsk_transform_to_2d_components (transform,
&skew_x, &skew_y,
&scale_x, &scale_y,
&angle,
&dx, &dy);
transform2 = gsk_transform_skew (
gsk_transform_scale (
gsk_transform_rotate (
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (dx, dy)),
angle),
scale_x, scale_y),
skew_x, skew_y);
gsk_transform_to_matrix (transform, &m);
gsk_transform_to_matrix (transform2, &m2);
g_assert_true (graphene_matrix_near (&m, &m2, 0 .001 ));
gsk_transform_unref (transform);
gsk_transform_unref (transform2);
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (2 , 3 ));
gsk_transform_to_2d_components (transform,
&skew_x, &skew_y,
&scale_x, &scale_y,
&angle,
&dx, &dy);
g_assert_cmpfloat_with_epsilon (skew_x, 0 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (skew_y, 0 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (scale_x, 1 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (scale_y, 1 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (angle, 0 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (dx, 2 , 0 .0001 );
g_assert_cmpfloat_with_epsilon (dy, 3 , 0 .0001 );
gsk_transform_unref (transform);
}
static void
test_from_2d (void )
{
GskTransform *transform;
gfloat cases[][6 ] = {
{ 1 .f, 2 .f, 3 .f, 4 .f, 5 .f, 6 .f },
{ 0 .f, 2 .f, 3 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 0 .f, 3 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 2 .f, 0 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 2 .f, 3 .f, 0 .f, 5 .f, 6 .f },
{ 0 .f, 0 .f, 3 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 0 .f, 0 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 2 .f, 0 .f, 0 .f, 5 .f, 6 .f },
{ 0 .f, 2 .f, 3 .f, 0 .f, 5 .f, 6 .f },
{ 0 .f, 0 .f, 0 .f, 4 .f, 5 .f, 6 .f },
{ 1 .f, 0 .f, 0 .f, 0 .f, 5 .f, 6 .f },
{ 0 .f, 0 .f, 0 .f, 0 .f, 5 .f, 6 .f },
};
for (gsize i = 0 ; i < G_N_ELEMENTS(cases); i++) {
transform = gsk_transform_matrix_2d (NULL,
cases[i][0 ], cases[i][1 ],
cases[i][2 ], cases[i][3 ],
cases[i][4 ], cases[i][5 ]);
gfloat xx,yx,xy,yy,dx,dy;
gsk_transform_to_2d (transform,
&xx, &yx,
&xy, &yy,
&dx, &dy);
g_assert_cmpfloat (cases[i][0 ], ==, xx);
g_assert_cmpfloat (cases[i][1 ], ==, yx);
g_assert_cmpfloat (cases[i][2 ], ==, xy);
g_assert_cmpfloat (cases[i][3 ], ==, yy);
g_assert_cmpfloat (cases[i][4 ], ==, dx);
g_assert_cmpfloat (cases[i][5 ], ==, dy);
gsk_transform_unref (transform);
}
}
static void
test_transform_point (void )
{
GskTransform *t, *t2, *t3;
graphene_point_t p;
t = gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (1 , 2 )), 2 , 2 );
t2 = gsk_transform_translate (gsk_transform_scale (NULL, 2 , 2 ), &GRAPHENE_POINT_INIT (1 , 2 ));
t3 = gsk_transform_rotate (NULL, 90 );
gsk_transform_transform_point (NULL, &GRAPHENE_POINT_INIT (1 ,1 ), &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (1 , 1 )));
gsk_transform_transform_point (t, &GRAPHENE_POINT_INIT (1 ,1 ), &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (3 , 4 )));
gsk_transform_transform_point (t2, &GRAPHENE_POINT_INIT (1 ,1 ), &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (4 , 6 )));
gsk_transform_transform_point (t3, &GRAPHENE_POINT_INIT (2 ,1 ), &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (-1 , 2 )));
gsk_transform_unref (t);
gsk_transform_unref (t2);
gsk_transform_unref (t3);
}
static void
test_scale_transform (void )
{
GskTransform *t1, *t2;
char *string;
gboolean res;
GskTransform *x;
t1 = gsk_transform_scale (NULL, 4 , 9 );
t2 = gsk_transform_scale (gsk_transform_scale (NULL, 2 , 3 ), 2 , 3 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D_AFFINE);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D_AFFINE);
g_assert_true (gsk_transform_equal (t1, t2));
string = gsk_transform_to_string (t1);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_true (gsk_transform_equal (t1, x));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
g_free (string);
gsk_transform_unref (x);
}
static void
test_skew_transform (void )
{
GskTransform *t1, *t2, *t3, *t4;
char *string;
gboolean res;
GskTransform *x;
t1 = gsk_transform_skew (NULL, 30 , 60 );
t2 = gsk_transform_skew (NULL, 0 , 30 );
t3 = gsk_transform_skew (NULL, 0 , -30 );
t4 = gsk_transform_skew (NULL, 30 , 0 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_invert (t2);
graphene_assert_fuzzy_transform_equal (t2, t3, EPSILON);
string = gsk_transform_to_string (t1);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_true (gsk_transform_equal (t1, x));
g_free (string);
gsk_transform_unref (x);
string = gsk_transform_to_string (t3);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_true (gsk_transform_equal (t3, x));
g_free (string);
gsk_transform_unref (x);
string = gsk_transform_to_string (t4);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_true (gsk_transform_equal (t4, x));
g_free (string);
gsk_transform_unref (x);
t3 = gsk_transform_transform (t3, t4);
g_assert_true (gsk_transform_get_category (t3) == GSK_TRANSFORM_CATEGORY_2D);
gsk_transform_unref (t1);
gsk_transform_unref (t2);
gsk_transform_unref (t3);
gsk_transform_unref (t4);
}
static void
test_perspective_transform (void )
{
GskTransform *t1, *t2;
t1 = gsk_transform_perspective (NULL, 1000 );
t2 = gsk_transform_perspective (NULL, 300 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_ANY);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_ANY);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_perspective (t2, 700 );
g_assert_true (gsk_transform_equal (t1, t2));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
}
static void
test_rotate_transform (void )
{
GskTransform *t1, *t2, *t3;
graphene_vec3_t vec;
t1 = gsk_transform_rotate (NULL, 60 );
t2 = gsk_transform_rotate (NULL, 20 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_rotate (t2, 40 );
g_assert_true (gsk_transform_equal (t1, t2));
t1 = gsk_transform_invert (t1);
t3 = gsk_transform_rotate (NULL, -60 );
g_assert_true (gsk_transform_equal (t1, t3));
gsk_transform_unref (t2);
t2 = gsk_transform_rotate_3d (NULL, -60 , graphene_vec3_init (&vec, 0 , 0 , 1 ));
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_true (gsk_transform_equal (t1, t2));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
gsk_transform_unref (t3);
t1 = gsk_transform_rotate (NULL, 180 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
t1 = gsk_transform_rotate (t1, 180 );
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_IDENTITY);
g_assert_null (t1);
t1 = gsk_transform_rotate (NULL, 360 );
g_assert_null (t1);
t1 = gsk_transform_rotate (NULL, -360 );
g_assert_null (t1);
}
static void
test_rotate3d_transform (void )
{
GskTransform *t1, *t2;
graphene_vec3_t vec;
t1 = gsk_transform_rotate_3d (NULL, 60 , graphene_vec3_init (&vec, 1 , 2 , 3 ));
t2 = gsk_transform_rotate_3d (NULL, -60 , graphene_vec3_init (&vec, 1 , 2 , 3 ));
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_3D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_3D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_invert (t2);
g_assert_true (gsk_transform_equal (t1, t2));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
}
static void
test_matrix_transform (void )
{
GskTransform *t1, *t2;
float xx, yx, xy, yy, dx, dy;
graphene_matrix_t m;
if (!gsk_transform_parse ("matrix(2, 0, 0, 3, 1, -1)" , &t1))
g_assert_not_reached ();
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
gsk_transform_to_2d (t1, &xx, &yx, &xy, &yy, &dx, &dy);
g_assert_cmpfloat (xx, ==, 2 .f);
g_assert_cmpfloat (yx, ==, 0 .f);
g_assert_cmpfloat (xy, ==, 0 .f);
g_assert_cmpfloat (yy, ==, 3 .f);
g_assert_cmpfloat (dx, ==, 1 .f);
g_assert_cmpfloat (dy, ==, -1 .f);
graphene_matrix_init_from_float (&m,
(const float []) { 2 .f, 0 .f, 0 .f, 0 .f,
0 .f, 3 .f, 0 .f, 0 .f,
0 .f, 0 .f, 1 .f, 0 .f,
1 ., -1 .f, 0 .f, 1 .f});
t2 = gsk_transform_matrix (NULL, &m);
g_assert_true (gsk_transform_equal (t1, t2));
t1 = gsk_transform_invert (t1);
t2 = gsk_transform_transform (t2, t1);
graphene_assert_fuzzy_transform_equal (t2, NULL, EPSILON);
gsk_transform_unref (t1);
gsk_transform_unref (t2);
}
static void
test_matrix_roundtrip (void )
{
GskTransform *transform;
gboolean res;
const char *input;
char *str;
input = "matrix(2, 3, 4, 5, 6, 7)" ;
res = gsk_transform_parse (input, &transform);
g_assert_true (res);
g_assert_true (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D);
str = gsk_transform_to_string (transform);
g_assert_cmpstr (str, ==, input);
g_free (str);
input = "matrix3d(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)" ;
res = gsk_transform_parse (input, &transform);
g_assert_true (res);
g_assert_true (gsk_transform_get_category (transform) < GSK_TRANSFORM_CATEGORY_2D);
str = gsk_transform_to_string (transform);
g_assert_cmpstr (str, ==, input);
g_free (str);
}
static void
test_to_dihedral (void )
{
GskTransform *transform;
GdkDihedral dihedral;
float sx, sy, dx, dy;
g_test_summary ("Tests that gsk_transform_to_dihedral gives the expected results on a various transforms" );
transform = gsk_transform_scale (NULL, 10 .0 , 5 .0 );
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_NORMAL);
g_assert_cmpfloat (sx, ==, 10 .0 );
g_assert_cmpfloat (sy, ==, 5 .0 );
g_assert_cmpfloat (dx, ==, 0 .0 );
g_assert_cmpfloat (dy, ==, 0 .0 );
transform = gsk_transform_rotate (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), 90 );
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_90);
g_assert_cmpfloat (sx, ==, 1 .0 );
g_assert_cmpfloat (sy, ==, 1 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
transform = gsk_transform_scale (gsk_transform_translate (gsk_transform_scale (NULL, 2 .0 , 3 .0 ), &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), -1 , 1 );
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_FLIPPED);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 2 .0 * 10 .0 );
g_assert_cmpfloat (dy, ==, 3 .0 * 5 .0 );
transform = gsk_transform_rotate (gsk_transform_rotate (gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), 2 .0 , 3 .0 ), 90 ), 90 );
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_180);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
transform = gsk_transform_rotate (gsk_transform_scale (gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), 2 .0 , 3 .0 ), -1 , 1 ), 90 );
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_FLIPPED_90);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
transform = gsk_transform_dihedral (gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10 .0 , 5 .0 )), 2 .0 , 3 .0 ), GDK_DIHEDRAL_FLIPPED_90);
gsk_transform_to_dihedral (transform, &dihedral, &sx, &sy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_true (dihedral == GDK_DIHEDRAL_FLIPPED_90);
g_assert_cmpfloat (sx, ==, 2 .0 );
g_assert_cmpfloat (sy, ==, 3 .0 );
g_assert_cmpfloat (dx, ==, 10 .0 );
g_assert_cmpfloat (dy, ==, 5 .0 );
}
static void
test_dihedral_matrix (void )
{
g_test_summary ("Tests that gsk_transform_to_2d and gdk_dihedral_get_mat2 agree" );
for (int i = 0 ; i <= GDK_DIHEDRAL_FLIPPED_270; i++)
{
float f[16 ] = { 1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 };
float m[16 ] = { 1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 };
graphene_matrix_t matrix;
graphene_matrix_t test;
GskTransform *transform = gsk_transform_dihedral (NULL, (GdkDihedral) i);
gsk_transform_to_2d (transform,
&f[4 * 0 + 0 ], &f[4 * 0 + 1 ],
&f[4 * 1 + 0 ], &f[4 * 1 + 1 ],
&f[4 * 3 + 0 ], &f[4 * 3 + 1 ]);
graphene_matrix_init_from_float (&test, f);
/* Note that the xy/yx arguments are flipped in gdk_dihedral_get_mat2,
* compared to gsk_transform_to_2d
*/
gdk_dihedral_get_mat2 ((GdkDihedral) i,
&m[4 * 0 + 0 ], &m[4 * 1 + 0 ],
&m[4 * 0 + 1 ], &m[4 * 1 + 1 ]);
graphene_matrix_init_from_float (&matrix, m);
graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
gsk_transform_unref (transform);
}
}
static void
test_fine_category (void )
{
GskTransform *transform;
g_test_summary ("Tests that we get the fine categories of dihedral transforms right" );
transform = gsk_transform_rotate (NULL, 90 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_rotate (NULL, 180 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_rotate (NULL, 270 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_scale (NULL, -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_NEGATIVE_AFFINE);
gsk_transform_unref (transform);
transform = gsk_transform_scale (NULL, 1 , -1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_NEGATIVE_AFFINE);
gsk_transform_unref (transform);
transform = gsk_transform_scale (NULL, -1 , -1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_NEGATIVE_AFFINE);
gsk_transform_unref (transform);
transform = gsk_transform_scale (gsk_transform_rotate (NULL, 90 ), -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_scale (gsk_transform_rotate (NULL, 180 ), -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_scale (gsk_transform_rotate (NULL, 270 ), -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_scale (gsk_transform_rotate (NULL, 360 ), -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_NEGATIVE_AFFINE);
gsk_transform_unref (transform);
transform = gsk_transform_scale (gsk_transform_rotate (NULL, 450 ), -1 , 1 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_rotate (NULL, -450 );
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
transform = gsk_transform_dihedral (NULL, GDK_DIHEDRAL_FLIPPED_90);
g_assert_true (gsk_transform_get_fine_category (transform) == GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL);
gsk_transform_unref (transform);
}
static void
test_invert_singular (void )
{
GskTransform *transform, *inverse;
transform = gsk_transform_matrix_2d (NULL, 0 , 0 , 0 , 0 , 0 , 0 );
inverse = gsk_transform_invert (transform);
g_assert_true (inverse == NULL);
transform = gsk_transform_matrix_2d (NULL, 0 , 0 , 1 , 2 , 3 , 4 );
inverse = gsk_transform_invert (transform);
g_assert_true (inverse == NULL);
transform = gsk_transform_scale (NULL, 0 , 0 );
inverse = gsk_transform_invert (transform);
g_assert_true (inverse == NULL);
transform = gsk_transform_scale (NULL, 1 , 0 );
inverse = gsk_transform_invert (transform);
g_assert_true (inverse == NULL);
transform = gsk_transform_skew (NULL, 45 , 45 );
inverse = gsk_transform_invert (transform);
g_assert_true (inverse == NULL);
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_set_nonfatal_assertions ();
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/identity" , test_identity);
g_test_add_func ("/transform/identity-equal" , test_identity_equal);
g_test_add_func ("/transform/invert" , test_invert);
g_test_add_func ("/transform/print-parse" , test_print_parse);
g_test_add_func ("/transform/check-axis-aligneness" , test_axis_aligned);
g_test_add_func ("/transform/to-affine" , test_to_affine);
g_test_add_func ("/transform/bounds" , test_transform_bounds);
g_test_add_func ("/transform/point" , test_transform_point);
g_test_add_func ("/transform/to-2d" , test_to_2d);
g_test_add_func ("/transform/to-2d-components" , test_to_2d_components);
g_test_add_func ("/transform/from-2d" , test_from_2d);
g_test_add_func ("/transform/scale" , test_scale_transform);
g_test_add_func ("/transform/skew" , test_skew_transform);
g_test_add_func ("/transform/perspective" , test_perspective_transform);
g_test_add_func ("/transform/rotate" , test_rotate_transform);
g_test_add_func ("/transform/rotate3d" , test_rotate3d_transform);
g_test_add_func ("/transform/matrix" , test_matrix_transform);
g_test_add_func ("/transform/matrix/roundtrip" , test_matrix_roundtrip);
g_test_add_func ("/transform/to-dihedral" , test_to_dihedral);
g_test_add_func ("/transform/dihedral-matrix" , test_dihedral_matrix);
g_test_add_func ("/transform/fine-category" , test_fine_category);
g_test_add_func ("/transform/invert-singular" , test_invert_singular);
return g_test_run ();
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland