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.
This commit is contained in:
@ -108,14 +108,14 @@ gimp_grid_class_init (GimpGridClass *klass)
|
|||||||
"xspacing",
|
"xspacing",
|
||||||
_("Spacing X"),
|
_("Spacing X"),
|
||||||
_("Horizontal spacing of grid lines."),
|
_("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_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_YSPACING,
|
GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_YSPACING,
|
||||||
"yspacing",
|
"yspacing",
|
||||||
_("Spacing Y"),
|
_("Spacing Y"),
|
||||||
_("Vertical spacing of grid lines."),
|
_("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_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
GIMP_CONFIG_PROP_UNIT (object_class, PROP_SPACING_UNIT,
|
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));
|
g_return_if_fail (GIMP_IS_GRID (grid));
|
||||||
|
|
||||||
/* FIXME subpixel grid */
|
if (xspacing) *xspacing = grid->xspacing;
|
||||||
if (xspacing) *xspacing = RINT (grid->xspacing);
|
if (yspacing) *yspacing = grid->yspacing;
|
||||||
if (yspacing) *yspacing = RINT (grid->yspacing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -295,9 +294,8 @@ gimp_grid_get_offset (GimpGrid *grid,
|
|||||||
{
|
{
|
||||||
g_return_if_fail (GIMP_IS_GRID (grid));
|
g_return_if_fail (GIMP_IS_GRID (grid));
|
||||||
|
|
||||||
/* FIXME subpixel grid */
|
if (xoffset) *xoffset = grid->xoffset;
|
||||||
if (xoffset) *xoffset = RINT (grid->xoffset);
|
if (yoffset) *yoffset = grid->yoffset;
|
||||||
if (yoffset) *yoffset = RINT (grid->yoffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
const gchar *
|
||||||
|
@ -100,21 +100,17 @@ gimp_image_snap_x (GimpImage *image,
|
|||||||
GimpGrid *grid = gimp_image_get_grid (image);
|
GimpGrid *grid = gimp_image_get_grid (image);
|
||||||
gdouble xspacing;
|
gdouble xspacing;
|
||||||
gdouble xoffset;
|
gdouble xoffset;
|
||||||
gdouble i;
|
|
||||||
|
|
||||||
gimp_grid_get_spacing (grid, &xspacing, NULL);
|
gimp_grid_get_spacing (grid, &xspacing, NULL);
|
||||||
gimp_grid_get_offset (grid, &xoffset, NULL);
|
gimp_grid_get_offset (grid, &xoffset, NULL);
|
||||||
|
|
||||||
/* the snap-to-grid part could probably be rewritten */
|
if (xspacing > 0.0)
|
||||||
while (xoffset > xspacing)
|
|
||||||
xoffset -= xspacing;
|
|
||||||
|
|
||||||
for (i = xoffset; i <= gimp_image_get_width (image); i += xspacing)
|
|
||||||
{
|
{
|
||||||
if (i < 0)
|
gdouble nearest;
|
||||||
continue;
|
|
||||||
|
|
||||||
snapped |= gimp_image_snap_distance (x, i,
|
nearest = xoffset + RINT ((x - xoffset) / xspacing) * xspacing;
|
||||||
|
|
||||||
|
snapped |= gimp_image_snap_distance (x, nearest,
|
||||||
epsilon_x,
|
epsilon_x,
|
||||||
&mindist, tx);
|
&mindist, tx);
|
||||||
}
|
}
|
||||||
@ -185,20 +181,17 @@ gimp_image_snap_y (GimpImage *image,
|
|||||||
GimpGrid *grid = gimp_image_get_grid (image);
|
GimpGrid *grid = gimp_image_get_grid (image);
|
||||||
gdouble yspacing;
|
gdouble yspacing;
|
||||||
gdouble yoffset;
|
gdouble yoffset;
|
||||||
gdouble i;
|
|
||||||
|
|
||||||
gimp_grid_get_spacing (grid, NULL, &yspacing);
|
gimp_grid_get_spacing (grid, NULL, &yspacing);
|
||||||
gimp_grid_get_offset (grid, NULL, &yoffset);
|
gimp_grid_get_offset (grid, NULL, &yoffset);
|
||||||
|
|
||||||
while (yoffset > yspacing)
|
if (yspacing > 0.0)
|
||||||
yoffset -= yspacing;
|
|
||||||
|
|
||||||
for (i = yoffset; i <= gimp_image_get_height (image); i += yspacing)
|
|
||||||
{
|
{
|
||||||
if (i < 0)
|
gdouble nearest;
|
||||||
continue;
|
|
||||||
|
|
||||||
snapped |= gimp_image_snap_distance (y, i,
|
nearest = yoffset + RINT ((y - yoffset) / yspacing) * yspacing;
|
||||||
|
|
||||||
|
snapped |= gimp_image_snap_distance (y, nearest,
|
||||||
epsilon_y,
|
epsilon_y,
|
||||||
&mindist, ty);
|
&mindist, ty);
|
||||||
}
|
}
|
||||||
@ -291,33 +284,28 @@ gimp_image_snap_point (GimpImage *image,
|
|||||||
GimpGrid *grid = gimp_image_get_grid (image);
|
GimpGrid *grid = gimp_image_get_grid (image);
|
||||||
gdouble xspacing, yspacing;
|
gdouble xspacing, yspacing;
|
||||||
gdouble xoffset, yoffset;
|
gdouble xoffset, yoffset;
|
||||||
gdouble i;
|
|
||||||
|
|
||||||
gimp_grid_get_spacing (grid, &xspacing, &yspacing);
|
gimp_grid_get_spacing (grid, &xspacing, &yspacing);
|
||||||
gimp_grid_get_offset (grid, &xoffset, &yoffset);
|
gimp_grid_get_offset (grid, &xoffset, &yoffset);
|
||||||
|
|
||||||
while (xoffset > xspacing)
|
if (xspacing > 0.0)
|
||||||
xoffset -= xspacing;
|
|
||||||
|
|
||||||
while (yoffset > yspacing)
|
|
||||||
yoffset -= yspacing;
|
|
||||||
|
|
||||||
for (i = xoffset; i <= gimp_image_get_width (image); i += xspacing)
|
|
||||||
{
|
{
|
||||||
if (i < 0)
|
gdouble nearest;
|
||||||
continue;
|
|
||||||
|
|
||||||
snapped |= gimp_image_snap_distance (x, i,
|
nearest = xoffset + RINT ((x - xoffset) / xspacing) * xspacing;
|
||||||
|
|
||||||
|
snapped |= gimp_image_snap_distance (x, nearest,
|
||||||
epsilon_x,
|
epsilon_x,
|
||||||
&mindist_x, tx);
|
&mindist_x, tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = yoffset; i <= gimp_image_get_height (image); i += yspacing)
|
if (yspacing > 0.0)
|
||||||
{
|
{
|
||||||
if (i < 0)
|
gdouble nearest;
|
||||||
continue;
|
|
||||||
|
|
||||||
snapped |= gimp_image_snap_distance (y, i,
|
nearest = yoffset + RINT ((y - yoffset) / yspacing) * yspacing;
|
||||||
|
|
||||||
|
snapped |= gimp_image_snap_distance (y, nearest,
|
||||||
epsilon_y,
|
epsilon_y,
|
||||||
&mindist_y, ty);
|
&mindist_y, ty);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <gegl.h>
|
#include <gegl.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
@ -191,6 +193,7 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
GimpImage *image = gimp_canvas_item_get_image (item);
|
GimpImage *image = gimp_canvas_item_get_image (item);
|
||||||
gdouble xspacing, yspacing;
|
gdouble xspacing, yspacing;
|
||||||
gdouble xoffset, yoffset;
|
gdouble xoffset, yoffset;
|
||||||
|
gboolean vert, horz;
|
||||||
gdouble x, y;
|
gdouble x, y;
|
||||||
gdouble dx1, dy1, dx2, dy2;
|
gdouble dx1, dy1, dx2, dy2;
|
||||||
gint x0, x1, x2, x3;
|
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_spacing (private->grid, &xspacing, &yspacing);
|
||||||
gimp_grid_get_offset (private->grid, &xoffset, &yoffset);
|
gimp_grid_get_offset (private->grid, &xoffset, &yoffset);
|
||||||
|
|
||||||
g_return_if_fail (xspacing > 0.0 &&
|
g_return_if_fail (xspacing >= 0.0 &&
|
||||||
yspacing > 0.0);
|
yspacing >= 0.0);
|
||||||
|
|
||||||
/* skip grid drawing when the space between grid lines starts
|
/* skip grid drawing when the space between grid lines starts
|
||||||
* disappearing, see bug #599267.
|
* disappearing, see bug #599267.
|
||||||
*/
|
*/
|
||||||
if (xspacing * shell->scale_x < 2.0 ||
|
vert = (xspacing * shell->scale_x >= 2.0);
|
||||||
yspacing * shell->scale_y < 2.0)
|
horz = (yspacing * shell->scale_y >= 2.0);
|
||||||
|
|
||||||
|
if (! vert && ! horz)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cairo_clip_extents (cr, &dx1, &dy1, &dx2, &dy2);
|
cairo_clip_extents (cr, &dx1, &dy1, &dx2, &dy2);
|
||||||
@ -223,15 +228,14 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
width = gimp_image_get_width (image);
|
width = gimp_image_get_width (image);
|
||||||
height = gimp_image_get_height (image);
|
height = gimp_image_get_height (image);
|
||||||
|
|
||||||
while (xoffset > 0)
|
xoffset = fmod (xoffset, xspacing);
|
||||||
xoffset -= xspacing;
|
yoffset = fmod (yoffset, yspacing);
|
||||||
|
|
||||||
while (yoffset > 0)
|
|
||||||
yoffset -= yspacing;
|
|
||||||
|
|
||||||
switch (gimp_grid_get_style (private->grid))
|
switch (gimp_grid_get_style (private->grid))
|
||||||
{
|
{
|
||||||
case GIMP_GRID_DOTS:
|
case GIMP_GRID_DOTS:
|
||||||
|
if (vert && horz)
|
||||||
|
{
|
||||||
for (x = xoffset; x <= width; x += xspacing)
|
for (x = xoffset; x <= width; x += xspacing)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
@ -256,9 +260,12 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GIMP_GRID_INTERSECTIONS:
|
case GIMP_GRID_INTERSECTIONS:
|
||||||
|
if (vert && horz)
|
||||||
|
{
|
||||||
for (x = xoffset; x <= width; x += xspacing)
|
for (x = xoffset; x <= width; x += xspacing)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
@ -304,6 +311,7 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GIMP_GRID_ON_OFF_DASH:
|
case GIMP_GRID_ON_OFF_DASH:
|
||||||
@ -312,6 +320,8 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
gimp_canvas_item_transform_xy (item, 0, 0, &x0, &y0);
|
gimp_canvas_item_transform_xy (item, 0, 0, &x0, &y0);
|
||||||
gimp_canvas_item_transform_xy (item, width, height, &x3, &y3);
|
gimp_canvas_item_transform_xy (item, width, height, &x3, &y3);
|
||||||
|
|
||||||
|
if (vert)
|
||||||
|
{
|
||||||
for (x = xoffset; x < width; x += xspacing)
|
for (x = xoffset; x < width; x += xspacing)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
@ -325,7 +335,10 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
cairo_line_to (cr, x_real + 0.5, y3 + 1);
|
cairo_line_to (cr, x_real + 0.5, y3 + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (horz)
|
||||||
|
{
|
||||||
for (y = yoffset; y < height; y += yspacing)
|
for (y = yoffset; y < height; y += yspacing)
|
||||||
{
|
{
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
@ -339,6 +352,7 @@ gimp_canvas_grid_draw (GimpCanvasItem *item,
|
|||||||
cairo_line_to (cr, x3 + 1, y_real + 0.5);
|
cairo_line_to (cr, x3 + 1, y_real + 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,12 +192,15 @@ gimp_grid_editor_constructed (GObject *object)
|
|||||||
gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
|
gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
|
||||||
|
|
||||||
gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
|
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),
|
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),
|
gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
|
||||||
_("Pixels"), 1, 4, 0.0);
|
_("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_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0);
|
||||||
gtk_widget_show (sizeentry);
|
gtk_widget_show (sizeentry);
|
||||||
|
|
||||||
@ -224,12 +227,15 @@ gimp_grid_editor_constructed (GObject *object)
|
|||||||
gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
|
gtk_table_set_row_spacings (GTK_TABLE (sizeentry), 2);
|
||||||
|
|
||||||
gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
|
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),
|
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),
|
gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry),
|
||||||
_("Pixels"), 1, 4, 0.0);
|
_("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_box_pack_start (GTK_BOX (hbox), sizeentry, FALSE, FALSE, 0);
|
||||||
gtk_widget_show (sizeentry);
|
gtk_widget_show (sizeentry);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user