[gimp] app: add support for subpixel image grids



commit 1572bccc9f1f781b720bb030730f34a1f59c498b
Author: Ell <ell_se yahoo com>
Date:   Sun Feb 19 18:03:02 2017 -0500

    app: add support for subpixel image grids
    
    In particular, this enables grids whose points of intersection
    are at the middle of the image's pixels, which is useful for
    undistorted painting with odd-sized brushes using tools other than
    the pencil.
    
    This commit also changes the grid visibility behavior, so that the
    the visibiltiy of horizontal and vertical grid lines (depending on
    the zoom level) is independent.

 app/core/gimpgrid.c          |   14 ++--
 app/core/gimpimage-snap.c    |   56 ++++++---------
 app/display/gimpcanvasgrid.c |  162 +++++++++++++++++++++++-------------------
 app/widgets/gimpgrideditor.c |   14 +++-
 4 files changed, 126 insertions(+), 120 deletions(-)
---
diff --git a/app/core/gimpgrid.c b/app/core/gimpgrid.c
index 3b8109a..7893a02 100644
--- a/app/core/gimpgrid.c
+++ b/app/core/gimpgrid.c
@@ -108,14 +108,14 @@ gimp_grid_class_init (GimpGridClass *klass)
                            "xspacing",
                            _("Spacing X"),
                            _("Horizontal spacing of grid lines."),
-                           1.0, GIMP_MAX_IMAGE_SIZE, 10.0,
+                           0.0, GIMP_MAX_IMAGE_SIZE, 10.0,
                            GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_YSPACING,
                            "yspacing",
                            _("Spacing Y"),
                            _("Vertical spacing of grid lines."),
