mirror of https://github.com/GNOME/gimp.git
Bug 721009 - new transform tool with freely placeable handles
Add new tool GimpHandleTransformTool which allows to freely place up to 4 handles on the image, then move any one of them, which transforms the image so that the remaining handles keep their position. Did quite some cleanup on the code before pushing --Mitch
This commit is contained in:
parent
67673e0b09
commit
2989bad35a
|
@ -244,6 +244,7 @@ static const GimpDialogFactoryEntry entries[] =
|
|||
FOREIGN ("gimp-threshold-tool-dialog", TRUE, FALSE),
|
||||
FOREIGN ("gimp-perspective-tool-dialog", TRUE, FALSE),
|
||||
FOREIGN ("gimp-unified-transform-tool-dialog", TRUE, FALSE),
|
||||
FOREIGN ("gimp-handle-transform-tool-dialog", TRUE, FALSE),
|
||||
|
||||
FOREIGN ("gimp-toolbox-color-dialog", TRUE, FALSE),
|
||||
FOREIGN ("gimp-gradient-editor-color-dialog", TRUE, FALSE),
|
||||
|
|
|
@ -96,6 +96,10 @@ libapptools_a_sources = \
|
|||
gimpfuzzyselecttool.h \
|
||||
gimpgegltool.c \
|
||||
gimpgegltool.h \
|
||||
gimphandletransformoptions.c \
|
||||
gimphandletransformoptions.h \
|
||||
gimphandletransformtool.c \
|
||||
gimphandletransformtool.h \
|
||||
gimphealtool.c \
|
||||
gimphealtool.h \
|
||||
gimphistogramoptions.c \
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "gimpforegroundselecttool.h"
|
||||
#include "gimpfuzzyselecttool.h"
|
||||
#include "gimpgegltool.h"
|
||||
#include "gimphandletransformtool.h"
|
||||
#include "gimphealtool.h"
|
||||
#include "gimphuesaturationtool.h"
|
||||
#include "gimpinktool.h"
|
||||
|
@ -160,6 +161,7 @@ gimp_tools_init (Gimp *gimp)
|
|||
gimp_cage_tool_register,
|
||||
gimp_flip_tool_register,
|
||||
gimp_perspective_tool_register,
|
||||
gimp_handle_transform_tool_register,
|
||||
gimp_shear_tool_register,
|
||||
gimp_scale_tool_register,
|
||||
gimp_rotate_tool_register,
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libgimpconfig/gimpconfig.h"
|
||||
#include "libgimpwidgets/gimpwidgets.h"
|
||||
|
||||
#include "tools-types.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimptoolinfo.h"
|
||||
|
||||
#include "widgets/gimppropwidgets.h"
|
||||
#include "widgets/gimpspinscale.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
#include "gimphandletransformoptions.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_HANDLE_MODE
|
||||
};
|
||||
|
||||
|
||||
static void gimp_handle_transform_options_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_handle_transform_options_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpHandleTransformOptions, gimp_handle_transform_options,
|
||||
GIMP_TYPE_TRANSFORM_OPTIONS)
|
||||
|
||||
#define parent_class gimp_handle_transform_options_parent_class
|
||||
|
||||
|
||||
static void
|
||||
gimp_handle_transform_options_class_init (GimpHandleTransformOptionsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = gimp_handle_transform_options_set_property;
|
||||
object_class->get_property = gimp_handle_transform_options_get_property;
|
||||
|
||||
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_HANDLE_MODE,
|
||||
"handle-mode",
|
||||
N_("Handle mode"),
|
||||
GIMP_TYPE_TRANSFORM_HANDLE_MODE,
|
||||
GIMP_HANDLE_MODE_TRANSFORM,
|
||||
GIMP_PARAM_STATIC_STRINGS);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_options_init (GimpHandleTransformOptions *options)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_options_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHandleTransformOptions *options = GIMP_HANDLE_TRANSFORM_OPTIONS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_HANDLE_MODE:
|
||||
options->handle_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_options_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHandleTransformOptions *options = GIMP_HANDLE_TRANSFORM_OPTIONS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_HANDLE_MODE:
|
||||
g_value_set_enum (value, options->handle_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_handle_transform_options_gui:
|
||||
* @tool_options: a #GimpToolOptions
|
||||
*
|
||||
* Build the Transform Tool Options.
|
||||
*
|
||||
* Return value: a container holding the transform tool options
|
||||
**/
|
||||
GtkWidget *
|
||||
gimp_handle_transform_options_gui (GimpToolOptions *tool_options)
|
||||
{
|
||||
GObject *config = G_OBJECT (tool_options);
|
||||
GtkWidget *vbox = gimp_transform_options_gui (tool_options);
|
||||
GtkWidget *frame;
|
||||
GtkWidget *button;
|
||||
gint i;
|
||||
|
||||
frame = gimp_prop_enum_radio_frame_new (config, "handle-mode",
|
||||
_("Handle mode"), 0, 0);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
/* add modifier to name, add tooltip */
|
||||
button = g_object_get_data (G_OBJECT (frame), "radio-button");
|
||||
|
||||
if (GTK_IS_RADIO_BUTTON (button))
|
||||
{
|
||||
GSList *list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
|
||||
|
||||
for (i = g_slist_length (list) - 1 ; list; list = list->next, i--)
|
||||
{
|
||||
GdkModifierType shift = gimp_get_extend_selection_mask ();
|
||||
GdkModifierType ctrl = gimp_get_constrain_behavior_mask ();
|
||||
GdkModifierType modifier = 0;
|
||||
gchar *tooltip = "";
|
||||
gchar *tip;
|
||||
gchar *label;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case GIMP_HANDLE_MODE_ADD_MOVE:
|
||||
modifier = shift;
|
||||
tooltip = "Add or move transform handles";
|
||||
break;
|
||||
|
||||
case GIMP_HANDLE_MODE_REMOVE:
|
||||
modifier = ctrl;
|
||||
tooltip = "Remove transform handles";
|
||||
break;
|
||||
|
||||
case GIMP_HANDLE_MODE_TRANSFORM:
|
||||
modifier = 0;
|
||||
tooltip = "Transform image by moving handles";
|
||||
break;
|
||||
}
|
||||
|
||||
if (modifier)
|
||||
{
|
||||
label = g_strdup_printf ("%s (%s)",
|
||||
gtk_button_get_label (GTK_BUTTON (list->data)),
|
||||
gimp_get_mod_string (modifier));
|
||||
gtk_button_set_label (GTK_BUTTON (list->data), label);
|
||||
g_free (label);
|
||||
|
||||
tip = g_strdup_printf ("%s (%s)",
|
||||
tooltip, gimp_get_mod_string (modifier));
|
||||
gimp_help_set_help_data (list->data, tip, NULL);
|
||||
g_free (tip);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_help_set_help_data (list->data, tooltip, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vbox;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_HANDLE_TRANSFORM_OPTIONS_H__
|
||||
#define __GIMP_HANDLE_TRANSFORM_OPTIONS_H__
|
||||
|
||||
|
||||
#include "gimptransformoptions.h"
|
||||
|
||||
|
||||
#define GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS (gimp_handle_transform_options_get_type ())
|
||||
#define GIMP_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptions))
|
||||
#define GIMP_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptionsClass))
|
||||
#define GIMP_IS_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS))
|
||||
#define GIMP_IS_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS))
|
||||
#define GIMP_HANDLE_TRANSFORM_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptionsClass))
|
||||
|
||||
|
||||
typedef struct _GimpHandleTransformOptions GimpHandleTransformOptions;
|
||||
typedef struct _GimpHandleTransformOptionsClass GimpHandleTransformOptionsClass;
|
||||
|
||||
struct _GimpHandleTransformOptions
|
||||
{
|
||||
GimpTransformOptions parent_instance;
|
||||
|
||||
GimpTransformHandleMode handle_mode;
|
||||
};
|
||||
|
||||
struct _GimpHandleTransformOptionsClass
|
||||
{
|
||||
GimpTransformOptionsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType gimp_handle_transform_options_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * gimp_handle_transform_options_gui (GimpToolOptions *tool_options);
|
||||
|
||||
|
||||
#endif /* __GIMP_HANDLE_TRANSFORM_OPTIONS_H__ */
|
|
@ -0,0 +1,985 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
#include "libgimpwidgets/gimpwidgets.h"
|
||||
|
||||
#include "tools-types.h"
|
||||
|
||||
#include "widgets/gimphelp-ids.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
#include "display/gimpcanvasitem.h"
|
||||
#include "display/gimpdisplay.h"
|
||||
#include "display/gimptoolgui.h"
|
||||
|
||||
#include "gimphandletransformoptions.h"
|
||||
#include "gimphandletransformtool.h"
|
||||
#include "gimptoolcontrol.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
|
||||
/* the transformation is defined by 8 points:
|
||||
*
|
||||
* 4 points on the original image and 4 corresponding points on the
|
||||
* transformed image. The first NUM points on the transformed image
|
||||
* are visible as handles.
|
||||
*
|
||||
* For these handles, the constants TRANSFORM_HANDLE_N,
|
||||
* TRANSFORM_HANDLE_S, TRANSFORM_HANDLE_E and TRANSFORM_HANDLE_W are
|
||||
* used. Actually, it makes no sense to name the handles with north,
|
||||
* south, east, and west. But this way, we don't need to define even
|
||||
* more enum constants.
|
||||
*/
|
||||
|
||||
/* index into trans_info array */
|
||||
enum
|
||||
{
|
||||
X0,
|
||||
Y0,
|
||||
X1,
|
||||
Y1,
|
||||
X2,
|
||||
Y2,
|
||||
X3,
|
||||
Y3,
|
||||
OX0,
|
||||
OY0,
|
||||
OX1,
|
||||
OY1,
|
||||
OX2,
|
||||
OY2,
|
||||
OX3,
|
||||
OY3,
|
||||
NUM
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void gimp_handle_transform_tool_button_press (GimpTool *tool,
|
||||
const GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpButtonPressType press_type,
|
||||
GimpDisplay *display);
|
||||
static void gimp_handle_transform_tool_button_release (GimpTool *tool,
|
||||
const GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpButtonReleaseType release_type,
|
||||
GimpDisplay *display);
|
||||
static void gimp_handle_transform_tool_modifier_key (GimpTool *tool,
|
||||
GdkModifierType key,
|
||||
gboolean press,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_handle_transform_tool_dialog (GimpTransformTool *tr_tool);
|
||||
static void gimp_handle_transform_tool_dialog_update (GimpTransformTool *tr_tool);
|
||||
static void gimp_handle_transform_tool_prepare (GimpTransformTool *tr_tool);
|
||||
static void gimp_handle_transform_tool_motion (GimpTransformTool *tr_tool);
|
||||
static void gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool);
|
||||
static gchar *gimp_handle_transform_tool_get_undo_desc (GimpTransformTool *tr_tool);
|
||||
static TransformAction
|
||||
gimp_handle_transform_tool_pick_function (GimpTransformTool *tr_tool,
|
||||
const GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display);
|
||||
static void gimp_handle_transform_tool_cursor_update (GimpTransformTool *tr_tool,
|
||||
GimpCursorType *cursor,
|
||||
GimpCursorModifier *modifier);
|
||||
static void gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool,
|
||||
gint handle_w,
|
||||
gint handle_h);
|
||||
|
||||
static gboolean is_handle_position_valid (GimpTransformTool *tr_tool,
|
||||
gint active_handle);
|
||||
static void handle_micro_move (GimpTransformTool *tr_tool,
|
||||
gint active_handle);
|
||||
static inline gdouble calc_angle (gdouble ax,
|
||||
gdouble ay,
|
||||
gdouble bx,
|
||||
gdouble by);
|
||||
static inline gdouble calc_len (gdouble a,
|
||||
gdouble b);
|
||||
static inline gdouble calc_lineintersect_ratio (gdouble p1x,
|
||||
gdouble p1y,
|
||||
gdouble p2x,
|
||||
gdouble p2y,
|
||||
gdouble q1x,
|
||||
gdouble q1y,
|
||||
gdouble q2x,
|
||||
gdouble q2y);
|
||||
static gboolean mod_gauss (gdouble matrix[],
|
||||
gdouble solution[],
|
||||
gint s);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpHandleTransformTool, gimp_handle_transform_tool,
|
||||
GIMP_TYPE_TRANSFORM_TOOL)
|
||||
|
||||
#define parent_class gimp_handle_transform_tool_parent_class
|
||||
|
||||
|
||||
void
|
||||
gimp_handle_transform_tool_register (GimpToolRegisterCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
(* callback) (GIMP_TYPE_HANDLE_TRANSFORM_TOOL,
|
||||
GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS,
|
||||
gimp_handle_transform_options_gui,
|
||||
GIMP_CONTEXT_BACKGROUND_MASK,
|
||||
"gimp-handle-transform-tool",
|
||||
_("Handle Transform"),
|
||||
_("Handle Transform Tool: "
|
||||
"Deform the layer, selection or path with handles"),
|
||||
N_("_Handle Transform"), "<ctrl><shift>H",
|
||||
NULL, GIMP_HELP_TOOL_HANDLE_TRANSFORM,
|
||||
GIMP_STOCK_TOOL_HANDLE_TRANSFORM,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_class_init (GimpHandleTransformToolClass *klass)
|
||||
{
|
||||
GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
|
||||
GimpTransformToolClass *trans_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
|
||||
|
||||
tool_class->button_press = gimp_handle_transform_tool_button_press;
|
||||
tool_class->button_release = gimp_handle_transform_tool_button_release;
|
||||
tool_class->modifier_key = gimp_handle_transform_tool_modifier_key;
|
||||
|
||||
trans_class->dialog = gimp_handle_transform_tool_dialog;
|
||||
trans_class->dialog_update = gimp_handle_transform_tool_dialog_update;
|
||||
trans_class->prepare = gimp_handle_transform_tool_prepare;
|
||||
trans_class->motion = gimp_handle_transform_tool_motion;
|
||||
trans_class->recalc_matrix = gimp_handle_transform_tool_recalc_matrix;
|
||||
trans_class->get_undo_desc = gimp_handle_transform_tool_get_undo_desc;
|
||||
trans_class->pick_function = gimp_handle_transform_tool_pick_function;
|
||||
trans_class->cursor_update = gimp_handle_transform_tool_cursor_update;
|
||||
trans_class->draw_gui = gimp_handle_transform_tool_draw_gui;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_init (GimpHandleTransformTool *ht_tool)
|
||||
{
|
||||
GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (ht_tool);
|
||||
|
||||
tr_tool->progress_text = _("Handle transformation");
|
||||
tr_tool->use_grid = TRUE;
|
||||
|
||||
ht_tool->saved_handle_mode = GIMP_HANDLE_MODE_TRANSFORM;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_button_press (GimpTool *tool,
|
||||
const GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpButtonPressType press_type,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHandleTransformTool *ht = GIMP_HANDLE_TRANSFORM_TOOL (tool);
|
||||
GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
|
||||
GimpHandleTransformOptions *options;
|
||||
gint num;
|
||||
gint active_handle;
|
||||
|
||||
options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
||||
|
||||
num = (gint) tr_tool->trans_info[NUM];
|
||||
active_handle = tr_tool->function - TRANSFORM_HANDLE_N;
|
||||
|
||||
/* There is nothing to be done on creation */
|
||||
if (tr_tool->function == TRANSFORM_CREATING)
|
||||
{
|
||||
GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time,
|
||||
state, press_type, display);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE)
|
||||
{
|
||||
/* add handle */
|
||||
|
||||
if (num < 4 && tr_tool->function == TRANSFORM_HANDLE_NONE)
|
||||
{
|
||||
tr_tool->trans_info[X0 + 2 * num] = coords->x;
|
||||
tr_tool->trans_info[Y0 + 2 * num] = coords->y;
|
||||
tr_tool->function = TRANSFORM_HANDLE_N + num;
|
||||
tr_tool->trans_info[NUM]++;
|
||||
|
||||
/* check for valid position and calculating of OX0...OY3 is
|
||||
* done on button release
|
||||
*/
|
||||
}
|
||||
|
||||
/* move handles without changing the transformation matrix */
|
||||
ht->matrix_recalculation = FALSE;
|
||||
}
|
||||
else if (options->handle_mode == GIMP_HANDLE_MODE_REMOVE &&
|
||||
num > 0 &&
|
||||
active_handle >= 0 &&
|
||||
active_handle < 4)
|
||||
{
|
||||
/* remove handle */
|
||||
|
||||
gdouble tempx = tr_tool->trans_info[X0 + 2 * active_handle];
|
||||
gdouble tempy = tr_tool->trans_info[Y0 + 2 * active_handle];
|
||||
gdouble tempox = tr_tool->trans_info[OX0 + 2 * active_handle];
|
||||
gdouble tempoy = tr_tool->trans_info[OY0 + 2 * active_handle];
|
||||
gint i;
|
||||
|
||||
num--;
|
||||
tr_tool->trans_info[NUM]--;
|
||||
|
||||
for (i = active_handle; i < num; i++)
|
||||
{
|
||||
tr_tool->trans_info[X0 + 2 * i] = tr_tool->trans_info[X1 + 2 * i];
|
||||
tr_tool->trans_info[Y0 + 2 * i] = tr_tool->trans_info[Y1 + 2 * i];
|
||||
tr_tool->trans_info[OX0 + 2 * i] = tr_tool->trans_info[OX1 + 2 * i];
|
||||
tr_tool->trans_info[OY0 + 2 * i] = tr_tool->trans_info[OY1 + 2 * i];
|
||||
}
|
||||
|
||||
tr_tool->trans_info[X0 + 2 * num] = tempx;
|
||||
tr_tool->trans_info[Y0 + 2 * num] = tempy;
|
||||
tr_tool->trans_info[OX0 + 2 * num] = tempox;
|
||||
tr_tool->trans_info[OY0 + 2 * num] = tempoy;
|
||||
}
|
||||
|
||||
GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time,
|
||||
state, press_type, display);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_button_release (GimpTool *tool,
|
||||
const GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpButtonReleaseType release_type,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHandleTransformTool *ht = GIMP_HANDLE_TRANSFORM_TOOL (tool);
|
||||
GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
|
||||
GimpHandleTransformOptions *options;
|
||||
gint active_handle;
|
||||
|
||||
options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
||||
|
||||
active_handle = tr_tool->function - TRANSFORM_HANDLE_N;
|
||||
|
||||
if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE &&
|
||||
active_handle >= 0 &&
|
||||
active_handle < 4)
|
||||
{
|
||||
GimpMatrix3 matrix;
|
||||
|
||||
if (! is_handle_position_valid (tr_tool, active_handle))
|
||||
{
|
||||
handle_micro_move (tr_tool, active_handle);
|
||||
}
|
||||
|
||||
/* handle was added or moved. calculate new original position */
|
||||
matrix = tr_tool->transform;
|
||||
gimp_matrix3_invert (&matrix);
|
||||
gimp_matrix3_transform_point (&matrix,
|
||||
tr_tool->trans_info[X0 + 2 * active_handle],
|
||||
tr_tool->trans_info[Y0 + 2 * active_handle],
|
||||
&tr_tool->trans_info[OX0 + 2 * active_handle],
|
||||
&tr_tool->trans_info[OY0 + 2 * active_handle]);
|
||||
}
|
||||
|
||||
if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
|
||||
{
|
||||
/* force redraw */
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
|
||||
ht->matrix_recalculation = TRUE;
|
||||
|
||||
GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time,
|
||||
state, release_type, display);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_modifier_key (GimpTool *tool,
|
||||
GdkModifierType key,
|
||||
gboolean press,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tool);
|
||||
GimpHandleTransformOptions *options;
|
||||
GdkModifierType shift = gimp_get_extend_selection_mask ();
|
||||
GdkModifierType ctrl = gimp_get_constrain_behavior_mask ();
|
||||
GimpTransformHandleMode handle_mode;
|
||||
|
||||
options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tool);
|
||||
|
||||
handle_mode = options->handle_mode;
|
||||
|
||||
if (press)
|
||||
{
|
||||
if (key == (state & (shift | ctrl)))
|
||||
{
|
||||
/* first modifier pressed */
|
||||
ht_tool->saved_handle_mode = options->handle_mode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! (state & (shift | ctrl)))
|
||||
{
|
||||
/* last modifier released */
|
||||
handle_mode = ht_tool->saved_handle_mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (state & shift)
|
||||
{
|
||||
handle_mode = GIMP_HANDLE_MODE_ADD_MOVE;
|
||||
}
|
||||
else if (state & ctrl)
|
||||
{
|
||||
handle_mode = GIMP_HANDLE_MODE_REMOVE;
|
||||
}
|
||||
|
||||
if (handle_mode != options->handle_mode)
|
||||
{
|
||||
g_object_set (options, "handle-mode", handle_mode, NULL);
|
||||
}
|
||||
|
||||
GIMP_TOOL_CLASS (parent_class)->modifier_key (tool, key, press,
|
||||
state, display);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_dialog (GimpTransformTool *tr_tool)
|
||||
{
|
||||
GimpHandleTransformTool *handle_transform = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool);
|
||||
GtkWidget *frame;
|
||||
GtkWidget *table;
|
||||
gint x, y;
|
||||
|
||||
frame = gimp_frame_new (_("Transformation Matrix"));
|
||||
gtk_box_pack_start (GTK_BOX (gimp_tool_gui_get_vbox (tr_tool->gui)), frame,
|
||||
FALSE, FALSE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
table = gtk_table_new (3, 3, FALSE);
|
||||
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), table);
|
||||
gtk_widget_show (table);
|
||||
|
||||
for (y = 0; y < 3; y++)
|
||||
for (x = 0; x < 3; x++)
|
||||
{
|
||||
GtkWidget *label = gtk_label_new (" ");
|
||||
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.0);
|
||||
gtk_label_set_width_chars (GTK_LABEL (label), 12);
|
||||
gtk_table_attach (GTK_TABLE (table), label,
|
||||
x, x + 1, y, y + 1, GTK_EXPAND, GTK_FILL, 0, 0);
|
||||
gtk_widget_show (label);
|
||||
|
||||
handle_transform->label[y][x] = label;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_dialog_update (GimpTransformTool *tr_tool)
|
||||
{
|
||||
GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool);
|
||||
gint x, y;
|
||||
|
||||
for (y = 0; y < 3; y++)
|
||||
{
|
||||
for (x = 0; x < 3; x++)
|
||||
{
|
||||
gchar buf[32];
|
||||
|
||||
g_snprintf (buf, sizeof (buf),
|
||||
"%10.5f", tr_tool->transform.coeff[y][x]);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (ht_tool->label[y][x]), buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_prepare (GimpTransformTool *tr_tool)
|
||||
{
|
||||
GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool);
|
||||
|
||||
tr_tool->trans_info[X0] = (gdouble) tr_tool->x1;
|
||||
tr_tool->trans_info[Y0] = (gdouble) tr_tool->y1;
|
||||
tr_tool->trans_info[X1] = (gdouble) tr_tool->x2;
|
||||
tr_tool->trans_info[Y1] = (gdouble) tr_tool->y1;
|
||||
tr_tool->trans_info[X2] = (gdouble) tr_tool->x1;
|
||||
tr_tool->trans_info[Y2] = (gdouble) tr_tool->y2;
|
||||
tr_tool->trans_info[X3] = (gdouble) tr_tool->x2;
|
||||
tr_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
|
||||
tr_tool->trans_info[OX0] = (gdouble) tr_tool->x1;
|
||||
tr_tool->trans_info[OY0] = (gdouble) tr_tool->y1;
|
||||
tr_tool->trans_info[OX1] = (gdouble) tr_tool->x2;
|
||||
tr_tool->trans_info[OY1] = (gdouble) tr_tool->y1;
|
||||
tr_tool->trans_info[OX2] = (gdouble) tr_tool->x1;
|
||||
tr_tool->trans_info[OY2] = (gdouble) tr_tool->y2;
|
||||
tr_tool->trans_info[OX3] = (gdouble) tr_tool->x2;
|
||||
tr_tool->trans_info[OY3] = (gdouble) tr_tool->y2;
|
||||
tr_tool->trans_info[NUM] = 0;
|
||||
|
||||
ht_tool->matrix_recalculation = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_motion (GimpTransformTool *tr_tool)
|
||||
{
|
||||
GimpHandleTransformOptions *options;
|
||||
gint active_handle;
|
||||
gint num;
|
||||
|
||||
options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
||||
|
||||
active_handle = tr_tool->function - TRANSFORM_HANDLE_N;
|
||||
num = (gint) tr_tool->trans_info[NUM];
|
||||
|
||||
if (active_handle >= 0 && active_handle < 4)
|
||||
{
|
||||
if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE)
|
||||
{
|
||||
tr_tool->trans_info[X0 + 2*active_handle] += tr_tool->curx - tr_tool->lastx;
|
||||
tr_tool->trans_info[Y0 + 2*active_handle] += tr_tool->cury - tr_tool->lasty;
|
||||
/* check for valid position and calculating of OX0...OY3 is
|
||||
* done on button release hopefully this makes the code run
|
||||
* faster Moving could be even faster if there was caching
|
||||
* for the image preview
|
||||
*/
|
||||
}
|
||||
else if (options->handle_mode == GIMP_HANDLE_MODE_TRANSFORM)
|
||||
{
|
||||
gdouble angle, angle_sin, angle_cos, scale;
|
||||
gdouble fixed_handles_x[3];
|
||||
gdouble fixed_handles_y[3];
|
||||
gdouble oldpos_x[4], oldpos_y[4];
|
||||
gdouble newpos_x[4], newpos_y[4];
|
||||
gint i, j;
|
||||
|
||||
for (i = 0, j = 0; i < 4; i++)
|
||||
{
|
||||
/* Find all visible handles that are not being moved */
|
||||
if (i < num && i != active_handle)
|
||||
{
|
||||
fixed_handles_x[j] = tr_tool->prev_trans_info[0][X0+i*2];
|
||||
fixed_handles_y[j] = tr_tool->prev_trans_info[0][Y0+i*2];
|
||||
j++;
|
||||
}
|
||||
|
||||
newpos_x[i] = oldpos_x[i] = tr_tool->prev_trans_info[0][X0+i*2];
|
||||
newpos_y[i] = oldpos_y[i] = tr_tool->prev_trans_info[0][Y0+i*2];
|
||||
}
|
||||
|
||||
newpos_x[active_handle] = oldpos_x[active_handle] + tr_tool->curx - tr_tool->mousex;
|
||||
newpos_y[active_handle] = oldpos_y[active_handle] + tr_tool->cury - tr_tool->mousey;
|
||||
|
||||
switch (num)
|
||||
{
|
||||
case 1:
|
||||
/* move */
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
newpos_x[i] = oldpos_x[i] + tr_tool->curx - tr_tool->mousex;
|
||||
newpos_y[i] = oldpos_y[i] + tr_tool->cury - tr_tool->mousey;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* rotate and keep-aspect-scale */
|
||||
scale = calc_len (newpos_x[active_handle] - fixed_handles_x[0],
|
||||
newpos_y[active_handle] - fixed_handles_y[0])
|
||||
/ calc_len (oldpos_x[active_handle] - fixed_handles_x[0],
|
||||
oldpos_y[active_handle] - fixed_handles_y[0]);
|
||||
|
||||
angle = calc_angle (oldpos_x[active_handle] - fixed_handles_x[0],
|
||||
oldpos_y[active_handle] - fixed_handles_y[0],
|
||||
newpos_x[active_handle] - fixed_handles_x[0],
|
||||
newpos_y[active_handle] - fixed_handles_y[0]);
|
||||
|
||||
angle_sin = sin (angle);
|
||||
angle_cos = cos (angle);
|
||||
|
||||
for (i = 2; i < 4; i++)
|
||||
{
|
||||
newpos_x[i] = fixed_handles_x[0]
|
||||
+ scale * (angle_cos * (oldpos_x[i]-fixed_handles_x[0])
|
||||
+ angle_sin * (oldpos_y[i]-fixed_handles_y[0]) );
|
||||
newpos_y[i] = fixed_handles_y[0]
|
||||
+ scale * (-angle_sin * (oldpos_x[i]-fixed_handles_x[0])
|
||||
+ angle_cos * (oldpos_y[i]-fixed_handles_y[0]) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* shear and non-aspect-scale */
|
||||
scale = calc_lineintersect_ratio (oldpos_x[3], oldpos_y[3],
|
||||
oldpos_x[active_handle], oldpos_y[active_handle],
|
||||
fixed_handles_x[0], fixed_handles_y[0],
|
||||
fixed_handles_x[1], fixed_handles_y[1]);
|
||||
|
||||
newpos_x[3] = oldpos_x[3] + scale * (tr_tool->curx - tr_tool->mousex);
|
||||
newpos_y[3] = oldpos_y[3] + scale * (tr_tool->cury - tr_tool->mousey);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tr_tool->trans_info[X0 + 2*i] = newpos_x[i];
|
||||
tr_tool->trans_info[Y0 + 2*i] = newpos_y[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
|
||||
{
|
||||
gdouble coeff[8*9];
|
||||
gdouble sol[8];
|
||||
int i;
|
||||
gdouble opos_x[4], opos_y[4];
|
||||
gdouble pos_x[4], pos_y[4];
|
||||
GimpHandleTransformTool *handle_transform = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool);
|
||||
|
||||
if (handle_transform->matrix_recalculation)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
pos_x[i] = tr_tool->trans_info[X0+i*2];
|
||||
pos_y[i] = tr_tool->trans_info[Y0+i*2];
|
||||
opos_x[i] = tr_tool->trans_info[OX0+i*2];
|
||||
opos_y[i] = tr_tool->trans_info[OY0+i*2];
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
coeff[i*9+0] = opos_x[i];
|
||||
coeff[i*9+1] = opos_y[i];
|
||||
coeff[i*9+2] = 1;
|
||||
coeff[i*9+3] = 0;
|
||||
coeff[i*9+4] = 0;
|
||||
coeff[i*9+5] = 0;
|
||||
coeff[i*9+6] = -opos_x[i]*pos_x[i];
|
||||
coeff[i*9+7] = -opos_y[i]*pos_x[i];
|
||||
coeff[i*9+8] = pos_x[i];
|
||||
|
||||
coeff[(i+4)*9+0] = 0;
|
||||
coeff[(i+4)*9+1] = 0;
|
||||
coeff[(i+4)*9+2] = 0;
|
||||
coeff[(i+4)*9+3] = opos_x[i];
|
||||
coeff[(i+4)*9+4] = opos_y[i];
|
||||
coeff[(i+4)*9+5] = 1;
|
||||
coeff[(i+4)*9+6] = -opos_x[i]*pos_y[i];
|
||||
coeff[(i+4)*9+7] = -opos_y[i]*pos_y[i];
|
||||
coeff[(i+4)*9+8] = pos_y[i];
|
||||
}
|
||||
|
||||
if (mod_gauss(coeff, sol, 8))
|
||||
{
|
||||
tr_tool->transform.coeff[0][0] = sol[0];
|
||||
tr_tool->transform.coeff[0][1] = sol[1];
|
||||
tr_tool->transform.coeff[0][2] = sol[2];
|
||||
tr_tool->transform.coeff[1][0] = sol[3];
|
||||
tr_tool->transform.coeff[1][1] = sol[4];
|
||||
tr_tool->transform.coeff[1][2] = sol[5];
|
||||
tr_tool->transform.coeff[2][0] = sol[6];
|
||||
tr_tool->transform.coeff[2][1] = sol[7];
|
||||
tr_tool->transform.coeff[2][2] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this should not happen
|
||||
* reset the matrix so the user sees that something went wrong */
|
||||
gimp_matrix3_identity (&tr_tool->transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
gimp_handle_transform_tool_get_undo_desc (GimpTransformTool *tr_tool)
|
||||
{
|
||||
return g_strdup (C_("undo-type", "Handle transform"));
|
||||
}
|
||||
|
||||
static TransformAction
|
||||
gimp_handle_transform_tool_pick_function (GimpTransformTool *tr_tool,
|
||||
const GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
TransformAction i;
|
||||
|
||||
for (i = TRANSFORM_HANDLE_N; i < TRANSFORM_HANDLE_N + 4; i++)
|
||||
{
|
||||
if (tr_tool->handles[i] &&
|
||||
gimp_canvas_item_hit (tr_tool->handles[i], coords->x, coords->y))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return TRANSFORM_HANDLE_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_cursor_update (GimpTransformTool *tr_tool,
|
||||
GimpCursorType *cursor,
|
||||
GimpCursorModifier *modifier)
|
||||
{
|
||||
GimpHandleTransformOptions *options;
|
||||
GimpToolCursorType tool_cursor = GIMP_TOOL_CURSOR_NONE;
|
||||
|
||||
options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
||||
|
||||
*cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
|
||||
*modifier = GIMP_CURSOR_MODIFIER_NONE;
|
||||
|
||||
/* do not show modifiers when the tool isn't active */
|
||||
if (! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tr_tool)))
|
||||
return;
|
||||
|
||||
if (options->handle_mode == GIMP_HANDLE_MODE_TRANSFORM &&
|
||||
tr_tool->function > TRANSFORM_HANDLE_NONE)
|
||||
{
|
||||
switch ((gint) tr_tool->trans_info[NUM])
|
||||
{
|
||||
case 1:
|
||||
tool_cursor = GIMP_TOOL_CURSOR_MOVE;
|
||||
break;
|
||||
case 2:
|
||||
tool_cursor = GIMP_TOOL_CURSOR_ROTATE;
|
||||
break;
|
||||
case 3:
|
||||
tool_cursor = GIMP_TOOL_CURSOR_SHEAR;
|
||||
break;
|
||||
case 4:
|
||||
tool_cursor = GIMP_TOOL_CURSOR_PERSPECTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE)
|
||||
{
|
||||
if (tr_tool->function > TRANSFORM_HANDLE_NONE)
|
||||
*modifier = GIMP_CURSOR_MODIFIER_MOVE;
|
||||
else
|
||||
*modifier = GIMP_CURSOR_MODIFIER_PLUS;
|
||||
}
|
||||
else if (options->handle_mode == GIMP_HANDLE_MODE_REMOVE)
|
||||
{
|
||||
*modifier = GIMP_CURSOR_MODIFIER_MINUS;
|
||||
}
|
||||
|
||||
gimp_tool_control_set_tool_cursor (GIMP_TOOL (tr_tool)->control,
|
||||
tool_cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool,
|
||||
gint handle_w,
|
||||
gint handle_h)
|
||||
{
|
||||
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tr_tool);
|
||||
gint i;
|
||||
|
||||
#if 0
|
||||
/* show additional points for debugging */
|
||||
for (i = tr_tool->trans_info[NUM]; i < 4; i++)
|
||||
{
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_FILLED_CIRCLE,
|
||||
tr_tool->trans_info[X0+2*i],
|
||||
tr_tool->trans_info[Y0+2*i],
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_FILLED_DIAMOND,
|
||||
tr_tool->trans_info[OX0+2*i],
|
||||
tr_tool->trans_info[OY0+2*i],
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
}
|
||||
|
||||
for (i = 0; i < tr_tool->trans_info[NUM]; i++)
|
||||
{
|
||||
tr_tool->handles[TRANSFORM_HANDLE_N + i] =
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_DIAMOND,
|
||||
tr_tool->trans_info[OX0+2*i],
|
||||
tr_tool->trans_info[OY0+2*i],
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < tr_tool->trans_info[NUM]; i++)
|
||||
{
|
||||
tr_tool->handles[TRANSFORM_HANDLE_N + i] =
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_CIRCLE,
|
||||
tr_tool->trans_info[X0 + 2 * i],
|
||||
tr_tool->trans_info[Y0 + 2 * i],
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if a handle is not on the connection line of two other handles */
|
||||
static gboolean
|
||||
is_handle_position_valid (GimpTransformTool *tr_tool,
|
||||
gint active_handle)
|
||||
{
|
||||
gint i, j, k;
|
||||
|
||||
if (tr_tool->trans_info[NUM] < 3)
|
||||
{
|
||||
/* there aren't two other handles */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (tr_tool->trans_info[NUM] == 3)
|
||||
{
|
||||
return ((tr_tool->trans_info[X0] - tr_tool->trans_info[X1]) *
|
||||
(tr_tool->trans_info[Y1] - tr_tool->trans_info[Y2]) !=
|
||||
|
||||
(tr_tool->trans_info[X1] - tr_tool->trans_info[X2]) *
|
||||
(tr_tool->trans_info[Y0] - tr_tool->trans_info[Y1]));
|
||||
}
|
||||
|
||||
/* tr_tool->trans_info[NUM] == 4 */
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
for (j = i + 1; j < 3; j++)
|
||||
{
|
||||
for (k = j + 1; i < 4; i++)
|
||||
{
|
||||
if (active_handle == i ||
|
||||
active_handle == j ||
|
||||
active_handle == k)
|
||||
{
|
||||
if ((tr_tool->trans_info[X0 + 2 * i] -
|
||||
tr_tool->trans_info[X0 + 2 * j]) *
|
||||
(tr_tool->trans_info[Y0 + 2 * j] -
|
||||
tr_tool->trans_info[Y0 + 2 * k]) ==
|
||||
|
||||
(tr_tool->trans_info[X0 + 2 * j] -
|
||||
tr_tool->trans_info[X0 + 2 * k]) *
|
||||
(tr_tool->trans_info[Y0 + 2 * i] -
|
||||
tr_tool->trans_info[Y0 + 2 * j]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* three handles on a line causes problems.
|
||||
* Let's move the new handle around a bit to find a better position */
|
||||
static void
|
||||
handle_micro_move (GimpTransformTool *tr_tool,
|
||||
gint active_handle)
|
||||
{
|
||||
gdouble posx = tr_tool->trans_info[X0 + 2 * active_handle];
|
||||
gdouble posy = tr_tool->trans_info[Y0 + 2 * active_handle];
|
||||
gdouble dx, dy;
|
||||
|
||||
for (dx = -0.1; dx < 0.11; dx += 0.1)
|
||||
{
|
||||
tr_tool->trans_info[X0 + 2 * active_handle] = posx + dx;
|
||||
|
||||
for (dy = -0.1; dy < 0.11; dy += 0.1)
|
||||
{
|
||||
tr_tool->trans_info[Y0 + 2 * active_handle] = posy + dy;
|
||||
|
||||
if (is_handle_position_valid (tr_tool, active_handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* finds the clockwise angle between the vectors given, 0-2π */
|
||||
static inline gdouble
|
||||
calc_angle (gdouble ax,
|
||||
gdouble ay,
|
||||
gdouble bx,
|
||||
gdouble by)
|
||||
{
|
||||
gdouble angle;
|
||||
gdouble direction;
|
||||
gdouble length = sqrt ((ax * ax + ay * ay) * (bx * bx + by * by));
|
||||
|
||||
angle = acos ((ax * bx + ay * by) / length);
|
||||
direction = ax * by - ay * bx;
|
||||
|
||||
return ((direction < 0) ? angle : 2 * G_PI - angle);
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_len (gdouble a,
|
||||
gdouble b)
|
||||
{
|
||||
return sqrt (a * a + b * b);
|
||||
}
|
||||
|
||||
|
||||
/* imagine two lines, one through the points p1 and p2, the other one
|
||||
* through the points q1 and q2. Find the intersection point r.
|
||||
* Calculate (distance p1 to r)/(distance p2 to r)
|
||||
*/
|
||||
static inline gdouble
|
||||
calc_lineintersect_ratio (gdouble p1x, gdouble p1y,
|
||||
gdouble p2x, gdouble p2y,
|
||||
gdouble q1x, gdouble q1y,
|
||||
gdouble q2x, gdouble q2y)
|
||||
{
|
||||
gdouble denom, u;
|
||||
|
||||
denom = (q2y - q1y) * (p2x - p1x) - (q2x - q1x) * (p2y - p1y);
|
||||
if (denom == 0.0)
|
||||
{
|
||||
/* u is infinite, so u/(u-1) is 1 */
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
u = (q2y - q1y) * (q1x - p1x) - (q1y - p1y) * (q2x - q1x);
|
||||
u /= denom;
|
||||
|
||||
return u / (u - 1);
|
||||
}
|
||||
|
||||
|
||||
/* modified gaussian algorithm
|
||||
* solves a system of linear equations
|
||||
*
|
||||
* Example:
|
||||
* 1x + 2y + 4z = 25
|
||||
* 2x + 1y = 4
|
||||
* 3x + 5y + 2z = 23
|
||||
* Solution: x=1, y=2, z=5
|
||||
*
|
||||
* Input:
|
||||
* matrix = { 1,2,4,25,2,1,0,4,3,5,2,23 }
|
||||
* s = 3 (Number of variables)
|
||||
* Output:
|
||||
* return value == TRUE (TRUE, if there is a single unique solution)
|
||||
* solution == { 1,2,5 } (if the return value is FALSE, the content
|
||||
* of solution is of no use)
|
||||
*/
|
||||
static gboolean
|
||||
mod_gauss (gdouble matrix[],
|
||||
gdouble solution[],
|
||||
gint s)
|
||||
{
|
||||
gint p[s]; /* row permutation */
|
||||
gint i, j, r, temp;
|
||||
gdouble q;
|
||||
gint t = s + 1;
|
||||
|
||||
for (i = 0; i < s; i++)
|
||||
{
|
||||
p[i] = i;
|
||||
}
|
||||
|
||||
for (r = 0; r < s; r++)
|
||||
{
|
||||
/* make sure that (r,r) is not 0 */
|
||||
if (matrix[p[r] * t + r] == 0.0)
|
||||
{
|
||||
/* we need to permutate rows */
|
||||
for (i = r + 1; i <= s; i++)
|
||||
{
|
||||
if (i == s)
|
||||
{
|
||||
/* if this happens, the linear system has zero or
|
||||
* more than one solutions.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (matrix[p[i] * t + r] != 0.0)
|
||||
break;
|
||||
}
|
||||
|
||||
temp = p[r];
|
||||
p[r] = p[i];
|
||||
p[i] = temp;
|
||||
}
|
||||
|
||||
/* make (r,r) == 1 */
|
||||
q = 1.0 / matrix[p[r] * t + r];
|
||||
matrix[p[r] * t + r] = 1.0;
|
||||
|
||||
for (j = r + 1; j < t; j++)
|
||||
{
|
||||
matrix[p[r] * t + j] *= q;
|
||||
}
|
||||
|
||||
/* make that all entries in column r are 0 (except (r,r)) */
|
||||
for (i = 0; i < s; i++)
|
||||
{
|
||||
if (i == r)
|
||||
continue;
|
||||
|
||||
for (j = r + 1; j < t ; j++)
|
||||
{
|
||||
matrix[p[i] * t + j] -= matrix[p[r] * t + j] * matrix[p[i] * t + r];
|
||||
}
|
||||
|
||||
/* we don't need to execute the following line
|
||||
* since we won't access this element again:
|
||||
*
|
||||
* matrix[p[i] * t + r] = 0.0;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < s; i++)
|
||||
{
|
||||
solution[i] = matrix[p[i] * t + s];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_HANDLE_TRANSFORM_TOOL_H__
|
||||
#define __GIMP_HANDLE_TRANSFORM_TOOL_H__
|
||||
|
||||
|
||||
#include "gimptransformtool.h"
|
||||
|
||||
|
||||
#define GIMP_TYPE_HANDLE_TRANSFORM_TOOL (gimp_handle_transform_tool_get_type ())
|
||||
#define GIMP_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformTool))
|
||||
#define GIMP_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformToolClass))
|
||||
#define GIMP_IS_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL))
|
||||
#define GIMP_IS_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HANDLE_TRANSFORM_TOOL))
|
||||
#define GIMP_HANDLE_TRANSFORM_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformToolClass))
|
||||
|
||||
#define GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS(t) (GIMP_HANDLE_TRANSFORM_OPTIONS (gimp_tool_get_options (GIMP_TOOL (t))))
|
||||
|
||||
|
||||
typedef struct _GimpHandleTransformTool GimpHandleTransformTool;
|
||||
typedef struct _GimpHandleTransformToolClass GimpHandleTransformToolClass;
|
||||
|
||||
struct _GimpHandleTransformTool
|
||||
{
|
||||
GimpTransformTool parent_instance;
|
||||
|
||||
GtkWidget *label[3][3];
|
||||
gboolean matrix_recalculation;
|
||||
|
||||
GimpTransformHandleMode saved_handle_mode;
|
||||
};
|
||||
|
||||
struct _GimpHandleTransformToolClass
|
||||
{
|
||||
GimpTransformToolClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
void gimp_handle_transform_tool_register (GimpToolRegisterCallback callback,
|
||||
gpointer data);
|
||||
|
||||
GType gimp_handle_transform_tool_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __GIMP_HANDLE_TRANSFORM_TOOL_H__ */
|
|
@ -59,6 +59,7 @@
|
|||
#include "display/gimptoolgui.h"
|
||||
|
||||
#include "gimptoolcontrol.h"
|
||||
#include "gimphandletransformtool.h"
|
||||
#include "gimpperspectivetool.h"
|
||||
#include "gimpunifiedtransformtool.h"
|
||||
#include "gimptransformoptions.h"
|
||||
|
@ -1088,10 +1089,15 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
|
|||
if (gimp_transform_options_show_preview (options))
|
||||
{
|
||||
GimpMatrix3 matrix = tr_tool->transform;
|
||||
gboolean perspective;
|
||||
|
||||
if (options->direction == GIMP_TRANSFORM_BACKWARD)
|
||||
gimp_matrix3_invert (&matrix);
|
||||
|
||||
perspective = (GIMP_IS_PERSPECTIVE_TOOL (tr_tool) ||
|
||||
GIMP_IS_HANDLE_TRANSFORM_TOOL (tr_tool) ||
|
||||
GIMP_IS_UNIFIED_TRANSFORM_TOOL (tr_tool));
|
||||
|
||||
gimp_draw_tool_add_transform_preview (draw_tool,
|
||||
tool->drawable,
|
||||
&matrix,
|
||||
|
@ -1099,8 +1105,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
|
|||
tr_tool->y1,
|
||||
tr_tool->x2,
|
||||
tr_tool->y2,
|
||||
GIMP_IS_PERSPECTIVE_TOOL (tr_tool) ||
|
||||
GIMP_IS_UNIFIED_TRANSFORM_TOOL (tr_tool),
|
||||
perspective,
|
||||
options->preview_opacity);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef enum
|
|||
* of the enums at the top of each transformation tool, stored in
|
||||
* trans_info and related
|
||||
*/
|
||||
#define TRANS_INFO_SIZE 10
|
||||
#define TRANS_INFO_SIZE 17
|
||||
|
||||
typedef gdouble TransInfo[TRANS_INFO_SIZE];
|
||||
|
||||
|
|
|
@ -73,6 +73,37 @@ gimp_button_release_type_get_type (void)
|
|||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
gimp_transform_handle_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ GIMP_HANDLE_MODE_ADD_MOVE, "GIMP_HANDLE_MODE_ADD_MOVE", "add-move" },
|
||||
{ GIMP_HANDLE_MODE_REMOVE, "GIMP_HANDLE_MODE_REMOVE", "remove" },
|
||||
{ GIMP_HANDLE_MODE_TRANSFORM, "GIMP_HANDLE_MODE_TRANSFORM", "transform" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const GimpEnumDesc descs[] =
|
||||
{
|
||||
{ GIMP_HANDLE_MODE_ADD_MOVE, NC_("transform-handle-mode", "Add/Move"), NULL },
|
||||
{ GIMP_HANDLE_MODE_REMOVE, NC_("transform-handle-mode", "Remove"), NULL },
|
||||
{ GIMP_HANDLE_MODE_TRANSFORM, NC_("transform-handle-mode", "Transform"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("GimpTransformHandleMode", values);
|
||||
gimp_type_set_translation_context (type, "transform-handle-mode");
|
||||
gimp_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
gimp_rectangle_constraint_get_type (void)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,18 @@ typedef enum
|
|||
} GimpButtonReleaseType;
|
||||
|
||||
|
||||
#define GIMP_TYPE_TRANSFORM_HANDLE_MODE (gimp_transform_handle_mode_get_type ())
|
||||
|
||||
GType gimp_transform_handle_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GIMP_HANDLE_MODE_ADD_MOVE, /*< desc="Add/Move" >*/
|
||||
GIMP_HANDLE_MODE_REMOVE, /*< desc="Remove" >*/
|
||||
GIMP_HANDLE_MODE_TRANSFORM, /*< desc="Transform" >*/
|
||||
} GimpTransformHandleMode;
|
||||
|
||||
|
||||
#define GIMP_TYPE_RECTANGLE_CONSTRAINT (gimp_rectangle_constraint_get_type ())
|
||||
|
||||
GType gimp_rectangle_constraint_get_type (void) G_GNUC_CONST;
|
||||
|
|
|
@ -281,6 +281,7 @@
|
|||
#define GIMP_HELP_TOOL_FOREGROUND_SELECT "gimp-tool-foreground-select"
|
||||
#define GIMP_HELP_TOOL_FUZZY_SELECT "gimp-tool-fuzzy-select"
|
||||
#define GIMP_HELP_TOOL_GEGL "gimp-tool-gegl"
|
||||
#define GIMP_HELP_TOOL_HANDLE_TRANSFORM "gimp-tool-handle-transform"
|
||||
#define GIMP_HELP_TOOL_HEAL "gimp-tool-heal"
|
||||
#define GIMP_HELP_TOOL_HUE_SATURATION "gimp-tool-hue-saturation"
|
||||
#define GIMP_HELP_TOOL_INK "gimp-tool-ink"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
|
@ -180,6 +180,7 @@ icons16_DATA = \
|
|||
16/gimp-tool-foreground-select.png \
|
||||
16/gimp-tool-free-select.png \
|
||||
16/gimp-tool-fuzzy-select.png \
|
||||
16/gimp-tool-handle-transform.png \
|
||||
16/gimp-tool-heal.png \
|
||||
16/gimp-tool-hue-saturation.png \
|
||||
16/gimp-tool-ink.png \
|
||||
|
@ -290,6 +291,7 @@ icons22_DATA = \
|
|||
22/gimp-tool-foreground-select.png \
|
||||
22/gimp-tool-free-select.png \
|
||||
22/gimp-tool-fuzzy-select.png \
|
||||
22/gimp-tool-handle-transform.png \
|
||||
22/gimp-tool-heal.png \
|
||||
22/gimp-tool-hue-saturation.png \
|
||||
22/gimp-tool-ink.png \
|
||||
|
|
|
@ -256,6 +256,7 @@ static const GtkStockItem gimp_stock_items[] =
|
|||
{ GIMP_STOCK_TOOL_FOREGROUND_SELECT, N_("_Select"), 0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_FUZZY_SELECT, NULL, 0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_HUE_SATURATION, NULL, 0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_HANDLE_TRANSFORM,N_("_Transform"),0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_HEAL, NULL, 0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_INK, NULL, 0, 0, LIBGIMP_DOMAIN },
|
||||
{ GIMP_STOCK_TOOL_ISCISSORS, NULL, 0, 0, LIBGIMP_DOMAIN },
|
||||
|
|
|
@ -125,6 +125,7 @@ G_BEGIN_DECLS
|
|||
#define GIMP_STOCK_TOOL_FREE_SELECT "gimp-tool-free-select"
|
||||
#define GIMP_STOCK_TOOL_FOREGROUND_SELECT "gimp-tool-foreground-select"
|
||||
#define GIMP_STOCK_TOOL_FUZZY_SELECT "gimp-tool-fuzzy-select"
|
||||
#define GIMP_STOCK_TOOL_HANDLE_TRANSFORM "gimp-tool-handle-transform"
|
||||
#define GIMP_STOCK_TOOL_HEAL "gimp-tool-heal"
|
||||
#define GIMP_STOCK_TOOL_HUE_SATURATION "gimp-tool-hue-saturation"
|
||||
#define GIMP_STOCK_TOOL_INK "gimp-tool-ink"
|
||||
|
|
|
@ -602,6 +602,7 @@
|
|||
<menuitem action="tools-shear" />
|
||||
<menuitem action="tools-perspective" />
|
||||
<menuitem action="tools-unified-transform" />
|
||||
<menuitem action="tools-handle-transform" />
|
||||
<menuitem action="tools-flip" />
|
||||
<menuitem action="tools-cage" />
|
||||
<menuitem action="tools-warp" />
|
||||
|
|
|
@ -368,6 +368,8 @@ app/tools/gimpforegroundselecttool.c
|
|||
app/tools/gimpfreeselecttool.c
|
||||
app/tools/gimpfuzzyselecttool.c
|
||||
app/tools/gimpgegltool.c
|
||||
app/tools/gimphandletransformoptions.c
|
||||
app/tools/gimphandletransformtool.c
|
||||
app/tools/gimphealtool.c
|
||||
app/tools/gimphistogramoptions.c
|
||||
app/tools/gimphuesaturationtool.c
|
||||
|
|
Loading…
Reference in New Issue