app/vectors/gimpvectors.h removed temp_anchor stuff. I don't think that

2003-08-19  Simon Budig  <simon@gimp.org>

        * 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.
This commit is contained in:
Simon Budig 2003-08-19 01:05:48 +00:00 committed by Simon Budig
parent 180aacb96b
commit 5ccd61bcb5
5 changed files with 264 additions and 113 deletions

View File

@ -1,3 +1,14 @@
2003-08-19 Simon Budig <simon@gimp.org>
* 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 <sven@gimp.org>
* libgimpwidgets/gimppickbutton.c: fixed color picking from other

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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. */

View File

@ -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. */