33
33
#include "gimpbezierstroke.h"
36
/* local prototypes */
38
static void gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass);
39
static void gimp_bezier_stroke_init (GimpBezierStroke *bezier_stroke);
40
static gdouble gimp_bezier_stroke_nearest_point_get (const GimpStroke *stroke,
41
const GimpCoords *coord,
42
const gdouble precision,
43
GimpCoords *ret_point,
44
GimpAnchor **ret_segment_start,
45
GimpAnchor **ret_segment_end,
48
gimp_bezier_stroke_segment_nearest_point_get (const GimpCoords *beziercoords,
49
const GimpCoords *coord,
50
const gdouble precision,
51
GimpCoords *ret_point,
54
static void gimp_bezier_stroke_anchor_move_relative (GimpStroke *stroke,
56
const GimpCoords *deltacoord,
57
GimpAnchorFeatureType feature);
58
static void gimp_bezier_stroke_anchor_move_absolute (GimpStroke *stroke,
60
const GimpCoords *coord,
61
GimpAnchorFeatureType feature);
62
static void gimp_bezier_stroke_anchor_convert (GimpStroke *stroke,
64
GimpAnchorFeatureType feature);
65
static void gimp_bezier_stroke_anchor_delete (GimpStroke *stroke,
67
static gboolean gimp_bezier_stroke_point_is_movable
71
static void gimp_bezier_stroke_point_move_relative
75
const GimpCoords *deltacoord,
76
GimpAnchorFeatureType feature);
77
static void gimp_bezier_stroke_point_move_absolute
81
const GimpCoords *coord,
82
GimpAnchorFeatureType feature);
84
static void gimp_bezier_stroke_close (GimpStroke *stroke);
86
static GimpStroke * gimp_bezier_stroke_open (GimpStroke *stroke,
87
GimpAnchor *end_anchor);
88
static gboolean gimp_bezier_stroke_anchor_is_insertable
92
static GimpAnchor * gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
95
static gboolean gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
96
GimpAnchor *neighbor);
97
static gboolean gimp_bezier_stroke_connect_stroke (GimpStroke *stroke,
99
GimpStroke *extension,
100
GimpAnchor *neighbor);
101
static GArray * gimp_bezier_stroke_interpolate (const GimpStroke *stroke,
102
const gdouble precision,
105
static void gimp_bezier_stroke_finalize (GObject *object);
108
static GList * gimp_bezier_stroke_get_anchor_listitem (GList *list);
110
static void gimp_bezier_coords_subdivide (const GimpCoords *beziercoords,
111
const gdouble precision,
112
GArray **ret_coords);
113
static void gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords,
114
const gdouble precision,
118
static gboolean gimp_bezier_coords_is_straight (const GimpCoords *beziercoords,
119
const gdouble precision);
122
/* private variables */
124
static GimpStrokeClass *parent_class = NULL;
128
gimp_bezier_stroke_get_type (void)
130
static GType bezier_stroke_type = 0;
132
if (! bezier_stroke_type)
134
static const GTypeInfo bezier_stroke_info =
136
sizeof (GimpBezierStrokeClass),
137
(GBaseInitFunc) NULL,
138
(GBaseFinalizeFunc) NULL,
139
(GClassInitFunc) gimp_bezier_stroke_class_init,
140
NULL, /* class_finalize */
141
NULL, /* class_data */
142
sizeof (GimpBezierStroke),
144
(GInstanceInitFunc) gimp_bezier_stroke_init,
147
bezier_stroke_type = g_type_register_static (GIMP_TYPE_STROKE,
149
&bezier_stroke_info, 0);
152
return bezier_stroke_type;
36
/* local prototypes */
39
gimp_bezier_stroke_nearest_point_get (const GimpStroke *stroke,
40
const GimpCoords *coord,
41
const gdouble precision,
42
GimpCoords *ret_point,
43
GimpAnchor **ret_segment_start,
44
GimpAnchor **ret_segment_end,
47
gimp_bezier_stroke_segment_nearest_point_get
48
(const GimpCoords *beziercoords,
49
const GimpCoords *coord,
50
const gdouble precision,
51
GimpCoords *ret_point,
55
gimp_bezier_stroke_nearest_tangent_get (const GimpStroke *stroke,
56
const GimpCoords *coord1,
57
const GimpCoords *coord2,
58
const gdouble precision,
60
GimpAnchor **ret_segment_start,
61
GimpAnchor **ret_segment_end,
64
gimp_bezier_stroke_segment_nearest_tangent_get
65
(const GimpCoords *beziercoords,
66
const GimpCoords *coord1,
67
const GimpCoords *coord2,
68
const gdouble precision,
69
GimpCoords *ret_point,
72
gimp_bezier_stroke_anchor_move_relative
75
const GimpCoords *deltacoord,
76
GimpAnchorFeatureType feature);
78
gimp_bezier_stroke_anchor_move_absolute
81
const GimpCoords *coord,
82
GimpAnchorFeatureType feature);
84
gimp_bezier_stroke_anchor_convert (GimpStroke *stroke,
86
GimpAnchorFeatureType feature);
88
gimp_bezier_stroke_anchor_delete (GimpStroke *stroke,
91
gimp_bezier_stroke_point_is_movable (GimpStroke *stroke,
95
gimp_bezier_stroke_point_move_relative (GimpStroke *stroke,
98
const GimpCoords *deltacoord,
99
GimpAnchorFeatureType feature);
101
gimp_bezier_stroke_point_move_absolute (GimpStroke *stroke,
104
const GimpCoords *coord,
105
GimpAnchorFeatureType feature);
107
static void gimp_bezier_stroke_close (GimpStroke *stroke);
110
gimp_bezier_stroke_open (GimpStroke *stroke,
111
GimpAnchor *end_anchor);
113
gimp_bezier_stroke_anchor_is_insertable
118
gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
122
gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
123
GimpAnchor *neighbor);
125
gimp_bezier_stroke_connect_stroke (GimpStroke *stroke,
127
GimpStroke *extension,
128
GimpAnchor *neighbor);
130
gimp_bezier_stroke_interpolate (const GimpStroke *stroke,
131
const gdouble precision,
134
static void gimp_bezier_stroke_finalize (GObject *object);
137
static GList * gimp_bezier_stroke_get_anchor_listitem
140
static void gimp_bezier_coords_subdivide (const GimpCoords *beziercoords,
141
const gdouble precision,
143
GArray **ret_params);
144
static void gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords,
145
const gdouble start_t,
147
const gdouble precision,
152
static gboolean gimp_bezier_coords_is_straight
153
(const GimpCoords *beziercoords,
154
const gdouble precision);
157
G_DEFINE_TYPE (GimpBezierStroke, gimp_bezier_stroke, GIMP_TYPE_STROKE)
159
#define parent_class gimp_bezier_stroke_parent_class
156
163
gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass)
158
GObjectClass *object_class;
159
GimpStrokeClass *stroke_class;
161
object_class = G_OBJECT_CLASS (klass);
162
stroke_class = GIMP_STROKE_CLASS (klass);
164
parent_class = g_type_class_peek_parent (klass);
165
GObjectClass *object_class = G_OBJECT_CLASS (klass);
166
GimpStrokeClass *stroke_class = GIMP_STROKE_CLASS (klass);
166
168
object_class->finalize = gimp_bezier_stroke_finalize;
168
170
stroke_class->nearest_point_get = gimp_bezier_stroke_nearest_point_get;
171
stroke_class->nearest_tangent_get = gimp_bezier_stroke_nearest_tangent_get;
172
stroke_class->nearest_intersection_get = NULL;
169
173
stroke_class->anchor_move_relative = gimp_bezier_stroke_anchor_move_relative;
170
174
stroke_class->anchor_move_absolute = gimp_bezier_stroke_anchor_move_absolute;
171
175
stroke_class->anchor_convert = gimp_bezier_stroke_anchor_convert;
780
gimp_bezier_stroke_nearest_tangent_get (const GimpStroke *stroke,
781
const GimpCoords *coord1,
782
const GimpCoords *coord2,
783
const gdouble precision,
785
GimpAnchor **ret_segment_start,
786
GimpAnchor **ret_segment_end,
789
gdouble min_dist, dist, pos;
791
GimpCoords segmentcoords[4];
793
GimpAnchor *segment_start, *segment_end = NULL;
797
if (!stroke->anchors)
803
for (anchorlist = stroke->anchors;
804
anchorlist && GIMP_ANCHOR (anchorlist->data)->type != GIMP_ANCHOR_ANCHOR;
805
anchorlist = g_list_next (anchorlist));
807
segment_start = anchorlist->data;
809
for ( ; anchorlist; anchorlist = g_list_next (anchorlist))
811
anchor = anchorlist->data;
813
segmentcoords[count] = anchor->position;
818
segment_end = anchorlist->data;
819
dist = gimp_bezier_stroke_segment_nearest_tangent_get (segmentcoords,
824
if (dist >= 0 && (dist < min_dist || min_dist < 0))
831
if (ret_segment_start)
832
*ret_segment_start = segment_start;
834
*ret_segment_end = segment_end;
836
segment_start = anchorlist->data;
837
segmentcoords[0] = segmentcoords[3];
842
if (stroke->closed && stroke->anchors)
844
anchorlist = stroke->anchors;
848
segmentcoords[count] = GIMP_ANCHOR (anchorlist->data)->position;
851
anchorlist = g_list_next (anchorlist);
854
segment_end = GIMP_ANCHOR (anchorlist->data);
855
segmentcoords[3] = segment_end->position;
858
dist = gimp_bezier_stroke_segment_nearest_tangent_get (segmentcoords,
863
if (dist >= 0 && (dist < min_dist || min_dist < 0))
870
if (ret_segment_start)
871
*ret_segment_start = segment_start;
873
*ret_segment_end = segment_end;
881
gimp_bezier_stroke_segment_nearest_tangent_get (const GimpCoords *beziercoords,
882
const GimpCoords *coord1,
883
const GimpCoords *coord2,
884
const gdouble precision,
885
GimpCoords *ret_point,
888
GArray *ret_coords, *ret_params;
889
GimpCoords dir, line, dcoord, min_point;
890
gdouble min_dist = -1, dist, length2, scalar, ori, ori2;
893
gimp_coords_difference (coord2, coord1, &line);
895
ret_coords = g_array_new (FALSE, FALSE, sizeof (GimpCoords));
896
ret_params = g_array_new (FALSE, FALSE, sizeof (gdouble));
898
g_printerr ("(%.2f, %.2f)-(%.2f,%.2f): ", coord1->x, coord1->y,
899
coord2->x, coord2->y);
901
gimp_bezier_coords_subdivide (beziercoords, precision,
902
&ret_coords, &ret_params);
904
g_return_val_if_fail (ret_coords->len == ret_params->len, -1.0);
906
if (ret_coords->len < 2)
909
gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, 1),
910
&g_array_index (ret_coords, GimpCoords, 0),
912
ori = dir.x * line.y - dir.y * line.x;
914
for (i = 2; i < ret_coords->len; i++)
916
gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, i),
917
&g_array_index (ret_coords, GimpCoords, i-1),
919
ori2 = dir.x * line.y - dir.y * line.x;
925
/* Kandidat finden */;
927
/* ret_coords[i] ist der Kandidat */;
930
gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, i),
934
length2 = gimp_coords_scalarprod (&line, &line);
935
scalar = gimp_coords_scalarprod (&line, &dcoord) / length2;
937
if (scalar >= 0 && scalar <= 1)
939
gimp_coords_mix (1.0, coord1,
942
gimp_coords_difference (&min_point,
943
&g_array_index (ret_coords, GimpCoords, i),
945
dist = gimp_coords_length (&dcoord);
947
if (dist < min_dist || min_dist < 0)
950
*ret_point = g_array_index (ret_coords, GimpCoords, i);
951
*ret_pos = g_array_index (ret_params, gdouble, i);
961
g_printerr ("%f: (%.2f, %.2f) /%.3f/\n", min_dist,
962
(*ret_point).x, (*ret_point).y, *ret_pos);
964
g_array_free (ret_coords, TRUE);
965
g_array_free (ret_params, TRUE);
799
971
gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
800
972
GimpAnchor *neighbor)
1758
1923
gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
1759
1924
gdouble radius_x,
1762
1928
GimpStroke *stroke;
1763
1929
GimpCoords p1 = *center;
1764
1930
GimpCoords p2 = *center;
1765
1931
GimpCoords p3 = *center;
1766
gdouble cx = center->x;
1767
gdouble cy = center->y;
1932
GimpCoords dx = *center;
1933
GimpCoords dy = *center;
1768
1934
const gdouble circlemagic = 4.0 * (G_SQRT2 - 1.0) / 3.0;
1769
1935
GimpAnchor *handle;
1771
p1.x = cx - radius_x;
1937
dx.x = radius_x * cos (angle);
1938
dx.y = - radius_x * sin (angle);
1939
dy.x = radius_y * sin (angle);
1940
dy.y = radius_y * cos (angle);
1942
gimp_coords_mix (1.0, center, 1.0, &dx, &p1);
1773
1943
stroke = gimp_bezier_stroke_new_moveto (&p1);
1775
p1.x = cx - radius_x;
1776
p1.y = cy + radius_y * circlemagic;
1777
p2.x = cx - radius_x * circlemagic;
1778
p2.y = cy + radius_y;
1780
p3.y = cy + radius_y;
1782
gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1784
p1.x = cx + radius_x * circlemagic;
1785
p1.y = cy + radius_y;
1786
p2.x = cx + radius_x;
1787
p2.y = cy + radius_y * circlemagic;
1788
p3.x = cx + radius_x;
1791
gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1793
p1.x = cx + radius_x;
1794
p1.y = cy - radius_y * circlemagic;
1795
p2.x = cx + radius_x * circlemagic;
1796
p2.y = cy - radius_y;
1798
p3.y = cy - radius_y;
1945
handle = g_list_last (GIMP_STROKE (stroke)->anchors)->data;
1946
gimp_coords_mix (1.0, &p1, -circlemagic, &dy, &handle->position);
1948
gimp_coords_mix (1.0, &p1, circlemagic, &dy, &p1);
1949
gimp_coords_mix (1.0, center, 1.0, &dy, &p3);
1950
gimp_coords_mix (1.0, &p3, circlemagic, &dx, &p2);
1951
gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1953
gimp_coords_mix (1.0, &p3, -circlemagic, &dx, &p1);
1954
gimp_coords_mix (1.0, center, -1.0, &dx, &p3);
1955
gimp_coords_mix (1.0, &p3, circlemagic, &dy, &p2);
1956
gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1958
gimp_coords_mix (1.0, &p3, -circlemagic, &dy, &p1);
1959
gimp_coords_mix (1.0, center, -1.0, &dy, &p3);
1960
gimp_coords_mix (1.0, &p3, -circlemagic, &dx, &p2);
1800
1962
gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1802
1964
handle = g_list_first (GIMP_STROKE (stroke)->anchors)->data;
1804
handle->position.x = cx - radius_x * circlemagic;
1805
handle->position.y = cy - radius_y;
1807
handle = g_list_last (GIMP_STROKE (stroke)->anchors)->data;
1809
handle->position.x = cx - radius_x;
1810
handle->position.y = cy - radius_y * circlemagic;
1965
gimp_coords_mix (1.0, &p3, circlemagic, &dx, &handle->position);
1812
1967
gimp_stroke_close (stroke);
1849
2008
gimp_bezier_coords_is_straight (const GimpCoords *beziercoords,
1850
2009
gdouble precision)
1852
GimpCoords line, tan1, tan2, d1, d2;
1855
gimp_coords_difference (&(beziercoords[3]),
1859
if (gimp_coords_length_squared (&line) < precision * precision)
1861
gimp_coords_difference (&(beziercoords[1]),
1864
gimp_coords_difference (&(beziercoords[2]),
1867
if ((gimp_coords_length_squared (&tan1) < precision * precision) &&
1868
(gimp_coords_length_squared (&tan2) < precision * precision))
1874
/* Tangents are too big for the small baseline */
1880
gimp_coords_difference (&(beziercoords[1]),
1883
gimp_coords_difference (&(beziercoords[2]),
1887
l2 = gimp_coords_scalarprod (&line, &line);
1888
s1 = gimp_coords_scalarprod (&line, &tan1) / l2;
1889
s2 = gimp_coords_scalarprod (&line, &tan2) / l2;
1891
if (s1 < 0 || s1 > 1 || s2 < 0 || s2 > 1 || s2 < s1)
1893
/* The tangents get projected outside the baseline */
1897
gimp_coords_mix (1.0, &tan1, - s1, &line, &d1);
1898
gimp_coords_mix (1.0, &tan2, - s2, &line, &d2);
1900
if ((gimp_coords_length_squared (&d1) > precision * precision) ||
1901
(gimp_coords_length_squared (&d2) > precision * precision))
1903
/* The control points are too far away from the baseline */
2011
GimpCoords pt1, pt2;
2013
/* calculate the "ideal" positions for the control points */
2015
gimp_coords_mix (2.0 / 3.0, &(beziercoords[0]),
2016
1.0 / 3.0, &(beziercoords[3]),
2018
gimp_coords_mix (1.0 / 3.0, &(beziercoords[0]),
2019
2.0 / 3.0, &(beziercoords[3]),
2022
/* calculate the deviation of the actual control points */
2024
return (gimp_coords_manhattan_dist (&(beziercoords[1]), &pt1) < precision &&
2025
gimp_coords_manhattan_dist (&(beziercoords[2]), &pt2) < precision);
1970
2093
precision)) /* 1st half */
1972
2095
*ret_coords = g_array_append_vals (*ret_coords, &(subdivided[0]), 3);
2099
params[0] = start_t;
2100
params[1] = (2 * start_t + middle_t) / 3;
2101
params[2] = (start_t + 2 * middle_t) / 3;
2102
*ret_params = g_array_append_vals (*ret_params, &(params[0]), 3);
1976
gimp_bezier_coords_subdivide2 (&(subdivided[0]), precision,
1977
ret_coords, depth-1);
2107
gimp_bezier_coords_subdivide2 (&(subdivided[0]),
2108
start_t, (start_t + end_t) / 2,
2110
ret_coords, ret_params, depth-1);
1980
2113
if (!depth || gimp_bezier_coords_is_straight (&(subdivided[3]),
1981
2114
precision)) /* 2nd half */
1983
2116
*ret_coords = g_array_append_vals (*ret_coords, &(subdivided[3]), 3);
2120
params[0] = middle_t;
2121
params[1] = (2 * middle_t + end_t) / 3;
2122
params[2] = (middle_t + 2 * end_t) / 3;
2123
*ret_params = g_array_append_vals (*ret_params, &(params[0]), 3);
1987
gimp_bezier_coords_subdivide2 (&(subdivided[3]), precision,
1988
ret_coords, depth-1);
2128
gimp_bezier_coords_subdivide2 (&(subdivided[3]),
2129
(start_t + end_t) / 2, end_t,
2131
ret_coords, ret_params, depth-1);