~ubuntu-branches/ubuntu/maverick/gimp/maverick-updates

« back to all changes in this revision

Viewing changes to plug-ins/gfig/gfig-bezier.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2005-12-09 19:44:52 UTC
  • Revision ID: james.westby@ubuntu.com-20051209194452-yggpemjlofpjqyf4
Tags: upstream-2.2.9
ImportĀ upstreamĀ versionĀ 2.2.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * This is a plug-in for the GIMP.
 
5
 *
 
6
 * Generates images containing vector type drawings.
 
7
 *
 
8
 * Copyright (C) 1997 Andy Thomas  alt@picnic.demon.co.uk
 
9
 *
 
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.
 
14
 *
 
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.
 
19
 *
 
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.
 
23
 *
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
 
 
28
#include <math.h>
 
29
#include <stdio.h>
 
30
#include <string.h>
 
31
 
 
32
#include <gtk/gtk.h>
 
33
 
 
34
#include <libgimp/gimp.h>
 
35
#include <libgimp/gimpui.h>
 
36
 
 
37
#include "gfig.h"
 
38
#include "gfig-line.h"
 
39
#include "gfig-dobject.h"
 
40
#include "gfig-dialog.h"
 
41
 
 
42
#include "libgimp/stdplugins-intl.h"
 
43
 
 
44
#define FP_PNT_MAX  10
 
45
 
 
46
typedef gdouble (*fp_pnt)[2];
 
47
 
 
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;
 
53
 
 
54
GfigObject      *tmp_bezier;       /* Needed when drawing bezier curves */
 
55
 
 
56
static void        fp_pnt_start    (void);
 
57
static void        fp_pnt_add      (gdouble     p1,
 
58
                                    gdouble     p2,
 
59
                                    gdouble     p3,
 
60
                                    gdouble     p4);
 
61
static gdouble    *d_bz_get_array  (gint       *sz);
 
62
static void        d_bz_line       (void);
 
63
static void        DrawBezier      (fp_pnt      points,
 
64
                                    gint        np,
 
65
                                    gdouble     mid,
 
66
                                    gint        depth);
 
67
static void        d_paint_bezier  (GfigObject *obj);
 
68
static GfigObject *d_copy_bezier   (GfigObject *obj);
 
69
static void        d_update_bezier (GdkPoint   *pnt);
 
70
 
 
71
static void
 
72
fp_pnt_start (void)
 
73
{
 
74
  fp_pnt_cnt = 0;
 
75
}
 
76
 
 
77
/* Add a line segment to collection array */
 
78
static void
 
79
fp_pnt_add (gdouble p1,
 
80
            gdouble p2,
 
81
            gdouble p3,
 
82
            gdouble p4)
 
83
{
 
84
  if (!fp_pnt_pnts)
 
85
    {
 
86
      fp_pnt_pnts = g_new0 (gdouble, FP_PNT_MAX);
 
87
      fp_pnt_chunk = 1;
 
88
    }
 
89
 
 
90
  if (((fp_pnt_cnt + 4) / FP_PNT_MAX) >= fp_pnt_chunk)
 
91
    {
 
92
      /* more space pls */
 
93
      fp_pnt_chunk++;
 
94
      fp_pnt_pnts = g_renew (gdouble, fp_pnt_pnts, fp_pnt_chunk * FP_PNT_MAX);
 
95
    }
 
96
 
 
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;
 
101
}
 
102
 
 
103
static gdouble *
 
104
d_bz_get_array (gint *sz)
 
105
{
 
106
  *sz = fp_pnt_cnt;
 
107
  return fp_pnt_pnts;
 
108
}
 
109
 
 
110
static void
 
111
d_bz_line (void)
 
112
{
 
113
  gint i, x0, y0, x1, y1;
 
114
 
 
115
  g_assert ((fp_pnt_cnt % 4) == 0);
 
116
 
 
117
  for (i = 0 ; i < fp_pnt_cnt; i += 4)
 
118
    {
 
119
      x0 = fp_pnt_pnts[i];
 
120
      y0 = fp_pnt_pnts[i + 1];
 
121
      x1 = fp_pnt_pnts[i + 2];
 
122
      y1 = fp_pnt_pnts[i + 3];
 
123
 
 
124
      gfig_draw_line (x0, y0, x1, y1);
 
125
    }
 
126
}
 
127
 
 
128
/*  Return points to plot */
 
129
/* Terminate by point with DBL_MAX, DBL_MAX */
 
130
static void
 
131
DrawBezier (fp_pnt  points,
 
132
            gint    np,
 
133
            gdouble mid,
 
134
            gint    depth)
 
