2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This is a plug-in for the GIMP.
6
* Generates images containing vector type drawings.
8
* Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34
#include <libgimp/gimp.h>
35
#include <libgimp/gimpui.h>
38
#include "gfig-line.h"
39
#include "gfig-dobject.h"
40
#include "gfig-dialog.h"
42
#include "libgimp/stdplugins-intl.h"
46
typedef gdouble (*fp_pnt)[2];
48
static gboolean bezier_closed = FALSE;
49
static gboolean bezier_line_frame = FALSE;
50
static int fp_pnt_cnt = 0;
51
static int fp_pnt_chunk = 0;
52
static gdouble *fp_pnt_pnts = NULL;
54
GfigObject *tmp_bezier; /* Needed when drawing bezier curves */
56
static void fp_pnt_start (void);
57
static void fp_pnt_add (gdouble p1,
61
static gdouble *d_bz_get_array (gint *sz);
62
static void d_bz_line (void);
63
static void DrawBezier (fp_pnt points,
67
static void d_paint_bezier (GfigObject *obj);
68
static GfigObject *d_copy_bezier (GfigObject *obj);
69
static void d_update_bezier (GdkPoint *pnt);
77
/* Add a line segment to collection array */
79
fp_pnt_add (gdouble p1,
86
fp_pnt_pnts = g_new0 (gdouble, FP_PNT_MAX);
90
if (((fp_pnt_cnt + 4) / FP_PNT_MAX) >= fp_pnt_chunk)
94
fp_pnt_pnts = g_renew (gdouble, fp_pnt_pnts, fp_pnt_chunk * FP_PNT_MAX);
97
fp_pnt_pnts[fp_pnt_cnt++] = p1;
98
fp_pnt_pnts[fp_pnt_cnt++] = p2;
99
fp_pnt_pnts[fp_pnt_cnt++] = p3;
100
fp_pnt_pnts[fp_pnt_cnt++] = p4;
104
d_bz_get_array (gint *sz)
113
gint i, x0, y0, x1, y1;
115
g_assert ((fp_pnt_cnt % 4) == 0);
117
for (i = 0 ; i < fp_pnt_cnt; i += 4)
120
y0 = fp_pnt_pnts[i + 1];
121
x1 = fp_pnt_pnts[i + 2];
122
y1 = fp_pnt_pnts[i + 3];
124
gfig_draw_line (x0, y0, x1, y1);
128
/* Return points to plot */
129
/* Terminate by point with DBL_MAX, DBL_MAX */
131
DrawBezier (fp_pnt points,
136
gint i, j, x0 = 0, y0 = 0, x1, y1;
140
if (depth == 0) /* draw polyline */
142
for (i = 0; i < np; i++)
144
x1 = (int) points[i][0];
145
y1 = (int) points[i][1];
146
if (i > 0 && (x1 != x0 || y1 != y0))
149
fp_pnt_add ((gdouble) x0, (gdouble) y0,
150
(gdouble) x1, (gdouble) y1);
156
else /* subdivide control points at mid */
158
left = (fp_pnt)g_new (gdouble, np * 2);
159
right = (fp_pnt)g_new (gdouble, np * 2);
160
for (i = 0; i < np; i++)
162
right[i][0] = points[i][0];
163
right[i][1] = points[i][1];
165
left[0][0] = right[0][0];
166
left[0][1] = right[0][1];
167
for (j = np - 1; j >= 1; j--)
169
for (i = 0; i < j; i++)
171
right[i][0] = (1 - mid) * right[i][0] + mid * right[i + 1][0];
172
right[i][1] = (1 - mid) * right[i][1] + mid * right[i + 1][1];
174
left[np - j][0] = right[0][0];
175
left[np - j][1] = right[0][1];
179
DrawBezier (left, np, mid, depth - 1);
180
DrawBezier (right, np, mid, depth - 1);
188
d_draw_bezier (GfigObject *obj)
193
gdouble (*line_pnts)[2];
197
/* First count the number of points */
198
for (spnt = obj->points; spnt; spnt = spnt->next)
202
return; /* no-line */
204
line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
206
/* Go around all the points drawing a line from one to the next */
207
for (spnt = obj->points; spnt; spnt = spnt->next)
209
draw_sqr (&spnt->pnt, obj == gfig_context->selected_obj);
210
line_pnts[i][0] = spnt->pnt.x;
211
line_pnts[i][1] = spnt->pnt.y;
215
/* Generate an array of doubles which are the control points */
217
if (bezier_line_frame && tmp_bezier)
220
DrawBezier (line_pnts, seg_count, 0.5, 0);
225
DrawBezier (line_pnts, seg_count, 0.5, 3);
227
/*bezier4 (line_pnts, seg_count, 20);*/
233
d_paint_bezier (GfigObject *obj)
236
gdouble (*bz_line_pnts)[2];
241
/* First count the number of points */
242
for (spnt = obj->points; spnt; spnt = spnt->next)
246
return; /* no-line */
248
bz_line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
250
/* Go around all the points drawing a line from one to the next */
251
for (spnt = obj->points; spnt; spnt = spnt->next)
253
bz_line_pnts[i][0] = spnt->pnt.x;
254
bz_line_pnts[i][1] = spnt->pnt.y;
259
DrawBezier (bz_line_pnts, seg_count, 0.5, 5);
260
line_pnts = d_bz_get_array (&i);
262
/* Scale before drawing */
263
if (selvals.scaletoimage)
264
scale_to_original_xy (&line_pnts[0], i / 2);
266
scale_to_xy (&line_pnts[0], i / 2);
269
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
271
gfig_paint (selvals.brshtype,
272
gfig_context->drawable_id,
276
g_free (bz_line_pnts);
277
/* Don't free line_pnts - may need again */
281
d_copy_bezier (GfigObject *obj)
285
g_assert (obj->type == BEZIER);
287
np = d_new_object (BEZIER, obj->points->pnt.x, obj->points->pnt.y);
288
np->points->next = d_copy_dobjpoints (obj->points->next);
289
np->type_data = obj->type_data;
295
d_bezier_object_class_init (void)
297
GfigObjectClass *class = &dobj_class[BEZIER];
299
class->type = BEZIER;
300
class->name = "BEZIER";
301
class->drawfunc = d_draw_bezier;
302
class->paintfunc = d_paint_bezier;
303
class->copyfunc = d_copy_bezier;
304
class->update = d_update_bezier;
308
d_update_bezier (GdkPoint *pnt)
310
DobjPoints *s_pnt, *l_pnt;
311
gint saved_cnt_pnt = selvals.opts.showcontrol;
313
g_assert (tmp_bezier != NULL);
315
/* Undraw last one then draw new one */
316
s_pnt = tmp_bezier->points;
319
return; /* No points */
321
/* Hack - turn off cnt points in draw routine
324
if ((l_pnt = s_pnt->next))
332
draw_circle (&l_pnt->pnt, TRUE);
333
selvals.opts.showcontrol = 0;
334
d_draw_bezier (tmp_bezier);
339
/* Radius is a few pixels away */
340
/* First edge point */
341
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
346
selvals.opts.showcontrol = 0;
347
d_draw_bezier (tmp_bezier);
348
selvals.opts.showcontrol = saved_cnt_pnt;
350
/* Realy draw the control points */
351
draw_circle (&l_pnt->pnt, TRUE);
355
d_bezier_start (GdkPoint *pnt,
361
tmp_bezier = obj_creating = d_new_object (BEZIER, pnt->x, pnt->y);
366
d_bezier_end (GdkPoint *pnt,
373
tmp_bezier = obj_creating;
376
l_pnt = tmp_bezier->points->next;
383
/* Undraw circle on last pnt */
391
draw_circle (&l_pnt->pnt, TRUE);
392
draw_sqr (&l_pnt->pnt, TRUE);
396
gboolean tmp_frame = bezier_line_frame;
397
/* if closed then add first point */
398
d_draw_bezier (tmp_bezier);
399
d_pnt_add_line (tmp_bezier,
400
tmp_bezier->points->pnt.x,
401
tmp_bezier->points->pnt.y, -1);
402
/* Final has no frame */
403
bezier_line_frame = FALSE;
404
d_draw_bezier (tmp_bezier);
405
bezier_line_frame = tmp_frame; /* What is was */
407
else if (bezier_line_frame)
409
gboolean tmp_frame = bezier_line_frame;
410
d_draw_bezier (tmp_bezier);
411
bezier_line_frame = FALSE;
412
d_draw_bezier (tmp_bezier);
413
bezier_line_frame = tmp_frame; /* What is was */
416
add_to_all_obj (gfig_context->current_obj, obj_creating);
419
/* small mem leak if !l_pnt ? */
425
if (!tmp_bezier->points->next)
427
draw_circle (&tmp_bezier->points->pnt, TRUE);
428
draw_sqr (&tmp_bezier->points->pnt, TRUE);
431
d_draw_bezier (tmp_bezier);
432
d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
433
d_draw_bezier (tmp_bezier);
438
tool_options_bezier (GtkWidget *notebook)
443
vbox = gtk_vbox_new (FALSE, 0);
444
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
445
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, NULL);
446
gtk_widget_show (vbox);
448
toggle = gtk_check_button_new_with_label (_("Closed"));
449
g_signal_connect (toggle, "toggled",
450
G_CALLBACK (gimp_toggle_button_update),
452
gimp_help_set_help_data (toggle,
453
_("Close curve on completion"), NULL);
454
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), bezier_closed);
455
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
456
gtk_widget_show (toggle);
458
toggle = gtk_check_button_new_with_label (_("Show Line Frame"));
459
g_signal_connect (toggle, "toggled",
460
G_CALLBACK (gimp_toggle_button_update),
462
gimp_help_set_help_data (toggle,
463
_("Draws lines between the control points. "
464
"Only during curve creation"), NULL);
465
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), bezier_line_frame);
466
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
467
gtk_widget_show (toggle);