~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/vectors/gimpbezierstroke.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * gimpbezierstroke.c
33
33
#include "gimpbezierstroke.h"
34
34
 
35
35
 
36
 
/* local prototypes */
37
 
 
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,
46
 
                                                     gdouble          *ret_pos);
47
 
static gdouble
48
 
       gimp_bezier_stroke_segment_nearest_point_get (const GimpCoords  *beziercoords,
49
 
                                                     const GimpCoords  *coord,
50
 
                                                     const gdouble      precision,
51
 
                                                     GimpCoords        *ret_point,
52
 
                                                     gdouble           *ret_pos,
53
 
                                                     gint               depth);
54
 
static void gimp_bezier_stroke_anchor_move_relative (GimpStroke        *stroke,
55
 
                                                     GimpAnchor        *anchor,
56
 
                                                     const GimpCoords  *deltacoord,
57
 
                                                     GimpAnchorFeatureType feature);
58
 
static void gimp_bezier_stroke_anchor_move_absolute (GimpStroke        *stroke,
59
 
                                                     GimpAnchor        *anchor,
60
 
                                                     const GimpCoords  *coord,
61
 
                                                     GimpAnchorFeatureType feature);
62
 
static void gimp_bezier_stroke_anchor_convert   (GimpStroke            *stroke,
63
 
                                                 GimpAnchor            *anchor,
64
 
                                                 GimpAnchorFeatureType  feature);
65
 
static void gimp_bezier_stroke_anchor_delete        (GimpStroke        *stroke,
66
 
                                                     GimpAnchor        *anchor);
67
 
static gboolean gimp_bezier_stroke_point_is_movable
68
 
                                                (GimpStroke            *stroke,
69
 
                                                 GimpAnchor            *predec,
70
 
                                                 gdouble                position);
71
 
static void gimp_bezier_stroke_point_move_relative
72
 
                                              (GimpStroke            *stroke,
73
 
                                               GimpAnchor            *predec,
74
 
                                               gdouble                position,
75
 
                                               const GimpCoords      *deltacoord,
76
 
                                               GimpAnchorFeatureType  feature);
77
 
static void gimp_bezier_stroke_point_move_absolute
78
 
                                              (GimpStroke            *stroke,
79
 
                                               GimpAnchor            *predec,
80
 
                                               gdouble                position,
81
 
                                               const GimpCoords      *coord,
82
 
                                               GimpAnchorFeatureType  feature);
83
 
 
84
 
static void gimp_bezier_stroke_close          (GimpStroke            *stroke);
85
 
 
86
 
static GimpStroke * gimp_bezier_stroke_open     (GimpStroke        *stroke,
87
 
                                                 GimpAnchor        *end_anchor);
88
 
static gboolean gimp_bezier_stroke_anchor_is_insertable
89
 
                                                    (GimpStroke        *stroke,
90
 
                                                     GimpAnchor        *predec,
91
 
                                                     gdouble            position);
92
 
static GimpAnchor * gimp_bezier_stroke_anchor_insert (GimpStroke       *stroke,
93
 
                                                      GimpAnchor       *predec,
94
 
                                                      gdouble           position);
95
 
static gboolean gimp_bezier_stroke_is_extendable    (GimpStroke      *stroke,
96
 
                                                     GimpAnchor      *neighbor);
97
 
static gboolean gimp_bezier_stroke_connect_stroke   (GimpStroke      *stroke,
98
 
                                                     GimpAnchor      *anchor,
99
 
                                                     GimpStroke      *extension,
100
 
                                                     GimpAnchor      *neighbor);
101
 
static GArray *   gimp_bezier_stroke_interpolate (const GimpStroke  *stroke,
102
 
                                                  const gdouble      precision,
103
 
                                                  gboolean          *closed);
104
 
 
105
 
static void gimp_bezier_stroke_finalize   (GObject               *object);
106
 
 
107
 
 
108
 
static GList * gimp_bezier_stroke_get_anchor_listitem (GList     *list);
109
 
 
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,
115
 
                                           GArray               **ret_coords,
116
 
                                           gint                   depth);
117
 
 
118
 
static gboolean gimp_bezier_coords_is_straight (const GimpCoords *beziercoords,
119
 
                                                const gdouble     precision);
120
 
 
121
 
 
122
 
/*  private variables  */
123
 
 
124
 
static GimpStrokeClass *parent_class = NULL;
125
 
 
126
 
 
127
 
GType
128
 
gimp_bezier_stroke_get_type (void)
129
 
{
130
 
  static GType bezier_stroke_type = 0;
131
 
 
132
 
  if (! bezier_stroke_type)
133
 
    {
134
 
      static const GTypeInfo bezier_stroke_info =
135
 
      {
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),
143
 
        0,              /* n_preallocs    */
144
 
        (GInstanceInitFunc) gimp_bezier_stroke_init,
145
 
      };
146
 
 
147
 
      bezier_stroke_type = g_type_register_static (GIMP_TYPE_STROKE,
148
 
                                                   "GimpBezierStroke",
149
 
                                                   &bezier_stroke_info, 0);
150
 
    }
151
 
 
152
 
  return bezier_stroke_type;
153
 
}
 
36
/*  local prototypes  */
 
37
 
 
38
static gdouble
 
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,
 
45
                                            gdouble               *ret_pos);
 
46
static gdouble
 
47
    gimp_bezier_stroke_segment_nearest_point_get
 
48
                                           (const GimpCoords      *beziercoords,
 
49
                                            const GimpCoords      *coord,
 
50
                                            const gdouble          precision,
 
51
                                            GimpCoords            *ret_point,
 
52
                                            gdouble               *ret_pos,
 
53
                                            gint                   depth);
 
54
static gdouble
 
55
    gimp_bezier_stroke_nearest_tangent_get (const GimpStroke      *stroke,
 
56
                                            const GimpCoords      *coord1,
 
57
                                            const GimpCoords      *coord2,
 
58
                                            const gdouble          precision,
 
59
                                            GimpCoords            *nearest,
 
60
                                            GimpAnchor           **ret_segment_start,
 
61
                                            GimpAnchor           **ret_segment_end,
 
62
                                            gdouble               *ret_pos);
 
63
static gdouble
 
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,
 
70
                                            gdouble               *ret_pos);
 
71
static void
 
72
    gimp_bezier_stroke_anchor_move_relative
 
73
                                           (GimpStroke            *stroke,
 
74
                                            GimpAnchor            *anchor,
 
75
                                            const GimpCoords      *deltacoord,
 
76
                                            GimpAnchorFeatureType  feature);
 
77
static void
 
78
    gimp_bezier_stroke_anchor_move_absolute
 
79
                                           (GimpStroke            *stroke,
 
80
                                            GimpAnchor            *anchor,
 
81
                                            const GimpCoords      *coord,
 
82
                                            GimpAnchorFeatureType  feature);
 
83
static void
 
84
    gimp_bezier_stroke_anchor_convert      (GimpStroke            *stroke,
 
85
                                            GimpAnchor            *anchor,
 
86
                                            GimpAnchorFeatureType  feature);
 
87
static void
 
88
    gimp_bezier_stroke_anchor_delete       (GimpStroke            *stroke,
 
89
                                            GimpAnchor            *anchor);
 
90
static gboolean
 
91
    gimp_bezier_stroke_point_is_movable    (GimpStroke            *stroke,
 
92
                                            GimpAnchor            *predec,
 
93
                                            gdouble                position);
 
94
static void
 
95
    gimp_bezier_stroke_point_move_relative (GimpStroke            *stroke,
 
96
                                            GimpAnchor            *predec,
 
97
                                            gdouble                position,
 
98
                                            const GimpCoords      *deltacoord,
 
99
                                            GimpAnchorFeatureType  feature);
 
100
static void
 
101
    gimp_bezier_stroke_point_move_absolute (GimpStroke            *stroke,
 
102
                                            GimpAnchor            *predec,
 
103
                                            gdouble                position,
 
104
                                            const GimpCoords      *coord,
 
105
                                            GimpAnchorFeatureType  feature);
 
106
 
 
107
static void gimp_bezier_stroke_close       (GimpStroke            *stroke);
 
108
 
 
109
static GimpStroke *
 
110
    gimp_bezier_stroke_open                (GimpStroke            *stroke,
 
111
                                            GimpAnchor            *end_anchor);
 
112
static gboolean
 
113
    gimp_bezier_stroke_anchor_is_insertable
 
