mirror of
https://gitlab.gnome.org/GNOME/gimp
synced 2024-10-22 04:22:29 +00:00
Generalized to allow a variable number of lines for snapping, and
2008-01-14 Martin Nordholts <martinn@svn.gnome.org> * app/tools/tools-utils.[ch] (gimp_tool_motion_constrain): Generalized to allow a variable number of lines for snapping, and rewritten to make snapping happen more intuitively; snap the shortest distance rather than only horizontally or vertically. (gimp_tool_utils_point_to_line_distance): New helper function. * app/tools/gimpblendtool.c * app/tools/gimpmeasuretool.c * app/tools/gimppainttool.c: Adjust to the new function signature. svn path=/trunk/; revision=24609
This commit is contained in:
parent
f8808d8afc
commit
4ef8797faa
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2008-01-14 Martin Nordholts <martinn@svn.gnome.org>
|
||||
|
||||
* app/tools/tools-utils.[ch]
|
||||
(gimp_tool_motion_constrain): Generalized to allow a variable
|
||||
number of lines for snapping, and rewritten to make snapping
|
||||
happen more intuitively; snap the shortest distance rather than
|
||||
only horizontally or vertically.
|
||||
(gimp_tool_utils_point_to_line_distance): New helper function.
|
||||
|
||||
* app/tools/gimpblendtool.c
|
||||
* app/tools/gimpmeasuretool.c
|
||||
* app/tools/gimppainttool.c: Adjust to the new function signature.
|
||||
|
||||
2008-01-14 Michael Natterer <mitch@gimp.org>
|
||||
|
||||
* app/gegl/Makefile.am
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
#include "gimp-intl.h"
|
||||
|
||||
|
||||
#define TARGET_SIZE 15
|
||||
#define TARGET_SIZE 15
|
||||
#define N_SNAP_LINES 12
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
@ -287,7 +288,8 @@ gimp_blend_tool_motion (GimpTool *tool,
|
|||
if (state & GDK_CONTROL_MASK)
|
||||
{
|
||||
gimp_tool_motion_constrain (blend_tool->start_x, blend_tool->start_y,
|
||||
&blend_tool->end_x, &blend_tool->end_y);
|
||||
&blend_tool->end_x, &blend_tool->end_y,
|
||||
N_SNAP_LINES);
|
||||
}
|
||||
|
||||
gimp_tool_pop_status (tool, display);
|
||||
|
@ -319,7 +321,8 @@ gimp_blend_tool_active_modifier_key (GimpTool *tool,
|
|||
if (press)
|
||||
{
|
||||
gimp_tool_motion_constrain (blend_tool->start_x, blend_tool->start_y,
|
||||
&blend_tool->end_x, &blend_tool->end_y);
|
||||
&blend_tool->end_x, &blend_tool->end_y,
|
||||
N_SNAP_LINES);
|
||||
}
|
||||
|
||||
gimp_tool_pop_status (tool, display);
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
|
||||
#define TARGET 12
|
||||
#define ARC_RADIUS 30
|
||||
#define N_SNAP_LINES 12
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
@ -434,7 +435,9 @@ gimp_measure_tool_motion (GimpTool *tool,
|
|||
gdouble x = measure->x[i];
|
||||
gdouble y = measure->y[i];
|
||||
|
||||
gimp_tool_motion_constrain (measure->x[0], measure->y[0], &x, &y);
|
||||
gimp_tool_motion_constrain (measure->x[0], measure->y[0],
|
||||
&x, &y,
|
||||
N_SNAP_LINES);
|
||||
|
||||
measure->x[i] = ROUND (x);
|
||||
measure->y[i] = ROUND (y);
|
||||
|
@ -505,7 +508,9 @@ gimp_measure_tool_active_modifier_key (GimpTool *tool,
|
|||
y = measure->mouse_y;
|
||||
|
||||
if (press)
|
||||
gimp_tool_motion_constrain (measure->x[0], measure->y[0], &x, &y);
|
||||
gimp_tool_motion_constrain (measure->x[0], measure->y[0],
|
||||
&x, &y,
|
||||
N_SNAP_LINES);
|
||||
|
||||
measure->x[measure->point] = ROUND (x);
|
||||
measure->y[measure->point] = ROUND (y);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
#define HANDLE_SIZE 15
|
||||
#define STATUSBAR_SIZE 200
|
||||
#define N_SNAP_LINES 12
|
||||
|
||||
|
||||
static GObject * gimp_paint_tool_constructor (GType type,
|
||||
|
@ -256,7 +257,8 @@ gimp_paint_tool_round_line (GimpPaintCore *core,
|
|||
/* Restrict to multiples of 15 degrees if ctrl is pressed */
|
||||
if (state & GDK_CONTROL_MASK)
|
||||
gimp_tool_motion_constrain (core->last_coords.x, core->last_coords.y,
|
||||
&core->cur_coords.x, &core->cur_coords.y);
|
||||
&core->cur_coords.x, &core->cur_coords.y,
|
||||
N_SNAP_LINES);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -25,34 +25,46 @@
|
|||
#include "tools-utils.h"
|
||||
|
||||
|
||||
static gdouble gimp_tool_utils_point_to_line_distance (const GimpVector2 *point,
|
||||
const GimpVector2 *point_on_line,
|
||||
const GimpVector2 *normalized_line_direction,
|
||||
GimpVector2 *closest_line_point);
|
||||
|
||||
|
||||
/**
|
||||
* gimp_tool_motion_constrain_helper:
|
||||
* @dx: the (fixed) delta-x
|
||||
* @dy: a suggested delta-y
|
||||
* gimp_tool_utils_point_to_line_distance:
|
||||
* @point: The point to calculate the distance for.
|
||||
* @point_on_line: A point on the line.
|
||||
* @line_direction: Normalized line direction vector.
|
||||
* @closest_line_point: Gets set to the point on the line that is
|
||||
* closest to @point.
|
||||
*
|
||||
* Returns: An adjusted dy' near dy such that the slope (dx,dy')
|
||||
* is a multiple of 15 degrees.
|
||||
* Returns: The shortest distance from @point to the line defined by
|
||||
* @point_on_line and @normalized_line_direction.
|
||||
**/
|
||||
static gdouble
|
||||
gimp_tool_motion_constrain_helper (gdouble dx,
|
||||
gdouble dy)
|
||||
gimp_tool_utils_point_to_line_distance (const GimpVector2 *point,
|
||||
const GimpVector2 *point_on_line,
|
||||
const GimpVector2 *line_direction,
|
||||
GimpVector2 *closest_line_point)
|
||||
{
|
||||
static const gdouble slope[4] = { 0, 0.26795, 0.57735, 1 };
|
||||
static const gdouble divider[3] = { 0.13165, 0.41421, 0.76732 };
|
||||
gint i;
|
||||
GimpVector2 distance_vector;
|
||||
GimpVector2 tmp_a;
|
||||
GimpVector2 tmp_b;
|
||||
gdouble d;
|
||||
|
||||
if (dy < 0)
|
||||
return - gimp_tool_motion_constrain_helper (dx, -dy);
|
||||
gimp_vector2_sub (&tmp_a, point, point_on_line);
|
||||
|
||||
dx = fabs (dx);
|
||||
d = gimp_vector2_inner_product (&tmp_a, line_direction);
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
if (dy < dx * divider[i])
|
||||
break;
|
||||
tmp_b = gimp_vector2_mul_val (*line_direction, d);
|
||||
|
||||
dy = dx * slope[i];
|
||||
*closest_line_point = gimp_vector2_add_val (*point_on_line,
|
||||
tmp_b);
|
||||
|
||||
return dy;
|
||||
gimp_vector2_sub (&distance_vector, closest_line_point, point);
|
||||
|
||||
return gimp_vector2_length (&distance_vector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,33 +73,47 @@ gimp_tool_motion_constrain_helper (gdouble dx,
|
|||
* @start_y:
|
||||
* @end_x:
|
||||
* @end_y:
|
||||
* @n_snap_lines: Number evenly disributed lines to snap to.
|
||||
*
|
||||
* Restricts the motion vector to 15 degree steps by changing the end
|
||||
* point (if necessary).
|
||||
* Projects a line onto the specified subset of evenly radially
|
||||
* distributed lines. @n_lines of 2 makes the line snap horizontally
|
||||
* or vertically. @n_lines of 4 snaps on 45 degree steps. @n_lines of
|
||||
* 12 on 15 degree steps. etc.
|
||||
**/
|
||||
void
|
||||
gimp_tool_motion_constrain (gdouble start_x,
|
||||
gdouble start_y,
|
||||
gdouble *end_x,
|
||||
gdouble *end_y)
|
||||
gimp_tool_motion_constrain (gdouble start_x,
|
||||
gdouble start_y,
|
||||
gdouble *end_x,
|
||||
gdouble *end_y,
|
||||
gint n_snap_lines)
|
||||
{
|
||||
gdouble dx = *end_x - start_x;
|
||||
gdouble dy = *end_y - start_y;
|
||||
GimpVector2 line_point = { start_x, start_y };
|
||||
GimpVector2 point = { *end_x, *end_y };
|
||||
GimpVector2 constrained_point;
|
||||
GimpVector2 line_dir;
|
||||
gdouble shortest_dist_moved = G_MAXDOUBLE;
|
||||
gdouble dist_moved;
|
||||
gdouble angle;
|
||||
gint i;
|
||||
|
||||
/* 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_tool_motion_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.
|
||||
*/
|
||||
for (i = 0; i < n_snap_lines; i++)
|
||||
{
|
||||
angle = i * G_PI / n_snap_lines;
|
||||
|
||||
if (fabs (dx) > fabs (dy))
|
||||
*end_y = (start_y + gimp_tool_motion_constrain_helper (dx, dy));
|
||||
else
|
||||
*end_x = (start_x + gimp_tool_motion_constrain_helper (dy, dx));
|
||||
gimp_vector2_set (&line_dir,
|
||||
cos (angle),
|
||||
sin (angle));
|
||||
|
||||
dist_moved = gimp_tool_utils_point_to_line_distance (&point,
|
||||
&line_point,
|
||||
&line_dir,
|
||||
&constrained_point);
|
||||
if (dist_moved < shortest_dist_moved)
|
||||
{
|
||||
shortest_dist_moved = dist_moved;
|
||||
|
||||
*end_x = constrained_point.x;
|
||||
*end_y = constrained_point.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
void gimp_tool_motion_constrain (gdouble start_x,
|
||||
gdouble start_y,
|
||||
gdouble *end_x,
|
||||
gdouble *end_y);
|
||||
gdouble *end_y,
|
||||
gint n_snap_lines);
|
||||
|
||||
|
||||
#endif /* __TOOLS_UTILS_H__ */
|
||||
|
|
Loading…
Reference in a new issue