From 5ccd61bcb58ae67c9149911a55781e16423c9371 Mon Sep 17 00:00:00 2001 From: Simon Budig Date: Tue, 19 Aug 2003 01:05:48 +0000 Subject: [PATCH] app/vectors/gimpvectors.h removed temp_anchor stuff. I don't think that 2003-08-19 Simon Budig * app/vectors/gimpvectors.h * app/vectors/gimpstroke.[ch]: removed temp_anchor stuff. I don't think that this is needed. Added virtual function to determine the closest point on the curve to a given target point. * app/vectors/gimpbezierstroke.c: implemented gimp_bezier_stroke_nearest_point_get () - up to now untested and unused. --- ChangeLog | 11 ++ app/vectors/gimpbezierstroke.c | 236 ++++++++++++++++++++++++++++++--- app/vectors/gimpstroke.c | 91 +++---------- app/vectors/gimpstroke.h | 28 ++-- app/vectors/gimpvectors.h | 11 -- 5 files changed, 264 insertions(+), 113 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d28b1080b..e904863179 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-08-19 Simon Budig + + * app/vectors/gimpvectors.h + * app/vectors/gimpstroke.[ch]: removed temp_anchor stuff. I don't + think that this is needed. Added virtual function to determine the + closest point on the curve to a given target point. + + * app/vectors/gimpbezierstroke.c: implemented + gimp_bezier_stroke_nearest_point_get () - up to now untested and + unused. + 2003-08-19 Sven Neumann * libgimpwidgets/gimppickbutton.c: fixed color picking from other diff --git a/app/vectors/gimpbezierstroke.c b/app/vectors/gimpbezierstroke.c index 822a9e7acd..cc32473099 100644 --- a/app/vectors/gimpbezierstroke.c +++ b/app/vectors/gimpbezierstroke.c @@ -36,6 +36,19 @@ static void gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass); static void gimp_bezier_stroke_init (GimpBezierStroke *bezier_stroke); +static gdouble gimp_bezier_stroke_nearest_point_get (const GimpStroke *stroke, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + GimpAnchor **ret_segment_start, + gdouble *ret_pos); +static gdouble + gimp_bezier_stroke_segment_nearest_point_get (const GimpCoords *beziercoords, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + gdouble *ret_pos, + gint depth); static void gimp_bezier_stroke_anchor_move_relative (GimpStroke *stroke, GimpAnchor *anchor, const GimpCoords *deltacoord, @@ -71,7 +84,7 @@ static void gimp_bezier_coords_difference (const GimpCoords *a, GimpCoords *difference); static void gimp_bezier_coords_scale (const gdouble f, const GimpCoords *a, - GimpCoords *ret_multiply); + GimpCoords *ret_product); static void gimp_bezier_coords_subdivide (const GimpCoords *beziercoords, const gdouble precision, GArray **ret_coords); @@ -134,6 +147,7 @@ gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass) object_class->finalize = gimp_bezier_stroke_finalize; + stroke_class->nearest_point_get = gimp_bezier_stroke_nearest_point_get; stroke_class->anchor_move_relative = gimp_bezier_stroke_anchor_move_relative; stroke_class->anchor_move_absolute = gimp_bezier_stroke_anchor_move_absolute; stroke_class->anchor_convert = gimp_bezier_stroke_anchor_convert; @@ -207,6 +221,199 @@ gimp_bezier_stroke_new_from_coords (const GimpCoords *coords, return stroke; } +static gdouble +gimp_bezier_stroke_nearest_point_get (const GimpStroke *stroke, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + GimpAnchor **ret_segment_start, + gdouble *ret_pos) +{ + gdouble min_dist, dist, pos; + GimpCoords point; + GimpCoords segmentcoords[4]; + GList *anchorlist; + GimpAnchor *segment_start, *anchor; + gint count; + + g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), - 1.0); + + if (!stroke->anchors) + return -1.0; + + count = 0; + min_dist = -1; + + for (anchorlist = stroke->anchors; + anchorlist && ((GimpAnchor *) anchorlist->data)->type != GIMP_ANCHOR_ANCHOR; + anchorlist = g_list_next (anchorlist)); + + segment_start = anchorlist->data; + + for ( ; anchorlist; anchorlist = g_list_next (anchorlist)) + { + anchor = anchorlist->data; + + segmentcoords[count] = anchor->position; + count++; + + if (count == 4) + { + dist = gimp_bezier_stroke_segment_nearest_point_get (segmentcoords, + coord, precision, + &point, &pos, + 10); + + if (dist < min_dist || min_dist < 0) + { + min_dist = dist; + if (ret_pos) + *ret_pos = pos; + if (ret_point) + *ret_point = point; + if (ret_segment_start) + *ret_segment_start = segment_start; + } + segment_start = anchorlist->data; + segmentcoords[0] = segmentcoords[3]; + count = 1; + } + } + + if (stroke->closed && stroke->anchors) + { + anchorlist = stroke->anchors; + + while (count < 3) + { + segmentcoords[count] = ((GimpAnchor *) anchorlist->data)->position; + count++; + } + anchorlist = g_list_next (anchorlist); + if (anchorlist) + segmentcoords[3] = ((GimpAnchor *) anchorlist->data)->position; + + dist = gimp_bezier_stroke_segment_nearest_point_get (segmentcoords, + coord, precision, + &point, &pos, + 10); + + if (dist < min_dist || min_dist < 0) + { + min_dist = dist; + if (ret_pos) + *ret_pos = pos; + if (ret_point) + *ret_point = point; + if (ret_segment_start) + *ret_segment_start = segment_start; + } + } + + return min_dist; +} + + +static gdouble +gimp_bezier_stroke_segment_nearest_point_get (const GimpCoords *beziercoords, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + gdouble *ret_pos, + gint depth) +{ + /* + * beziercoords has to contain four GimpCoords with the four control points + * of the bezier segment. We subdivide it at the parameter 0.5. + */ + + GimpCoords subdivided[8]; + gdouble dist1, dist2; + GimpCoords point1, point2; + gdouble pos1, pos2; + + if (!depth || gimp_bezier_coords_is_straight (beziercoords, precision)) + { + GimpCoords line, dcoord; + gdouble length2, scalar; + + gimp_bezier_coords_difference (&(beziercoords[3]), + &(beziercoords[0]), + &line); + + gimp_bezier_coords_difference (coord, + &(beziercoords[0]), + &dcoord); + + length2 = gimp_bezier_coords_scalarprod (&line, &line); + scalar = gimp_bezier_coords_scalarprod (&line, &dcoord) / length2; + + scalar = CLAMP (scalar, 0.0, 1.0); + *ret_pos = scalar; + + gimp_bezier_coords_mix (1.0, &(beziercoords[0]), + scalar, &line, + ret_point); + + gimp_bezier_coords_difference (coord, ret_point, &dcoord); + + return gimp_bezier_coords_length (&dcoord); + } + + /* ok, we have to subdivide */ + + subdivided[0] = beziercoords[0]; + subdivided[6] = beziercoords[3]; + + if (!depth) g_printerr ("Hit rekursion depth limit!\n"); + + gimp_bezier_coords_average (&(beziercoords[0]), &(beziercoords[1]), + &(subdivided[1])); + + gimp_bezier_coords_average (&(beziercoords[1]), &(beziercoords[2]), + &(subdivided[7])); + + gimp_bezier_coords_average (&(beziercoords[2]), &(beziercoords[3]), + &(subdivided[5])); + + gimp_bezier_coords_average (&(subdivided[1]), &(subdivided[7]), + &(subdivided[2])); + + gimp_bezier_coords_average (&(subdivided[7]), &(subdivided[5]), + &(subdivided[4])); + + gimp_bezier_coords_average (&(subdivided[2]), &(subdivided[4]), + &(subdivided[3])); + + /* + * We now have the coordinates of the two bezier segments in + * subdivided [0-3] and subdivided [3-6] + */ + + dist1 = gimp_bezier_stroke_segment_nearest_point_get (&(subdivided[0]), + coord, precision, + &point1, &pos1, + depth - 1); + + dist2 = gimp_bezier_stroke_segment_nearest_point_get (&(subdivided[3]), + coord, precision, + &point2, &pos2, + depth - 1); + + if (dist1 <= dist2) + { + *ret_point = point1; + *ret_pos = 0.5 * pos1; + return dist1; + } + else + { + *ret_point = point2; + *ret_pos = 0.5 + 0.5 * pos2; + return dist2; + } +} + static gboolean gimp_bezier_stroke_is_extendable (GimpStroke *stroke, @@ -780,9 +987,9 @@ gimp_bezier_coords_difference (const GimpCoords *a, static void gimp_bezier_coords_scale (const gdouble f, const GimpCoords *a, - GimpCoords *ret_multiply) + GimpCoords *ret_product) { - gimp_bezier_coords_mix (f, a, 0.0, NULL, ret_multiply); + gimp_bezier_coords_mix (f, a, 0.0, NULL, ret_product); } @@ -864,7 +1071,6 @@ gimp_bezier_coords_is_straight (const GimpCoords *beziercoords, else { /* Tangents are too big for the small baseline */ - /* g_printerr ("Zu grosse Tangenten bei zu kleiner Basislinie\n"); */ return 0; } } @@ -884,7 +1090,6 @@ gimp_bezier_coords_is_straight (const GimpCoords *beziercoords, if (s1 < 0 || s1 > 1 || s2 < 0 || s2 > 1 || s2 < s1) { /* The tangents get projected outside the baseline */ - /* g_printerr ("Tangenten projezieren sich ausserhalb der Basisline\n"); */ return 0; } @@ -895,7 +1100,6 @@ gimp_bezier_coords_is_straight (const GimpCoords *beziercoords, (gimp_bezier_coords_length2 (&d2) > precision * precision)) { /* The control points are too far away from the baseline */ - /* g_printerr ("Zu grosser Abstand zur Basislinie\n"); */ return 0; } @@ -904,6 +1108,15 @@ gimp_bezier_coords_is_straight (const GimpCoords *beziercoords, } +static void +gimp_bezier_coords_subdivide (const GimpCoords *beziercoords, + const gdouble precision, + GArray **ret_coords) +{ + gimp_bezier_coords_subdivide2 (beziercoords, precision, ret_coords, 10); +} + + static void gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords, const gdouble precision, @@ -971,15 +1184,4 @@ gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords, gimp_bezier_coords_subdivide2 (&(subdivided[3]), precision, ret_coords, depth-1); } - - /* g_printerr ("gimp_bezier_coords_subdivide end: %d entries\n", (*ret_coords)->len); */ -} - - -static void -gimp_bezier_coords_subdivide (const GimpCoords *beziercoords, - const gdouble precision, - GArray **ret_coords) -{ - gimp_bezier_coords_subdivide2 (beziercoords, precision, ret_coords, 10); } diff --git a/app/vectors/gimpstroke.c b/app/vectors/gimpstroke.c index 59e163177c..367122e262 100644 --- a/app/vectors/gimpstroke.c +++ b/app/vectors/gimpstroke.c @@ -76,10 +76,6 @@ static gdouble gimp_stroke_real_get_distance (const GimpStroke *stroke, static GArray * gimp_stroke_real_interpolate (const GimpStroke *stroke, gdouble precision, gboolean *closed); -static GimpAnchor * gimp_stroke_real_temp_anchor_get (const GimpStroke *stroke); -static GimpAnchor * gimp_stroke_real_temp_anchor_set (GimpStroke *stroke, - const GimpCoords *coord); -static gboolean gimp_stroke_real_temp_anchor_fix (GimpStroke *stroke); static GimpStroke * gimp_stroke_real_duplicate (const GimpStroke *stroke); static GimpStroke * gimp_stroke_real_make_bezier (const GimpStroke *stroke); @@ -176,10 +172,6 @@ gimp_stroke_class_init (GimpStrokeClass *klass) klass->get_distance = gimp_stroke_real_get_distance; klass->interpolate = gimp_stroke_real_interpolate; - klass->temp_anchor_get = gimp_stroke_real_temp_anchor_get; - klass->temp_anchor_set = gimp_stroke_real_temp_anchor_set; - klass->temp_anchor_fix = gimp_stroke_real_temp_anchor_fix; - klass->duplicate = gimp_stroke_real_duplicate; klass->make_bezier = gimp_stroke_real_make_bezier; @@ -199,7 +191,6 @@ static void gimp_stroke_init (GimpStroke *stroke) { stroke->anchors = NULL; - stroke->temp_anchor = NULL; stroke->closed = FALSE; } @@ -214,9 +205,6 @@ gimp_stroke_finalize (GObject *object) for (list = stroke->anchors; list; list = list->next) gimp_anchor_free ((GimpAnchor *) list->data); - if (stroke->temp_anchor) - gimp_anchor_free (stroke->temp_anchor); - G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -244,6 +232,26 @@ gimp_stroke_anchor_get (const GimpStroke *stroke, return GIMP_STROKE_GET_CLASS (stroke)->anchor_get (stroke, coord); } + +gdouble +gimp_stroke_nearest_point_get (const GimpStroke *stroke, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + GimpAnchor **ret_segment_start, + gdouble *ret_pos) +{ + g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE); + g_return_val_if_fail (coord != NULL, FALSE); + + return GIMP_STROKE_GET_CLASS (stroke)->nearest_point_get (stroke, + coord, + precision, + ret_point, + ret_segment_start, + ret_pos); +} + static GimpAnchor * gimp_stroke_real_anchor_get (const GimpStroke *stroke, const GimpCoords *coord) @@ -548,60 +556,6 @@ gimp_stroke_real_interpolate (const GimpStroke *stroke, return NULL; } - -GimpAnchor * -gimp_stroke_temp_anchor_get (const GimpStroke *stroke) -{ - g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL); - - return GIMP_STROKE_GET_CLASS (stroke)->temp_anchor_get (stroke); -} - -static GimpAnchor * -gimp_stroke_real_temp_anchor_get (const GimpStroke *stroke) -{ - g_printerr ("gimp_stroke_temp_anchor_get: default implementation\n"); - - return NULL; -} - - -GimpAnchor * -gimp_stroke_temp_anchor_set (GimpStroke *stroke, - const GimpCoords *coord) -{ - g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL); - - return GIMP_STROKE_GET_CLASS (stroke)->temp_anchor_set (stroke, coord); -} - -static GimpAnchor * -gimp_stroke_real_temp_anchor_set (GimpStroke *stroke, - const GimpCoords *coord) -{ - g_printerr ("gimp_stroke_temp_anchor_set: default implementation\n"); - - return NULL; -} - - -gboolean -gimp_stroke_temp_anchor_fix (GimpStroke *stroke) -{ - g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE); - - return GIMP_STROKE_GET_CLASS (stroke)->temp_anchor_fix (stroke); -} - -static gboolean -gimp_stroke_real_temp_anchor_fix (GimpStroke *stroke) -{ - g_printerr ("gimp_stroke_temp_anchor_fix: default implementation\n"); - - return FALSE; -} - - GimpStroke * gimp_stroke_duplicate (const GimpStroke *stroke) { @@ -627,11 +581,6 @@ gimp_stroke_real_duplicate (const GimpStroke *stroke) list->data = gimp_anchor_duplicate ((GimpAnchor *) list->data); } - if (stroke->temp_anchor) - { - new_stroke->temp_anchor = gimp_anchor_duplicate (stroke->temp_anchor); - } - return new_stroke; } diff --git a/app/vectors/gimpstroke.h b/app/vectors/gimpstroke.h index 3d88122ca2..1ed93ddc61 100644 --- a/app/vectors/gimpstroke.h +++ b/app/vectors/gimpstroke.h @@ -40,7 +40,6 @@ struct _GimpStroke GList *anchors; - GimpAnchor *temp_anchor; gboolean closed; }; @@ -54,6 +53,12 @@ struct _GimpStrokeClass GimpAnchor * (* anchor_get) (const GimpStroke *stroke, const GimpCoords *coord); + gdouble (* nearest_point_get) (const GimpStroke *stroke, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + GimpAnchor **ret_segment_start, + gdouble *ret_pos); GimpAnchor * (* anchor_get_next) (const GimpStroke *stroke, const GimpAnchor *prev); void (* anchor_select) (GimpStroke *stroke, @@ -89,11 +94,6 @@ struct _GimpStrokeClass const gdouble precision, gboolean *ret_closed); - GimpAnchor * (* temp_anchor_get) (const GimpStroke *stroke); - GimpAnchor * (* temp_anchor_set) (GimpStroke *stroke, - const GimpCoords *coord); - gboolean (* temp_anchor_fix) (GimpStroke *stroke); - GimpStroke * (* duplicate) (const GimpStroke *stroke); GimpStroke * (* make_bezier) (const GimpStroke *stroke); @@ -146,6 +146,14 @@ GType gimp_stroke_get_type (void) G_GNUC_CONST; GimpAnchor * gimp_stroke_anchor_get (const GimpStroke *stroke, const GimpCoords *coord); +gdouble gimp_stroke_nearest_point_get (const GimpStroke *stroke, + const GimpCoords *coord, + const gdouble precision, + GimpCoords *ret_point, + GimpAnchor **ret_segment_start, + gdouble *ret_pos); + + /* prev == NULL: "first" anchor */ GimpAnchor * gimp_stroke_anchor_get_next (const GimpStroke *stroke, const GimpAnchor *prev); @@ -196,14 +204,6 @@ GArray * gimp_stroke_interpolate (const GimpStroke *stroke, gdouble precision, gboolean *closed); - -/* Allow a singular temorary anchor (marking the "working point")? */ - -GimpAnchor * gimp_stroke_temp_anchor_get (const GimpStroke *stroke); -GimpAnchor * gimp_stroke_temp_anchor_set (GimpStroke *stroke, - const GimpCoords *coord); -gboolean gimp_stroke_temp_anchor_fix (GimpStroke *stroke); - GimpStroke * gimp_stroke_duplicate (const GimpStroke *stroke); /* creates a bezier approximation. */ diff --git a/app/vectors/gimpvectors.h b/app/vectors/gimpvectors.h index e96320c009..2f084fea09 100644 --- a/app/vectors/gimpvectors.h +++ b/app/vectors/gimpvectors.h @@ -154,17 +154,6 @@ gint gimp_vectors_interpolate (const GimpVectors *vectors, gint max_points, GimpCoords *ret_coords); - -/* Allow a singular temorary anchor (marking the "working point")? */ - -GimpAnchor * gimp_vectors_temp_anchor_get (const GimpVectors *vectors); - -GimpAnchor * gimp_vectors_temp_anchor_set (GimpVectors *vectors, - const GimpCoords *coord); - -gboolean gimp_vectors_temp_anchor_fix (GimpVectors *vectors); - - /* usually overloaded */ /* creates a bezier approximation. */