114
                                           (GimpStroke            *stroke,
 
115
                                            GimpAnchor            *predec,
 
116
                                            gdouble                position);
 
117
static GimpAnchor *
 
118
    gimp_bezier_stroke_anchor_insert       (GimpStroke            *stroke,
 
119
                                            GimpAnchor            *predec,
 
120
                                            gdouble                position);
 
121
static gboolean
 
122
    gimp_bezier_stroke_is_extendable       (GimpStroke            *stroke,
 
123
                                            GimpAnchor            *neighbor);
 
124
static gboolean
 
125
    gimp_bezier_stroke_connect_stroke      (GimpStroke            *stroke,
 
126
                                            GimpAnchor            *anchor,
 
127
                                            GimpStroke            *extension,
 
128
                                            GimpAnchor            *neighbor);
 
129
static GArray *
 
130
    gimp_bezier_stroke_interpolate         (const GimpStroke      *stroke,
 
131
                                            const gdouble          precision,
 
132
                                            gboolean              *closed);
 
133
 
 
134
static void gimp_bezier_stroke_finalize    (GObject               *object);
 
135
 
 
136
 
 
137
static GList * gimp_bezier_stroke_get_anchor_listitem
 
138
                                           (GList                 *list);
 
139
 
 
140
static void gimp_bezier_coords_subdivide   (const GimpCoords      *beziercoords,
 
141
                                            const gdouble          precision,
 
142
                                            GArray               **ret_coords,
 
143
                                            GArray               **ret_params);
 
144
static void gimp_bezier_coords_subdivide2  (const GimpCoords      *beziercoords,
 
145
                                            const gdouble          start_t,
 
146
                                            const gdouble          end_t,
 
147
                                            const gdouble          precision,
 
148
                                            GArray               **ret_coords,
 
149
                                            GArray               **ret_params,
 
150
                                            gint                   depth);
 
151
 
 
152
static gboolean gimp_bezier_coords_is_straight
 
153
                                           (const GimpCoords      *beziercoords,
 
154
                                            const gdouble          precision);
 
155
 
 
156
 
 
157
G_DEFINE_TYPE (GimpBezierStroke, gimp_bezier_stroke, GIMP_TYPE_STROKE)
 
158
 
 
159
#define parent_class gimp_bezier_stroke_parent_class
 
160
 
154
161
 
155
162
static void
156
163
gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass)
157
164
{
158
 
  GObjectClass    *object_class;
159
 
  GimpStrokeClass *stroke_class;
160
 
 
161
 
  object_class = G_OBJECT_CLASS (klass);
162
 
  stroke_class = GIMP_STROKE_CLASS (klass);
163
 
 
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);
165
167
 
166
168
  object_class->finalize             = gimp_bezier_stroke_finalize;
167
169
 
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;
184
188
}
185
189
 
186
190
static void
187
 
gimp_bezier_stroke_init (GimpBezierStroke *bezier_stroke)
 
191
gimp_bezier_stroke_init (GimpBezierStroke *stroke)
188
192
{
189
 
  /* pass */
190
193
}
191
194
 
192
195
static void
247
250
  /* Anchors always are surrounded by two handles that have to
248
251
   * be deleted too */
249
252
 
250
 
  g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
251
 
  g_return_if_fail (anchor && anchor->type == GIMP_ANCHOR_ANCHOR);
252
 
 
253
253
  list2 = g_list_find (stroke->anchors, anchor);
254
254
  list = g_list_previous(list2);
255
255
 
270
270
  GList *list, *list2;
271
271
  GimpStroke *new_stroke = NULL;
272
272
 
273
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), NULL);
274
 
  g_return_val_if_fail (end_anchor &&
275
 
                        end_anchor->type == GIMP_ANCHOR_ANCHOR, NULL);
276
 
 
277
273
  list = g_list_find (stroke->anchors, end_anchor);
278
274
 
279
275
  g_return_val_if_fail (list != NULL && list->next != NULL, NULL);
309
305
                                         GimpAnchor *predec,
310
306
                                         gdouble     position)
311
307
{
312
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), FALSE);
313
 
 
314
308
  return (g_list_find (stroke->anchors, predec) != NULL);
315
309
}
316
310
 
325
319
  GimpCoords beziercoords[4];
326
320
  gint i;
