Skip to content

Commit 4eac9f7

Browse files
committed
Implement quadratic bezier curve
Add quadratic bezier curve support by converting quadratic spline to cubic spline. The conversion follows the formula: CP1 = P0 + 2/3 * (P1 - P0) CP2 = P2 + 2/3 * (P1 - P2) where: - P0, P1, P2 are quadratic control points - CP1, CP2 are the resulting cubic control points Ref: https://fontforge.org/docs/techref/bezier.html#converting-truetype-to-postscript
1 parent f8e868b commit 4eac9f7

File tree

3 files changed

+93
-33
lines changed

3 files changed

+93
-33
lines changed

apps/spline.c

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,59 @@
1515

1616
#define _apps_spline_pixmap(spline) ((spline)->widget.window->pixmap)
1717

18-
#define NPT 4
1918

2019
typedef struct _apps_spline {
2120
twin_widget_t widget;
22-
twin_point_t points[NPT];
21+
int n_points;
22+
twin_point_t *points;
2323
int which;
2424
twin_fixed_t line_width;
2525
twin_cap_t cap_style;
2626
} apps_spline_t;
2727

28+
static void _draw_aux_line(twin_path_t *path,
29+
apps_spline_t *spline,
30+
int idx1,
31+
int idx2)
32+
{
33+
twin_path_move(path, spline->points[idx1].x, spline->points[idx1].y);
34+
twin_path_draw(path, spline->points[idx2].x, spline->points[idx2].y);
35+
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
36+
twin_int_to_fixed(2));
37+
twin_path_empty(path);
38+
}
39+
2840
static void _apps_spline_paint(apps_spline_t *spline)
2941
{
3042
twin_path_t *path;
31-
int i;
32-
3343
path = twin_path_create();
3444
twin_path_set_cap_style(path, spline->cap_style);
45+
3546
twin_path_move(path, spline->points[0].x, spline->points[0].y);
36-
twin_path_curve(path, spline->points[1].x, spline->points[1].y,
37-
spline->points[2].x, spline->points[2].y,
38-
spline->points[3].x, spline->points[3].y);
47+
if (spline->n_points == 4) {
48+
twin_path_curve(path, spline->points[1].x, spline->points[1].y,
49+
spline->points[2].x, spline->points[2].y,
50+
spline->points[3].x, spline->points[3].y);
51+
} else if (spline->n_points == 3) {
52+
twin_path_quadratic_curve(path, spline->points[1].x,
53+
spline->points[1].y, spline->points[2].x,
54+
spline->points[2].y);
55+
}
3956
twin_paint_stroke(_apps_spline_pixmap(spline), 0xff404040, path,
4057
spline->line_width);
4158
twin_path_set_cap_style(path, TwinCapButt);
4259
twin_paint_stroke(_apps_spline_pixmap(spline), 0xffffff00, path,
4360
twin_int_to_fixed(2));
44-
4561
twin_path_empty(path);
46-
twin_path_move(path, spline->points[0].x, spline->points[0].y);
47-
twin_path_draw(path, spline->points[1].x, spline->points[1].y);
48-
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
49-
twin_int_to_fixed(2));
50-
twin_path_empty(path);
51-
twin_path_move(path, spline->points[3].x, spline->points[3].y);
52-
twin_path_draw(path, spline->points[2].x, spline->points[2].y);
53-
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
54-
twin_int_to_fixed(2));
55-
twin_path_empty(path);
56-
for (i = 0; i < NPT; i++) {
62+
if (spline->n_points == 4) {
63+
_draw_aux_line(path, spline, 0, 1);
64+
_draw_aux_line(path, spline, 3, 2);
65+
} else if (spline->n_points == 3) {
66+
_draw_aux_line(path, spline, 0, 1);
67+
_draw_aux_line(path, spline, 1, 2);
68+
}
69+
70+
for (int i = 0; i < spline->n_points; i++) {
5771
twin_path_empty(path);
5872
twin_path_circle(path, spline->points[i].x, spline->points[i].y,
5973
twin_int_to_fixed(10));
@@ -81,7 +95,7 @@ static int _apps_spline_hit(apps_spline_t *spline,
8195
{
8296
int i;
8397

84-
for (i = 0; i < NPT; i++)
98+
for (i = 0; i < spline->n_points; i++)
8599
if (twin_fixed_abs(x - spline->points[i].x) < spline->line_width / 2 &&
86100
twin_fixed_abs(y - spline->points[i].y) < spline->line_width / 2)
87101
return i;
@@ -123,28 +137,40 @@ static twin_dispatch_result_t _apps_spline_dispatch(twin_widget_t *widget,
123137

124138
static void _apps_spline_init(apps_spline_t *spline,
125139
twin_box_t *parent,
126-
twin_dispatch_proc_t dispatch)
140+
twin_dispatch_proc_t dispatch,
141+
int n_points)
127142
{
128143
static const twin_widget_layout_t preferred = {0, 0, 1, 1};
129144
_twin_widget_init(&spline->widget, parent, 0, preferred, dispatch);
130145
twin_widget_set(&spline->widget, 0xffffffff);
131146
spline->line_width = twin_int_to_fixed(100);
132147
spline->cap_style = TwinCapRound;
133-
spline->points[0].x = twin_int_to_fixed(100);
134-
spline->points[0].y = twin_int_to_fixed(100);
135-
spline->points[1].x = twin_int_to_fixed(300);
136-
spline->points[1].y = twin_int_to_fixed(300);
137-
spline->points[2].x = twin_int_to_fixed(100);
138-
spline->points[2].y = twin_int_to_fixed(300);
139-
spline->points[3].x = twin_int_to_fixed(300);
140-
spline->points[3].y = twin_int_to_fixed(100);
148+
spline->points = calloc(n_points, sizeof(twin_point_t));
149+
spline->n_points = n_points;
150+
if (n_points == 4) {
151+
spline->points[0].x = twin_int_to_fixed(100);
152+
spline->points[0].y = twin_int_to_fixed(100);
153+
spline->points[1].x = twin_int_to_fixed(300);
154+
spline->points[1].y = twin_int_to_fixed(300);
155+
spline->points[2].x = twin_int_to_fixed(100);
156+
spline->points[2].y = twin_int_to_fixed(300);
157+
spline->points[3].x = twin_int_to_fixed(300);
158+
spline->points[3].y = twin_int_to_fixed(100);
159+
} else if (n_points == 3) {
160+
spline->points[0].x = twin_int_to_fixed(100);
161+
spline->points[0].y = twin_int_to_fixed(100);
162+
spline->points[1].x = twin_int_to_fixed(200);
163+
spline->points[1].y = twin_int_to_fixed(300);
164+
spline->points[2].x = twin_int_to_fixed(300);
165+
spline->points[2].y = twin_int_to_fixed(100);
166+
}
141167
}
142168

143-
static apps_spline_t *apps_spline_create(twin_box_t *parent)
169+
static apps_spline_t *apps_spline_create(twin_box_t *parent, int n_points)
144170
{
145171
apps_spline_t *spline = malloc(sizeof(apps_spline_t));
146172

147-
_apps_spline_init(spline, parent, _apps_spline_dispatch);
173+
_apps_spline_init(spline, parent, _apps_spline_dispatch, n_points);
148174
return spline;
149175
}
150176

@@ -157,7 +183,12 @@ void apps_spline_start(twin_screen_t *screen,
157183
{
158184
twin_toplevel_t *toplevel = twin_toplevel_create(
159185
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, name);
160-
apps_spline_t *spline = apps_spline_create(&toplevel->box);
161-
(void) spline;
186+
apps_spline_t *spline_cubic = apps_spline_create(&toplevel->box, 4);
187+
twin_toplevel_t *toplevel2 = twin_toplevel_create(
188+
screen, TWIN_ARGB32, TwinWindowApplication, x + 20, y + 20, w, h, name);
189+
apps_spline_t *spline_quad = apps_spline_create(&toplevel2->box, 3);
190+
(void) spline_cubic;
191+
(void) spline_quad;
162192
twin_toplevel_show(toplevel);
193+
twin_toplevel_show(toplevel2);
163194
}

include/twin.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,12 @@ void twin_path_curve(twin_path_t *path,
10611061
twin_fixed_t x3,
10621062
twin_fixed_t y3);
10631063

1064+
void twin_path_quadratic_curve(twin_path_t *path,
1065+
twin_fixed_t x1,
1066+
twin_fixed_t y1,
1067+
twin_fixed_t x2,
1068+
twin_fixed_t y2);
1069+
10641070
/*
10651071
* timeout.c
10661072
*/

src/spline.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,26 @@ void twin_path_curve(twin_path_t *path,
164164
_twin_matrix_x(&path->state.matrix, x3, y3),
165165
_twin_matrix_y(&path->state.matrix, x3, y3));
166166
}
167+
168+
void twin_path_quadratic_curve(twin_path_t *path,
169+
twin_fixed_t x1,
170+
twin_fixed_t y1,
171+
twin_fixed_t x2,
172+
twin_fixed_t y2)
173+
{
174+
twin_spoint_t p0 = _twin_path_current_spoint(path);
175+
/* Convert quadratic to cubic control point */
176+
/* CP1 = P0 + 2/3 * (P1 - P0) */
177+
twin_sfixed_t dx1 = twin_fixed_to_sfixed(x1) - p0.x;
178+
twin_sfixed_t dy1 = twin_fixed_to_sfixed(y1) - p0.y;
179+
twin_sfixed_t cx1 = p0.x + twin_sfixed_mul(dx1, twin_int_to_sfixed(2) / 3);
180+
twin_sfixed_t cy1 = p0.y + twin_sfixed_mul(dy1, twin_int_to_sfixed(2) / 3);
181+
/* CP2 = P2 + 2/3 * (P1 - P2) */
182+
twin_sfixed_t x2s = twin_fixed_to_sfixed(x2);
183+
twin_sfixed_t y2s = twin_fixed_to_sfixed(y2);
184+
twin_sfixed_t dx2 = twin_fixed_to_sfixed(x1) - x2s;
185+
twin_sfixed_t dy2 = twin_fixed_to_sfixed(y1) - y2s;
186+
twin_sfixed_t cx2 = x2s + twin_sfixed_mul(dx2, twin_int_to_sfixed(2) / 3);
187+
twin_sfixed_t cy2 = y2s + twin_sfixed_mul(dy2, twin_int_to_sfixed(2) / 3);
188+
_twin_path_scurve(path, cx1, cy1, cx2, cy2, x2s, y2s);
189+
}

0 commit comments

Comments
 (0)