Commit 1572bccc authored by Ell's avatar Ell

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.
parent 63f1ec41
......@@ -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 *
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment