app: add "orientation" property to GimpToolCompass + improvements

Add an "orientation" property to GimpToolCompass, which can be one
of "auto", "horizontal", or "vertical", and which controls the
orientation of the line against which the angle is measured, when
not in 3-point mode (previously, the line would always be
horizontal.)  When "orientation" is "auto", the orientation is
automatically set to either horizontal or vertical, such that the
measured angle is <= 45 deg.

Keep the line horizontal, or vertical, in display-space, rather
than in image-space, so that the compass works correctly even when
the canvas is rotated and/or flipped.

Fix the compass's behavior when the image's horizontal and vertical
resolutions are different, both with and without dot-for-dot.

Add "pixel-angle" and "unit-angle" read-only properties, which
return the measured angle either with or without taking the image's
resolution into account, respectively.  These properties will be
used by the measure tool in the next commit, instead of having it
implement its own angle calculation.

(cherry picked from commit d2f33cf1be)
This commit is contained in:
Ell
2018-07-15 18:07:54 -04:00
parent 4cb91320a4
commit fc4ca7fbcf
5 changed files with 291 additions and 188 deletions

View File

@ -455,6 +455,37 @@ gimp_vector_mode_get_type (void)
return type;
}
GType
gimp_compass_orientation_get_type (void)
{
static const GEnumValue values[] =
{
{ GIMP_COMPASS_ORIENTATION_AUTO, "GIMP_COMPASS_ORIENTATION_AUTO", "auto" },
{ GIMP_COMPASS_ORIENTATION_HORIZONTAL, "GIMP_COMPASS_ORIENTATION_HORIZONTAL", "horizontal" },
{ GIMP_COMPASS_ORIENTATION_VERTICAL, "GIMP_COMPASS_ORIENTATION_VERTICAL", "vertical" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
{ GIMP_COMPASS_ORIENTATION_AUTO, NC_("compass-orientation", "Auto"), NULL },
{ GIMP_COMPASS_ORIENTATION_HORIZONTAL, NC_("compass-orientation", "Horizontal"), NULL },
{ GIMP_COMPASS_ORIENTATION_VERTICAL, NC_("compass-orientation", "Vertical"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("GimpCompassOrientation", values);
gimp_type_set_translation_context (type, "compass-orientation");
gimp_enum_set_value_descriptions (type, descs);
}
return type;
}
GType
gimp_zoom_focus_get_type (void)
{

View File

@ -197,6 +197,18 @@ typedef enum
} GimpVectorMode;
#define GIMP_TYPE_COMPASS_ORIENTATION (gimp_compass_orientation_get_type ())
GType gimp_compass_orientation_get_type (void) G_GNUC_CONST;
typedef enum
{
GIMP_COMPASS_ORIENTATION_AUTO, /*< desc="Auto" >*/
GIMP_COMPASS_ORIENTATION_HORIZONTAL, /*< desc="Horizontal" >*/
GIMP_COMPASS_ORIENTATION_VERTICAL /*< desc="Vertical" >*/
} GimpCompassOrientation;
#define GIMP_TYPE_ZOOM_FOCUS (gimp_zoom_focus_get_type ())
GType gimp_zoom_focus_get_type (void) G_GNUC_CONST;

View File

@ -42,6 +42,7 @@
#include "gimpdisplay.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-appearance.h"
#include "gimpdisplayshell-transform.h"
#include "gimpdisplayshell-utils.h"
#include "gimptoolcompass.h"
@ -49,6 +50,8 @@
#define ARC_RADIUS 30
#define EPSILON 1e-6
/* possible measure functions */
typedef enum
@ -64,13 +67,16 @@ typedef enum
enum
{
PROP_0,
PROP_ORIENTATION,
PROP_N_POINTS,
PROP_X1,
PROP_Y1,
PROP_X2,
PROP_Y2,
PROP_X3,
PROP_Y3
PROP_Y3,
PROP_PIXEL_ANGLE,
PROP_UNIT_ANGLE
};
enum
@ -81,12 +87,16 @@ enum
struct _GimpToolCompassPrivate
{
GimpCompassOrientation orientation;
gint n_points;
gint x[3];
gint y[3];
gdouble angle1;
gdouble angle2;
GimpVector2 radius1;
GimpVector2 radius2;
gdouble display_angle;
gdouble pixel_angle;
gdouble unit_angle;
CompassFunction function;
gdouble mouse_x;
@ -97,8 +107,8 @@ struct _GimpToolCompassPrivate
GimpCanvasItem *line1;
GimpCanvasItem *line2;
GimpCanvasItem *angle;
GimpCanvasItem *angle_line;
GimpCanvasItem *arc;
GimpCanvasItem *arc_line;
GimpCanvasItem *handles[3];
};
@ -153,6 +163,9 @@ static gboolean gimp_tool_compass_get_cursor (GimpToolWidget *widget
static gint gimp_tool_compass_get_point (GimpToolCompass *compass,
const GimpCoords *coords);
static void gimp_tool_compass_update_hilight (GimpToolCompass *compass);
static void gimp_tool_compass_update_angle (GimpToolCompass *compass,
GimpCompassOrientation orientation,
gboolean flip);
G_DEFINE_TYPE (GimpToolCompass, gimp_tool_compass, GIMP_TYPE_TOOL_WIDGET)
@ -195,6 +208,13 @@ gimp_tool_compass_class_init (GimpToolCompassClass *klass)
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN);
g_object_class_install_property (object_class, PROP_ORIENTATION,
g_param_spec_enum ("orientation", NULL, NULL,
GIMP_TYPE_COMPASS_ORIENTATION,
GIMP_COMPASS_ORIENTATION_AUTO,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_N_POINTS,
g_param_spec_int ("n-points", NULL, NULL,
1, 3, 1,
@ -243,6 +263,16 @@ gimp_tool_compass_class_init (GimpToolCompassClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_PIXEL_ANGLE,
g_param_spec_double ("pixel-angle", NULL, NULL,
-G_PI, G_PI, 0.0,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_UNIT_ANGLE,
g_param_spec_double ("unit-angle", NULL, NULL,
-G_PI, G_PI, 0.0,
GIMP_PARAM_READABLE));
g_type_class_add_private (klass, sizeof (GimpToolCompassPrivate));
}
@ -256,72 +286,6 @@ gimp_tool_compass_init (GimpToolCompass *compass)
compass->private->point = -1;
}
static gdouble
gimp_tool_compass_get_angle (gint dx,
gint dy,
gdouble xres,
gdouble yres)
{
gdouble angle;
if (dx)
angle = gimp_rad_to_deg (atan (((gdouble) (dy) / yres) /
((gdouble) (dx) / xres)));
else if (dy)
angle = dy > 0 ? 270.0 : 90.0;
else
angle = 180.0;
if (dx > 0)
{
if (dy > 0)
angle = 360.0 - angle;
else
angle = -angle;
}
else
{
angle = 180.0 - angle;
}
return angle;
}
static void
gimp_tool_compass_update_angles (GimpToolCompass *compass)
{
GimpToolWidget *widget = GIMP_TOOL_WIDGET (compass);
GimpToolCompassPrivate *private = compass->private;
GimpDisplayShell *shell = gimp_tool_widget_get_shell (widget);
GimpImage *image = gimp_display_get_image (shell->display);
gint ax, ay;
gint bx, by;
gdouble xres;
gdouble yres;
ax = private->x[1] - private->x[0];
ay = private->y[1] - private->y[0];
if (private->n_points == 3)
{
bx = private->x[2] - private->x[0];
by = private->y[2] - private->y[0];
}
else
{
bx = 0;
by = 0;
}
gimp_image_get_resolution (image, &xres, &yres);
if (private->n_points != 3)
bx = ax > 0 ? 1 : -1;
private->angle1 = gimp_tool_compass_get_angle (ax, ay, xres, yres);
private->angle2 = gimp_tool_compass_get_angle (bx, by, xres, yres);
}
static void
gimp_tool_compass_constructed (GObject *object)
{
@ -349,7 +313,7 @@ gimp_tool_compass_constructed (GObject *object)
private->x[2],
private->y[2]);
private->angle = gimp_tool_widget_add_handle (widget,
private->arc = gimp_tool_widget_add_handle (widget,
GIMP_HANDLE_CIRCLE,
private->x[0],
private->y[0],
@ -357,7 +321,7 @@ gimp_tool_compass_constructed (GObject *object)
ARC_RADIUS * 2 + 1,
GIMP_HANDLE_ANCHOR_CENTER);
private->angle_line = gimp_tool_widget_add_line (widget,
private->arc_line = gimp_tool_widget_add_line (widget,
private->x[0],
private->y[0],
private->x[0] + 10,
@ -413,6 +377,9 @@ gimp_tool_compass_set_property (GObject *object,
case PROP_Y3:
private->y[2] = g_value_get_int (value);
break;
case PROP_ORIENTATION:
private->orientation = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -452,6 +419,15 @@ gimp_tool_compass_get_property (GObject *object,
case PROP_Y3:
g_value_set_int (value, private->y[2]);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, private->orientation);
break;
case PROP_PIXEL_ANGLE:
g_value_set_double (value, private->pixel_angle);
break;
case PROP_UNIT_ANGLE:
g_value_set_double (value, private->unit_angle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -468,10 +444,13 @@ gimp_tool_compass_changed (GimpToolWidget *widget)
gdouble angle1;
gdouble angle2;
gint draw_arc = 0;
gdouble target;
gdouble arc_radius;
gdouble arc_line_length;
gimp_tool_compass_update_angles (compass);
gimp_tool_compass_update_angle (compass, private->orientation, FALSE);
angle1 = -atan2 (private->radius1.y * shell->scale_y,
private->radius1.x * shell->scale_x);
angle2 = -private->display_angle;
gimp_canvas_line_set (private->line1,
private->x[0],
@ -505,36 +484,26 @@ gimp_tool_compass_changed (GimpToolWidget *widget)
draw_arc++;
}
angle1 = private->angle2 / 180.0 * G_PI;
angle2 = (private->angle1 - private->angle2) / 180.0 * G_PI;
if (angle2 > G_PI)
angle2 -= 2.0 * G_PI;
if (angle2 < -G_PI)
angle2 += 2.0 * G_PI;
gimp_canvas_handle_set_position (private->angle,
gimp_canvas_handle_set_position (private->arc,
private->x[0], private->y[0]);
gimp_canvas_handle_set_angles (private->angle, angle1, angle2);
gimp_canvas_item_set_visible (private->angle,
gimp_canvas_handle_set_angles (private->arc, angle1, angle2);
gimp_canvas_item_set_visible (private->arc,
private->n_points > 1 &&
draw_arc == private->n_points - 1 &&
angle2 != 0.0);
fabs (angle2) > EPSILON);
target = FUNSCALEX (shell, (GIMP_CANVAS_HANDLE_SIZE_CROSS >> 1));
arc_radius = FUNSCALEX (shell, ARC_RADIUS);
arc_line_length = (ARC_RADIUS + (GIMP_CANVAS_HANDLE_SIZE_CROSS >> 1)) /
hypot (private->radius2.x * shell->scale_x,
private->radius2.y * shell->scale_y);
gimp_canvas_line_set (private->angle_line,
gimp_canvas_line_set (private->arc_line,
private->x[0],
private->y[0],
private->x[0] + (private->x[1] > private->x[0] ?
(arc_radius + target) :
-(arc_radius + target)),
private->y[0]);
gimp_canvas_item_set_visible (private->angle_line,
private->x[0] + private->radius2.x * arc_line_length,
private->y[0] + private->radius2.y * arc_line_length);
gimp_canvas_item_set_visible (private->arc_line,
private->n_points == 2 &&
angle2 != 0.0);
fabs (angle2) > EPSILON);
gimp_canvas_handle_set_position (private->handles[0],
private->x[0], private->y[0]);
@ -1051,11 +1020,99 @@ gimp_tool_compass_update_hilight (GimpToolCompass *compass)
}
}
static void
gimp_tool_compass_update_angle (GimpToolCompass *compass,
GimpCompassOrientation orientation,
gboolean flip)
{
GimpToolWidget *widget = GIMP_TOOL_WIDGET (compass);
GimpToolCompassPrivate *private = compass->private;
GimpDisplayShell *shell = gimp_tool_widget_get_shell (widget);
GimpImage *image = gimp_display_get_image (shell->display);
GimpVector2 radius1;
GimpVector2 radius2;
gdouble xres;
gdouble yres;
gimp_image_get_resolution (image, &xres, &yres);
private->radius1.x = private->x[1] - private->x[0];
private->radius1.y = private->y[1] - private->y[0];
if (private->n_points == 3)
{
private->radius2.x = private->x[2] - private->x[0];
private->radius2.y = private->y[2] - private->y[0];
}
else
{
gdouble angle = -shell->rotate_angle * G_PI / 180.0;
if (orientation == GIMP_COMPASS_ORIENTATION_VERTICAL)
angle -= G_PI / 2.0;
if (flip)
angle += G_PI;
if (shell->flip_horizontally)
angle = G_PI - angle;
if (shell->flip_vertically)
angle = -angle;
private->radius2.x = cos (angle);
private->radius2.y = sin (angle);
if (! shell->dot_for_dot)
{
private->radius2.x *= xres;
private->radius2.y *= yres;
gimp_vector2_normalize (&private->radius2);
}
}
radius1 = private->radius1;
radius2 = private->radius2;
private->pixel_angle = atan2 (gimp_vector2_cross_product (&radius1, &radius2).x,
gimp_vector2_inner_product (&radius1, &radius2));
radius1.x /= xres;
radius1.y /= yres;
radius2.x /= xres;
radius2.y /= yres;
private->unit_angle = atan2 (gimp_vector2_cross_product (&radius1, &radius2).x,
gimp_vector2_inner_product (&radius1, &radius2));
if (shell->dot_for_dot)
private->display_angle = private->pixel_angle;
else
private->display_angle = private->unit_angle;
if (private->n_points == 2)
{
if (! flip && fabs (private->display_angle) > G_PI / 2.0 + EPSILON)
{
gimp_tool_compass_update_angle (compass, orientation, TRUE);
}
else if (orientation == GIMP_COMPASS_ORIENTATION_AUTO &&
fabs (private->display_angle) > G_PI / 4.0 + EPSILON)
{
gimp_tool_compass_update_angle (compass,
GIMP_COMPASS_ORIENTATION_VERTICAL,
FALSE);
}
}
}
/* public functions */
GimpToolWidget *
gimp_tool_compass_new (GimpDisplayShell *shell,
GimpCompassOrientation orientation,
gint n_points,
gint x1,
gint y1,
@ -1068,6 +1125,7 @@ gimp_tool_compass_new (GimpDisplayShell *shell,
return g_object_new (GIMP_TYPE_TOOL_COMPASS,
"shell", shell,
"orientation", orientation,
"n-points", n_points,
"x1", x1,
"y1", y1,

View File

@ -59,6 +59,7 @@ struct _GimpToolCompassClass
GType gimp_tool_compass_get_type (void) G_GNUC_CONST;
GimpToolWidget * gimp_tool_compass_new (GimpDisplayShell *shell,
GimpCompassOrientation orinetation,
gint n_points,
gint x1,
gint y1,

View File

@ -436,6 +436,7 @@ gimp_measure_tool_start (GimpMeasureTool *measure,
measure->y[2] = 0;
measure->widget = gimp_tool_compass_new (shell,
GIMP_COMPASS_ORIENTATION_AUTO,
measure->n_points,
measure->x[0],
measure->y[0],