[gimp] Bug 768726 - Canvas rotation, flipping applied in image space ...



commit 3fbd47eb2ea4d34c31b2f8840eab1d7b7f4ea0b5
Author: Ell <ell_se yahoo com>
Date:   Sat Jul 16 21:23:02 2016 +0000

    Bug 768726 - Canvas rotation, flipping applied in image space ...
    
    ... not screen space
    
    Flip and rotate the canvas around the center of the viewport,
    instead of the center of the image.  Scroll the display as
    necessary to keep the center of the viewport fixed during
    these operations.  This applies to both the corresponding
    menu items, and rotation using Shift+Space.
    
    Likewise, flip the canvas across the designated axis in
    screen space, instead of image space.  Rotate the display as
    necessary, such that the reflection appears to happen in
    screen space, regardless of the current rotation angle of the
    canvas.

 app/display/gimpdisplayshell-rotate.c |  128 +++++++++++++++++++++++---------
 1 files changed, 92 insertions(+), 36 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-rotate.c b/app/display/gimpdisplayshell-rotate.c
index efc7f6f..be1a45e 100644
--- a/app/display/gimpdisplayshell-rotate.c
+++ b/app/display/gimpdisplayshell-rotate.c
@@ -17,6 +17,8 @@
 
 #include "config.h"
 
+#include <math.h>
+
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -29,6 +31,18 @@
 #include "gimpdisplayshell-expose.h"
 #include "gimpdisplayshell-rotate.h"
 #include "gimpdisplayshell-scale.h"
+#include "gimpdisplayshell-scroll.h"
+#include "gimpdisplayshell-transform.h"
+
+
+/*  local function prototypes  */
+
+static void   gimp_display_shell_save_viewport_center    (GimpDisplayShell *shell,
+                                                          gdouble          *x,
+                                                          gdouble          *y);
+static void   gimp_display_shell_restore_viewport_center (GimpDisplayShell *shell,
+                                                          gdouble           x,
+                                                          gdouble           y);
 
 
 /*  public functions  */