135
{
 
136
  gint   i, j, x0 = 0, y0 = 0, x1, y1;
 
137
  fp_pnt left;
 
138
  fp_pnt right;
 
139
 
 
140
    if (depth == 0) /* draw polyline */
 
141
      {
 
142
        for (i = 0; i < np; i++)
 
143
          {
 
144
            x1 = (int) points[i][0];
 
145
            y1 = (int) points[i][1];
 
146
            if (i > 0 && (x1 != x0 || y1 != y0))
 
147
              {
 
148
                /* Add pnts up */
 
149
                fp_pnt_add ((gdouble) x0, (gdouble) y0,
 
150
                            (gdouble) x1, (gdouble) y1);
 
151
              }
 
152
            x0 = x1;
 
153
            y0 = y1;
 
154
          }
 
155
      }
 
156
    else /* subdivide control points at mid */
 
157
      {
 
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++)
 
161
          {
 
162
            right[i][0] = points[i][0];
 
163
            right[i][1] = points[i][1];
 
164
          }
 
165
        left[0][0] = right[0][0];
 
166
        left[0][1] = right[0][1];
 
167
        for (j = np - 1; j >= 1; j--)
 
168
          {
 
169
            for (i = 0; i < j; i++)
 
170
              {
 
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];
 
173
              }
 
174
            left[np - j][0] = right[0][0];
 
175
            left[np - j][1] = right[0][1];
 
176
          }
 
177
        if (depth > 0)
 
178
          {
 
179
            DrawBezier (left, np, mid, depth - 1);
 
180
            DrawBezier (right, np, mid, depth - 1);
 
181
            g_free (left);
 
182
            g_free (right);
 
183
          }
 
184
      }
 
185
}
 
186
 
 
187
void
 
188
d_draw_bezier (GfigObject *obj)
 
189
{
 
190
  DobjPoints *spnt;
 
191
  gint        seg_count = 0;
 
192
  gint        i = 0;
 
193
  gdouble   (*line_pnts)[2];
 
194
 
 
195
  spnt = obj->points;
 
196
 
 
197
  /* First count the number of points */
 
198
  for (spnt = obj->points; spnt; spnt = spnt->next)
 
199
    seg_count++;
 
200
 
 
201
  if (!seg_count)
 
202
    return; /* no-line */
 
203
 
 
204
  line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
 
205
 
 
206
  /* Go around all the points drawing a line from one to the next */
 
207
  for (spnt = obj->points; spnt; spnt = spnt->next)
 
208
    {
 
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;
 
212
      i++;
 
213
    }
 
214
 
 
215
  /* Generate an array of doubles which are the control points */
 
216
 
 
217
  if (bezier_line_frame && tmp_bezier)
 
218
    {
 
219
      fp_pnt_start ();
 
220
      DrawBezier (line_pnts, seg_count, 0.5, 0);
 
221
      d_bz_line ();
 
222
    }
 
223
 
 
224
  fp_pnt_start ();
 
225
  DrawBezier (line_pnts, seg_count, 0.5, 3);
 
226
  d_bz_line ();
 
227
  /*bezier4 (line_pnts, seg_count, 20);*/
 
228
 
 
229
  g_free (line_pnts);
 
230
}
 
231
 
 
232
static void
 
233
d_paint_bezier (GfigObject *obj)
 
234
{
 
235
  gdouble    *line_pnts;
 
236
  gdouble   (*bz_line_pnts)[2];
 
237
  DobjPoints *spnt;
 
238
  gint        seg_count = 0;
 
239
  gint        i = 0;
 
240
 
 
241
  /* First count the number of points */
 
242
  for (spnt = obj->points; spnt; spnt = spnt->next)
 
243
    seg_count++;
 
244
 
 
245
  if (!seg_count)
 
246
    return; /* no-line */
 
247
 
 
248
  bz_line_pnts = (fp_pnt) g_new0 (gdouble, 2 * seg_count + 1);
 
249
 
 
250
  /* Go around all the points drawing a line from one to the next */
 
251
  for (spnt = obj->points; spnt; spnt = spnt->next)
 
252
    {
 
253
      bz_line_pnts[i][0] = spnt->pnt.x;
 
254
      bz_line_pnts[i][1] = spnt->pnt.y;
 
255
      i++;
 
256
    }
 
257
 
 
258
  fp_pnt_start ();
 
259
  DrawBezier (bz_line_pnts, seg_count, 0.5, 5);
 
260
  line_pnts = d_bz_get_array (&i);
 
261
 
 
262
  /* Scale before drawing */
 
263
  if (selvals.scaletoimage)
 
264
    scale_to_original_xy (&line_pnts[0], i / 2);
 
265
  else
 
266
    scale_to_xy (&line_pnts[0], i / 2);
 
267
 
 
268
  /* One go */
 
269
  if (obj->style.paint_type == PAINT_BRUSH_TYPE)
 
270
    {
 
271
      gfig_paint (selvals.brshtype,
 
272
                  gfig_context->drawable_id,
 
273
                  i, line_pnts);
 
274
    }
 
275
 
 
276
  g_free (bz_line_pnts);
 
277
  /* Don't free line_pnts - may need again */
 
278
}
 
279
 
 
280
static GfigObject *
 
281
d_copy_bezier (GfigObject *obj)
 
282
{
 
283
  GfigObject *np;
 
284
 
 
285
  g_assert (obj->type == BEZIER);
 
286
 
 
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;
 
290
 
 
291
  return np;
 
292
}
 
293
 
 
294
void
 
