[gtk/path-ops: 1/2] Add some tests for pathops




commit a1fa8d9b8d2b10f5454aa246588f364683f45dd8
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Mar 26 01:48:04 2022 -0400

    Add some tests for pathops

 testsuite/gsk/meson.build |   1 +
 testsuite/gsk/path-ops.c  | 337 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 338 insertions(+)
---
diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build
index e8f4fe88b2..a45a647743 100644
--- a/testsuite/gsk/meson.build
+++ b/testsuite/gsk/meson.build
@@ -212,6 +212,7 @@ tests = [
   ['path'],
   ['path-special-cases'],
   ['path-stroke'],
+  ['path-ops'],
   ['rounded-rect'],
   ['transform'],
   ['shader'],
diff --git a/testsuite/gsk/path-ops.c b/testsuite/gsk/path-ops.c
new file mode 100644
index 0000000000..79c3219754
--- /dev/null
+++ b/testsuite/gsk/path-ops.c
@@ -0,0 +1,337 @@
+/*
+ * 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" },
+ };
+
+  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);
+          break;
+        case OP_INTERSECTION:
+          p = gsk_path_intersection (p1, p2);
+          break;
+        case OP_DIFFERENCE:
+          p = gsk_path_difference (p1, p2);
+          break;
+        case OP_SYMMETRIC_DIFFERENCE:
+          p = gsk_path_symmetric_difference (p1, p2);
+          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 ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]