327
321
 
328
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), NULL);
329
 
  g_return_val_if_fail (predec->type == GIMP_ANCHOR_ANCHOR, NULL);
330
 
 
331
322
  segment_start = g_list_find (stroke->anchors, predec);
332
323
 
333
324
  if (! segment_start)
418
409
                                     GimpAnchor *predec,
419
410
                                     gdouble     position)
420
411
{
421
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), FALSE);
422
 
 
423
412
  return (g_list_find (stroke->anchors, predec) != NULL);
424
413
}
425
414
 
436
425
  gint        i;
437
426
  gdouble feel_good;
438
427
 
439
 
  g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
440
 
 
441
428
  segment_start = g_list_find (stroke->anchors, predec);
442
429
 
443
430
  g_return_if_fail (segment_start != NULL);
492
479
  GList      *segment_start, *list;
493
480
  gint        i;
494
481
 
495
 
  g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
496
 
 
497
482
  segment_start = g_list_find (stroke->anchors, predec);
498
483
 
499
484
  g_return_if_fail (segment_start != NULL);
528
513
  GList *start, *end;
529
514
  GimpAnchor *anchor;
530
515
 
531
 
  g_return_if_fail (stroke->anchors != NULL);
532
 
 
533
516
  start = g_list_first (stroke->anchors);
534
517
  end = g_list_last (stroke->anchors);
535
518
 
586
569
  GimpAnchor *anchor;
587
570
  gint        count;
588
571
 
589
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), - 1.0);
590
 
 
591
572
  if (!stroke->anchors)
592
573
    return -1.0;
593
574
 
745
726
  subdivided[0] = beziercoords[0];
746
727
  subdivided[6] = beziercoords[3];
747
728
 
748
 
  /* if (!depth) g_printerr ("Hit rekursion depth limit!\n"); */
 
729
  /* if (!depth) g_printerr ("Hit recursion depth limit!\n"); */
749
730
 
750
731
  gimp_coords_average (&(beziercoords[0]), &(beziercoords[1]),
751
732
                       &(subdivided[1]));
795
776
}
796
777
 
797
778
 
 
779
static gdouble
 
780
gimp_bezier_stroke_nearest_tangent_get (const GimpStroke  *stroke,
 
781
                                        const GimpCoords  *coord1,
 
782
                                        const GimpCoords  *coord2,
 
783
                                        const gdouble      precision,
 
784
                                        GimpCoords        *nearest,
 
785
                                        GimpAnchor       **ret_segment_start,
 
786
                                        GimpAnchor       **ret_segment_end,
 
787
                                        gdouble           *ret_pos)
 
