1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpmath/gimpmath.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "tools-types.h"
27
28 #include "widgets/gimphelp-ids.h"
29
30 #include "display/gimpdisplay.h"
31 #include "display/gimpdisplayshell.h"
32 #include "display/gimpdisplayshell-transform.h"
33 #include "display/gimptoolgui.h"
34 #include "display/gimptooltransformgrid.h"
35
36 #include "gimpperspectivetool.h"
37 #include "gimptoolcontrol.h"
38 #include "gimptransformgridoptions.h"
39
40 #include "gimp-intl.h"
41
42
43 /* index into trans_info array */
44 enum
45 {
46 X0,
47 Y0,
48 X1,
49 Y1,
50 X2,
51 Y2,
52 X3,
53 Y3
54 };
55
56
57 /* local function prototypes */
58
59 static void gimp_perspective_tool_matrix_to_info (GimpTransformGridTool *tg_tool,
60 const GimpMatrix3 *transform);
61 static void gimp_perspective_tool_prepare (GimpTransformGridTool *tg_tool);
62 static void gimp_perspective_tool_readjust (GimpTransformGridTool *tg_tool);
63 static GimpToolWidget * gimp_perspective_tool_get_widget (GimpTransformGridTool *tg_tool);
64 static void gimp_perspective_tool_update_widget (GimpTransformGridTool *tg_tool);
65 static void gimp_perspective_tool_widget_changed (GimpTransformGridTool *tg_tool);
66
67 static void gimp_perspective_tool_info_to_points (GimpGenericTransformTool *generic);
68
69
G_DEFINE_TYPE(GimpPerspectiveTool,gimp_perspective_tool,GIMP_TYPE_GENERIC_TRANSFORM_TOOL)70 G_DEFINE_TYPE (GimpPerspectiveTool, gimp_perspective_tool,
71 GIMP_TYPE_GENERIC_TRANSFORM_TOOL)
72
73 #define parent_class gimp_perspective_tool_parent_class
74
75
76 void
77 gimp_perspective_tool_register (GimpToolRegisterCallback callback,
78 gpointer data)
79 {
80 (* callback) (GIMP_TYPE_PERSPECTIVE_TOOL,
81 GIMP_TYPE_TRANSFORM_GRID_OPTIONS,
82 gimp_transform_grid_options_gui,
83 GIMP_CONTEXT_PROP_MASK_BACKGROUND,
84 "gimp-perspective-tool",
85 _("Perspective"),
86 _("Perspective Tool: "
87 "Change perspective of the layer, selection or path"),
88 N_("_Perspective"), "<shift>P",
89 NULL, GIMP_HELP_TOOL_PERSPECTIVE,
90 GIMP_ICON_TOOL_PERSPECTIVE,
91 data);
92 }
93
94 static void
gimp_perspective_tool_class_init(GimpPerspectiveToolClass * klass)95 gimp_perspective_tool_class_init (GimpPerspectiveToolClass *klass)
96 {
97 GimpTransformToolClass *tr_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
98 GimpTransformGridToolClass *tg_class = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
99 GimpGenericTransformToolClass *generic_class = GIMP_GENERIC_TRANSFORM_TOOL_CLASS (klass);
100
101 tg_class->matrix_to_info = gimp_perspective_tool_matrix_to_info;
102 tg_class->prepare = gimp_perspective_tool_prepare;
103 tg_class->readjust = gimp_perspective_tool_readjust;
104 tg_class->get_widget = gimp_perspective_tool_get_widget;
105 tg_class->update_widget = gimp_perspective_tool_update_widget;
106 tg_class->widget_changed = gimp_perspective_tool_widget_changed;
107
108 generic_class->info_to_points = gimp_perspective_tool_info_to_points;
109
110 tr_class->undo_desc = C_("undo-type", "Perspective");
111 tr_class->progress_text = _("Perspective transformation");
112 }
113
114 static void
gimp_perspective_tool_init(GimpPerspectiveTool * perspective_tool)115 gimp_perspective_tool_init (GimpPerspectiveTool *perspective_tool)
116 {
117 GimpTool *tool = GIMP_TOOL (perspective_tool);
118
119 gimp_tool_control_set_tool_cursor (tool->control,
120 GIMP_TOOL_CURSOR_PERSPECTIVE);
121 }
122
123 static void
gimp_perspective_tool_matrix_to_info(GimpTransformGridTool * tg_tool,const GimpMatrix3 * transform)124 gimp_perspective_tool_matrix_to_info (GimpTransformGridTool *tg_tool,
125 const GimpMatrix3 *transform)
126 {
127 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
128
129 gimp_matrix3_transform_point (transform,
130 tr_tool->x1,
131 tr_tool->y1,
132 &tg_tool->trans_info[X0],
133 &tg_tool->trans_info[Y0]);
134 gimp_matrix3_transform_point (transform,
135 tr_tool->x2,
136 tr_tool->y1,
137 &tg_tool->trans_info[X1],
138 &tg_tool->trans_info[Y1]);
139 gimp_matrix3_transform_point (transform,
140 tr_tool->x1,
141 tr_tool->y2,
142 &tg_tool->trans_info[X2],
143 &tg_tool->trans_info[Y2]);
144 gimp_matrix3_transform_point (transform,
145 tr_tool->x2,
146 tr_tool->y2,
147 &tg_tool->trans_info[X3],
148 &tg_tool->trans_info[Y3]);
149 }
150
151 static void
gimp_perspective_tool_prepare(GimpTransformGridTool * tg_tool)152 gimp_perspective_tool_prepare (GimpTransformGridTool *tg_tool)
153 {
154 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
155
156 GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->prepare (tg_tool);
157
158 tg_tool->trans_info[X0] = (gdouble) tr_tool->x1;
159 tg_tool->trans_info[Y0] = (gdouble) tr_tool->y1;
160 tg_tool->trans_info[X1] = (gdouble) tr_tool->x2;
161 tg_tool->trans_info[Y1] = (gdouble) tr_tool->y1;
162 tg_tool->trans_info[X2] = (gdouble) tr_tool->x1;
163 tg_tool->trans_info[Y2] = (gdouble) tr_tool->y2;
164 tg_tool->trans_info[X3] = (gdouble) tr_tool->x2;
165 tg_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
166 }
167
168 static void
gimp_perspective_tool_readjust(GimpTransformGridTool * tg_tool)169 gimp_perspective_tool_readjust (GimpTransformGridTool *tg_tool)
170 {
171 GimpTool *tool = GIMP_TOOL (tg_tool);
172 GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
173 gdouble x;
174 gdouble y;
175 gdouble r;
176
177 x = shell->disp_width / 2.0;
178 y = shell->disp_height / 2.0;
179 r = MAX (MIN (x, y) / G_SQRT2 -
180 GIMP_TOOL_TRANSFORM_GRID_MAX_HANDLE_SIZE / 2.0,
181 GIMP_TOOL_TRANSFORM_GRID_MAX_HANDLE_SIZE / 2.0);
182
183 gimp_display_shell_untransform_xy_f (shell,
184 x - r, y - r,
185 &tg_tool->trans_info[X0],
186 &tg_tool->trans_info[Y0]);
187 gimp_display_shell_untransform_xy_f (shell,
188 x + r, y - r,
189 &tg_tool->trans_info[X1],
190 &tg_tool->trans_info[Y1]);
191 gimp_display_shell_untransform_xy_f (shell,
192 x - r, y + r,
193 &tg_tool->trans_info[X2],
194 &tg_tool->trans_info[Y2]);
195 gimp_display_shell_untransform_xy_f (shell,
196 x + r, y + r,
197 &tg_tool->trans_info[X3],
198 &tg_tool->trans_info[Y3]);
199 }
200
201 static GimpToolWidget *
gimp_perspective_tool_get_widget(GimpTransformGridTool * tg_tool)202 gimp_perspective_tool_get_widget (GimpTransformGridTool *tg_tool)
203 {
204 GimpTool *tool = GIMP_TOOL (tg_tool);
205 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
206 GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
207 GimpToolWidget *widget;
208
209 widget = gimp_tool_transform_grid_new (shell,
210 &tr_tool->transform,
211 tr_tool->x1,
212 tr_tool->y1,
213 tr_tool->x2,
214 tr_tool->y2);
215
216 g_object_set (widget,
217 "inside-function", GIMP_TRANSFORM_FUNCTION_PERSPECTIVE,
218 "outside-function", GIMP_TRANSFORM_FUNCTION_PERSPECTIVE,
219 "use-perspective-handles", TRUE,
220 "use-center-handle", TRUE,
221 NULL);
222
223 return widget;
224 }
225
226 static void
gimp_perspective_tool_update_widget(GimpTransformGridTool * tg_tool)227 gimp_perspective_tool_update_widget (GimpTransformGridTool *tg_tool)
228 {
229 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
230
231 GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
232
233 g_object_set (tg_tool->widget,
234 "x1", (gdouble) tr_tool->x1,
235 "y1", (gdouble) tr_tool->y1,
236 "x2", (gdouble) tr_tool->x2,
237 "y2", (gdouble) tr_tool->y2,
238 NULL);
239 }
240
241 static void
gimp_perspective_tool_widget_changed(GimpTransformGridTool * tg_tool)242 gimp_perspective_tool_widget_changed (GimpTransformGridTool *tg_tool)
243 {
244 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
245 GimpMatrix3 *transform;
246
247 g_object_get (tg_tool->widget,
248 "transform", &transform,
249 NULL);
250
251 gimp_matrix3_transform_point (transform,
252 tr_tool->x1, tr_tool->y1,
253 &tg_tool->trans_info[X0],
254 &tg_tool->trans_info[Y0]);
255 gimp_matrix3_transform_point (transform,
256 tr_tool->x2, tr_tool->y1,
257 &tg_tool->trans_info[X1],
258 &tg_tool->trans_info[Y1]);
259 gimp_matrix3_transform_point (transform,
260 tr_tool->x1, tr_tool->y2,
261 &tg_tool->trans_info[X2],
262 &tg_tool->trans_info[Y2]);
263 gimp_matrix3_transform_point (transform,
264 tr_tool->x2, tr_tool->y2,
265 &tg_tool->trans_info[X3],
266 &tg_tool->trans_info[Y3]);
267
268 g_free (transform);
269
270 GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->widget_changed (tg_tool);
271 }
272
273 static void
gimp_perspective_tool_info_to_points(GimpGenericTransformTool * generic)274 gimp_perspective_tool_info_to_points (GimpGenericTransformTool *generic)
275 {
276 GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (generic);
277 GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (generic);
278
279 generic->input_points[0] = (GimpVector2) {tr_tool->x1, tr_tool->y1};
280 generic->input_points[1] = (GimpVector2) {tr_tool->x2, tr_tool->y1};
281 generic->input_points[2] = (GimpVector2) {tr_tool->x1, tr_tool->y2};
282 generic->input_points[3] = (GimpVector2) {tr_tool->x2, tr_tool->y2};
283
284 generic->output_points[0] = (GimpVector2) {tg_tool->trans_info[X0],
285 tg_tool->trans_info[Y0]};
286 generic->output_points[1] = (GimpVector2) {tg_tool->trans_info[X1],
287 tg_tool->trans_info[Y1]};
288 generic->output_points[2] = (GimpVector2) {tg_tool->trans_info[X2],
289 tg_tool->trans_info[Y2]};
290 generic->output_points[3] = (GimpVector2) {tg_tool->trans_info[X3],
291 tg_tool->trans_info[Y3]};
292 }
293