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 "libgimpbase/gimpbase.h"
24 #include "libgimpmath/gimpmath.h"
25 
26 #include "display-types.h"
27 
28 #include "core/gimp-utils.h"
29 #include "core/gimpimage.h"
30 #include "core/gimpunit.h"
31 
32 #include "gimpdisplay.h"
33 #include "gimpdisplayshell.h"
34 #include "gimpdisplayshell-utils.h"
35 
36 #include "gimp-intl.h"
37 
38 void
gimp_display_shell_get_constrained_line_params(GimpDisplayShell * shell,gdouble * offset_angle,gdouble * xres,gdouble * yres)39 gimp_display_shell_get_constrained_line_params (GimpDisplayShell *shell,
40                                                 gdouble          *offset_angle,
41                                                 gdouble          *xres,
42                                                 gdouble          *yres)
43 {
44   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
45   g_return_if_fail (offset_angle != NULL);
46   g_return_if_fail (xres != NULL);
47   g_return_if_fail (yres != NULL);
48 
49   if (shell->flip_horizontally ^ shell->flip_vertically)
50     *offset_angle = +shell->rotate_angle;
51   else
52     *offset_angle = -shell->rotate_angle;
53 
54   *xres = 1.0;
55   *yres = 1.0;
56 
57   if (! shell->dot_for_dot)
58     {
59       GimpImage *image = gimp_display_get_image (shell->display);
60 
61       if (image)
62         gimp_image_get_resolution (image, xres, yres);
63     }
64 }
65 
66 void
gimp_display_shell_constrain_line(GimpDisplayShell * shell,gdouble start_x,gdouble start_y,gdouble * end_x,gdouble * end_y,gint n_snap_lines)67 gimp_display_shell_constrain_line (GimpDisplayShell *shell,
68                                    gdouble           start_x,
69                                    gdouble           start_y,
70                                    gdouble          *end_x,
71                                    gdouble          *end_y,
72                                    gint              n_snap_lines)
73 {
74   gdouble offset_angle;
75   gdouble xres, yres;
76 
77   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
78   g_return_if_fail (end_x != NULL);
79   g_return_if_fail (end_y != NULL);
80 
81   gimp_display_shell_get_constrained_line_params (shell,
82                                                   &offset_angle,
83                                                   &xres, &yres);
84 
85   gimp_constrain_line (start_x, start_y,
86                        end_x,   end_y,
87                        n_snap_lines,
88                        offset_angle,
89                        xres, yres);
90 }
91 
92 gdouble
gimp_display_shell_constrain_angle(GimpDisplayShell * shell,gdouble angle,gint n_snap_lines)93 gimp_display_shell_constrain_angle (GimpDisplayShell *shell,
94                                     gdouble           angle,
95                                     gint              n_snap_lines)
96 {
97   gdouble x, y;
98 
99   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), 0.0);
100 
101   x = cos (angle);
102   y = sin (angle);
103 
104   gimp_display_shell_constrain_line (shell,
105                                      0.0, 0.0,
106                                      &x,  &y,
107                                      n_snap_lines);
108 
109   return atan2 (y, x);
110 }
111 
112 /**
113  * gimp_display_shell_get_line_status:
114  * @status:    initial status text.
115  * @separator: separator text between the line information and @status.
116  * @shell:     #GimpDisplayShell this status text will be displayed for.
117  * @x1:        abscissa of first point.
118  * @y1:        ordinate of first point.
119  * @x2:        abscissa of second point.
120  * @y2:        ordinate of second point.
121  *
122  * Utility function to prepend the status message with a distance and
123  * angle value. Obviously this is only to be used for tools when it
124  * makes sense, and in particular when there is a concept of line. For
125  * instance when shift-clicking a painting tool or in the blend tool,
126  * etc.
127  * This utility prevents code duplication but also ensures a common
128  * display for every tool where such a status is needed. It will take
129  * into account the shell unit settings and will use the ideal digit
130  * precision according to current image resolution.
131  *
132  * Return value: a newly allocated string containing the enhanced status.
133  **/
134 gchar *
gimp_display_shell_get_line_status(GimpDisplayShell * shell,const gchar * status,const gchar * separator,gdouble x1,gdouble y1,gdouble x2,gdouble y2)135 gimp_display_shell_get_line_status (GimpDisplayShell *shell,
136                                     const gchar      *status,
137                                     const gchar      *separator,
138                                     gdouble           x1,
139                                     gdouble           y1,
140                                     gdouble           x2,
141                                     gdouble           y2)
142 {
143   GimpImage *image;
144   gchar     *enhanced_status;
145   gdouble    xres;
146   gdouble    yres;
147   gdouble    dx, dy, pixel_dist;
148   gdouble    angle;
149 
150   image = gimp_display_get_image (shell->display);
151   if (! image)
152     {
153       /* This makes no sense to add line information when no image is
154        * attached to the display. */
155       return g_strdup (status);
156     }
157 
158   if (shell->unit == GIMP_UNIT_PIXEL)
159     xres = yres = 1.0;
160   else
161     gimp_image_get_resolution (image, &xres, &yres);
162 
163   dx = x2 - x1;
164   dy = y2 - y1;
165   pixel_dist = sqrt (SQR (dx) + SQR (dy));
166 
167   if (dx)
168     {
169       angle = gimp_rad_to_deg (atan ((dy/yres) / (dx/xres)));
170       if (dx > 0)
171         {
172           if (dy > 0)
173             angle = 360.0 - angle;
174           else if (dy < 0)
175             angle = -angle;
176         }
177       else
178         {
179           angle = 180.0 - angle;
180         }
181     }
182   else if (dy)
183     {
184       angle = dy > 0 ? 270.0 : 90.0;
185     }
186   else
187     {
188       angle = 0.0;
189     }
190 
191   if (shell->unit == GIMP_UNIT_PIXEL)
192     {
193       enhanced_status = g_strdup_printf ("%.1f %s, %.2f\302\260%s%s",
194                                          pixel_dist, _("pixels"), angle,
195                                          separator, status);
196     }
197   else
198     {
199       gdouble inch_dist;
200       gdouble unit_dist;
201       gint    digits = 0;
202 
203       /* The distance in unit. */
204       inch_dist = sqrt (SQR (dx / xres) + SQR (dy / yres));
205       unit_dist = gimp_unit_get_factor (shell->unit) * inch_dist;
206 
207       /* The ideal digit precision for unit in current resolution. */
208       if (inch_dist)
209         digits = gimp_unit_get_scaled_digits (shell->unit,
210                                               pixel_dist / inch_dist);
211 
212       enhanced_status = g_strdup_printf ("%.*f %s, %.2f\302\260%s%s",
213                                          digits, unit_dist,
214                                          gimp_unit_get_symbol (shell->unit),
215                                          angle, separator, status);
216 
217     }
218 
219   return enhanced_status;
220 }
221