788
{
 
789
  gdouble     min_dist, dist, pos;
 
790
  GimpCoords  point;
 
791
  GimpCoords  segmentcoords[4];
 
792
  GList      *anchorlist;
 
793
  GimpAnchor *segment_start, *segment_end = NULL;
 
794
  GimpAnchor *anchor;
 
795
  gint        count;
 
796
 
 
797
  if (!stroke->anchors)
 
798
    return -1.0;
 
799
 
 
800
  count = 0;
 
801
  min_dist = -1;
 
802
 
 
803
  for (anchorlist = stroke->anchors;
 
804
       anchorlist && GIMP_ANCHOR (anchorlist->data)->type != GIMP_ANCHOR_ANCHOR;
 
805
       anchorlist = g_list_next (anchorlist));
 
806
 
 
807
  segment_start = anchorlist->data;
 
808
 
 
809
  for ( ; anchorlist; anchorlist = g_list_next (anchorlist))
 
810
    {
 
811
      anchor = anchorlist->data;
 
812
 
 
813
      segmentcoords[count] = anchor->position;
 
814
      count++;
 
815
 
 
816
      if (count == 4)
 
817
        {
 
818
          segment_end = anchorlist->data;
 
819
          dist = gimp_bezier_stroke_segment_nearest_tangent_get (segmentcoords,
 
820
                                                                 coord1, coord2,
 
821
                                                                 precision,
 
822
                                                                 &point, &pos);
 
823
 
 
824
          if (dist >= 0 && (dist < min_dist || min_dist < 0))
 
825
            {
 
826
              min_dist = dist;
 
827
              if (ret_pos)
 
828
                *ret_pos = pos;
 
829
              if (nearest)
 
830
                *nearest = point;
 
831
              if (ret_segment_start)
 
832
                *ret_segment_start = segment_start;
 
833
              if (ret_segment_end)
 
834
                *ret_segment_end = segment_end;
 
835
            }
 
836
          segment_start = anchorlist->data;
 
837
          segmentcoords[0] = segmentcoords[3];
 
838
          count = 1;
 
839
        }
 
840
    }
 
841
 
 
842
  if (stroke->closed && stroke->anchors)
 
843
    {
 
844
      anchorlist = stroke->anchors;
 
845
 
 
846
      while (count < 3)
 
847
        {
 
848
          segmentcoords[count] = GIMP_ANCHOR (anchorlist->data)->position;
 
849
          count++;
 
850
        }
 
851
      anchorlist = g_list_next (anchorlist);
 
852
      if (anchorlist)
 
853
        {
 
854
          segment_end = GIMP_ANCHOR (anchorlist->data);
 
855
          segmentcoords[3] = segment_end->position;
 
856
        }
 
857
 
 
858
      dist = gimp_bezier_stroke_segment_nearest_tangent_get (segmentcoords,
 
859
                                                             coord1, coord2,
 
860
                                                             precision,
 
861
                                                             &point, &pos);
 
862
 
 
863
      if (dist >= 0 && (dist < min_dist || min_dist < 0))
 
864
        {
 
865
          min_dist = dist;
 
866
          if (ret_pos)
 
867
            *ret_pos = pos;
 
868
          if (nearest)
 
869
            *nearest = point;
 
870
          if (ret_segment_start)
 
871
            *ret_segment_start = segment_start;
 
872
          if (ret_segment_end)
 
873
            *ret_segment_end = segment_end;
 
874
        }
 
875
    }
 
876
 
 
877
  return min_dist;
 
878
}
 
879
 
 
880
static gdouble
 
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,
 
886
                                                gdouble          *ret_pos)
 
887
{
 
888
  GArray *ret_coords, *ret_params;
 
889
  GimpCoords dir, line, dcoord, min_point;
 
890
  gdouble min_dist = -1, dist, length2, scalar, ori, ori2;
 
891
  gint i;
 
892
 
 
893
  gimp_coords_difference (coord2, coord1, &line);
 
894
 
 
895
  ret_coords = g_array_new (FALSE, FALSE, sizeof (GimpCoords));
 
896
  ret_params = g_array_new (FALSE, FALSE, sizeof (gdouble));
 
897
 
 
898
  g_printerr ("(%.2f, %.2f)-(%.2f,%.2f): ", coord1->x, coord1->y,
 
899
              coord2->x, coord2->y);
 
900
 
 
901
  gimp_bezier_coords_subdivide (beziercoords, precision,
 
902
                                &ret_coords, &ret_params);
 
903
 
 
904
  g_return_val_if_fail (ret_coords->len == ret_params->len, -1.0);
 
905
 
 
906
  if (ret_coords->len < 2)
 
907
    return -1;
 
908
 
 
909
  gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, 1),
 
910
                          &g_array_index (ret_coords, GimpCoords, 0),
 
911
                          &dir);
 
912
  ori = dir.x * line.y - dir.y * line.x;
 
913
 
 
914
  for (i = 2; i < ret_coords->len; i++)
 
915
    {
 
916
      gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, i),
 
917
                              &g_array_index (ret_coords, GimpCoords, i-1),
 
918
                              &dir);
 
919
      ori2 = dir.x * line.y - dir.y * line.x;
 
920
 
 
921
      if (ori * ori2 <= 0)
 