-                           1.0, GIMP_MAX_IMAGE_SIZE, 10.0,
+                           0.0, GIMP_MAX_IMAGE_SIZE, 10.0,
                            GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_UNIT (object_class, PROP_SPACING_UNIT,
@@ -283,9 +283,8 @@ gimp_grid_get_spacing (GimpGrid *grid,
 {
   g_return_if_fail (GIMP_IS_GRID (grid));
 
-  /* FIXME subpixel grid */
-  if (xspacing) *xspacing = RINT (grid->xspacing);
-  if (yspacing) *yspacing = RINT (grid->yspacing);
+  if (xspacing) *xspacing = grid->xspacing;
+  if (yspacing) *yspacing = grid->yspacing;
 }
 
 void
@@ -295,9 +294,8 @@ gimp_grid_get_offset (GimpGrid *grid,
 {
   g_return_if_fail (GIMP_IS_GRID (grid));
 
-  /* FIXME subpixel grid */
-  if (xoffset) *xoffset = RINT (grid->xoffset);
-  if (yoffset) *yoffset = RINT (grid->yoffset);
+  if (xoffset) *xoffset = grid->xoffset;
+  if (yoffset) *yoffset = grid->yoffset;
 }
 
 const gchar *
diff --git a/app/core/gimpimage-snap.c b/app/core/gimpimage-snap.c
index 5934704..4e67ae6 100644
--- a/app/core/gimpimage-snap.c
+++ b/app/core/gimpimage-snap.c
@@ -100,21 +100,17 @@ gimp_image_snap_x (GimpImage *image,
       GimpGrid *grid = gimp_image_get_grid (image);
       gdouble   xspacing;
       gdouble   xoffset;
-      gdouble   i;
 
       gimp_grid_get_spacing (grid, &xspacing, NULL);
       gimp_grid_get_offset  (grid, &xoffset,  NULL);
 
-      /* the snap-to-grid part could probably be rewritten */
-      while (xoffset > xspacing)
-        xoffset -= xspacing;
-
-      for (i = xoffset; i <= gimp_image_get_width (image); i += xspacing)
+      if (xspacing > 0.0)
         {
-          if (i < 0)
-            continue;
+          gdouble nearest;
+
+          nearest = xoffset + RINT ((x - xoffset) / xspacing) * xspacing;
 
-          snapped |= gimp_image_snap_distance (x, i,
+          snapped |= gimp_image_snap_distance (x, nearest,
                                                epsilon_x,
                                                &mindist, tx);
         }
@@ -183,22 +179,19 @@ gimp_image_snap_y (GimpImage *image,
   if (snap_to_grid)
     {
       GimpGrid *grid = gimp_image_get_grid (image);
-      gdouble    yspacing;
-      gdouble    yoffset;
-      gdouble    i;
+      gdouble   yspacing;
+      gdouble   yoffset;
 
       gimp_grid_get_spacing (grid, NULL, &yspacing);
       gimp_grid_get_offset  (grid, NULL, &yoffset);
 
-      while (yoffset > yspacing)
-        yoffset -= yspacing;
-
-      for (i = yoffset; i <= gimp_image_get_height (image); i += yspacing)
+      if (yspacing > 0.0)
         {
-          if (i < 0)
-            continue;
+          gdouble nearest;
+
+          nearest = yoffset + RINT ((y - yoffset) / yspacing) * yspacing;
 
-          snapped |= gimp_image_snap_distance (y, i,
+          snapped |= gimp_image_snap_distance (y, nearest,
                                                epsilon_y,
                                                &mindist, ty);
         }
@@ -291,33 +284,28 @@ gimp_image_snap_point (GimpImage *image,
       GimpGrid *grid = gimp_image_get_grid (image);
       gdouble   xspacing, yspacing;
       gdouble   xoffset, yoffset;
-      gdouble   i;
 
       gimp_grid_get_spacing (grid, &xspacing, &yspacing);
       gimp_grid_get_offset  (grid, &xoffset,  &yoffset);
 
-      while (xoffset > xspacing)
-        xoffset -= xspacing;
-
-      while (yoffset > yspacing)
-        yoffset -= yspacing;
-
-      for (i = xoffset; i <= gimp_image_get_width (image); i += xspacing)
+      if (xspacing > 0.0)
         {
-          if (i < 0)
-            continue;
+          gdouble nearest;
 
-          snapped |= gimp_image_snap_distance (x, i,
+          nearest = xoffset + RINT ((x - xoffset) / xspacing) * xspacing;
+
+          snapped |= gimp_image_snap_distance (x, nearest,
                                                epsilon_x,
                                                &mindist_x, tx);
         }
 
-      for (i = yoffset; i <= gimp_image_get_height (image); i += yspacing)
+      if (yspacing > 0.0)
         {
-          if (i < 0)
-            continue;
+          gdouble nearest;
+
+          nearest = yoffset + RINT ((y - yoffset) / yspacing) * yspacing;
 
-          snapped |= gimp_image_snap_distance (y, i,
+          snapped |= gimp_image_snap_distance (y, nearest,
                                                epsilon_y,
                                                &mindist_y, ty);
         }
diff --git a/app/display/gimpcanvasgrid.c b/app/display/gimpcanvasgrid.c
index ed32977..0a7bada 100644
--- a/app/display/gimpcanvasgrid.c
+++ b/app/display/gimpcanvasgrid.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <math.h>
+
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -191,6 +193,7 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
   GimpImage             *image   = gimp_canvas_item_get_image (item);
   gdouble                xspacing, yspacing;
   gdouble                xoffset, yoffset;
+  gboolean               vert, horz;
   gdouble                x, y;
   gdouble                dx1, dy1, dx2, dy2;
   gint                   x0, x1, x2, x3;
@@ -203,14 +206,16 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
   gimp_grid_get_spacing (private->grid, &xspacing, &yspacing);
   gimp_grid_get_offset  (private->grid, &xoffset,  &yoffset);
 
-  g_return_if_fail (xspacing > 0.0 &&
-                    yspacing > 0.0);
+  g_return_if_fail (xspacing >= 0.0 &&
+                    yspacing >= 0.0);
 
   /*  skip grid drawing when the space between grid lines starts
    *  disappearing, see bug #599267.
    */
-  if (xspacing * shell->scale_x < 2.0 ||
-      yspacing * shell->scale_y < 2.0)
+  vert = (xspacing * shell->scale_x >= 2.0);
+  horz = (yspacing * shell->scale_y >= 2.0);
+
+  if (! vert && ! horz)
     return;
 
   cairo_clip_extents (cr, &dx1, &dy1, &dx2, &dy2);
@@ -223,84 +228,87 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
   width  = gimp_image_get_width  (image);
   height = gimp_image_get_height (image);
 
-  while (xoffset > 0)
-    xoffset -= xspacing;
-
-  while (yoffset > 0)
-    yoffset -= yspacing;
+  xoffset = fmod (xoffset, xspacing);
+  yoffset = fmod (yoffset, yspacing);
 
   switch (gimp_grid_get_style (private->grid))
     {
     case GIMP_GRID_DOTS:
-      for (x = xoffset; x <= width; x += xspacing)
+      if (vert && horz)
         {
-          if (x < 0)
-            continue;
-
-          gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
-
-          if (x_real < x1 || x_real >= x2)
-            continue;
-
-          for (y = yoffset; y <= height; y += yspacing)
+          for (x = xoffset; x <= width; x += xspacing)
             {
-              if (y < 0)
+              if (x < 0)
                 continue;
 
-              gimp_canvas_item_transform_xy (item, x, y, &x_real, &y_real);
+              gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
 
-              if (y_real >= y1 && y_real < y2)
+              if (x_real < x1 || x_real >= x2)
+                continue;
+
+              for (y = yoffset; y <= height; y += yspacing)
                 {
-                  cairo_move_to (cr, x_real,     y_real + 0.5);
-                  cairo_line_to (cr, x_real + 1, y_real + 0.5);
+                  if (y < 0)
+                    continue;
+
+                  gimp_canvas_item_transform_xy (item, x, y, &x_real, &y_real);
+
+                  if (y_real >= y1 && y_real < y2)
+                    {
+                      cairo_move_to (cr, x_real,     y_real + 0.5);
+                      cairo_line_to (cr, x_real + 1, y_real + 0.5);
+                    }
                 }
             }
         }
       break;
 
     case GIMP_GRID_INTERSECTIONS:
-      for (x = xoffset; x <= width; x += xspacing)
+      if (vert && horz)
         {
-          if (x < 0)
-            continue;
-
-          gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
-
-          if (x_real + CROSSHAIR < x1 || x_real - CROSSHAIR >= x2)
-            continue;
-
-          for (y = yoffset; y <= height; y += yspacing)
+          for (x = xoffset; x <= width; x += xspacing)
             {
-              if (y < 0)
+              if (x < 0)
                 continue;
 
-              gimp_canvas_item_transform_xy (item, x, y, &x_real, &y_real);
+              gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
 
-              if (y_real + CROSSHAIR < y1 || y_real - CROSSHAIR >= y2)
+              if (x_real + CROSSHAIR < x1 || x_real - CROSSHAIR >= x2)
                 continue;
 
-              if (x_real >= x1 && x_real < x2)
-                {
-                  cairo_move_to (cr,
-                                 x_real + 0.5,
-                                 CLAMP (y_real - CROSSHAIR,
-                                        y1, y2 - 1));
-                  cairo_line_to (cr,
-                                 x_real + 0.5,
-                                 CLAMP (y_real + CROSSHAIR,
-                                        y1, y2 - 1) + 1);
-                }
-
-              if (y_real >= y1 && y_real < y2)
+              for (y = yoffset; y <= height; y += yspacing)
                 {
-                  cairo_move_to (cr,
-                                 CLAMP (x_real - CROSSHAIR,
-                                        x1, x2 - 1),
-                                 y_real + 0.5);
-                  cairo_line_to (cr,
-                                 CLAMP (x_real + CROSSHAIR,
-                                        x1, x2 - 1) + 1,
-                                 y_real + 0.5);
+                  if (y < 0)
+                    continue;
+
+                  gimp_canvas_item_transform_xy (item, x, y, &x_real, &y_real);
+
+                  if (y_real + CROSSHAIR < y1 || y_real - CROSSHAIR >= y2)
+                    continue;
+
+                  if (x_real >= x1 && x_real < x2)
+                    {
+                      cairo_move_to (cr,
+                                     x_real + 0.5,
+                                     CLAMP (y_real - CROSSHAIR,
+                                            y1, y2 - 1));
+                      cairo_line_to (cr,
+                                     x_real + 0.5,
+                                     CLAMP (y_real + CROSSHAIR,
+                                            y1, y2 - 1) + 1);
+                    }
+
+                  if (y_real >= y1 && y_real < y2)
+                    {
+                      cairo_move_to (cr,
+                                     CLAMP (x_real - CROSSHAIR,
+                                            x1, x2 - 1),
+                                     y_real + 0.5);
+                      cairo_line_to (cr,
+                                     CLAMP (x_real + CROSSHAIR,
+                                            x1, x2 - 1) + 1,
+                                     y_real + 0.5);
+                    }
                 }
             }
         }
@@ -312,31 +320,37 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
       gimp_canvas_item_transform_xy (item, 0, 0, &x0, &y0);
       gimp_canvas_item_transform_xy (item, width, height, &x3, &y3);
 
-      for (x = xoffset; x < width; x += xspacing)
+      if (vert)
         {
-          if (x < 0)
-            continue;
+          for (x = xoffset; x < width; x += xspacing)
+            {
+              if (x < 0)
+                continue;
 
-          gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
+              gimp_canvas_item_transform_xy (item, x, 0, &x_real, &y_real);
 
-          if (x_real >= x1 && x_real < x2)
-            {
-              cairo_move_to (cr, x_real + 0.5, y0);
-              cairo_line_to (cr, x_real + 0.5, y3 + 1);
+              if (x_real >= x1 && x_real < x2)
+                {
+                  cairo_move_to (cr, x_real + 0.5, y0);
+                  cairo_line_to (cr, x_real + 0.5, y3 + 1);
+                }
             }
         }
 
-      for (y = yoffset; y < height; y += yspacing)
+      if (horz)
         {
-          if (y < 0)
-            continue;
+          for (y = yoffset; y < height; y += yspacing)
+            {
+              if (y < 0)
+                continue;
 
-          gimp_canvas_item_transform_xy (item, 0, y, &x_real, &y_real);
+              gimp_canvas_item_transform_xy (item, 0, y, &x_real, &y_real);
 
-          if (y_real >= y1 && y_real < y2)
-            {
-              cairo_move_to (cr, x0,     y_real + 0.5);
-              cairo_line_to (cr, x3 + 1, y_real + 0.5);
+              if (y_real >= y1 && y_real < y2)
+                {
+                  cairo_move_to (cr, x0,     y_real + 0.5);
+                  cairo_line_to (cr, x3 + 1, y_real + 0.5);
+                }
             }
         }
       break;
diff --git a/app/widgets/gimpgrideditor.c b/app/widgets/gimpgrideditor.c
index 1895127..0ba5406 100644
--- a/app/widgets/gimpgrideditor.c
+++ b/app/widgets/gimpgrideditor.c
@@ -192,12 +192,15 @@ gimp_grid_editor_constructed (GObject *object)
   gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
 
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
-                                _("Width"), 0, 1, 0.0);
+                                _("Horizontal"), 0, 1, 0.0);
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
-                                _("Height"), 0, 2, 0.0);
+                                _("Vertical"), 0, 2, 0.0);
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
                                 _("Pixels"), 1, 4, 0.0);
 
+  gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (sizeentry), 0, 2);
+  gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (sizeentry), 1, 2);
+
   gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0);
   gtk_widget_show (sizeentry);
 
@@ -224,12 +227,15 @@ gimp_grid_editor_constructed (GObject *object)
   gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
 
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
-                                _("Width"), 0, 1, 0.0);
+                                _("Horizontal"), 0, 1, 0.0);
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
-                                _("Height"), 0, 2, 0.0);
+                                _("Vertical"), 0, 2, 0.0);
   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
                                 _("Pixels"), 1, 4, 0.0);
 
+  gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (sizeentry), 0, 2);
+  gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (sizeentry), 1, 2);
+
   gtk_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0);
   gtk_widget_show (sizeentry);
 


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