295
d_bezier_object_class_init (void)
 
296
{
 
297
  GfigObjectClass *class = &dobj_class[BEZIER];
 
298
 
 
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;
 
305
}
 
306
 
 
307
static void
 
308
d_update_bezier (GdkPoint *pnt)
 
309
{
 
310
  DobjPoints *s_pnt, *l_pnt;
 
311
  gint        saved_cnt_pnt = selvals.opts.showcontrol;
 
312
 
 
313
  g_assert (tmp_bezier != NULL);
 
314
 
 
315
  /* Undraw last one then draw new one */
 
316
  s_pnt = tmp_bezier->points;
 
317
 
 
318
  if (!s_pnt)
 
319
    return; /* No points */
 
320
 
 
321
  /* Hack - turn off cnt points in draw routine
 
322
   */
 
323
 
 
324
  if ((l_pnt = s_pnt->next))
 
325
    {
 
326
      /* Undraw */
 
327
      while (l_pnt->next)
 
328
        {
 
329
          l_pnt = l_pnt->next;
 
330
        }
 
331
 
 
332
      draw_circle (&l_pnt->pnt, TRUE);
 
333
      selvals.opts.showcontrol = 0;
 
334
      d_draw_bezier (tmp_bezier);
 
335
      l_pnt->pnt = *pnt;
 
336
    }
 
337
  else
 
338
    {
 
339
      /* Radius is a few pixels away */
 
340
      /* First edge point */
 
341
      d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
 
342
      l_pnt = s_pnt->next;
 
343
    }
 
344
 
 
345
  /* draw it */
 
346
  selvals.opts.showcontrol = 0;
 
347
  d_draw_bezier (tmp_bezier);
 
348
  selvals.opts.showcontrol = saved_cnt_pnt;
 
349
 
 
350
  /* Realy draw the control points */
 
351
  draw_circle (&l_pnt->pnt, TRUE);
 
352
}
 
353
 
 
354
void
 
355
d_bezier_start (GdkPoint *pnt,
 
356
                gboolean  shift_down)
 
357
{
 
358
  if (!tmp_bezier)
 
359
    {
 
360
      /* New curve */
 
361
      tmp_bezier = obj_creating = d_new_object (BEZIER, pnt->x, pnt->y);
 
362
    }
 
363
}
 
364
 
 
365
void
 
366
d_bezier_end (GdkPoint *pnt,
 
367
              gboolean  shift_down)
 
368
{
 
369
  DobjPoints *l_pnt;
 
370
 
 
371
  if (!tmp_bezier)
 
372
    {
 
373
      tmp_bezier = obj_creating;
 
374
    }
 
375
 
 
376
  l_pnt = tmp_bezier->points->next;
 
377
 
 
378
  if (!l_pnt)
 
379
    return;
 
380
 
 
381
  if (shift_down)
 
382
    {
 
383
      /* Undraw circle on last pnt */
 
384
      while (l_pnt->next)
 
385
        {
 
386
          l_pnt = l_pnt->next;
 
387
        }
 
388
 
 
389
      if (l_pnt)
 
390
        {
 
391
          draw_circle (&l_pnt->pnt, TRUE);
 
392
          draw_sqr (&l_pnt->pnt, TRUE);
 
393
 
 
394
          if (bezier_closed)
 
395
            {
 
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 */
 
406
            }
 
407
          else if (bezier_line_frame)
 
408
            {
 
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 */
 
414
            }
 
415
 
 
416
          add_to_all_obj (gfig_context->current_obj, obj_creating);
 
417
        }
 
418
 
 
419
      /* small mem leak if !l_pnt ? */
 
420
      tmp_bezier = NULL;
 
421
      obj_creating = NULL;
 
422
    }
 
423
  else
 
424
    {
 
425
      if (!tmp_bezier->points->next)
 
426
        {
 
427
          draw_circle (&tmp_bezier->points->pnt, TRUE);
 
428
          draw_sqr (&tmp_bezier->points->pnt, TRUE);
 
429
        }
 
430
 
 
431
      d_draw_bezier (tmp_bezier);
 
432
      d_pnt_add_line (tmp_bezier, pnt->x, pnt->y,-1);
 
433
      d_draw_bezier (tmp_bezier);
 
434
    }
 
435
}
 
436
 
 
437
void
 
438
tool_options_bezier (GtkWidget *notebook)
 
439
{
 
440
  GtkWidget *vbox;
 
441
  GtkWidget *toggle;
 
442
 
 
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);
 
447
 
 
448
  toggle = gtk_check_button_new_with_label (_("Closed"));
 
449
  g_signal_connect (toggle, "toggled",
 
450
                    G_CALLBACK (gimp_toggle_button_update),
 
451
                    &bezier_closed);
 
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);
 
457
 
 
458
  toggle = gtk_check_button_new_with_label (_("Show Line Frame"));
 
459
  g_signal_connect (toggle, "toggled",
 
460
                    G_CALLBACK (gimp_toggle_button_update),
 
461
                    &bezier_line_frame);
 
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);
 
468
}
 
469