922
        {
 
923
#if 0
 
924
          if (ori2 == 0)
 
925
            /* Kandidat finden */;
 
926
          else
 
927
            /* ret_coords[i] ist der Kandidat */;
 
928
#endif
 
929
 
 
930
          gimp_coords_difference (&g_array_index (ret_coords, GimpCoords, i),
 
931
                                  coord1,
 
932
                                  &dcoord);
 
933
 
 
934
          length2 = gimp_coords_scalarprod (&line, &line);
 
935
          scalar = gimp_coords_scalarprod (&line, &dcoord) / length2;
 
936
 
 
937
          if (scalar >= 0 && scalar <= 1)
 
938
            {
 
939
              gimp_coords_mix (1.0, coord1,
 
940
                               scalar, &line,
 
941
                               &min_point);
 
942
              gimp_coords_difference (&min_point,
 
943
                                      &g_array_index (ret_coords, GimpCoords, i),
 
944
                                      &dcoord);
 
945
              dist = gimp_coords_length (&dcoord);
 
946
 
 
947
              if (dist < min_dist || min_dist < 0)
 
948
                {
 
949
                  min_dist   = dist;
 
950
                  *ret_point = g_array_index (ret_coords, GimpCoords, i);
 
951
                  *ret_pos   = g_array_index (ret_params, gdouble, i);
 
952
                }
 
953
            }
 
954
        }
 
955
      ori = ori2;
 
956
    }
 
957
 
 
958
  if (min_dist < 0)
 
959
    g_printerr ("-\n");
 
960
  else
 
961
    g_printerr ("%f: (%.2f, %.2f) /%.3f/\n", min_dist,
 
962
                (*ret_point).x, (*ret_point).y, *ret_pos);
 
963
 
 
964
  g_array_free (ret_coords, TRUE);
 
965
  g_array_free (ret_params, TRUE);
 
966
 
 
967
  return min_dist;
 
968
}
 
969
 
798
970
static gboolean
799
971
gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
800
972
                                  GimpAnchor *neighbor)
803
975
  GList            *listneighbor;
804
976
  gint              loose_end;
805
977
 
806
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), FALSE);
807
978
  bezier_stroke = GIMP_BEZIER_STROKE (stroke);
808
979
 
809
980
  if (stroke->closed)
894
1065
  GList            *listneighbor;
895
1066
  gint              loose_end, control_count;
896
1067
 
897
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), NULL);
898
1068
  bezier_stroke = GIMP_BEZIER_STROKE (stroke);
899
1069
 
900
 
  g_return_val_if_fail (!stroke->closed, NULL);
901
 
 
902
1070
  if (stroke->anchors == NULL)
903
1071
    {
904
1072
      /* assure that there is no neighbor specified */
1104
1272
{
1105
1273
  GList *list1, *list2;
1106
1274
 
1107
 
  g_return_val_if_fail (stroke->closed == FALSE &&
1108
 
                        extension->closed == FALSE, FALSE);
1109
 
 
1110
1275
  list1 = g_list_find (stroke->anchors, anchor);
1111
1276
  list1 = gimp_bezier_stroke_get_anchor_listitem (list1);
1112
1277
  list2 = g_list_find (extension->anchors, neighbor);
1285
1450
  gint        count;
1286
1451
  gboolean    need_endpoint = FALSE;
1287
1452
 
1288
 
  g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), NULL);
1289
 
 
1290
1453
  if (!stroke->anchors)
1291
1454
    {
1292
1455
      if (ret_closed)
1311
1474
 
1312
1475
      if (count == 4)
1313
1476
        {
1314
 
          gimp_bezier_coords_subdivide (segmentcoords, precision, &ret_coords);
 
1477
          gimp_bezier_coords_subdivide (segmentcoords, precision,
 
1478
                                        &ret_coords, NULL);
1315
1479
          segmentcoords[0] = segmentcoords[3];
1316
1480
          count = 1;
1317
1481
          need_endpoint = TRUE;
1331
1495
      if (anchorlist)
1332
1496
        segmentcoords[3] = GIMP_ANCHOR (anchorlist->data)->position;
1333
1497
 
1334
 
      gimp_bezier_coords_subdivide (segmentcoords, precision, &ret_coords);
 
1498
      gimp_bezier_coords_subdivide (segmentcoords, precision,
 
1499
                                    &ret_coords, NULL);
1335
1500
      need_endpoint = TRUE;
1336
1501
 
1337
1502
    }
1515
1680
                      GimpCoords *ellips)
1516
1681
{
1517
1682
  gdouble       phi_s, phi_e;
1518
 
  GimpCoords    template    = { 0, 0, 1, 0.5, 0.5, 0.5 };
 
1683
  GimpCoords    template    = GIMP_COORDS_DEFAULT_VALUES;
1519
1684
  const gdouble circlemagic = 4.0 * (G_SQRT2 - 1.0) / 3.0;
1520
1685
  gdouble       y[4];
1521
1686
  gdouble       h0, h1;
1757
1922
GimpStroke *
1758
1923
gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
1759
1924
                                gdouble           radius_x,
1760
 
                                gdouble           radius_y)
 
