2002-02-25 11:16:41 +08:00
|
|
|
/* The GIMP -- an image manipulation program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* gimpstroke.c
|
|
|
|
* Copyright (C) 2002 Simon Budig <simon@gimp.org>
|
2003-07-18 02:06:32 +08:00
|
|
|
*
|
2002-02-25 11:16:41 +08:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2003-09-07 00:39:08 +08:00
|
|
|
#include <libart_lgpl/libart.h>
|
|
|
|
|
2003-09-07 02:40:48 +08:00
|
|
|
#include <glib-object.h>
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
#include "vectors-types.h"
|
|
|
|
|
2003-08-08 01:05:14 +08:00
|
|
|
#include "core/gimpdrawable-transform-utils.h"
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
#include "gimpanchor.h"
|
|
|
|
#include "gimpstroke.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* Prototypes */
|
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
static void gimp_stroke_class_init (GimpStrokeClass *klass);
|
|
|
|
static void gimp_stroke_init (GimpStroke *stroke);
|
|
|
|
static void gimp_stroke_finalize (GObject *object);
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
static gsize gimp_stroke_get_memsize (GimpObject *object,
|
2003-08-25 18:49:33 +08:00
|
|
|
gsize *gui_size);
|
2003-02-01 02:08:32 +08:00
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
static gdouble gimp_stroke_real_nearest_point_get (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
const gdouble precision,
|
|
|
|
GimpCoords *ret_point,
|
|
|
|
GimpAnchor **ret_segment_start,
|
|
|
|
gdouble *ret_pos);
|
2002-02-25 11:16:41 +08:00
|
|
|
static GimpAnchor * gimp_stroke_real_anchor_get (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord);
|
|
|
|
static GimpAnchor * gimp_stroke_real_anchor_get_next (const GimpStroke *stroke,
|
|
|
|
const GimpAnchor *prev);
|
2003-05-17 00:49:04 +08:00
|
|
|
static void gimp_stroke_real_anchor_select (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
gboolean exclusive);
|
|
|
|
static void gimp_stroke_real_anchor_move_relative (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
const GimpCoords *delta,
|
|
|
|
GimpAnchorFeatureType feature);
|
|
|
|
static void gimp_stroke_real_anchor_move_absolute (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
const GimpCoords *delta,
|
|
|
|
GimpAnchorFeatureType feature);
|
|
|
|
static void gimp_stroke_real_anchor_convert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpAnchorFeatureType feature);
|
|
|
|
static void gimp_stroke_real_anchor_delete (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor);
|
2003-08-26 08:27:03 +08:00
|
|
|
static gboolean gimp_stroke_real_point_is_movable
|
|
|
|
(GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position);
|
|
|
|
static void gimp_stroke_real_point_move_relative
|
|
|
|
(GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *deltacoord,
|
|
|
|
GimpAnchorFeatureType feature);
|
|
|
|
static void gimp_stroke_real_point_move_absolute
|
|
|
|
(GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
GimpAnchorFeatureType feature);
|
|
|
|
|
2003-09-01 08:39:47 +08:00
|
|
|
static void gimp_stroke_real_close (GimpStroke *stroke);
|
2003-08-22 09:12:26 +08:00
|
|
|
static GimpStroke * gimp_stroke_real_open (GimpStroke *stroke,
|
|
|
|
GimpAnchor *end_anchor);
|
2003-08-21 01:29:13 +08:00
|
|
|
static gboolean gimp_stroke_real_anchor_is_insertable
|
|
|
|
(GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position);
|
|
|
|
static GimpAnchor * gimp_stroke_real_anchor_insert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position);
|
2003-08-17 10:49:24 +08:00
|
|
|
|
|
|
|
static gboolean gimp_stroke_real_is_extendable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *neighbor);
|
|
|
|
|
2003-08-27 08:31:20 +08:00
|
|
|
static GimpAnchor * gimp_stroke_real_extend (GimpStroke *stroke,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GimpAnchor *neighbor,
|
|
|
|
GimpVectorExtendMode extend_mode);
|
|
|
|
|
|
|
|
gboolean gimp_stroke_real_connect_stroke (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpStroke *extension,
|
|
|
|
GimpAnchor *neighbor);
|
|
|
|
|
2003-08-17 10:49:24 +08:00
|
|
|
|
2003-08-22 01:47:12 +08:00
|
|
|
static gboolean gimp_stroke_real_is_empty (const GimpStroke *stroke);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static gdouble gimp_stroke_real_get_length (const GimpStroke *stroke);
|
|
|
|
static gdouble gimp_stroke_real_get_distance (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord);
|
|
|
|
static GArray * gimp_stroke_real_interpolate (const GimpStroke *stroke,
|
|
|
|
gdouble precision,
|
|
|
|
gboolean *closed);
|
|
|
|
static GimpStroke * gimp_stroke_real_duplicate (const GimpStroke *stroke);
|
|
|
|
static GimpStroke * gimp_stroke_real_make_bezier (const GimpStroke *stroke);
|
2003-08-08 01:05:14 +08:00
|
|
|
|
|
|
|
static void gimp_stroke_real_translate (GimpStroke *stroke,
|
|
|
|
gdouble offset_x, gdouble offset_y);
|
|
|
|
static void gimp_stroke_real_scale (GimpStroke *stroke,
|
|
|
|
gdouble scale_x, gdouble scale_y,
|
|
|
|
gint offset_x, gint offset_y);
|
|
|
|
static void gimp_stroke_real_resize (GimpStroke *stroke,
|
|
|
|
gint new_width, gint new_height,
|
|
|
|
gint offset_x, gint offset_y);
|
|
|
|
static void gimp_stroke_real_flip (GimpStroke *stroke,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis, gboolean clip_result);
|
|
|
|
static void gimp_stroke_real_rotate (GimpStroke *stroke,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x, gdouble center_y,
|
|
|
|
gboolean clip_result);
|
|
|
|
static void gimp_stroke_real_transform (GimpStroke *stroke,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interp_type,
|
|
|
|
gboolean clip_result,
|
|
|
|
GimpProgressFunc progress_callback,
|
|
|
|
gpointer progress_data);
|
|
|
|
|
2003-09-07 04:00:38 +08:00
|
|
|
static GList * gimp_stroke_real_get_draw_anchors (const GimpStroke *stroke);
|
2003-05-17 00:49:04 +08:00
|
|
|
static GList * gimp_stroke_real_get_draw_controls (const GimpStroke *stroke);
|
2003-09-07 04:00:38 +08:00
|
|
|
static GArray * gimp_stroke_real_get_draw_lines (const GimpStroke *stroke);
|
|
|
|
|
|
|
|
static void gimp_stroke_real_to_art_point (const GimpStroke *vectors,
|
|
|
|
ArtVpath *vec);
|
2003-05-17 00:49:04 +08:00
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
/* private variables */
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GimpObjectClass *parent_class = NULL;
|
2003-02-01 02:08:32 +08:00
|
|
|
|
|
|
|
|
2002-02-25 21:39:34 +08:00
|
|
|
GType
|
|
|
|
gimp_stroke_get_type (void)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2002-02-25 21:39:34 +08:00
|
|
|
static GType stroke_type = 0;
|
|
|
|
|
|
|
|
if (! stroke_type)
|
|
|
|
{
|
|
|
|
static const GTypeInfo stroke_info =
|
|
|
|
{
|
|
|
|
sizeof (GimpStrokeClass),
|
|
|
|
(GBaseInitFunc) NULL,
|
|
|
|
(GBaseFinalizeFunc) NULL,
|
|
|
|
(GClassInitFunc) gimp_stroke_class_init,
|
|
|
|
NULL, /* class_finalize */
|
|
|
|
NULL, /* class_data */
|
|
|
|
sizeof (GimpStroke),
|
|
|
|
0, /* n_preallocs */
|
|
|
|
(GInstanceInitFunc) gimp_stroke_init,
|
|
|
|
};
|
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
stroke_type = g_type_register_static (GIMP_TYPE_OBJECT,
|
2003-07-18 02:06:32 +08:00
|
|
|
"GimpStroke",
|
2002-02-25 21:39:34 +08:00
|
|
|
&stroke_info, 0);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2002-02-25 21:39:34 +08:00
|
|
|
return stroke_type;
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_class_init (GimpStrokeClass *klass)
|
|
|
|
{
|
2003-02-01 02:08:32 +08:00
|
|
|
GObjectClass *object_class;
|
|
|
|
GimpObjectClass *gimp_object_class;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
2003-02-01 02:08:32 +08:00
|
|
|
gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
object_class->finalize = gimp_stroke_finalize;
|
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_stroke_get_memsize;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
klass->changed = NULL;
|
|
|
|
klass->removed = NULL;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
klass->anchor_get = gimp_stroke_real_anchor_get;
|
|
|
|
klass->anchor_get_next = gimp_stroke_real_anchor_get_next;
|
2003-05-17 00:49:04 +08:00
|
|
|
klass->anchor_select = gimp_stroke_real_anchor_select;
|
2003-02-01 02:08:32 +08:00
|
|
|
klass->anchor_move_relative = gimp_stroke_real_anchor_move_relative;
|
|
|
|
klass->anchor_move_absolute = gimp_stroke_real_anchor_move_absolute;
|
2003-05-17 00:49:04 +08:00
|
|
|
klass->anchor_convert = gimp_stroke_real_anchor_convert;
|
|
|
|
klass->anchor_delete = gimp_stroke_real_anchor_delete;
|
2003-08-22 09:12:26 +08:00
|
|
|
|
2003-08-26 08:27:03 +08:00
|
|
|
klass->point_is_movable = gimp_stroke_real_point_is_movable;
|
|
|
|
klass->point_move_relative = gimp_stroke_real_point_move_relative;
|
|
|
|
klass->point_move_absolute = gimp_stroke_real_point_move_absolute;
|
|
|
|
|
|
|
|
klass->nearest_point_get = gimp_stroke_real_nearest_point_get;
|
2003-09-01 08:39:47 +08:00
|
|
|
klass->close = gimp_stroke_real_close;
|
2003-08-22 09:12:26 +08:00
|
|
|
klass->open = gimp_stroke_real_open;
|
2003-08-21 01:29:13 +08:00
|
|
|
klass->anchor_is_insertable = gimp_stroke_real_anchor_is_insertable;
|
|
|
|
klass->anchor_insert = gimp_stroke_real_anchor_insert;
|
2003-08-17 10:49:24 +08:00
|
|
|
klass->is_extendable = gimp_stroke_real_is_extendable;
|
|
|
|
klass->extend = gimp_stroke_real_extend;
|
2003-08-27 08:31:20 +08:00
|
|
|
klass->connect_stroke = gimp_stroke_real_connect_stroke;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-08-22 01:47:12 +08:00
|
|
|
klass->is_empty = gimp_stroke_real_is_empty;
|
2003-05-17 00:49:04 +08:00
|
|
|
klass->get_length = gimp_stroke_real_get_length;
|
|
|
|
klass->get_distance = gimp_stroke_real_get_distance;
|
|
|
|
klass->interpolate = gimp_stroke_real_interpolate;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-04-14 08:37:04 +08:00
|
|
|
klass->duplicate = gimp_stroke_real_duplicate;
|
2003-05-17 00:49:04 +08:00
|
|
|
klass->make_bezier = gimp_stroke_real_make_bezier;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-08-08 01:05:14 +08:00
|
|
|
klass->translate = gimp_stroke_real_translate;
|
|
|
|
klass->scale = gimp_stroke_real_scale;
|
|
|
|
klass->resize = gimp_stroke_real_resize;
|
|
|
|
klass->flip = gimp_stroke_real_flip;
|
|
|
|
klass->rotate = gimp_stroke_real_rotate;
|
|
|
|
klass->transform = gimp_stroke_real_transform;
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
klass->get_draw_anchors = gimp_stroke_real_get_draw_anchors;
|
|
|
|
klass->get_draw_controls = gimp_stroke_real_get_draw_controls;
|
|
|
|
klass->get_draw_lines = gimp_stroke_real_get_draw_lines;
|
2003-09-07 00:39:08 +08:00
|
|
|
|
2003-09-07 04:00:38 +08:00
|
|
|
klass->to_art_point = gimp_stroke_real_to_art_point;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_init (GimpStroke *stroke)
|
|
|
|
{
|
2003-04-14 08:37:04 +08:00
|
|
|
stroke->anchors = NULL;
|
2003-05-17 00:49:04 +08:00
|
|
|
stroke->closed = FALSE;
|
2003-07-03 02:01:19 +08:00
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2002-02-25 21:39:34 +08:00
|
|
|
static void
|
|
|
|
gimp_stroke_finalize (GObject *object)
|
|
|
|
{
|
2003-09-02 21:43:26 +08:00
|
|
|
GimpStroke *stroke = GIMP_STROKE (object);
|
2003-05-17 00:49:04 +08:00
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
if (stroke->anchors)
|
|
|
|
{
|
|
|
|
g_list_foreach (stroke->anchors, (GFunc) gimp_anchor_free, NULL);
|
|
|
|
g_list_free (stroke->anchors);
|
|
|
|
stroke->anchors = NULL;
|
|
|
|
}
|
2003-08-27 08:31:20 +08:00
|
|
|
|
2002-02-25 21:39:34 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
static gsize
|
2003-08-25 18:49:33 +08:00
|
|
|
gimp_stroke_get_memsize (GimpObject *object,
|
|
|
|
gsize *gui_size)
|
2003-02-01 02:08:32 +08:00
|
|
|
{
|
|
|
|
GimpStroke *stroke;
|
|
|
|
gsize memsize = 0;
|
|
|
|
|
|
|
|
stroke = GIMP_STROKE (object);
|
|
|
|
|
|
|
|
memsize += g_list_length (stroke->anchors) * (sizeof (GList) +
|
|
|
|
sizeof (GimpAnchor));
|
|
|
|
|
2003-08-25 18:49:33 +08:00
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
2003-02-01 02:08:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
GimpAnchor *
|
|
|
|
gimp_stroke_anchor_get (const GimpStroke *stroke,
|
2003-05-19 07:08:01 +08:00
|
|
|
const GimpCoords *coord)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->anchor_get (stroke, coord);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
2003-08-19 09:05:48 +08:00
|
|
|
|
|
|
|
gdouble
|
2003-08-26 08:27:03 +08:00
|
|
|
gimp_stroke_nearest_point_get (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
const gdouble precision,
|
|
|
|
GimpCoords *ret_point,
|
|
|
|
GimpAnchor **ret_segment_start,
|
|
|
|
gdouble *ret_pos)
|
2003-08-19 09:05:48 +08:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
static gdouble
|
2003-08-26 08:27:03 +08:00
|
|
|
gimp_stroke_real_nearest_point_get (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
const gdouble precision,
|
|
|
|
GimpCoords *ret_point,
|
|
|
|
GimpAnchor **ret_segment_start,
|
|
|
|
gdouble *ret_pos)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_nearest_point_get: default implementation\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
static GimpAnchor *
|
|
|
|
gimp_stroke_real_anchor_get (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord)
|
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
gdouble dx, dy;
|
|
|
|
gdouble mindist = -1;
|
|
|
|
GList *anchors;
|
2002-02-25 11:16:41 +08:00
|
|
|
GList *list;
|
|
|
|
GimpAnchor *anchor = NULL;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
anchors = gimp_stroke_get_draw_controls (stroke);
|
2002-12-31 11:18:49 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = anchors; list; list = g_list_next (list))
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2003-08-26 22:29:10 +08:00
|
|
|
dx = coord->x - GIMP_ANCHOR (list->data)->position.x;
|
|
|
|
dy = coord->y - GIMP_ANCHOR (list->data)->position.y;
|
2003-05-17 00:49:04 +08:00
|
|
|
|
2002-12-31 11:18:49 +08:00
|
|
|
if (mindist < 0 || mindist > dx * dx + dy * dy)
|
|
|
|
{
|
|
|
|
mindist = dx * dx + dy * dy;
|
2003-08-26 22:29:10 +08:00
|
|
|
anchor = GIMP_ANCHOR (list->data);
|
2002-12-31 11:18:49 +08:00
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
g_list_free (anchors);
|
2003-04-14 08:37:04 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
anchors = gimp_stroke_get_draw_anchors (stroke);
|
2002-12-31 11:18:49 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = anchors; list; list = g_list_next (list))
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2003-08-26 22:29:10 +08:00
|
|
|
dx = coord->x - GIMP_ANCHOR (list->data)->position.x;
|
|
|
|
dy = coord->y - GIMP_ANCHOR (list->data)->position.y;
|
2003-05-17 00:49:04 +08:00
|
|
|
|
2002-12-31 11:18:49 +08:00
|
|
|
if (mindist < 0 || mindist > dx * dx + dy * dy)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
mindist = dx * dx + dy * dy;
|
2003-08-26 22:29:10 +08:00
|
|
|
anchor = GIMP_ANCHOR (list->data);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
g_list_free (anchors);
|
2003-04-14 08:37:04 +08:00
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
return anchor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GimpAnchor *
|
|
|
|
gimp_stroke_anchor_get_next (const GimpStroke *stroke,
|
2003-05-19 07:08:01 +08:00
|
|
|
const GimpAnchor *prev)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->anchor_get_next (stroke, prev);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static GimpAnchor *
|
|
|
|
gimp_stroke_real_anchor_get_next (const GimpStroke *stroke,
|
|
|
|
const GimpAnchor *prev)
|
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
GList *list;
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2002-02-26 00:57:19 +08:00
|
|
|
if (prev)
|
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
list = g_list_find (stroke->anchors, prev);
|
|
|
|
if (list)
|
|
|
|
list = g_list_next (list);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
2002-02-26 00:57:19 +08:00
|
|
|
else
|
2003-05-17 00:49:04 +08:00
|
|
|
{
|
|
|
|
list = stroke->anchors;
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
if (list)
|
2003-08-26 22:29:10 +08:00
|
|
|
return GIMP_ANCHOR (list->data);
|
2003-07-18 02:06:32 +08:00
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-31 00:36:01 +08:00
|
|
|
void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_anchor_select (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
gboolean exclusive)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->anchor_select (stroke, anchor, exclusive);
|
|
|
|
}
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static void
|
|
|
|
gimp_stroke_real_anchor_select (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
gboolean exclusive)
|
|
|
|
{
|
|
|
|
GList *list;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
list = stroke->anchors;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-08-17 10:49:24 +08:00
|
|
|
if (exclusive || anchor == NULL)
|
2003-05-17 00:49:04 +08:00
|
|
|
{
|
|
|
|
while (list)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
2003-08-26 22:29:10 +08:00
|
|
|
GIMP_ANCHOR (list->data)->selected = FALSE;
|
2003-05-17 00:49:04 +08:00
|
|
|
list = g_list_next (list);
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
}
|
2003-05-17 00:49:04 +08:00
|
|
|
|
|
|
|
list = g_list_find (stroke->anchors, anchor);
|
|
|
|
|
|
|
|
if (list)
|
2003-08-26 22:29:10 +08:00
|
|
|
GIMP_ANCHOR (list->data)->selected = TRUE;
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_anchor_move_relative (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
2003-05-19 07:08:01 +08:00
|
|
|
const GimpCoords *delta,
|
2003-05-17 00:49:04 +08:00
|
|
|
GimpAnchorFeatureType feature)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
2003-05-17 00:49:04 +08:00
|
|
|
g_return_if_fail (anchor != NULL);
|
|
|
|
g_return_if_fail (g_list_find (stroke->anchors, anchor));
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->anchor_move_relative (stroke, anchor,
|
|
|
|
delta, feature);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_real_anchor_move_relative (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
const GimpCoords *delta,
|
|
|
|
GimpAnchorFeatureType feature)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
anchor->position.x += delta->x;
|
|
|
|
anchor->position.y += delta->y;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_anchor_move_absolute (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
GimpAnchorFeatureType feature)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
2003-05-17 00:49:04 +08:00
|
|
|
g_return_if_fail (anchor != NULL);
|
|
|
|
g_return_if_fail (g_list_find (stroke->anchors, anchor));
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->anchor_move_absolute (stroke, anchor,
|
|
|
|
coord, feature);
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_real_anchor_move_absolute (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
GimpAnchorFeatureType feature)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
anchor->position.x = coord->x;
|
|
|
|
anchor->position.y = coord->y;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
2003-08-26 08:27:03 +08:00
|
|
|
gboolean
|
|
|
|
gimp_stroke_point_is_movable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->point_is_movable (stroke, predec,
|
|
|
|
position);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_stroke_real_point_is_movable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_point_move_relative (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *deltacoord,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->point_move_relative (stroke, predec,
|
|
|
|
position, deltacoord,
|
|
|
|
feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_real_point_move_relative (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *deltacoord,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_point_move_relative: default implementation\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_point_move_absolute (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->point_move_absolute (stroke, predec,
|
|
|
|
position, coord,
|
|
|
|
feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_real_point_move_absolute (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position,
|
|
|
|
const GimpCoords *coord,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_point_move_absolute: default implementation\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-03 09:26:05 +08:00
|
|
|
void
|
|
|
|
gimp_stroke_close (GimpStroke *stroke)
|
2003-09-01 08:39:47 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->close (stroke);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_close (GimpStroke *stroke)
|
2003-08-03 09:26:05 +08:00
|
|
|
{
|
|
|
|
stroke->closed = TRUE;
|
|
|
|
}
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-03-29 12:47:44 +08:00
|
|
|
void
|
|
|
|
gimp_stroke_anchor_convert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->anchor_convert (stroke, anchor, feature);
|
|
|
|
}
|
2003-03-29 12:47:44 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static void
|
|
|
|
gimp_stroke_real_anchor_convert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpAnchorFeatureType feature)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_anchor_convert: default implementation\n");
|
2003-03-29 12:47:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
void
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_anchor_delete (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->anchor_delete (stroke, anchor);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static void
|
|
|
|
gimp_stroke_real_anchor_delete (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_anchor_delete: default implementation\n");
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
2003-08-25 18:49:33 +08:00
|
|
|
|
2003-08-22 09:12:26 +08:00
|
|
|
GimpStroke *
|
|
|
|
gimp_stroke_open (GimpStroke *stroke,
|
|
|
|
GimpAnchor *end_anchor)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->open (stroke, end_anchor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpStroke *
|
|
|
|
gimp_stroke_real_open (GimpStroke *stroke,
|
|
|
|
GimpAnchor *end_anchor)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_open: default implementation\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-08-25 18:49:33 +08:00
|
|
|
|
2003-08-21 01:29:13 +08:00
|
|
|
gboolean
|
|
|
|
gimp_stroke_anchor_is_insertable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->anchor_is_insertable (stroke,
|
|
|
|
predec,
|
|
|
|
position);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_stroke_real_anchor_is_insertable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpAnchor *
|
|
|
|
gimp_stroke_anchor_insert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->anchor_insert (stroke,
|
|
|
|
predec, position);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpAnchor *
|
|
|
|
gimp_stroke_real_anchor_insert (GimpStroke *stroke,
|
|
|
|
GimpAnchor *predec,
|
|
|
|
gdouble position)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-17 10:49:24 +08:00
|
|
|
gboolean
|
|
|
|
gimp_stroke_is_extendable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *neighbor)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->is_extendable (stroke, neighbor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_stroke_real_is_extendable (GimpStroke *stroke,
|
|
|
|
GimpAnchor *neighbor)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-08-17 10:49:24 +08:00
|
|
|
GimpAnchor *
|
|
|
|
gimp_stroke_extend (GimpStroke *stroke,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GimpAnchor *neighbor,
|
|
|
|
GimpVectorExtendMode extend_mode)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->extend (stroke, coords,
|
|
|
|
neighbor, extend_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpAnchor *
|
|
|
|
gimp_stroke_real_extend (GimpStroke *stroke,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GimpAnchor *neighbor,
|
|
|
|
GimpVectorExtendMode extend_mode)
|
|
|
|
{
|
2003-08-27 08:31:20 +08:00
|
|
|
g_printerr ("gimp_stroke_extend: default implementation\n");
|
2003-08-17 10:49:24 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-08-27 08:31:20 +08:00
|
|
|
gboolean
|
|
|
|
gimp_stroke_connect_stroke (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpStroke *extension,
|
|
|
|
GimpAnchor *neighbor)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (extension), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->connect_stroke (stroke, anchor,
|
|
|
|
extension, neighbor);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_stroke_real_connect_stroke (GimpStroke *stroke,
|
|
|
|
GimpAnchor *anchor,
|
|
|
|
GimpStroke *extension,
|
|
|
|
GimpAnchor *neighbor)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_connect_stroke: default implementation\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2003-08-22 01:47:12 +08:00
|
|
|
gboolean
|
|
|
|
gimp_stroke_is_empty (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE);
|
|
|
|
|
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->is_empty (stroke);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_stroke_real_is_empty (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
return stroke->anchors == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
gdouble
|
|
|
|
gimp_stroke_get_length (const GimpStroke *stroke)
|
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), 0.0);
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->get_length (stroke);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static gdouble
|
|
|
|
gimp_stroke_real_get_length (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_get_length: default implementation\n");
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return 0.0;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gdouble
|
|
|
|
gimp_stroke_get_distance (const GimpStroke *stroke,
|
2003-05-17 00:49:04 +08:00
|
|
|
const GimpCoords *coord)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), 0.0);
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->get_distance (stroke, coord);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static gdouble
|
|
|
|
gimp_stroke_real_get_distance (const GimpStroke *stroke,
|
|
|
|
const GimpCoords *coord)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_get_distance: default implementation\n");
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return 0.0;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-29 07:52:29 +08:00
|
|
|
GArray *
|
2003-05-17 00:49:04 +08:00
|
|
|
gimp_stroke_interpolate (const GimpStroke *stroke,
|
|
|
|
gdouble precision,
|
|
|
|
gboolean *ret_closed)
|
2002-02-25 11:16:41 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), 0);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->interpolate (stroke, precision,
|
|
|
|
ret_closed);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GArray *
|
|
|
|
gimp_stroke_real_interpolate (const GimpStroke *stroke,
|
|
|
|
gdouble precision,
|
|
|
|
gboolean *ret_closed)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_interpolate: default implementation\n");
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return NULL;
|
2002-02-25 11:16:41 +08:00
|
|
|
}
|
|
|
|
|
2003-04-14 08:37:04 +08:00
|
|
|
GimpStroke *
|
|
|
|
gimp_stroke_duplicate (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
|
|
|
return (GIMP_STROKE_GET_CLASS (stroke))->duplicate (stroke);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpStroke *
|
|
|
|
gimp_stroke_real_duplicate (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
GimpStroke *new_stroke;
|
2003-05-17 00:49:04 +08:00
|
|
|
GList *list;
|
2003-04-14 08:37:04 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
new_stroke = g_object_new (G_TYPE_FROM_INSTANCE (stroke),
|
|
|
|
"name", GIMP_OBJECT (stroke)->name,
|
|
|
|
NULL);
|
2003-04-14 08:37:04 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
new_stroke->anchors = g_list_copy (stroke->anchors);
|
2003-04-14 08:37:04 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = new_stroke->anchors; list; list = g_list_next (list))
|
2003-04-14 08:37:04 +08:00
|
|
|
{
|
2003-08-26 22:29:10 +08:00
|
|
|
list->data = gimp_anchor_duplicate (GIMP_ANCHOR (list->data));
|
2003-04-14 08:37:04 +08:00
|
|
|
}
|
|
|
|
|
2003-09-02 18:18:49 +08:00
|
|
|
new_stroke->closed = stroke->closed;
|
|
|
|
|
2003-04-14 08:37:04 +08:00
|
|
|
return new_stroke;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-25 11:16:41 +08:00
|
|
|
GimpStroke *
|
|
|
|
gimp_stroke_make_bezier (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->make_bezier (stroke);
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GimpStroke *
|
|
|
|
gimp_stroke_real_make_bezier (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_make_bezier: default implementation\n");
|
2002-02-25 11:16:41 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-08 01:05:14 +08:00
|
|
|
void
|
|
|
|
gimp_stroke_translate (GimpStroke *stroke,
|
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->translate (stroke, offset_x, offset_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_translate (GimpStroke *stroke,
|
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
anchor->position.x += offset_x;
|
|
|
|
anchor->position.y += offset_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_scale (GimpStroke *stroke,
|
|
|
|
gdouble scale_x,
|
|
|
|
gdouble scale_y,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->scale (stroke,
|
|
|
|
scale_x, scale_y,
|
|
|
|
offset_x, offset_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_scale (GimpStroke *stroke,
|
|
|
|
gdouble scale_x,
|
|
|
|
gdouble scale_y,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
anchor->position.x *= scale_x;
|
|
|
|
anchor->position.y *= scale_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_resize (GimpStroke *stroke,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->resize (stroke,
|
|
|
|
new_width, new_height,
|
|
|
|
offset_x, offset_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_resize (GimpStroke *stroke,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
anchor->position.x += offset_x;
|
|
|
|
anchor->position.y += offset_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_flip (GimpStroke *stroke,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->flip (stroke, flip_type,
|
|
|
|
axis, clip_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_flip (GimpStroke *stroke,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
switch (flip_type)
|
|
|
|
{
|
|
|
|
case GIMP_ORIENTATION_HORIZONTAL:
|
|
|
|
anchor->position.x = -(anchor->position.x - axis) + axis;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ORIENTATION_VERTICAL:
|
|
|
|
anchor->position.y = -(anchor->position.y - axis) + axis;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_rotate (GimpStroke *stroke,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->rotate (stroke, rotate_type,
|
|
|
|
center_x, center_y, clip_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_rotate (GimpStroke *stroke,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
GList *list;
|
2003-08-25 18:49:33 +08:00
|
|
|
GimpMatrix3 matrix;
|
2003-08-08 01:05:14 +08:00
|
|
|
gdouble angle = 0.0;
|
|
|
|
|
|
|
|
switch (rotate_type)
|
|
|
|
{
|
|
|
|
case GIMP_ROTATE_90:
|
|
|
|
angle = G_PI_2;
|
|
|
|
break;
|
|
|
|
case GIMP_ROTATE_180:
|
|
|
|
angle = G_PI;
|
|
|
|
break;
|
|
|
|
case GIMP_ROTATE_270:
|
|
|
|
angle = - G_PI_2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_drawable_transform_matrix_rotate_center (center_x, center_y, angle,
|
|
|
|
&matrix);
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
gimp_matrix3_transform_point (&matrix,
|
|
|
|
anchor->position.x,
|
|
|
|
anchor->position.y,
|
|
|
|
&anchor->position.x,
|
|
|
|
&anchor->position.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_transform (GimpStroke *stroke,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interp_type,
|
|
|
|
gboolean clip_result,
|
|
|
|
GimpProgressFunc progress_callback,
|
|
|
|
gpointer progress_data)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->transform (stroke, matrix, direction,
|
|
|
|
interp_type, clip_result,
|
|
|
|
progress_callback, progress_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_stroke_real_transform (GimpStroke *stroke,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interp_type,
|
|
|
|
gboolean clip_result,
|
|
|
|
GimpProgressFunc progress_callback,
|
|
|
|
gpointer progress_data)
|
|
|
|
{
|
|
|
|
GimpMatrix3 local_matrix;
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
local_matrix = *matrix;
|
|
|
|
|
|
|
|
if (direction == GIMP_TRANSFORM_BACKWARD)
|
|
|
|
gimp_matrix3_invert (&local_matrix);
|
|
|
|
|
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
|
|
|
|
|
|
|
gimp_matrix3_transform_point (&local_matrix,
|
|
|
|
anchor->position.x,
|
|
|
|
anchor->position.y,
|
|
|
|
&anchor->position.x,
|
|
|
|
&anchor->position.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-31 00:36:01 +08:00
|
|
|
GList *
|
|
|
|
gimp_stroke_get_draw_anchors (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->get_draw_anchors (stroke);
|
|
|
|
}
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GList *
|
|
|
|
gimp_stroke_real_get_draw_anchors (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
GList *ret_list = NULL;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
2003-08-26 22:29:10 +08:00
|
|
|
if (GIMP_ANCHOR (list->data)->type == GIMP_ANCHOR_ANCHOR)
|
2003-05-17 00:49:04 +08:00
|
|
|
ret_list = g_list_prepend (ret_list, list->data);
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return g_list_reverse (ret_list);
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GList *
|
2002-12-31 11:18:49 +08:00
|
|
|
gimp_stroke_get_draw_controls (const GimpStroke *stroke)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->get_draw_controls (stroke);
|
|
|
|
}
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GList *
|
|
|
|
gimp_stroke_real_get_draw_controls (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
GList *ret_list = NULL;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
if (anchor->type == GIMP_ANCHOR_CONTROL)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
GimpAnchor *next = list->next ? list->next->data : NULL;
|
|
|
|
GimpAnchor *prev = list->prev ? list->prev->data : NULL;
|
|
|
|
|
|
|
|
if (next && next->type == GIMP_ANCHOR_ANCHOR && next->selected)
|
|
|
|
{
|
2003-09-04 05:35:24 +08:00
|
|
|
/* Ok, this is a hack.
|
|
|
|
* The idea is to give control points at the end of a
|
|
|
|
* stroke a higher priority for the interactive tool. */
|
|
|
|
if (prev)
|
|
|
|
ret_list = g_list_prepend (ret_list, anchor);
|
|
|
|
else
|
|
|
|
ret_list = g_list_append (ret_list, anchor);
|
2003-05-17 00:49:04 +08:00
|
|
|
}
|
|
|
|
else if (prev && prev->type == GIMP_ANCHOR_ANCHOR && prev->selected)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
2003-09-04 05:35:24 +08:00
|
|
|
/* same here... */
|
|
|
|
if (next)
|
|
|
|
ret_list = g_list_prepend (ret_list, anchor);
|
|
|
|
else
|
|
|
|
ret_list = g_list_append (ret_list, anchor);
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return g_list_reverse (ret_list);
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
2003-07-18 02:06:32 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
|
2002-12-31 00:36:01 +08:00
|
|
|
GArray *
|
2002-12-31 11:18:49 +08:00
|
|
|
gimp_stroke_get_draw_lines (const GimpStroke *stroke)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return GIMP_STROKE_GET_CLASS (stroke)->get_draw_lines (stroke);
|
|
|
|
}
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
static GArray *
|
|
|
|
gimp_stroke_real_get_draw_lines (const GimpStroke *stroke)
|
|
|
|
{
|
|
|
|
GList *list;
|
2003-08-22 21:00:25 +08:00
|
|
|
GArray *ret_lines = NULL;
|
|
|
|
gint count = 0;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
for (list = stroke->anchors; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpAnchor *anchor = list->data;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
if (anchor->type == GIMP_ANCHOR_ANCHOR && anchor->selected)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
if (list->next)
|
2002-12-31 00:36:01 +08:00
|
|
|
{
|
2003-05-17 00:49:04 +08:00
|
|
|
GimpAnchor *next = list->next->data;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-08-22 21:00:25 +08:00
|
|
|
if (count == 0)
|
|
|
|
ret_lines = g_array_new (FALSE, FALSE, sizeof (GimpCoords));
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
ret_lines = g_array_append_val (ret_lines, anchor->position);
|
|
|
|
ret_lines = g_array_append_val (ret_lines, next->position);
|
2003-08-22 21:00:25 +08:00
|
|
|
count += 1;
|
2003-05-17 00:49:04 +08:00
|
|
|
}
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
if (list->prev)
|
|
|
|
{
|
|
|
|
GimpAnchor *prev = list->prev->data;
|
2002-12-31 00:36:01 +08:00
|
|
|
|
2003-08-22 21:00:25 +08:00
|
|
|
if (count == 0)
|
|
|
|
ret_lines = g_array_new (FALSE, FALSE, sizeof (GimpCoords));
|
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
ret_lines = g_array_append_val (ret_lines, anchor->position);
|
|
|
|
ret_lines = g_array_append_val (ret_lines, prev->position);
|
2003-08-22 21:00:25 +08:00
|
|
|
count += 1;
|
2002-12-31 00:36:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-02-25 11:16:41 +08:00
|
|
|
|
2003-05-17 00:49:04 +08:00
|
|
|
return ret_lines;
|
|
|
|
}
|
2003-09-07 00:39:08 +08:00
|
|
|
|
2003-09-07 04:00:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_stroke_to_art_point (const GimpStroke *stroke,
|
|
|
|
ArtVpath *vec)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
|
|
|
|
|
|
|
GIMP_STROKE_GET_CLASS (stroke)->to_art_point (stroke, vec);
|
|
|
|
}
|
|
|
|
|
2003-09-07 00:39:08 +08:00
|
|
|
static void
|
2003-09-07 04:00:38 +08:00
|
|
|
gimp_stroke_real_to_art_point (const GimpStroke *stroke,
|
|
|
|
ArtVpath *vec)
|
2003-09-07 00:39:08 +08:00
|
|
|
{
|
|
|
|
g_printerr ("gimp_stroke_to_art_point: default implementation\n");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|