app/paint/gimppaintcore.c applied a patch from Henning Makholm

2003-05-23  Sven Neumann  <sven@gimp.org>

	* app/paint/gimppaintcore.c
	* app/tools/gimppainttool.c: applied a patch from Henning Makholm
	<henning@makholm.net> that improves drawing of narrow straight lines
	by moving the endpoints to pixel centers. Fixes bug #84145.
This commit is contained in:
Sven Neumann 2003-05-23 13:22:38 +00:00 committed by Sven Neumann
parent 0fc53e0f54
commit 83a2f4983e
4 changed files with 123 additions and 69 deletions

View File

@ -1,3 +1,10 @@
2003-05-23 Sven Neumann <sven@gimp.org>
* app/paint/gimppaintcore.c
* app/tools/gimppainttool.c: applied a patch from Henning Makholm
<henning@makholm.net> that improves drawing of narrow straight lines
by moving the endpoints to pixel centers. Fixes bug #84145.
2003-05-23 Michael Natterer <mitch@gimp.org>
* app/gui/color-notebook.c (color_notebook_new_internal): don't

View File

@ -493,48 +493,65 @@ gimp_paint_core_cleanup (GimpPaintCore *core)
}
}
/**
* gimp_paint_core_constrain_helper:
* @dx: the (fixed) delta-x
* @dy: a suggested delta-y
*
* Returns an adjusted dy' near dy such that the slope (dx,dy') is a
* multiple of 15 degrees.
**/
static gdouble
gimp_paint_core_constrain_helper (gdouble dx,
gdouble dy)
{
static gdouble slope[4] = { 0, 0.26795, 0.57735, 1 };
static gdouble divider[3] = { 0.13165, 0.41421, 0.76732 };
gint i;
if (dy < 0)
return - gimp_paint_core_constrain_helper (dx,-dy);
dx = fabs (dx);
for (i = 0; i < 3; i ++)
if (dy < dx * divider[i])
break;
dy = dx * slope[i];
return dy;
}
/**
* gimp_paint_core_constrain:
* @core: the #GimpPaintCore.
*
* Restricts the (core->last_coords, core->curr_coords) vector to 15
* degree steps, possibly changing core->curr_coords
*
* Restricts the (core->last_coords, core->cur_coords) vector to 15
* degree steps, possibly changing core->cur_coords.
**/
void
gimp_paint_core_constrain (GimpPaintCore *core)
{
static const gint tangens2[6] = { 34, 106, 196, 334, 618, 1944 };
static const gint cosinus[7] = { 256, 247, 222, 181, 128, 66, 0 };
gint dx, dy, i, radius, frac;
gdouble dx, dy;
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
dx = core->cur_coords.x - core->last_coords.x;
dy = core->cur_coords.y - core->last_coords.y;
if (dy)
{
radius = sqrt (SQR (dx) + SQR (dy));
frac = abs ((dx << 8) / dy);
for (i = 0; i < 6; i++)
{
if (frac < tangens2[i])
break;
}
dx = (dx > 0 ?
(cosinus[6-i] * radius) >> 8 :
- ((cosinus[6-i] * radius) >> 8));
dy = (dy > 0 ?
(cosinus[i] * radius) >> 8 :
- ((cosinus[i] * radius) >> 8));
}
core->cur_coords.x = core->last_coords.x + dx;
core->cur_coords.y = core->last_coords.y + dy;
/* This algorithm changes only one of dx and dy, and does not try
* to constrain the resulting dx and dy to integers. This gives
* at least two benefits:
* 1. gimp_paint_core_constrain is idempotent, even if followed by
* a rounding operation.
* 2. For any two lines with the same starting-point and ideal
* 15-degree direction, the points plotted by
* gimp_paint_core_interpolate for the shorter line will always
* be a superset of those plotted for the longer line.
*/
if (fabs(dx) > fabs(dy))
core->cur_coords.y = core->last_coords.y +
gimp_paint_core_constrain_helper (dx,dy);
else
core->cur_coords.x = core->last_coords.x +
gimp_paint_core_constrain_helper (dy,dx);
}
/**

View File

@ -235,6 +235,31 @@ gimp_paint_tool_control (GimpTool *tool,
GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
}
/**
* gimp_paint_tool_round_line:
* @core: the #GimpPaintCore
* @state: the modifier state
*
* Adjusts core->last_coords and core_cur_coords in preparation to
* drawing a straight line. The rounding of the slope to 15 degree
* steps if ctrl is pressed happens, as does rounding the start and
* end coordinates (which may be fractional in high zoom modes) to
* the center of pixels.
**/
static void
gimp_paint_tool_round_line (GimpPaintCore *core,
GdkModifierType state)
{
core->last_coords.x = floor (core->last_coords.x) + 0.5;
core->last_coords.y = floor (core->last_coords.y) + 0.5;
core->cur_coords.x = floor (core->cur_coords.x ) + 0.5;
core->cur_coords.y = floor (core->cur_coords.y ) + 0.5;
/* Restrict to multiples of 15 degrees if ctrl is pressed */
if (state & GDK_CONTROL_MASK)
gimp_paint_core_constrain (core);
}
static void
gimp_paint_tool_button_press (GimpTool *tool,
GimpCoords *coords,
@ -313,12 +338,7 @@ gimp_paint_tool_button_press (GimpTool *tool,
core->start_coords = core->last_coords;
if (state & GDK_CONTROL_MASK)
{
/* Restrict to multiples of 15 degrees if ctrl is pressed */
gimp_paint_core_constrain (core);
}
gimp_paint_tool_round_line (core, state);
}
gimp_tool_control_activate (tool->control);
@ -532,12 +552,7 @@ gimp_paint_tool_cursor_update (GimpTool *tool,
core->cur_coords.x -= off_x;
core->cur_coords.y -= off_y;
if (state & GDK_CONTROL_MASK)
{
/* Restrict to multiples of 15 degrees if ctrl is pressed */
gimp_paint_core_constrain (core);
}
gimp_paint_tool_round_line (core, state);
dx = core->cur_coords.x - core->last_coords.x;
dy = core->cur_coords.y - core->last_coords.y;
@ -627,8 +642,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw start target */
gimp_draw_tool_draw_handle (draw_tool,
GIMP_HANDLE_CROSS,
floor (core->last_coords.x) + 0.5,
floor (core->last_coords.y) + 0.5,
core->last_coords.x,
core->last_coords.y,
TARGET_SIZE,
TARGET_SIZE,
GTK_ANCHOR_CENTER,
@ -637,8 +652,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw end target */
gimp_draw_tool_draw_handle (draw_tool,
GIMP_HANDLE_CROSS,
floor (core->cur_coords.x) + 0.5,
floor (core->cur_coords.y) + 0.5,
core->cur_coords.x,
core->cur_coords.y,
TARGET_SIZE,
TARGET_SIZE,
GTK_ANCHOR_CENTER,
@ -646,10 +661,10 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw the line between the start and end coords */
gimp_draw_tool_draw_line (draw_tool,
floor (core->last_coords.x) + 0.5,
floor (core->last_coords.y) + 0.5,
floor (core->cur_coords.x) + 0.5,
floor (core->cur_coords.y) + 0.5,
core->last_coords.x,
core->last_coords.y,
core->cur_coords.x,
core->cur_coords.y,
TRUE);
}
}

View File

@ -235,6 +235,31 @@ gimp_paint_tool_control (GimpTool *tool,
GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
}
/**
* gimp_paint_tool_round_line:
* @core: the #GimpPaintCore
* @state: the modifier state
*
* Adjusts core->last_coords and core_cur_coords in preparation to
* drawing a straight line. The rounding of the slope to 15 degree
* steps if ctrl is pressed happens, as does rounding the start and
* end coordinates (which may be fractional in high zoom modes) to
* the center of pixels.
**/
static void
gimp_paint_tool_round_line (GimpPaintCore *core,
GdkModifierType state)
{
core->last_coords.x = floor (core->last_coords.x) + 0.5;
core->last_coords.y = floor (core->last_coords.y) + 0.5;
core->cur_coords.x = floor (core->cur_coords.x ) + 0.5;
core->cur_coords.y = floor (core->cur_coords.y ) + 0.5;
/* Restrict to multiples of 15 degrees if ctrl is pressed */
if (state & GDK_CONTROL_MASK)
gimp_paint_core_constrain (core);
}
static void
gimp_paint_tool_button_press (GimpTool *tool,
GimpCoords *coords,
@ -313,12 +338,7 @@ gimp_paint_tool_button_press (GimpTool *tool,
core->start_coords = core->last_coords;
if (state & GDK_CONTROL_MASK)
{
/* Restrict to multiples of 15 degrees if ctrl is pressed */
gimp_paint_core_constrain (core);
}
gimp_paint_tool_round_line (core, state);
}
gimp_tool_control_activate (tool->control);
@ -532,12 +552,7 @@ gimp_paint_tool_cursor_update (GimpTool *tool,
core->cur_coords.x -= off_x;
core->cur_coords.y -= off_y;
if (state & GDK_CONTROL_MASK)
{
/* Restrict to multiples of 15 degrees if ctrl is pressed */
gimp_paint_core_constrain (core);
}
gimp_paint_tool_round_line (core, state);
dx = core->cur_coords.x - core->last_coords.x;
dy = core->cur_coords.y - core->last_coords.y;
@ -627,8 +642,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw start target */
gimp_draw_tool_draw_handle (draw_tool,
GIMP_HANDLE_CROSS,
floor (core->last_coords.x) + 0.5,
floor (core->last_coords.y) + 0.5,
core->last_coords.x,
core->last_coords.y,
TARGET_SIZE,
TARGET_SIZE,
GTK_ANCHOR_CENTER,
@ -637,8 +652,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw end target */
gimp_draw_tool_draw_handle (draw_tool,
GIMP_HANDLE_CROSS,
floor (core->cur_coords.x) + 0.5,
floor (core->cur_coords.y) + 0.5,
core->cur_coords.x,
core->cur_coords.y,
TARGET_SIZE,
TARGET_SIZE,
GTK_ANCHOR_CENTER,
@ -646,10 +661,10 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
/* Draw the line between the start and end coords */
gimp_draw_tool_draw_line (draw_tool,
floor (core->last_coords.x) + 0.5,
floor (core->last_coords.y) + 0.5,
floor (core->cur_coords.x) + 0.5,
floor (core->cur_coords.y) + 0.5,
core->last_coords.x,
core->last_coords.y,
core->cur_coords.x,
core->cur_coords.y,
TRUE);
}
}