1925
                                gdouble           radius_y,
 
1926
                                gdouble           angle)
1761
1927
{
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;
1770
1936
 
1771
 
  p1.x = cx - radius_x;
1772
 
  p1.y = cy;
 
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);
 
1941
 
 
1942
  gimp_coords_mix (1.0, center, 1.0, &dx, &p1);
1773
1943
  stroke = gimp_bezier_stroke_new_moveto (&p1);
1774
1944
 
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;
1779
 
  p3.x = cx;
1780
 
  p3.y = cy + radius_y;
1781
 
 
1782
 
  gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1783
 
 
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;
1789
 
  p3.y = cy;
1790
 
 
1791
 
  gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1792
 
 
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;
1797
 
  p3.x = cx;
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);
 
1947
 
 
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);
 
1952
 
 
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);
 
1957
 
 
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);
1799
1961
 
1800
1962
  gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
1801
1963
 
1802
1964
  handle = g_list_first (GIMP_STROKE (stroke)->anchors)->data;
1803
 
 
1804
 
  handle->position.x = cx - radius_x * circlemagic;
1805
 
  handle->position.y = cy - radius_y;
1806
 
 
1807
 
  handle = g_list_last (GIMP_STROKE (stroke)->anchors)->data;
1808
 
 
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);
1811
1966
 
1812
1967
  gimp_stroke_close (stroke);
1813
1968
 
1842
1997
 * a helper function that determines if a bezier segment is "straight
1843
1998
 * enough" to be approximated by a line.
1844
1999
 *
 
2000
 * To be more exact, it also checks for the control points to be distributed
 
2001
 * evenly along the line. This makes it easier to reconstruct parameters for
 
2002
 * a given point along the segment.
 
2003
 *
1845
2004
 * Needs four GimpCoords in an array.
1846
2005
 */
1847
2006
 
1849
2008
gimp_bezier_coords_is_straight (const GimpCoords *beziercoords,
1850
2009
                                gdouble           precision)
1851
2010
{
1852
 
  GimpCoords line, tan1, tan2, d1, d2;
1853
 
  gdouble    l2, s1, s2;
1854
 
 
1855
 
  gimp_coords_difference (&(beziercoords[3]),
1856
 
                          &(beziercoords[0]),
1857
 
                          &line);
1858
 
 
1859
 
  if (gimp_coords_length_squared (&line) < precision * precision)
1860
 
    {
1861
 
      gimp_coords_difference (&(beziercoords[1]),
1862
 
                              &(beziercoords[0]),
1863
 
                              &tan1);
1864
 
      gimp_coords_difference (&(beziercoords[2]),
1865
 
                              &(beziercoords[3]),
1866
 
                              &tan2);
1867
 
      if ((gimp_coords_length_squared (&tan1) < precision * precision) &&
1868
 
          (gimp_coords_length_squared (&tan2) < precision * precision))
1869
 
        {
1870
 
          return 1;
1871
 
        }
1872
 
      else
1873
 
        {
1874
 
          /* Tangents are too big for the small baseline */
1875
 
          return 0;
1876
 
        }
1877
 
    }
1878
 
  else
1879
 
    {
1880
 
      gimp_coords_difference (&(beziercoords[1]),
1881
 
                              &(beziercoords[0]),
1882
 
                              &tan1);
1883
 
      gimp_coords_difference (&(beziercoords[2]),
1884
 
                              &(beziercoords[0]),
1885
 
                              &tan2);
1886
 
 
1887
 
      l2 = gimp_coords_scalarprod (&line, &line);
1888
 
      s1 = gimp_coords_scalarprod (&line, &tan1) / l2;
1889
 
      s2 = gimp_coords_scalarprod (&line, &tan2) / l2;
1890
 
 
1891
 
      if (s1 < 0 || s1 > 1 || s2 < 0 || s2 > 1 || s2 < s1)
1892
 
        {
1893
 
          /* The tangents get projected outside the baseline */
1894
 
          return 0;
1895
 
        }
1896
 
 
1897
 
      gimp_coords_mix (1.0, &tan1, - s1, &line, &d1);
1898
 
      gimp_coords_mix (1.0, &tan2, - s2, &line, &d2);
1899
 
 
1900
 
      if ((gimp_coords_length_squared (&d1) > precision * precision) ||
1901
 
          (gimp_coords_length_squared (&d2) > precision * precision))
1902
 
        {
1903
 
          /* The control points are too far away from the baseline */
1904
 
          return 0;
1905
 
        }
1906
 
 
1907
 
      return 1;
1908
 
    }
 
2011
  GimpCoords pt1, pt2;
 
2012
 
 
2013
  /* calculate the "ideal" positions for the control points */
 
2014
 
 
2015
  gimp_coords_mix (2.0 / 3.0, &(beziercoords[0]),
 
2016
                   1.0 / 3.0, &(beziercoords[3]),
 
2017
                   &pt1);
 
2018
  gimp_coords_mix (1.0 / 3.0, &(beziercoords[0]),
 
2019
                   2.0 / 3.0, &(beziercoords[3]),
 
2020
                   &pt2);
 
2021
 
 
2022
  /* calculate the deviation of the actual control points */
 
2023
 
 
2024
  return (gimp_coords_manhattan_dist (&(beziercoords[1]), &pt1) < precision &&
 
2025
          gimp_coords_manhattan_dist (&(beziercoords[2]), &pt2) < precision);
1909
2026
}
1910
2027
 
