Files
gtk/testsuite/gsk/path-ops.c
2022-04-08 16:44:29 -04:00

354 lines
16 KiB
C

/*
* Copyright © 2022 Red Hat, Inc.
*
* 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: Matthias Clasen <mclasen@redhat.com>
*/
#include <gtk/gtk.h>
typedef enum
{
OP_UNION,
OP_INTERSECTION,
OP_DIFFERENCE,
OP_SYMMETRIC_DIFFERENCE,
} Op;
static void
test_ops_simple (void)
{
struct {
const char *in1;
const char *in2;
Op op;
const char *out;
} tests[] = {
/* partially overlapping edge */
{ "M 100 100 L 100 200 L 200 200 Z",
"M 150 150 L 150 250 L 250 250 Z",
OP_UNION,
"M 100 100 L 100 200 L 150 200 L 150 250 L 250 250 L 200 200 L 150 150 L 100 100 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 150 150 L 150 250 L 250 250 Z",
OP_INTERSECTION,
"M 150 200 L 200 200 L 150 150 L 150 200 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 150 150 L 150 250 L 250 250 Z",
OP_DIFFERENCE,
"M 100 100 L 100 200 L 150 200 L 150 150 L 100 100 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 150 150 L 150 250 L 250 250 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 L 100 200 L 150 200 L 150 150 L 100 100 Z M 200 200 L 150 200 L 150 250 "
"L 250 250 L 200 200 Z" },
/* two triangles in general position */
{ "M 100 100 L 100 200 L 200 200 Z",
"M 170 120 L 100 240 L 170 240 Z",
OP_UNION,
"M 100 100 L 100 200 L 123.33333587646484 200 L 100 240 L 170 240 L 170 200 L 200 200 "
"L 170 170 L 170 120 L 151.57894897460938 151.57894897460938 L 100 100 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 170 120 L 100 240 L 170 240 Z",
OP_INTERSECTION,
"M 123.33333587646484 200 L 170 200 L 170 170 L 151.57894897460938 151.57894897460938 "
"L 123.33332824707031 200 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 170 120 L 100 240 L 170 240 Z",
OP_DIFFERENCE,
"M 100 100 L 100 200 L 123.33333587646484 200 L 151.57894897460938 151.57894897460938 "
"L 100 100 Z M 170 200 L 200 200 L 170 170 L 170 200 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 170 120 L 100 240 L 170 240 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 L 100 200 L 123.33333587646484 200 L 151.57894897460938 151.57894897460938 "
"L 100 100 Z M 170 200 L 123.33333587646484 200 L 100 240 L 170 240 L 170 200 Z "
"M 170 200 L 200 200 L 170 170 L 170 200 Z M 151.57894897460938 151.57894897460938 "
"L 170 170 L 170 120 L 151.57894897460938 151.57894897460938 Z" },
/* nested contours, oriented in opposite direction */
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 170 190 L 120 190 Z",
OP_UNION,
"M 100 100 L 100 200 L 200 200 L 100 100 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 170 190 L 120 190 Z",
OP_INTERSECTION,
"M 170 190 L 120 140 L 120 190 L 170 190 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 170 190 L 120 190 Z",
OP_DIFFERENCE,
"M 100 100 L 100 200 L 200 200 L 100 100 Z M 120 140 L 170 190 L 120 190 L 120 140 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 170 190 L 120 190 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 L 100 200 L 200 200 L 100 100 Z M 120 140 L 170 190 L 120 190 L 120 140 Z" },
/* nested contours, oriented in opposite direction, other way around */
{ "M 100 100 L 200 200 L 100 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_UNION,
"M 200 200 L 100 100 L 100 200 L 200 200 Z" },
{ "M 100 100 L 200 200 L 100 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_INTERSECTION,
"M 120 140 L 120 190 L 170 190 L 120 140 Z" },
{ "M 100 100 L 200 200 L 100 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_DIFFERENCE,
"M 200 200 L 100 100 L 100 200 L 200 200 Z M 120 190 L 120 140 L 170 190 L 120 190 Z" },
{ "M 100 100 L 200 200 L 100 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 200 200 L 100 100 L 100 200 L 200 200 Z M 120 190 L 120 140 L 170 190 L 120 190 Z" },
/* nested contours, oriented in the same direction */
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_UNION,
"M 100 100 L 100 200 L 200 200 L 100 100 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_INTERSECTION,
"M 120 140 L 120 190 L 170 190 L 120 140 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_DIFFERENCE,
"M 100 100 L 100 200 L 200 200 L 100 100 Z M 120 190 L 120 140 L 170 190 L 120 190 Z" },
{ "M 100 100 L 100 200 L 200 200 Z",
"M 120 140 L 120 190 L 170 190 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 L 100 200 L 200 200 L 100 100 Z M 120 190 L 120 140 L 170 190 L 120 190 Z" },
/* a 3-way intersection */
{ "M 100 200 L 150 104 L 145 104 L 200 200 Z",
"M 100 108.571 L 200 108.571 L 200 50 L 100 50 Z",
OP_UNION,
"M 147.61904907226562 108.57142639160156 L 100 200 L 200 200 "
"L 147.61904907226562 108.57142639160156 Z M 100 108.57099914550781 "
"L 147.61927795410156 108.57099914550781 L 200 108.57099914550781 L 200 50 "
"L 100 50 L 100 108.57099914550781 Z" },
{ "M 100 200 L 150 104 L 145 104 L 200 200 Z",
"M 100 108.571 L 200 108.571 L 200 50 L 100 50 Z",
OP_INTERSECTION,
"M 147.61904907226562 108.57142639160156 L 150 104 L 145 104 "
"L 147.61904907226562 108.57142639160156 Z" },
{ "M 100 200 L 150 104 L 145 104 L 200 200 Z",
"M 100 108.571 L 200 108.571 L 200 50 L 100 50 Z",
OP_DIFFERENCE,
"M 147.61904907226562 108.57142639160156 L 100 200 L 200 200 "
"L 147.61904907226562 108.57142639160156 Z" },
{ "M 100 200 L 150 104 L 145 104 L 200 200 Z",
"M 100 108.571 L 200 108.571 L 200 50 L 100 50 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 147.61904907226562 108.57142639160156 L 100 200 L 200 200 "
"L 147.61904907226562 108.57142639160156 Z M 150 104 "
"L 147.61904907226562 108.57142639160156 L 200 108.57099914550781 "
"L 200 50 L 100 50 L 100 108.57099914550781 L 147.61927795410156 108.57099914550781 "
"L 145 104 L 150 104 Z" },
/* touching quadratics */
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 200 Q 150 100 200 200 Z",
OP_UNION,
"M 100 100 "
"C 116.65585327148438 133.31172180175781, 133.31172180175781 149.97837829589844, 149.96757507324219 149.99998474121094 "
"C 166.64505004882812 150.0216064453125, 183.32252502441406 133.35494995117188, 200 100 "
"L 100 100 "
"Z "
"M 149.96755981445312 149.99998474121094 "
"C 133.31172180175781 150.02162170410156, 116.65585327148438 166.68827819824219, 100 200 "
"L 200 200 "
"C 183.32252502441406 166.64505004882812, 166.64505004882812 149.9783935546875, 149.96757507324219 150.00001525878906 "
"Z" },
/* overlapping quadratics, two intersections, different orientations */
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 Q 150 80 200 180 Z",
OP_UNION,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 118.42625427246094 148.24038696289062, 109.21312713623047 161.57374572753906, 100 180 "
"L 200 180 "
"C 190.78688049316406 161.57374572753906, 181.57374572753906 148.24038696289062, 172.36061096191406 139.99993896484375 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 "
"Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 Q 150 80 200 180 Z",
OP_INTERSECTION,
"M 127.63862609863281 139.9993896484375 "
"C 142.54594421386719 153.33332824707031, 157.45327758789062 153.33355712890625, 172.360595703125 140.00006103515625 "
"C 157.45353698730469 126.66668701171875, 142.54646301269531 126.66668701171875, 127.63938903808594 139.99993896484375 "
"Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 Q 150 80 200 180 Z",
OP_DIFFERENCE,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 142.54646301269531 126.66668701171875, 157.45353698730469 126.66668701171875, 172.36061096191406 139.99993896484375 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 Q 150 80 200 180 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 142.54646301269531 126.66668701171875, 157.45353698730469 126.66668701171875, 172.36061096191406 139.99993896484375 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 Z "
"M 172.36062622070312 140.00006103515625 "
"C 157.45327758789062 153.33355712890625, 142.54594421386719 153.33332824707031, 127.63862609863281 139.9993896484375 "
"C 118.42625427246094 148.24038696289062, 109.21312713623047 161.57374572753906, 100 180 "
"L 200 180 "
"C 190.78688049316406 161.57374572753906, 181.57374572753906 148.24038696289062, 172.36061096191406 139.99993896484375 "
"Z" },
/* overlapping quadratics, two intersections, same orientation */
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 L 200 180 Q 150 80 100 180 Z",
OP_UNION,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 118.42626190185547 148.24037170410156, 109.21312713623047 161.57373046875, 100 180 "
"L 200 180 "
"C 190.78712463378906 161.57424926757812, 181.57424926757812 148.24111938476562, 172.36137390136719 140.00062561035156 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 L 200 180 Q 150 80 100 180 Z",
OP_INTERSECTION,
"M 127.63862609863281 139.9993896484375 "
"C 142.54594421386719 153.33332824707031, 157.45327758789062 153.33355712890625, 172.360595703125 140.00006103515625 "
"C 157.45405578613281 126.66668701171875, 142.54672241210938 126.66645812988281, 127.63939666748047 139.99992370605469 Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 L 200 180 Q 150 80 100 180 Z",
OP_DIFFERENCE,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 142.54672241210938 126.66645812988281, 157.45405578613281 126.66668701171875, 172.36137390136719 140.00062561035156 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 Z" },
{ "M 100 100 Q 150 200 200 100 Z",
"M 100 180 L 200 180 Q 150 80 100 180 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 "
"C 109.21287536621094 118.42575073242188, 118.42575073242188 131.75888061523438, 127.63862609863281 139.9993896484375 "
"C 142.54672241210938 126.66645812988281, 157.45405578613281 126.66668701171875, 172.36137390136719 140.00062561035156 "
"C 181.57373046875 131.75961303710938, 190.786865234375 118.42626190185547, 200 100 "
"L 100 100 Z "
"M 172.36062622070312 140.00006103515625 "
"C 157.45327758789062 153.33355712890625, 142.54594421386719 153.33332824707031, 127.63862609863281 139.9993896484375 "
"C 118.42626190185547 148.24037170410156, 109.21312713623047 161.57373046875, 100 180 "
"L 200 180 "
"C 190.78712463378906 161.57424926757812, 181.57424926757812 148.24111938476562, 172.36137390136719 140.00062561035156 "
"Z" },
/* two polygons with near edges */
{ "M 100 100 L 100 200 L 400 200 L 400 100 Z",
"M 150 103 L 250 100 L 300 103 L 250 180 Z",
OP_UNION,
"M 100 100 L 100 200 L 400 200 L 400 100 L 250 100 L 100 100 Z" },
{ "M 100 100 L 100 200 L 400 200 L 400 100 Z",
"M 150 103 L 250 100 L 300 103 L 250 180 Z",
OP_INTERSECTION,
"M 250 100 L 150 103 L 250 180 L 300 103 L 250 100 Z" },
{ "M 100 100 L 100 200 L 400 200 L 400 100 Z",
"M 150 103 L 250 100 L 300 103 L 250 180 Z",
OP_DIFFERENCE,
"M 100 100 L 100 200 L 400 200 L 400 100 L 250 100 L 300 103 L 250 180 L 150 103 L 250 100 L 100 100 Z" },
{ "M 100 100 L 100 200 L 400 200 L 400 100 Z",
"M 150 103 L 250 100 L 300 103 L 250 180 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 100 100 L 100 200 L 400 200 L 400 100 L 250 100 L 300 103 L 250 180 L 150 103 L 250 100 L 100 100 Z" },
/* Collinear line segments */
{ "M 100 100 L 200 100 L 250 100 L 100 200 Z",
"M 150 100 L 300 100 L 300 200 Z",
OP_UNION,
"M 150 100 L 100 100 L 100 200 L 200 133.33332824707031 L 300 200 L 300 100 L 250 100 "
"L 200 100 L 150 100 Z" },
{ "M 100 100 L 200 100 L 250 100 L 100 200 Z",
"M 150 100 L 300 100 L 300 200 Z",
OP_INTERSECTION,
"M 200 100 L 150 100 L 200 133.33332824707031 L 250 100 L 200 100 Z" },
{ "M 100 100 L 200 100 L 250 100 L 100 200 Z",
"M 150 100 L 300 100 L 300 200 Z",
OP_DIFFERENCE,
"M 150 100 L 100 100 L 100 200 L 200 133.33332824707031 L 150 100 Z" },
{ "M 100 100 L 200 100 L 250 100 L 100 200 Z",
"M 150 100 L 300 100 L 300 200 Z",
OP_SYMMETRIC_DIFFERENCE,
"M 150 100 L 100 100 L 100 200 L 200 133.33332824707031 L 150 100 Z "
"M 250 100 L 200 133.33332824707031 L 300 200 L 300 100 L 250 100 Z" },
/* a complicated intersection */
{ "M 175 100 L 175 400 L 300 400 L 300 100 z",
"M 100 100 C 200 200 200 300 100 400 L 0 400 C 233.35 300 233.35 200 0 100 Z",
OP_UNION,
"M 175 100 L 175 248.73167419433594 L 175 249.94822692871094 L 175 251.26628112792969 "
"L 175 400 L 300 400 L 300 100 L 175 100 Z "
"M 174.9906005859375 248.32115173339844 "
"C 174.437255859375 198.88076782226562, 149.44038391113281 149.44038391113281, 100 100 "
"L 0 100 "
"C 115.68845367431641 149.57722473144531, 174.02178955078125 199.15444946289062, 175 248.73167419433594 "
"Z "
"M 100 400 "
"C 149.44171142578125 350.55828857421875, 174.4385986328125 301.11660766601562, 174.99066162109375 251.67486572265625 "
"C 174.02340698242188 300.84420776367188, 115.69005584716797 350.42208862304688, 0 400 "
"L 100 400 "
"Z" },
};
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
GskPath *p1, *p2, *p;
char *s;
if (g_test_verbose ())
g_test_message ("testcase %d op %d", i, tests[i].op);
p1 = gsk_path_parse (tests[i].in1);
p2 = gsk_path_parse (tests[i].in2);
switch (tests[i].op)
{
case OP_UNION:
p = gsk_path_union (p1, p2, GSK_FILL_RULE_WINDING);
break;
case OP_INTERSECTION:
p = gsk_path_intersection (p1, p2, GSK_FILL_RULE_WINDING);
break;
case OP_DIFFERENCE:
p = gsk_path_difference (p1, p2, GSK_FILL_RULE_WINDING);
break;
case OP_SYMMETRIC_DIFFERENCE:
p = gsk_path_symmetric_difference (p1, p2, GSK_FILL_RULE_WINDING);
break;
default:
g_assert_not_reached ();
}
g_assert_nonnull (p);
s = gsk_path_to_string (p);
g_assert_cmpstr (s, ==, tests[i].out);
g_free (s);
gsk_path_unref (p);
gsk_path_unref (p1);
gsk_path_unref (p2);
}
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/ops/simple", test_ops_simple);
return g_test_run ();
}