Commit b7e1bb24 authored by Simon Budig's avatar Simon Budig Committed by Simon Budig

app/vectors/gimpanchor.h Anchors now have an enum as type and have the

2002-12-30  Simon Budig  <simon@gimp.org>

        * app/vectors/gimpanchor.h
        * app/vectors/vectors-types.h: Anchors now have an enum as type and
        have the "selected" property.

        * app/vectors/gimpstroke.[ch]
        * app/vectors/gimpbezierstroke.c
        * app/vectors/gimpvectors-preview.c: Additional functions to get
        information about the graphical representation of the stroke and be
        able to select anchors.

        * app/tools/gimpvectortool.c: semi-usable interface, better graphical
        representation of what is going on. Also make use of the "selected"
        property of the anhors to just display a subset of the control
        handles.
parent cbe1c44c
2002-12-30 Simon Budig <simon@gimp.org>
* app/vectors/gimpanchor.h
* app/vectors/vectors-types.h: Anchors now have an enum as type and
have the "selected" property.
* app/vectors/gimpstroke.[ch]
* app/vectors/gimpbezierstroke.c
* app/vectors/gimpvectors-preview.c: Additional functions to get
information about the graphical representation of the stroke and be
able to select anchors.
* app/tools/gimpvectortool.c: semi-usable interface, better graphical
representation of what is going on. Also make use of the "selected"
property of the anhors to just display a subset of the control
handles.
2002-12-30 Sven Neumann <sven@gimp.org>
* app/config/gimppluginconfig.[ch]
......
......@@ -113,7 +113,7 @@ gimp_vector_tool_register (GimpToolRegisterCallback callback,
FALSE,
"gimp-vector-tool",
_("Vectors"),
_("Vector angles and lengths"),
_("the most promising path tool prototype... :-)"),
N_("/Tools/Vectors"), NULL,
NULL, "tools/vector.html",
GIMP_STOCK_TOOL_PATH,
......@@ -266,13 +266,20 @@ gimp_vector_tool_button_press (GimpTool *tool,
GIMP_HANDLE_CIRCLE,
anchor->position.x,
anchor->position.y,
TARGET, TARGET,
TARGET,
TARGET,
GTK_ANCHOR_CENTER,
FALSE))
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (vector_tool));
vector_tool->function = VECTORS_MOVING;
vector_tool->cur_stroke = stroke;
vector_tool->cur_anchor = anchor;
if (anchor->type == ANCHOR_HANDLE)
gimp_stroke_anchor_select (stroke, anchor, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (vector_tool));
}
}
......@@ -292,6 +299,8 @@ gimp_vector_tool_button_press (GimpTool *tool,
vector_tool->cur_stroke = stroke;
vector_tool->cur_anchor = anchor;
gimp_stroke_anchor_select (stroke, anchor, TRUE);
vector_tool->function = VECTORS_MOVING;
/* set the gdisplay */
......@@ -316,7 +325,12 @@ gimp_vector_tool_button_press (GimpTool *tool,
}
anchor = gimp_bezier_stroke_extend (GIMP_BEZIER_STROKE (vector_tool->cur_stroke), coords, vector_tool->cur_anchor);
vector_tool->cur_anchor = anchor;
if (anchor)
{
vector_tool->cur_anchor = anchor;
if (anchor->type == ANCHOR_HANDLE)
gimp_stroke_anchor_select (stroke, anchor, TRUE);
}
/* set the gdisplay */
tool->gdisp = gdisp;
......@@ -374,7 +388,8 @@ gimp_vector_tool_motion (GimpTool *tool,
switch (vector_tool->function)
{
case VECTORS_MOVING:
/* if we are moving the start point and only have two, make it the end point */
/* if we are moving the start point and only have two,
* make it the end point */
anchor = vector_tool->cur_anchor;
if (anchor)
......@@ -413,7 +428,8 @@ gimp_vector_tool_cursor_update (GimpTool *tool,
GIMP_HANDLE_CIRCLE,
anchor->position.x,
anchor->position.y,
TARGET, TARGET,
TARGET,
TARGET,
GTK_ANCHOR_CENTER,
FALSE))
{
......@@ -438,6 +454,7 @@ gimp_vector_tool_draw (GimpDrawTool *draw_tool)
GimpVectors *vectors;
GArray *coords;
gboolean closed;
GList *draw_anchors, *ptr;
vector_tool = GIMP_VECTOR_TOOL (draw_tool);
tool = GIMP_TOOL (draw_tool);
......@@ -446,21 +463,70 @@ gimp_vector_tool_draw (GimpDrawTool *draw_tool)
while ((cur_stroke = gimp_vectors_stroke_get_next (vectors, cur_stroke)))
{
/* anchor handles */
cur_anchor = NULL;
while ((cur_anchor = gimp_stroke_anchor_get_next (cur_stroke, cur_anchor)))
draw_anchors = gimp_stroke_get_draw_anchors (cur_stroke);
ptr = draw_anchors;
while (ptr)
{
cur_anchor = (GimpAnchor *) ptr->data;
if (cur_anchor->type == ANCHOR_HANDLE)
{
gimp_draw_tool_draw_handle (draw_tool,
cur_anchor->selected ?
GIMP_HANDLE_CIRCLE:
GIMP_HANDLE_FILLED_CIRCLE,
cur_anchor->position.x,
cur_anchor->position.y,
TARGET,
TARGET,
GTK_ANCHOR_CENTER,
FALSE);
}
ptr = ptr->next;
}
g_list_free (draw_anchors);
/* control handles */
draw_anchors = gimp_stroke_get_draw_controls (cur_stroke,
vector_tool->cur_anchor);
ptr = draw_anchors;
while (ptr)
{
cur_anchor = (GimpAnchor *) ptr->data;
gimp_draw_tool_draw_handle (draw_tool,
GIMP_HANDLE_CIRCLE,
GIMP_HANDLE_SQUARE,
cur_anchor->position.x,
cur_anchor->position.y,
TARGET,
TARGET,
TARGET-1,
TARGET-1,
GTK_ANCHOR_CENTER,
FALSE);
ptr = ptr->next;
}
coords = gimp_stroke_interpolate (cur_stroke, 1.0, &closed);
g_printerr ("Got %d coords from gimp_stroke_interpolate\n", coords->len);
g_list_free (draw_anchors);
/* the lines to the control handles */
coords = gimp_stroke_get_draw_lines (cur_stroke, vector_tool->cur_anchor);
if (coords->len % 2 == 0)
{
gint i;
for (i=0; i < coords->len; i += 2)
gimp_draw_tool_draw_strokes (draw_tool,
&(g_array_index (coords, GimpCoords, i)),
2, FALSE, FALSE);
}
g_array_free (coords, TRUE);
/* the stroke itself */
coords = gimp_stroke_interpolate (cur_stroke, 1.0, &closed);
if (coords->len)
gimp_draw_tool_draw_strokes (draw_tool,
......
......@@ -27,7 +27,8 @@ struct _GimpAnchor
{
GimpCoords position;
gint type; /* Interpretation dependant on GimpStroke type */
GimpAnchorType type; /* Interpretation dependant on GimpStroke type */
gboolean selected;
};
#endif /* __GIMP_ANCHOR_H__ */
......@@ -30,15 +30,15 @@
#include "gimpbezierstroke.h"
#define INPUT_RESOLUTION 256
#define DETAIL 0.25
/* private variables */
static GimpStrokeClass *parent_class = NULL;
/* local prototypes */
static void gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass);
static void gimp_bezier_stroke_init (GimpBezierStroke *bezier_stroke);
......@@ -52,6 +52,44 @@ static void gimp_bezier_coords_subdivide (GimpCoords *beziercoords,
const gdouble precision,
GArray **ret_coords);
static void gimp_bezier_coords_mix (gdouble amul,
GimpCoords *a,
gdouble bmul,
GimpCoords *b,
GimpCoords *ret_val);
static void gimp_bezier_coords_average (GimpCoords *a,
GimpCoords *b,
GimpCoords *ret_average);
static void gimp_bezier_coords_difference (GimpCoords *a,
GimpCoords *b,
GimpCoords *ret_difference);
static void gimp_bezier_coords_scale (gdouble f,
GimpCoords *a,
GimpCoords *ret_multiply);
static void gimp_bezier_coords_subdivide (GimpCoords *beziercoords,
const gdouble precision,
GArray **ret_coords);
static void gimp_bezier_coords_subdivide2 (GimpCoords *beziercoords,
const gdouble precision,
GArray **ret_coords,
gint depth);
static gdouble gimp_bezier_coords_scalarprod (GimpCoords *a,
GimpCoords *b);
static gdouble gimp_bezier_coords_length (GimpCoords *a);
static gdouble gimp_bezier_coords_length2 (GimpCoords *a);
static gboolean gimp_bezier_coords_is_straight (GimpCoords *beziercoords,
gdouble precision);
GType
gimp_bezier_stroke_get_type (void)
{
......@@ -133,7 +171,8 @@ gimp_bezier_stroke_new (const GimpCoords *start)
g_printerr ("Adding at %f, %f\n", start->x, start->y);
anchor->type = 0; /* FIXME */
anchor->type = ANCHOR_HANDLE;
anchor->selected = FALSE;
stroke->anchors = g_list_append (stroke->anchors, anchor);
return stroke;
......@@ -177,62 +216,91 @@ gimp_bezier_stroke_extend (GimpBezierStroke *bezier_stroke,
GimpStroke *stroke;
GList *listneighbor;
gint loose_end;
GimpAnchorType ntype1 = -1, ntype2 = -1;
g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (bezier_stroke), NULL);
g_return_val_if_fail ((neighbor != NULL), NULL);
stroke = GIMP_STROKE (bezier_stroke);
listneighbor = g_list_last (stroke->anchors);
loose_end = 0;
if (listneighbor->data != neighbor)
listneighbor = g_list_last (stroke->anchors);
if (listneighbor->data == neighbor)
{
loose_end = 1;
}
else
{
listneighbor = g_list_first (stroke->anchors);
if (listneighbor->data != neighbor)
if (listneighbor->data == neighbor)
{
listneighbor = NULL;
loose_end = 0;
loose_end = -1;
}
else
{
loose_end = -1;
listneighbor = NULL;
loose_end = 0;
}
}
else
{
loose_end = 1;
}
if (loose_end)
{
anchor = g_new0 (GimpAnchor, 1);
anchor->position.x = coords->x;
anchor->position.y = coords->y;
anchor->position.pressure = 1;
anchor->position.pressure = 1.0;
anchor->position.xtilt = 0.5;
anchor->position.ytilt = 0.5;
anchor->position.wheel = 0.5;
/* FIXME */
if (((GimpAnchor *) listneighbor->data)->type == 0)
anchor->type = 1;
anchor->selected = FALSE;
/* We have to detect the type of the newly added point... */
ntype1 = ((GimpAnchor *) listneighbor->data)->type;
if (loose_end == 1 && listneighbor->prev)
{
ntype2 = ((GimpAnchor *) listneighbor->prev->data)->type;
}
else if (loose_end == -1 && listneighbor->next)
{
ntype2 = ((GimpAnchor *) listneighbor->next->data)->type;
}
else
{
anchor->type = CONTROL_HANDLE;
}
if (ntype1 == ANCHOR_HANDLE)
{
anchor->type = CONTROL_HANDLE;
}
else
anchor->type = 0;
{
if (ntype2 == CONTROL_HANDLE)
{
anchor->type = ANCHOR_HANDLE;
}
else
{
anchor->type = CONTROL_HANDLE;
}
}
g_printerr ("Extending at %f, %f, type %d\n", coords->x, coords->y, anchor->type);
}
else
anchor = NULL;
g_printerr ("Extending at %f, %f, type %d\n",
coords->x, coords->y, anchor->type);
if (loose_end == 1)
stroke->anchors = g_list_append (stroke->anchors, anchor);
if (loose_end == 1)
stroke->anchors = g_list_append (stroke->anchors, anchor);
if (loose_end == -1)
stroke->anchors = g_list_prepend (stroke->anchors, anchor);
if (loose_end == -1)
stroke->anchors = g_list_prepend (stroke->anchors, anchor);
return anchor;
}
else
return NULL; /* No loose end to add an anchor to... */
return anchor;
}
......@@ -254,8 +322,11 @@ gimp_bezier_stroke_interpolate (const GimpStroke *stroke,
count = 0;
for (anchorlist = stroke->anchors; anchorlist;
anchorlist = g_list_next (anchorlist))
for (anchorlist = stroke->anchors;
anchorlist && ((GimpAnchor *) anchorlist->data)->type != ANCHOR_HANDLE;
anchorlist = g_list_next (anchorlist));
for ( ; anchorlist; anchorlist = g_list_next (anchorlist))
{
anchor = anchorlist->data;
......@@ -394,7 +465,8 @@ gimp_bezier_coords_length (GimpCoords *a)
*/
static gboolean
gimp_bezier_coords_is_straight (GimpCoords *beziercoords)
gimp_bezier_coords_is_straight (GimpCoords *beziercoords,
gdouble precision)
{
GimpCoords line, tan1, tan2, d1, d2;
gdouble l2, s1, s2;
......@@ -403,7 +475,7 @@ gimp_bezier_coords_is_straight (GimpCoords *beziercoords)
&(beziercoords[0]),
&line);
if (gimp_bezier_coords_length2 (&line) < DETAIL * DETAIL)
if (gimp_bezier_coords_length2 (&line) < precision * precision)
{
gimp_bezier_coords_difference (&(beziercoords[1]),
&(beziercoords[0]),
......@@ -411,8 +483,8 @@ gimp_bezier_coords_is_straight (GimpCoords *beziercoords)
gimp_bezier_coords_difference (&(beziercoords[2]),
&(beziercoords[3]),
&tan2);
if ((gimp_bezier_coords_length2 (&tan1) < DETAIL * DETAIL) &&
(gimp_bezier_coords_length2 (&tan2) < DETAIL * DETAIL))
if ((gimp_bezier_coords_length2 (&tan1) < precision * precision) &&
(gimp_bezier_coords_length2 (&tan2) < precision * precision))
{
return 1;
}
......@@ -446,8 +518,8 @@ gimp_bezier_coords_is_straight (GimpCoords *beziercoords)
gimp_bezier_coords_mix (1.0, &tan1, - s1, &line, &d1);
gimp_bezier_coords_mix (1.0, &tan2, - s2, &line, &d2);
if ((gimp_bezier_coords_length2 (&d1) > DETAIL * DETAIL) ||
(gimp_bezier_coords_length2 (&d2) > DETAIL * DETAIL))
if ((gimp_bezier_coords_length2 (&d1) > precision * precision) ||
(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"); */
......@@ -505,8 +577,8 @@ gimp_bezier_coords_subdivide2 (GimpCoords *beziercoords,
* if the stroke is sufficiently close to a straight line.
*/
if (!depth ||
gimp_bezier_coords_is_straight (&(subdivided[0]))) /* 1st half */
if (!depth || gimp_bezier_coords_is_straight (&(subdivided[0]),
precision)) /* 1st half */
{
*ret_coords = g_array_append_vals (*ret_coords, &(subdivided[0]), 3);
}
......@@ -516,8 +588,8 @@ gimp_bezier_coords_subdivide2 (GimpCoords *beziercoords,
ret_coords, depth-1);
}
if (!depth ||
gimp_bezier_coords_is_straight (&(subdivided[3]))) /* 2nd half */
if (!depth || gimp_bezier_coords_is_straight (&(subdivided[3]),
precision)) /* 2nd half */
{
*ret_coords = g_array_append_vals (*ret_coords, &(subdivided[3]), 3);
}
......
......@@ -114,6 +114,10 @@ gimp_stroke_class_init (GimpStrokeClass *klass)
klass->temp_anchor_fix = NULL;
klass->make_bezier = NULL;
klass->get_draw_anchors = NULL;
klass->get_draw_controls = NULL;
klass->get_draw_lines = NULL;
}
static void
......@@ -214,6 +218,40 @@ gimp_stroke_real_anchor_get_next (const GimpStroke *stroke,
}
void
gimp_stroke_anchor_select (GimpStroke *stroke,
GimpAnchor *anchor,
gboolean exclusive)
{
GimpStrokeClass *stroke_class;
g_return_if_fail (GIMP_IS_STROKE (stroke));
stroke_class = GIMP_STROKE_GET_CLASS (stroke);
if (stroke_class->anchor_select)
stroke_class->anchor_select (stroke, anchor, exclusive);
else
{
GList *cur_ptr;
cur_ptr = stroke->anchors;
if (exclusive)
{
while (cur_ptr)
{
((GimpAnchor *) cur_ptr->data)->selected = FALSE;
cur_ptr = g_list_next (cur_ptr);
}
}
if ((cur_ptr = g_list_find (stroke->anchors, anchor)) != NULL)
((GimpAnchor *) cur_ptr->data)->selected = TRUE;
}
}
void
gimp_stroke_anchor_move_relative (GimpStroke *stroke,
GimpAnchor *anchor,
......@@ -431,4 +469,123 @@ gimp_stroke_make_bezier (const GimpStroke *stroke)
GList *
gimp_stroke_get_draw_anchors (const GimpStroke *stroke)
{
GimpStrokeClass *stroke_class;
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
stroke_class = GIMP_STROKE_GET_CLASS (stroke);
if (stroke_class->get_draw_anchors)
return stroke_class->get_draw_anchors (stroke);
else
{
GList *cur_ptr, *ret_list = NULL;
cur_ptr = stroke->anchors;
while (cur_ptr)
{
if (((GimpAnchor *) cur_ptr->data)->type == ANCHOR_HANDLE)
ret_list = g_list_append (ret_list, cur_ptr->data);
cur_ptr = g_list_next (cur_ptr);
}
return ret_list;
}
}
GList *
gimp_stroke_get_draw_controls (const GimpStroke *stroke,
const GimpAnchor *active)
{
GimpStrokeClass *stroke_class;
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
stroke_class = GIMP_STROKE_GET_CLASS (stroke);
if (stroke_class->get_draw_controls)
return stroke_class->get_draw_controls (stroke, active);
else
{
GList *cur_ptr, *ret_list = NULL;
cur_ptr = stroke->anchors;
while (cur_ptr)
{
if (((GimpAnchor *) cur_ptr->data)->type == CONTROL_HANDLE)
{
if (cur_ptr->next &&
((GimpAnchor *) cur_ptr->next->data)->type == ANCHOR_HANDLE &&
((GimpAnchor *) cur_ptr->next->data)->selected)
ret_list = g_list_append (ret_list, cur_ptr->data);
else if (cur_ptr->prev &&
((GimpAnchor *) cur_ptr->prev->data)->type == ANCHOR_HANDLE &&
((GimpAnchor *) cur_ptr->prev->data)->selected)
ret_list = g_list_append (ret_list, cur_ptr->data);
}
cur_ptr = g_list_next (cur_ptr);
}
return ret_list;
}
return NULL;
}
GArray *
gimp_stroke_get_draw_lines (const GimpStroke *stroke,
const GimpAnchor *active)
{
GimpStrokeClass *stroke_class;
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
stroke_class = GIMP_STROKE_GET_CLASS (stroke);
if (stroke_class->get_draw_lines)
return stroke_class->get_draw_lines (stroke, active);
else
{
GList *cur_ptr;
GArray *ret_lines = g_array_new (FALSE, FALSE, sizeof (GimpCoords));
cur_ptr = stroke->anchors;
while (cur_ptr)
{
if (((GimpAnchor *) cur_ptr->data)->type == ANCHOR_HANDLE &&
((GimpAnchor *) cur_ptr->data)->selected)
{
if (cur_ptr->next)
{
ret_lines = g_array_append_val (ret_lines,
((GimpAnchor *) cur_ptr->data)->position);
ret_lines = g_array_append_val (ret_lines,
((GimpAnchor *) cur_ptr->next->data)->position);
}
if (cur_ptr->prev)
{
ret_lines = g_array_append_val (ret_lines,
((GimpAnchor *) cur_ptr->data)->position);
ret_lines = g_array_append_val (ret_lines,
((GimpAnchor *) cur_ptr->prev->data)->position);
}
}
cur_ptr = g_list_next (cur_ptr);
}
return ret_lines;
}
}
......@@ -59,6 +59,10 @@ struct _GimpStrokeClass
GimpAnchor * (* anchor_get_next) (const GimpStroke *stroke,
const GimpAnchor *prev);
void (* anchor_select) (GimpStroke *stroke,
GimpAnchor *anchor,
gboolean exclusive);
void (* anchor_move_relative) (GimpStroke *stroke,
GimpAnchor *anchor,
const GimpCoords *deltacoord,
......@@ -82,7 +86,7 @@ struct _GimpStrokeClass
const gdouble precision,
gboolean *ret_closed);
GimpAnchor * (* temp_anchor_get) (const GimpStroke *stroke);
GimpAnchor * (* temp_anchor_set) (GimpStroke *stroke,
......@@ -92,6 +96,14 @@ struct _GimpStrokeClass
GimpStroke * (* make_bezier) (const GimpStroke *stroke);
GList * (* get_draw_anchors) (const GimpStroke *stroke);
GList * (* get_draw_controls) (const GimpStroke *stroke,
const GimpAnchor *active);
GArray * (* get_draw_lines) (const GimpStroke *stroke,
const GimpAnchor *active);
};
......@@ -103,26 +115,30 @@ GType gimp_stroke_get_type (void) G_GNUC_CONST;
/* accessing / modifying the anchors */
GimpAnchor * gimp_stroke_anchor_get (const GimpStroke *stroke,
const GimpCoords *coord);
const GimpCoords *coord);
/* prev == NULL: "first" anchor */
GimpAnchor * gimp_stroke_anchor_get_next (const GimpStroke *stroke,
const GimpAnchor *prev);
const GimpAnchor *prev);
void gimp_stroke_anchor_select (GimpStroke *stroke,
GimpAnchor *anchor,
gboolean exclusive);
/* type will be an xorable enum:
* VECTORS_NONE, VECTORS_FIX_ANGLE, VECTORS_FIX_RATIO, VECTORS_RESTRICT_ANGLE
* or so.
*/
void gimp_stroke_anchor_move_relative (GimpStroke *stroke,
GimpAnchor *anchor,
const GimpCoords *deltacoord,
const gint type);
GimpAnchor *anchor,
const GimpCoords *deltacoord,
const gint type);
void gimp_stroke_anchor_move_absolute (GimpStroke *stroke,
GimpAnchor *anchor,
const GimpCoords *coord,
const gint type);
GimpAnchor *anchor,
const GimpCoords *coord,
const gint type);
void gimp_stroke_anchor_delete (GimpStroke *stroke,
GimpAnchor *anchor);
......@@ -155,7 +171,15 @@ gboolean gimp_stroke_temp_anchor_fix (GimpStroke *stroke);
/* creates a bezier approximation. */
GimpStroke * gimp_stroke_make_bezier (const GimpStroke *stroke);
GimpStroke * gimp_stroke_make_bezier (const GimpStroke *stroke);
GList * gimp_stroke_get_draw_anchors (const GimpStroke *stroke);
GList * gimp_stroke_get_draw_controls (const GimpStroke *stroke,
const GimpAnchor *active);
GArray * gimp_stroke_get_draw_lines (const GimpStroke *stroke,
const GimpAnchor *active);
#endif /* __GIMP_STROKE_H__ */
......@@ -44,7 +44,7 @@ gimp_vectors_get_new_preview (GimpViewable *viewable,
GArray *coords;
GimpCoords point;
GimpStroke *cur_stroke = NULL;
gdouble xscale, yscale, xres, yres;
gdouble xscale, yscale;
gint x, y;
guchar *data;
gboolean closed;
......
......@@ -27,6 +27,12 @@
typedef struct _GimpAnchor GimpAnchor;
typedef enum
{
ANCHOR_HANDLE,
CONTROL_HANDLE,
} GimpAnchorType;
typedef struct _GimpStroke GimpStroke;