Compare commits
5 Commits
curve-inte
...
path-ops2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08b786a984 | ||
|
|
54bf63259c | ||
|
|
53b5441e39 | ||
|
|
3b2ab7ad1e | ||
|
|
42eaacbab4 |
@@ -295,6 +295,7 @@
|
||||
<file>gears.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>glyphs.c</file>
|
||||
<file>gltransition.c</file>
|
||||
<file>headerbar.c</file>
|
||||
<file>hypertext.c</file>
|
||||
|
||||
1186
demos/gtk-demo/glyphs.c
Normal file
1186
demos/gtk-demo/glyphs.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@ demos = files([
|
||||
'gestures.c',
|
||||
'glarea.c',
|
||||
'gltransition.c',
|
||||
'glyphs.c',
|
||||
'headerbar.c',
|
||||
'hypertext.c',
|
||||
'iconscroll.c',
|
||||
|
||||
@@ -12,6 +12,11 @@ SYNOPSIS
|
||||
--------
|
||||
| **gtk4-path-tool** <COMMAND> [OPTIONS...] <PATH>
|
||||
|
|
||||
| **gtk4-path-tool** simplify [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** intersection [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** union [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** difference [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** symmetric-difference [OPTIONS...] <PATH> <PATH>
|
||||
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** show [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** render [OPTIONS...] <PATH>
|
||||
@@ -195,6 +200,7 @@ The interior of the path is filled.
|
||||
|
||||
The limit at which to clip miters at line joins. The default value is 4.
|
||||
|
||||
<<<<<<< HEAD
|
||||
``--dashes=VALUE``
|
||||
|
||||
The dash pattern to use for this stroke. A dash pattern is specified by
|
||||
@@ -208,6 +214,21 @@ The interior of the path is filled.
|
||||
The offset into the dash pattern where dashing should begin.
|
||||
The default value is 0.
|
||||
|
||||
Boolean Operations
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``intersection``, ``union``, ``difference`` and ``symmetric-difference`` commands
|
||||
perform boolean operations on paths. Given two paths, they create a new path which
|
||||
encircles the area that is the intersection, union, difference or symmetric difference
|
||||
of the areas encircled by the paths.
|
||||
|
||||
Simplification
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The ``simplify`` command removes areas of overlap from a path such that the resulting
|
||||
path encircles the same area, but every edge in the resulting path is a boundary between
|
||||
the inside and the outside.
|
||||
|
||||
Reversing
|
||||
^^^^^^^^^
|
||||
|
||||
|
||||
@@ -193,6 +193,30 @@ gboolean gsk_path_foreach_intersection (GskPath
|
||||
GskPathIntersectionFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GskPath * gsk_path_union (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GskPath * gsk_path_intersection (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GskPath * gsk_path_difference (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GskPath * gsk_path_symmetric_difference (GskPath *first,
|
||||
GskPath *second,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GskPath * gsk_path_simplify (GskPath *self,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
1818
gsk/gskpathops.c
Normal file
1818
gsk/gskpathops.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -56,5 +56,19 @@ gboolean gsk_path_foreach_with_tolerance (GskPath
|
||||
void gsk_path_builder_add_contour (GskPathBuilder *builder,
|
||||
GskContour *contour);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_OP_SIMPLIFY,
|
||||
GSK_PATH_OP_UNION,
|
||||
GSK_PATH_OP_INTERSECTION,
|
||||
GSK_PATH_OP_DIFFERENCE,
|
||||
GSK_PATH_OP_XOR
|
||||
} GskPathOp;
|
||||
|
||||
GskPath * gsk_path_op (GskPathOp operation,
|
||||
GskFillRule fill_rule,
|
||||
GskPath *first,
|
||||
GskPath *second);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ gsk_public_sources = files([
|
||||
'gskpathbuilder.c',
|
||||
'gskpathintersect.c',
|
||||
'gskpathmeasure.c',
|
||||
'gskpathops.c',
|
||||
'gskpathparser.c',
|
||||
'gskpathpoint.c',
|
||||
'gskrenderer.c',
|
||||
|
||||
@@ -375,6 +375,7 @@ tests = [
|
||||
['path', [ 'path-utils.c' ] ],
|
||||
['path-special-cases'],
|
||||
['path-intersect'],
|
||||
['path-ops', [ 'path-utils.c' ] ],
|
||||
]
|
||||
|
||||
test_cargs = []
|
||||
|
||||
381
testsuite/gsk/path-ops.c
Normal file
381
testsuite/gsk/path-ops.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "path-utils.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 "
|
||||
"Q 124.987984 149.975967, 149.975967 149.999985 "
|
||||
"Q 174.987976 150.024033, 200 100 "
|
||||
"L 100 100 "
|
||||
"Z "
|
||||
"M 149.975967 150 "
|
||||
"Q 124.987984 150.024033, 100 200 "
|
||||
"L 200 200 "
|
||||
"Q 174.987976 149.975967, 149.975967 150.000015 "
|
||||
"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 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 113.819695 152.360611, 100 180 "
|
||||
"L 200 180 "
|
||||
"Q 186.180313 152.360611, 172.360611 139.999939 "
|
||||
"Q 186.180298 127.639389, 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.638626 139.99939 "
|
||||
"Q 149.999619 160.000275, 172.360611 140.000061 "
|
||||
"Q 150 120.000061, 127.639389 139.999939 "
|
||||
"Z" },
|
||||
{ "M 100 100 Q 150 200 200 100 Z",
|
||||
"M 100 180 Q 150 80 200 180 Z",
|
||||
OP_DIFFERENCE,
|
||||
"M 100 100 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 150 120.000061, 172.360611 139.999939 "
|
||||
"Q 186.180298 127.639389, 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 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 150 120.000061, 172.360611 139.999939 "
|
||||
"Q 186.180298 127.639389, 200 100 "
|
||||
"L 100 100 "
|
||||
"Z "
|
||||
"M 172.360611 140.000061 "
|
||||
"Q 149.999619 160.000275, 127.638626 139.999374 "
|
||||
"Q 113.819695 152.360611, 100 180 "
|
||||
"L 200 180 "
|
||||
"Q 186.180313 152.360611, 172.360611 139.999939 "
|
||||
"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 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 113.819695 152.360611, 100 180 "
|
||||
"L 200 180 "
|
||||
"Q 186.180695 152.361374, 172.361389 140.000626 "
|
||||
"Q 186.180298 127.639389, 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.638626 139.99939 "
|
||||
"Q 149.999619 160.000275, 172.360611 140.000061 "
|
||||
"Q 150.000397 119.999725, 127.639397 139.999939 "
|
||||
"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 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 150.000397 119.999725, 172.361389 140.000626 "
|
||||
"Q 186.180298 127.639389, 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 "
|
||||
"Q 113.819313 127.638626, 127.638626 139.999374 "
|
||||
"Q 150.000397 119.999725, 172.361389 140.000626 "
|
||||
"Q 186.180298 127.639389, 200 100 "
|
||||
"L 100 100 "
|
||||
"Z "
|
||||
"M 172.360611 140.000061 "
|
||||
"Q 149.999619 160.000275, 127.638626 139.999374 "
|
||||
"Q 113.819695 152.360611, 100 180 "
|
||||
"L 200 180 "
|
||||
"Q 186.180695 152.361374, 172.361389 140.000626 "
|
||||
"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.333328 "
|
||||
"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.333328 "
|
||||
"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 union */
|
||||
{ "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.3333334 300 233.3333334 200 0 100 Z",
|
||||
OP_UNION,
|
||||
"M 175 100 "
|
||||
"L 175 250 "
|
||||
"L 175 400 "
|
||||
"L 300 400 "
|
||||
"L 300 100 "
|
||||
"L 175 100 "
|
||||
"Z "
|
||||
"M 175 250 "
|
||||
"Q 175 175, 100 100 "
|
||||
"L 0 100 "
|
||||
"Q 174.955811 174.981064, 174.999985 249.962112 "
|
||||
"Z "
|
||||
"M 100 400 "
|
||||
"Q 175 325, 175 250 "
|
||||
"Q 175.044189 324.981049, 0 400 "
|
||||
"L 100 400 "
|
||||
"Z" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
|
||||
{
|
||||
GskPath *p1, *p2, *p3, *p;
|
||||
|
||||
if (g_test_verbose ())
|
||||
{
|
||||
const char *opname[] = { "union", "intersection", "difference", "symmetric-difference" };
|
||||
g_test_message ("testcase %d op %s \"%s\" \"%s\"", i, opname[tests[i].op], tests[i].in1, tests[i].in2);
|
||||
}
|
||||
|
||||
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);
|
||||
p3 = gsk_path_parse (tests[i].out);
|
||||
assert_path_equal_with_epsilon (p, p3, 0.0001);
|
||||
|
||||
gsk_path_unref (p);
|
||||
gsk_path_unref (p1);
|
||||
gsk_path_unref (p2);
|
||||
gsk_path_unref (p3);
|
||||
}
|
||||
}
|
||||
|
||||
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 ();
|
||||
}
|
||||
104
tools/gtk-path-tool-pathops.c
Normal file
104
tools/gtk-path-tool-pathops.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* GTK+ 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 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* GLib 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 GTK+; see the file COPYING. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
void
|
||||
do_pathop (const char *op, int *argc, const char ***argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const char *fill = "winding";
|
||||
char **args = NULL;
|
||||
GOptionContext *context;
|
||||
GOptionEntry entries[] = {
|
||||
{ "fill-rule", 0, 0, G_OPTION_ARG_STRING, &fill, N_("Fill rule"), N_("RULE") },
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, NULL, N_("PATH…") },
|
||||
{ NULL, },
|
||||
};
|
||||
GskPath *path1, *path2, *result;
|
||||
GskFillRule fill_rule;
|
||||
char *prgname;
|
||||
char *summary;
|
||||
|
||||
prgname = g_strconcat ("gtk4-path-tool ", op, NULL);
|
||||
summary = g_strdup_printf (_("Apply the %s path operation."), op);
|
||||
g_set_prgname (prgname);
|
||||
|
||||
context = g_option_context_new (NULL);
|
||||
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
g_option_context_set_summary (context, summary);
|
||||
|
||||
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_option_context_free (context);
|
||||
|
||||
if (args == NULL)
|
||||
{
|
||||
g_printerr ("%s\n", _("No paths given."));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
path1 = get_path (args[0]);
|
||||
if (args[1] != NULL)
|
||||
path2 = get_path (args[1]);
|
||||
else
|
||||
path2 = NULL;
|
||||
|
||||
fill_rule = get_enum_value (GSK_TYPE_FILL_RULE, _("fill rule"), fill);
|
||||
|
||||
if (strcmp (op, "simplify") == 0)
|
||||
result = gsk_path_simplify (path1, fill_rule);
|
||||
else if (strcmp (op, "union") == 0)
|
||||
result = gsk_path_union (path1, path2, fill_rule);
|
||||
else if (strcmp (op, "intersection") == 0)
|
||||
result = gsk_path_intersection (path1, path2, fill_rule);
|
||||
else if (strcmp (op, "difference") == 0)
|
||||
result = gsk_path_difference (path1, path2, fill_rule);
|
||||
else if (strcmp (op, "symmetric-difference") == 0)
|
||||
result = gsk_path_symmetric_difference (path1, path2, fill_rule);
|
||||
else
|
||||
{
|
||||
char *msg = g_strdup_printf (_("'%s' is not a supported operation."), op);
|
||||
g_printerr ("%s\n", msg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
char *str = gsk_path_to_string (result);
|
||||
g_print ("%s\n", str);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s\n", _("That didn't work out."));
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,12 @@ usage (void)
|
||||
"Perform various tasks on paths.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" simplify Simplify the path\n"
|
||||
" intersection Intersect two paths\n"
|
||||
" union Create the union of two paths\n"
|
||||
" difference Create the difference of two paths\n"
|
||||
" symmetric-difference\n"
|
||||
" Create the symmetric difference of two paths\n"
|
||||
" decompose Decompose the path\n"
|
||||
" reverse Reverse the path\n"
|
||||
" restrict Restrict the path to a segment\n"
|
||||
@@ -128,8 +134,12 @@ main (int argc, const char *argv[])
|
||||
|
||||
if (strcmp (argv[0], "decompose") == 0)
|
||||
do_decompose (&argc, &argv);
|
||||
else if (strcmp (argv[0], "difference") == 0)
|
||||
do_pathop (argv[0], &argc, &argv);
|
||||
else if (strcmp (argv[0], "info") == 0)
|
||||
do_info (&argc, &argv);
|
||||
else if (strcmp (argv[0], "intersection") == 0)
|
||||
do_pathop (argv[0], &argc, &argv);
|
||||
else if (strcmp (argv[0], "render") == 0)
|
||||
do_render (&argc, &argv);
|
||||
else if (strcmp (argv[0], "restrict") == 0)
|
||||
@@ -138,6 +148,12 @@ main (int argc, const char *argv[])
|
||||
do_reverse (&argc, &argv);
|
||||
else if (strcmp (argv[0], "show") == 0)
|
||||
do_show (&argc, &argv);
|
||||
else if (strcmp (argv[0], "simplify") == 0)
|
||||
do_pathop (argv[0], &argc, &argv);
|
||||
else if (strcmp (argv[0], "symmetric-difference") == 0)
|
||||
do_pathop (argv[0], &argc, &argv);
|
||||
else if (strcmp (argv[0], "union") == 0)
|
||||
do_pathop (argv[0], &argc, &argv);
|
||||
else
|
||||
usage ();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ void do_restrict (int *argc, const char ***argv);
|
||||
void do_reverse (int *argc, const char ***argv);
|
||||
void do_render (int *argc, const char ***argv);
|
||||
void do_show (int *argc, const char ***argv);
|
||||
void do_pathop (const char *op, int *argc, const char ***argv);
|
||||
|
||||
GskPath *get_path (const char *arg);
|
||||
int get_enum_value (GType type,
|
||||
|
||||
@@ -26,6 +26,7 @@ gtk_tools = [
|
||||
['gtk4-path-tool', ['gtk-path-tool.c',
|
||||
'gtk-path-tool-decompose.c',
|
||||
'gtk-path-tool-info.c',
|
||||
'gtk-path-tool-pathops.c',
|
||||
'gtk-path-tool-render.c',
|
||||
'gtk-path-tool-restrict.c',
|
||||
'gtk-path-tool-reverse.c',
|
||||
|
||||
Reference in New Issue
Block a user