1911
2028
 
1914
2031
static void
1915
2032
gimp_bezier_coords_subdivide (const GimpCoords  *beziercoords,
1916
2033
                              const gdouble      precision,
1917
 
                              GArray           **ret_coords)
 
2034
                              GArray           **ret_coords,
 
2035
                              GArray           **ret_params)
1918
2036
{
1919
 
  gimp_bezier_coords_subdivide2 (beziercoords, precision, ret_coords, 10);
 
2037
  gimp_bezier_coords_subdivide2 (beziercoords, 0.0, 1.0,
 
2038
                                 precision, ret_coords, ret_params, 10);
1920
2039
}
1921
2040
 
1922
2041
 
1923
2042
static void
1924
2043
gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords,
 
2044
                               const gdouble     start_t,
 
2045
                               const gdouble     end_t,
1925
2046
                               const gdouble     precision,
1926
2047
                               GArray          **ret_coords,
 
2048
                               GArray          **ret_params,
1927
2049
                               gint              depth)
1928
2050
{
1929
2051
  /*
1932
2054
   */
1933
2055
 
1934
2056
  GimpCoords subdivided[8];
 
2057
  gdouble middle_t = (start_t + end_t) / 2;
1935
2058
 
1936
2059
  subdivided[0] = beziercoords[0];
1937
2060
  subdivided[6] = beziercoords[3];
1938
2061
 
1939
 
  /* if (!depth) g_printerr ("Hit rekursion depth limit!\n"); */
 
2062
  /* if (!depth) g_printerr ("Hit recursion depth limit!\n"); */
1940
2063
 
1941
2064
  gimp_coords_average (&(beziercoords[0]), &(beziercoords[1]),
1942
2065
                       &(subdivided[1]));
1970
2093
                                                precision)) /* 1st half */
1971
2094
    {
1972
2095
      *ret_coords = g_array_append_vals (*ret_coords, &(subdivided[0]), 3);
 
2096
      if (ret_params)
 
2097
        {
 
2098
          gdouble params[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);
 
2103
        }
1973
2104
    }
1974
2105
  else
1975
2106
    {
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,
 
2109
                                     precision,
 
2110
                                     ret_coords, ret_params, depth-1);
1978
2111
    }
1979
2112
 
1980
2113
  if (!depth || gimp_bezier_coords_is_straight (&(subdivided[3]),
1981
2114
                                                precision)) /* 2nd half */
1982
2115
    {
1983
2116
      *ret_coords = g_array_append_vals (*ret_coords, &(subdivided[3]), 3);
 
2117
      if (ret_params)
 
2118
        {
 
2119
          gdouble params[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);
 
2124
        }
1984
2125
    }
1985
2126
  else
1986
2127
    {
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,
 
2130
                                     precision,
 
2131
                                     ret_coords, ret_params, depth-1);
1989
2132
    }
1990
2133
}
1991