@@ -40,13 +54,35 @@ gimp_display_shell_flip (GimpDisplayShell *shell,
 {
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
+  flip_horizontally = flip_horizontally ? TRUE : FALSE;
+  flip_vertically   = flip_vertically   ? TRUE : FALSE;
+
   if (flip_horizontally != shell->flip_horizontally ||
       flip_vertically   != shell->flip_vertically)
     {
-      shell->flip_horizontally = flip_horizontally ? TRUE : FALSE;
-      shell->flip_vertically   = flip_vertically   ? TRUE : FALSE;
+      gdouble cx, cy;
+
+      /* Maintain the current center of the viewport. */
+      gimp_display_shell_save_viewport_center (shell, &cx, &cy);
+
+      /* Adjust the rotation angle so that the image gets reflected across the
+       * horizontal, and/or vertical, axes in screen space, regardless of the
+       * current rotation.
+       */
+      if (flip_horizontally == shell->flip_horizontally ||
+          flip_vertically   == shell->flip_vertically)
+        {
+          if (shell->rotate_angle != 0.0)
+            shell->rotate_angle = 360.0 - shell->rotate_angle;
+        }
+
+      shell->flip_horizontally = flip_horizontally;
+      shell->flip_vertically   = flip_vertically;
 
       gimp_display_shell_rotated (shell);
+
+      gimp_display_shell_restore_viewport_center (shell, cx, cy);
+
       gimp_display_shell_expose_full (shell);
     }
 }
@@ -64,19 +100,26 @@ void
 gimp_display_shell_rotate_to (GimpDisplayShell *shell,
                               gdouble           value)
 {
+  gdouble cx, cy;
+
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  while (value < 0.0)
-    value += 360;
+  /* Maintain the current center of the viewport. */
+  gimp_display_shell_save_viewport_center (shell, &cx, &cy);
 
-  while (value >= 360.0)
-    value -= 360;
+  /* Make sure the angle is within the range [0, 360). */
+  value = fmod (value, 360.0);
+  if (value < 0.0)
+    value += 360.0;
 
   shell->rotate_angle = value;
 
   gimp_display_shell_scroll_clamp_and_update (shell);
 
   gimp_display_shell_rotated (shell);
+
+  gimp_display_shell_restore_viewport_center (shell, cx, cy);
+
   gimp_display_shell_expose_full (shell);
 }
 
@@ -88,46 +131,32 @@ gimp_display_shell_rotate_drag (GimpDisplayShell *shell,
                                 gdouble           cur_y,
                                 gboolean          constrain)
 {
-  gint    image_width, image_height;
-  gdouble px, py;
-  gdouble x1, y1, x2, y2;
-  gdouble angle1, angle2, angle;
+  gdouble pivot_x, pivot_y;
+  gdouble src_x,   src_y,   src_angle;
+  gdouble dest_x,  dest_y,  dest_angle;
+  gdouble                   delta_angle;
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  gimp_display_shell_scale_get_image_size (shell,
-                                           &image_width, &image_height);
-
-  px = -shell->offset_x + image_width  / 2;
-  py = -shell->offset_y + image_height / 2;
+  /* Rotate the image around the center of the viewport. */
+  pivot_x     = shell->disp_width  / 2.0;
+  pivot_y     = shell->disp_height / 2.0;
 
-  x1 = cur_x  - px;
-  x2 = last_x - px;
-  y1 = py - cur_y;
-  y2 = py - last_y;
+  src_x       = last_x - pivot_x;
+  src_y       = last_y - pivot_y;
+  src_angle   = atan2 (src_y, src_x);
 
-  /*  find the first angle  */
-  angle1 = atan2 (y1, x1);
+  dest_x      = cur_x - pivot_x;
+  dest_y      = cur_y - pivot_y;
+  dest_angle  = atan2 (dest_y, dest_x);
 
-  /*  find the angle  */
-  angle2 = atan2 (y2, x2);
+  delta_angle = dest_angle - src_angle;
 
-  angle = angle2 - angle1;
-
-  if (angle > G_PI || angle < -G_PI)
-    angle = angle2 - ((angle1 < 0) ? 2.0 * G_PI + angle1 : angle1 - 2.0 * G_PI);
-
-  shell->rotate_drag_angle += (angle * 180.0 / G_PI);
-
-  if (shell->rotate_drag_angle < 0.0)
-    shell->rotate_drag_angle += 360;
-
-  if (shell->rotate_drag_angle >= 360.0)
-    shell->rotate_drag_angle -= 360;
+  shell->rotate_drag_angle += 180.0 * delta_angle / G_PI;
 
   gimp_display_shell_rotate_to (shell,
                                 constrain ?
-                                (gint) shell->rotate_drag_angle / 15 * 15 :
+                                RINT (shell->rotate_drag_angle / 15.0) * 15.0 :
                                 shell->rotate_drag_angle);
 }
 
@@ -179,3 +208,30 @@ gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell)
       shell->rotate_untransform = NULL;
     }
 }
+
+
+/*  private functions  */
+
+static void
+gimp_display_shell_save_viewport_center (GimpDisplayShell *shell,
+                                         gdouble          *x,
+                                         gdouble          *y)
+{
+  gimp_display_shell_unrotate_xy_f (shell,
+                                    shell->disp_width  / 2,
+                                    shell->disp_height / 2,
+                                    x, y);
+}
+
+static void
+gimp_display_shell_restore_viewport_center (GimpDisplayShell *shell,
+                                            gdouble           x,
+                                            gdouble           y)
+{
+  gimp_display_shell_rotate_xy_f (shell, x, y, &x, &y);
+
+  x += shell->offset_x - shell->disp_width  / 2;
+  y += shell->offset_y - shell->disp_height / 2;
+
+  gimp_display_shell_scroll_set_offset (shell, RINT (x), RINT (y));
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]